chore: add emqx_broker_bench.erl
This commit is contained in:
parent
910449e67b
commit
d926800204
|
@ -106,8 +106,9 @@ test_deps() ->
|
||||||
common_compile_opts() ->
|
common_compile_opts() ->
|
||||||
[ debug_info % alwyas include debug_info
|
[ debug_info % alwyas include debug_info
|
||||||
, {compile_info, [{emqx_vsn, get_vsn()}]}
|
, {compile_info, [{emqx_vsn, get_vsn()}]}
|
||||||
| [{d, 'EMQX_ENTERPRISE'} || is_enterprise()]
|
] ++
|
||||||
].
|
[{d, 'EMQX_ENTERPRISE'} || is_enterprise()] ++
|
||||||
|
[{d, 'EMQX_BENCHMARK'} || os:getenv("EMQX_BENCHMARK") =:= "1" ].
|
||||||
|
|
||||||
prod_compile_opts() ->
|
prod_compile_opts() ->
|
||||||
[ compressed
|
[ compressed
|
||||||
|
|
|
@ -0,0 +1,115 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2021 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
%% you may not use this file except in compliance with the License.
|
||||||
|
%% You may obtain a copy of the License at
|
||||||
|
%%
|
||||||
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
%%
|
||||||
|
%% Unless required by applicable law or agreed to in writing, software
|
||||||
|
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
%% See the License for the specific language governing permissions and
|
||||||
|
%% limitations under the License.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_broker_bench).
|
||||||
|
|
||||||
|
-ifdef(EMQX_BENCHMARK).
|
||||||
|
|
||||||
|
-export([start/1, run1/0, run1/2]).
|
||||||
|
|
||||||
|
run1() -> run1(4, 1000).
|
||||||
|
|
||||||
|
run1(Factor, Limit) ->
|
||||||
|
start(#{factor => Factor,
|
||||||
|
limit => Limit,
|
||||||
|
sub_ptn => <<"device/{{id}}/+/{{num}}/#">>,
|
||||||
|
pub_ptn => <<"device/{{id}}/xays/{{num}}/foo/bar/baz">>}).
|
||||||
|
|
||||||
|
%% setting fields:
|
||||||
|
%% - factor: spawn broker-pool-size * factor number of callers
|
||||||
|
%% - limit: limit the total number of topics for each caller
|
||||||
|
%% - sub_ptn: subscribe topic pattern like a/+/b/+/c/#
|
||||||
|
%% or a/+/{{id}}/{{num}}/# to generate pattern with {{id}}
|
||||||
|
%% replaced by worker id and {{num}} replaced by topic number.
|
||||||
|
%% - pub_ptn: topic pattern used to benchmark publish (match) performance
|
||||||
|
%% e.g. a/x/{{id}}/{{num}}/foo/bar
|
||||||
|
start(#{factor := Factor} = Settings) ->
|
||||||
|
BrokerPoolSize = emqx_vm:schedulers() * 2,
|
||||||
|
Pids = start_callers(BrokerPoolSize * Factor, Settings),
|
||||||
|
R = collect_results(Pids, #{subscribe => 0, match => 0}),
|
||||||
|
io:format(user, "mnesia table(s) RAM: ~p~n", [ram_bytes()]),
|
||||||
|
io:format(user, "~p~n", [erlang:memory()]),
|
||||||
|
io:format(user, "~p~n", [R]),
|
||||||
|
lists:foreach(fun(Pid) -> Pid ! stop end, Pids).
|
||||||
|
|
||||||
|
ram_bytes() ->
|
||||||
|
Wordsize = erlang:system_info(wordsize),
|
||||||
|
mnesia:table_info(emqx_trie, memory) * Wordsize +
|
||||||
|
case lists:member(emqx_trie_node, ets:all()) of
|
||||||
|
true ->
|
||||||
|
%% before 4.3
|
||||||
|
mnesia:table_info(emqx_trie_node, memory) * Wordsize;
|
||||||
|
false ->
|
||||||
|
0
|
||||||
|
end.
|
||||||
|
|
||||||
|
start_callers(0, _) -> [];
|
||||||
|
start_callers(N, Settings) ->
|
||||||
|
[start_caller(Settings#{id => N}) | start_callers(N - 1, Settings)].
|
||||||
|
|
||||||
|
collect_results([], R) -> R;
|
||||||
|
collect_results([Pid | Pids], Acc = #{subscribe := Sr, match := Mr}) ->
|
||||||
|
receive
|
||||||
|
{Pid, #{subscribe := Srd, match := Mrd}} ->
|
||||||
|
collect_results(Pids, Acc#{subscribe := Sr + Srd, match := Mr + Mrd})
|
||||||
|
end.
|
||||||
|
|
||||||
|
%% ops per second
|
||||||
|
rps(T, N) -> round(N / (T / 1000000)).
|
||||||
|
|
||||||
|
start_caller(#{id := Id, limit := N, sub_ptn := SubPtn, pub_ptn := PubPtn}) ->
|
||||||
|
Parent = self(),
|
||||||
|
proc_lib:spawn_link(
|
||||||
|
fun() ->
|
||||||
|
SubTopics = make_topics(SubPtn, Id, N),
|
||||||
|
{Ts, _} = timer:tc(fun() -> subscribe(SubTopics) end),
|
||||||
|
PubTopics = make_topics(PubPtn, Id, N),
|
||||||
|
{Tm, _} = timer:tc(fun() -> match(PubTopics) end),
|
||||||
|
_ = erlang:send(Parent, {self(), #{subscribe => rps(Ts, N), match => rps(Tm, N)}}),
|
||||||
|
receive
|
||||||
|
stop ->
|
||||||
|
ok
|
||||||
|
end
|
||||||
|
end).
|
||||||
|
|
||||||
|
match([]) -> ok;
|
||||||
|
match([Topic | Topics]) ->
|
||||||
|
_ = emqx_router:lookup_routes(Topic),
|
||||||
|
match(Topics).
|
||||||
|
|
||||||
|
subscribe([]) -> ok;
|
||||||
|
subscribe([Topic | Rest]) ->
|
||||||
|
ok = emqx_broker:subscribe(Topic),
|
||||||
|
subscribe(Rest).
|
||||||
|
|
||||||
|
make_topics(SubPtn0, Id, Limit) ->
|
||||||
|
SubPtn = emqx_topic:words(SubPtn0),
|
||||||
|
F = fun(N) -> render(Id, N, SubPtn) end,
|
||||||
|
lists:map(F, lists:seq(1, Limit)).
|
||||||
|
|
||||||
|
render(ID, N, Ptn) ->
|
||||||
|
render(ID, N, Ptn, []).
|
||||||
|
|
||||||
|
render(_ID, _N, [], Acc) ->
|
||||||
|
emqx_topic:join(lists:reverse(Acc));
|
||||||
|
render(ID, N, [<<"{{id}}">> | T], Acc) ->
|
||||||
|
render(ID, N, T, [integer_to_binary(ID) | Acc]);
|
||||||
|
render(ID, N, [<<"{{num}}">> | T], Acc) ->
|
||||||
|
render(ID, N, T, [integer_to_binary(N) | Acc]);
|
||||||
|
render(ID, N, [H | T], Acc) ->
|
||||||
|
render(ID, N, T, [H | Acc]).
|
||||||
|
|
||||||
|
-endif.
|
Loading…
Reference in New Issue