131 lines
4.2 KiB
Erlang
131 lines
4.2 KiB
Erlang
%%%-------------------------------------------------------------------
|
|
%% Copyright 2022 The Ip2Region Authors. All rights reserved.
|
|
%% Use of this source code is governed by a Apache2.0-style
|
|
%% license that can be found in the LICENSE file.
|
|
%%
|
|
%% @doc
|
|
%% ip2region xdb client benchmark test
|
|
%% @end
|
|
%%%-------------------------------------------------------------------
|
|
-module(xdb_benchmark).
|
|
-export([main/1]).
|
|
|
|
main(DataFile) ->
|
|
%% Keep benchmark output clean while still surfacing real errors.
|
|
_ = logger:set_handler_config(default, level, error),
|
|
_ = logger:set_primary_config(level, error),
|
|
{ok, _} = application:ensure_all_started(ip2region),
|
|
show_hw_sw_info(),
|
|
IpList = load_test_data(DataFile),
|
|
run(IpList).
|
|
|
|
show_hw_sw_info() ->
|
|
{Model, Clock, Cores, Threads} = cpu_info(),
|
|
io:format("~nSystem:~n", []),
|
|
io:format(" CPU : ~s", [Model]),
|
|
case Clock of
|
|
"" -> io:format("~n", []);
|
|
_ -> io:format(" @ ~s~n", [Clock])
|
|
end,
|
|
io:format(" Cores : ~s cores / ~s threads~n", [Cores, Threads]),
|
|
io:format(" Erlang : ~s~n", [string:trim(erlang:system_info(system_version))]),
|
|
ok.
|
|
|
|
cpu_info() ->
|
|
case os:type() of
|
|
{unix, darwin} ->
|
|
Model = sysctl("machdep.cpu.brand_string"),
|
|
Clock = first_non_empty([
|
|
format_clock(sysctl("hw.cpufrequency")),
|
|
format_clock(sysctl("hw.perflevel0.frequency")),
|
|
format_clock(sysctl("hw.perflevel1.frequency"))
|
|
]),
|
|
Cores = sysctl("hw.physicalcpu"),
|
|
Threads = sysctl("hw.logicalcpu"),
|
|
{Model, Clock, Cores, Threads};
|
|
{unix, linux} ->
|
|
Model = linux_cpu_field("model name"),
|
|
Clock = format_clock_mhz(linux_cpu_field("cpu MHz")),
|
|
Cores = string:trim(os:cmd("grep -c '^processor' /proc/cpuinfo 2>/dev/null")),
|
|
Threads = Cores,
|
|
{Model, Clock, Cores, Threads};
|
|
_ ->
|
|
{"unknown", "", "?", "?"}
|
|
end.
|
|
|
|
sysctl(Key) ->
|
|
string:trim(os:cmd("sysctl -n " ++ Key ++ " 2>/dev/null")).
|
|
|
|
linux_cpu_field(Key) ->
|
|
Cmd = "grep -m1 '^" ++ Key ++ "' /proc/cpuinfo 2>/dev/null | cut -d: -f2- | sed 's/^ *//'",
|
|
string:trim(os:cmd(Cmd)).
|
|
|
|
first_non_empty(["" | Rest]) -> first_non_empty(Rest);
|
|
first_non_empty([Val | _]) -> Val;
|
|
first_non_empty([]) -> "".
|
|
|
|
format_clock(HzStr) ->
|
|
case string:to_integer(string:trim(HzStr)) of
|
|
{ok, Hz, _} when Hz > 1000000000 ->
|
|
lists:flatten(io_lib:format("~.2f GHz", [Hz / 1000000000]));
|
|
{ok, Hz, _} when Hz > 1000000 ->
|
|
lists:flatten(io_lib:format("~.2f MHz", [Hz / 1000000]));
|
|
_ ->
|
|
""
|
|
end.
|
|
|
|
format_clock_mhz(MhzStr) ->
|
|
case string:to_float(string:trim(MhzStr)) of
|
|
{ok, Mhz, _} ->
|
|
lists:flatten(io_lib:format("~.3f GHz", [Mhz / 1000]));
|
|
_ ->
|
|
""
|
|
end.
|
|
|
|
load_test_data(DataFile) ->
|
|
{ok, Fd} = file:open(DataFile, [read]),
|
|
T0 = os:timestamp(),
|
|
IpList = load_test_data(Fd, []),
|
|
T1 = os:timestamp(),
|
|
Sec = timer:now_diff(T1, T0) / 1000000,
|
|
io:format(" Loaded : ~p IPs in ~.3f s~n", [length(IpList), Sec]),
|
|
IpList.
|
|
|
|
load_test_data(Fd, IpList) ->
|
|
case file:read_line(Fd) of
|
|
{ok, Ip} ->
|
|
case string:tokens(unicode:characters_to_list(Ip), "|") of
|
|
[SIp | _Tail] ->
|
|
load_test_data(Fd, [string:trim(SIp)| IpList]);
|
|
_ ->
|
|
load_test_data(Fd, IpList)
|
|
end;
|
|
_ ->
|
|
file:close(Fd),
|
|
IpList
|
|
end.
|
|
|
|
run(IpList) ->
|
|
garbage_collect(),
|
|
io:format("~nBenchmarks:~n", []),
|
|
run_test("cold", IpList),
|
|
run_test("warm", IpList),
|
|
io:format("~nDone.~n", []).
|
|
|
|
run_test(Label, IpList) ->
|
|
T0 = os:timestamp(),
|
|
run_test_aux(IpList),
|
|
T1 = os:timestamp(),
|
|
Sec = timer:now_diff(T1, T0) / 1000000,
|
|
Count = length(IpList),
|
|
Qps = Count / Sec,
|
|
MsOp = Sec * 1000 / Count,
|
|
UsOp = Sec * 1000000 / Count,
|
|
io:format(" ~-8s total=~7.3fs count=~7w qps=~12.2f avg=~9.6f ms/op (~6.3f us/op)~n",
|
|
[Label, Sec, Count, Qps, MsOp, UsOp]).
|
|
|
|
run_test_aux([]) -> ok;
|
|
run_test_aux([Ip | Tail]) ->
|
|
xdb:search(Ip),
|
|
run_test_aux(Tail).
|