Packages
ra
2.16.0-pre.9
3.1.9
3.1.8
3.1.7
3.1.6
3.1.5
3.1.4
3.1.3
3.1.2
3.1.1
3.1.0
3.0.2
3.0.1
3.0.0
3.0.0-beta.1
2.17.3
2.17.2
2.17.1
2.17.0
2.16.13
2.16.12
2.16.11
2.16.10
2.16.9
2.16.8
2.16.7
2.16.6
2.16.5
2.16.4
2.16.3
2.16.2
2.16.1
2.16.0
2.16.0-pre.12
2.16.0-pre.11
2.16.0-pre.10
2.16.0-pre.9
2.16.0-pre.8
2.16.0-pre.7
2.16.0-pre.6
2.16.0-pre.5
2.16.0-pre.4
2.16.0-pre.3
2.16.0-pre.2
2.16.0-pre.1
2.15.4
2.15.3
2.15.2
2.15.1
2.15.0
2.14.0
2.13.6
2.13.5
2.13.4
2.13.3
2.13.2
2.13.1
2.13.0
2.13.0-pre.1
2.12.0
2.11.0
2.11.0-pre.1
2.10.2-pre.2
2.10.2-pre.1
2.10.1
2.10.0
2.10.0-pre.3
2.10.0-pre.2
2.10.0-pre.1
2.9.10-pre.1
2.9.1
2.9.1-pre.2
2.9.1-pre.1
2.9.0
2.8.0
retired
2.7.3
2.7.2
2.7.1
2.7.0
2.7.0-pre.3
2.7.0-pre.2
2.7.0-pre.1
2.6.3
2.6.2
2.6.1
2.6.0-pre.1
2.5.1
2.5.1-pre.1
2.5.0
2.4.9
2.4.8
2.4.7
2.4.6
2.4.5
2.4.4
2.4.3
2.4.2
retired
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.13
2.0.12
2.0.11
2.0.10
2.0.9
2.0.8
2.0.7
2.0.6
2.0.5
2.0.4
2.0.3
2.0.2
2.0.1
2.0.0
1.1.9
1.1.8
1.1.7
1.1.6
1.1.5
1.1.4
1.1.3
1.1.2
1.1.1
1.1.0
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.9.6
0.9.5
0.9.4
0.9.2
0.3.3
retired
0.3.2
retired
0.3.1
retired
Raft library
Current section
Files
Jump to
Current section
Files
src/ra_bench.erl
%% This Source Code Form is subject to the terms of the Mozilla Public
%% License, v. 2.0. If a copy of the MPL was not distributed with this
%% file, You can obtain one at https://mozilla.org/MPL/2.0/.
%%
%% Copyright (c) 2017-2023 Broadcom. All Rights Reserved. The term Broadcom refers to Broadcom Inc. and/or its subsidiaries.
%%
%% @hidden
-module(ra_bench).
-behaviour(ra_machine).
-compile(inline_list_funcs).
-compile(inline).
-compile({no_auto_import, [apply/3]}).
-include_lib("eunit/include/eunit.hrl").
-define(PIPE_SIZE, 500).
-define(DATA_SIZE, 256).
-export([
init/1,
apply/3,
% profile/0,
% stop_profile/0
prepare/0,
run/3,
run/2,
run/1,
run/0,
print_metrics/1
]).
-define(TARGET_OPS_SEC, 100000).
-define(TARGET_SEC, 60).
-define(DEGREE, 5).
init(#{}) ->
undefined.
% msg_ids are scoped per customer
% ra_indexes holds all raft indexes for enqueues currently on queue
apply(#{index := I}, {noop, _}, State) ->
case I rem 100000 of
0 ->
{State, ok, {release_cursor, I, State}};
_ ->
{State, ok}
end.
run(Name, Nodes) ->
run(Name, Nodes, ?PIPE_SIZE).
run(Name, Nodes, Pipe)
when is_atom(Name)
andalso is_list(Nodes) ->
run(#{name => Name,
seconds => ?TARGET_SEC,
target => ?TARGET_OPS_SEC,
degree => ?DEGREE,
pipe => Pipe,
nodes => Nodes}).
run() ->
run(#{name => noop,
seconds => ?TARGET_SEC,
target => ?TARGET_OPS_SEC,
degree => ?DEGREE,
nodes => [node() | nodes()]}).
print_counter(Last, Counter) ->
V = counters:get(Counter, 1),
io:format("ops/sec: ~b~n", [ V - Last]),
timer:sleep(1000),
print_counter(V, Counter).
run(Nodes) when is_list(Nodes) ->
run(#{name => noop,
seconds => ?TARGET_SEC,
target => ?TARGET_OPS_SEC,
degree => ?DEGREE,
nodes => Nodes});
run(#{name := Name,
seconds := Secs,
target := Target,
nodes := Nodes,
degree := Degree} = Conf) ->
Pipe = maps:get(pipe, Conf, ?PIPE_SIZE),
io:format("running ra benchmark config: ~p~n", [Conf]),
io:format("starting servers on ~w~n", [Nodes]),
{ok, ServerIds, []} = start(Name, Nodes),
{ok, _, Leader} = ra:members(hd(ServerIds)),
TotalOps = Secs * Target,
Each = max(Pipe, TotalOps div Degree),
DataSize = maps:get(data_size, Conf, ?DATA_SIZE),
Counter = counters:new(1, [write_concurrency]),
Pids = [spawn_client(self(), Leader, Each, DataSize, Pipe, Counter)
|| _ <- lists:seq(1, Degree)],
io:format("running bench mark...~n", []),
Start = erlang:system_time(millisecond),
[P ! go || P <- Pids],
CounterPrinter = spawn(fun () ->
print_counter(counters:get(Counter, 1), Counter)
end),
%% wait for each pid
Wait = ((Secs * 10000) * 4),
[begin
receive
{done, P} ->
io:format("~w is done ", [P]),
ok
after Wait ->
exit({timeout, P})
end
end || P <- Pids],
End = erlang:system_time(millisecond),
Taken = End - Start,
exit(CounterPrinter, kill),
io:format("benchmark completed: ~b ops in ~bms rate ~.2f ops/sec~n",
[TotalOps, Taken, TotalOps / (Taken / 1000)]),
BName = atom_to_binary(Name, utf8),
_ = [rpc:call(N, ?MODULE, print_metrics, [BName])
|| N <- Nodes],
% _ = ra:delete_cluster(ServerIds),
%%
ok.
start(Name, Nodes) when is_atom(Name) ->
ServerIds = [{Name, N} || N <- Nodes],
Configs = [begin
rpc:call(N, ?MODULE, prepare, []),
Id = {Name, N},
UId = ra:new_uid(ra_lib:to_binary(Name)),
#{id => Id,
uid => UId,
cluster_name => Name,
metrics_key => atom_to_binary(Name, utf8),
log_init_args => #{uid => UId},
initial_members => ServerIds,
machine => {module, ?MODULE, #{}}}
end || N <- Nodes],
ra:start_cluster(default, Configs).
prepare() ->
_ = application:ensure_all_started(ra),
_ = ra_system:start_default(),
ra_env:configure_logger(logger),
LogFile = filename:join(ra_env:data_dir(), "ra-" ++ atom_to_list(node()) ++ ".log"),
logger:set_primary_config(level, debug),
Config = #{config => #{file => LogFile}},
logger:add_handler(ra_handler, logger_std_h, Config),
% application:load(sasl),
% application:set_env(sasl, sasl_error_logger, {file, SaslFile}),
ok.
send_n(_, _Data, 0, _Counter) -> ok;
send_n(Leader, Data, N, Counter) ->
ra:pipeline_command(Leader, {noop, Data}, make_ref(), normal),
counters:add(Counter, 1, 1),
send_n(Leader, Data, N-1, Counter).
client_loop(0, 0, _Leader, _Data, _Counter) ->
ok;
client_loop(Num, Sent, _Leader, Data, Counter) ->
receive
{ra_event, Leader, {applied, Applied}} ->
N = length(Applied),
ToSend = min(Sent, N),
send_n(Leader, Data, ToSend, Counter),
client_loop(Num - N, Sent - ToSend, Leader, Data, Counter);
{ra_event, _, {rejected, {not_leader, NewLeader, _}}} ->
io:format("new leader ~w~n", [NewLeader]),
send_n(NewLeader, Data, 1, Counter),
client_loop(Num, Sent, NewLeader, Data, Counter);
{ra_event, Leader, Evt} ->
io:format("unexpected ra_event ~w~n", [Evt]),
client_loop(Num, Sent, Leader, Data, Counter)
end.
spawn_client(Parent, Leader, Num, DataSize, Pipe, Counter) ->
Data = crypto:strong_rand_bytes(DataSize),
spawn_link(
fun () ->
%% first send one 1000 noop commands
%% then top up as they are applied
receive
go ->
send_n(Leader, Data, Pipe, Counter),
ok = client_loop(Num, Num - Pipe, Leader, Data, Counter),
Parent ! {done, self()}
end
end).
print_metrics(Name) ->
io:format("Node: ~w~n", [node()]),
io:format("metrics ~p~n", [ets:lookup(ra_metrics, Name)]),
io:format("counters ~p~n", [ra_counters:overview()]).
% profile() ->
% GzFile = atom_to_list(node()) ++ ".gz",
% lg:trace([noop, ra_server, ra_server_proc, ra_snapshot, ra_machine,
% ra_log, ra_flru, ra_machine, ra_log_meta, ra_log_segment],
% lg_file_tracer,
% GzFile, #{running => false, mode => profile}),
% ok.
% stop_profile() ->
% lg:stop(),
% Base = atom_to_list(node()),
% GzFile = Base ++ ".gz.*",
% lg_callgrind:profile_many(GzFile, Base ++ ".out",#{}),
% ok.