From a1667d118239d611ded6d83bc9c918a2a5dbb800 Mon Sep 17 00:00:00 2001 From: Alice39s Date: Sun, 28 Jun 2026 01:04:00 +0900 Subject: [PATCH] refactor(erlang): simplify benchmark output to ms/QPS and add CPU clock info --- binding/erlang/README.md | 60 ++++-------- binding/erlang/README_zh.md | 60 ++++-------- binding/erlang/benchmarks/xdb-benchmark.sh | 1 + binding/erlang/src/xdb_benchmark.erl | 102 +++++++++++++++------ 4 files changed, 112 insertions(+), 111 deletions(-) diff --git a/binding/erlang/README.md b/binding/erlang/README.md index 5a51647..73eeb6b 100644 --- a/binding/erlang/README.md +++ b/binding/erlang/README.md @@ -154,55 +154,31 @@ $ make bench-v6 #### IPv4 benchmark example ``` -CPU info: -model name : Apple M4 -cores/threads : 10/10 +System: + CPU : Apple M4 + Cores : 10 cores / 10 threads + Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace] + Loaded : 487169 IPs in 1.574 s -Erlang info: -system_version:Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace] -load test data use 1.34496s +Benchmarks: + file total= 9.460s count= 487169 qps= 51500.40 avg= 0.019417 ms/op (19.417 us/op) + cache total= 0.150s count= 487169 qps= 3245240.41 avg= 0.000308 ms/op ( 0.308 us/op) -start run benchmark tests - -search from file: -ip count:487169, -total time: 11.564375s, -search 42126.70377776577 times per second, -use 23.737912305585947 micro second per search - -search from cache: -ip count:487169, -total time: 0.213552s, -search 2281266.389450813 times per second, -use 0.43835301507279817 micro second per search - -benchmark test finish +Done. ``` #### IPv6 benchmark example ``` -CPU info: -model name : Apple M4 -cores/threads : 10/10 +System: + CPU : Apple M4 + Cores : 10 cores / 10 threads + Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace] + Loaded : 638953 IPs in 2.724 s -Erlang info: -system_version:Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace] -load test data use 2.472659s +Benchmarks: + file total= 16.326s count= 638953 qps= 39137.65 avg= 0.025551 ms/op (25.551 us/op) + cache total= 0.469s count= 638953 qps= 1361972.38 avg= 0.000734 ms/op ( 0.734 us/op) -start run benchmark tests - -search from file: -ip count:638953, -total time: 18.463896s, -search 34605.535039842085 times per second, -use 28.897111368128797 micro second per search - -search from cache: -ip count:638953, -total time: 0.541899s, -search 1179099.7953493178 times per second, -use 0.8481046336741513 micro second per search - -benchmark test finish +Done. ``` diff --git a/binding/erlang/README_zh.md b/binding/erlang/README_zh.md index 4355a9a..a6d3022 100644 --- a/binding/erlang/README_zh.md +++ b/binding/erlang/README_zh.md @@ -131,55 +131,31 @@ $ make bench-v6 #### IPv4 基准测试示例 ``` -CPU info: -model name : Apple M4 -cores/threads : 10/10 +System: + CPU : Apple M4 + Cores : 10 cores / 10 threads + Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace] + Loaded : 487169 IPs in 1.574 s -Erlang info: -system_version:Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace] -load test data use 1.34496s +Benchmarks: + file total= 9.460s count= 487169 qps= 51500.40 avg= 0.019417 ms/op (19.417 us/op) + cache total= 0.150s count= 487169 qps= 3245240.41 avg= 0.000308 ms/op ( 0.308 us/op) -start run benchmark tests - -search from file: -ip count:487169, -total time: 11.564375s, -search 42126.70377776577 times per second, -use 23.737912305585947 micro second per search - -search from cache: -ip count:487169, -total time: 0.213552s, -search 2281266.389450813 times per second, -use 0.43835301507279817 micro second per search - -benchmark test finish +Done. ``` #### IPv6 基准测试示例 ``` -CPU info: -model name : Apple M4 -cores/threads : 10/10 +System: + CPU : Apple M4 + Cores : 10 cores / 10 threads + Erlang : Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace] + Loaded : 638953 IPs in 2.724 s -Erlang info: -system_version:Erlang/OTP 29 [erts-17.0.2] [source] [64-bit] [smp:10:10] [ds:10:10:10] [async-threads:1] [jit] [dtrace] -load test data use 2.472659s +Benchmarks: + file total= 16.326s count= 638953 qps= 39137.65 avg= 0.025551 ms/op (25.551 us/op) + cache total= 0.469s count= 638953 qps= 1361972.38 avg= 0.000734 ms/op ( 0.734 us/op) -start run benchmark tests - -search from file: -ip count:638953, -total time: 18.463896s, -search 34605.535039842085 times per second, -use 28.897111368128797 micro second per search - -search from cache: -ip count:638953, -total time: 0.541899s, -search 1179099.7953493178 times per second, -use 0.8481046336741513 micro second per search - -benchmark test finish +Done. ``` diff --git a/binding/erlang/benchmarks/xdb-benchmark.sh b/binding/erlang/benchmarks/xdb-benchmark.sh index 218cdf4..e8aebc3 100755 --- a/binding/erlang/benchmarks/xdb-benchmark.sh +++ b/binding/erlang/benchmarks/xdb-benchmark.sh @@ -32,5 +32,6 @@ init:stop()." # shellcheck disable=SC2090 erl -pa _build/default/lib/poolboy/ebin \ -pa _build/default/lib/ip2region/ebin \ + -kernel logger_level error \ -noshell \ -eval "${EVAL}" diff --git a/binding/erlang/src/xdb_benchmark.erl b/binding/erlang/src/xdb_benchmark.erl index 0fa6e7f..e5e5ad1 100644 --- a/binding/erlang/src/xdb_benchmark.erl +++ b/binding/erlang/src/xdb_benchmark.erl @@ -11,30 +11,76 @@ -export([main/1]). main(DataFile) -> - application:ensure_started(ip2region), + %% Keep benchmark output clean while still surfacing real errors. + _ = logger:set_handler_config(default, level, error), + _ = logger:set_primary_config(level, error), + application:ensure_started(ip2region), show_hw_sw_info(), IpList = load_test_data(DataFile), run(IpList). show_hw_sw_info() -> - io:format("CPU info:~n", []), + {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} -> - io:format("model name : ~s~n", [string:trim(os:cmd("sysctl -n machdep.cpu.brand_string 2>/dev/null"))]), - io:format("cores/threads : ~s/~s~n", [string:trim(os:cmd("sysctl -n hw.physicalcpu 2>/dev/null")), - string:trim(os:cmd("sysctl -n hw.logicalcpu 2>/dev/null"))]); + 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} -> - io:format("~s", [os:cmd("egrep '^model name' /proc/cpuinfo | head -1")]), - io:format("~s", [os:cmd("egrep '^cache' /proc/cpuinfo | head -1")]), - io:format("~s", [os:cmd("egrep '^cpu MHz' /proc/cpuinfo | head -1")]), - io:format("~s", [os:cmd("egrep '^bogomips' /proc/cpuinfo | head -1")]), - io:format("cores/threads : ~s~n", [os:cmd("egrep -c '^processor' /proc/cpuinfo")]); + Model = linux_cpu_field("model name"), + Clock = format_clock_mhz(linux_cpu_field("cpu MHz")), + Cores = trim(os:cmd("grep -c '^processor' /proc/cpuinfo 2>/dev/null")), + Threads = Cores, + {Model, Clock, Cores, Threads}; _ -> - io:format("unsupported os~n", []) - end, - io:format("Erlang info:~n", []), - io:format("system_version:~s", [erlang:system_info(system_version)]), - ok. + {"unknown", "", "?", "?"} + end. + +sysctl(Key) -> + 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/^ *//'", + 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(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 GHz", [Hz / 1000000000])); + _ -> + "" + end. + +format_clock_mhz(MhzStr) -> + case string:to_float(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]), @@ -42,7 +88,7 @@ load_test_data(DataFile) -> IpList = load_test_data(Fd, []), T1 = os:timestamp(), Sec = timer:now_diff(T1, T0) / 1000000, - io:format("load test data use ~ps~n", [Sec]), + io:format(" Loaded : ~p IPs in ~.3f s~n", [length(IpList), Sec]), IpList. load_test_data(Fd, IpList) -> @@ -55,30 +101,32 @@ load_test_data(Fd, IpList) -> load_test_data(Fd, IpList) end; _ -> - file:close(Fd), + file:close(Fd), IpList end. run(IpList) -> garbage_collect(), - io:format("~nstart run benchmark tests~n", []), - io:format("~nsearch from file:~n", []), - run_test(IpList), - io:format("~nsearch from cache:~n", []), - run_test(IpList), - io:format("~nbenchmark test finish~n", []). + io:format("~nBenchmarks:~n", []), + run_test("file", IpList), + run_test("cache", IpList), + io:format("~nDone.~n", []). -run_test(IpList) -> +run_test(Label, IpList) -> T0 = os:timestamp(), run_test_aux(IpList), T1 = os:timestamp(), Sec = timer:now_diff(T1, T0) / 1000000, - IpCount = length(IpList), - io:format("ip count:~p,~ntotal time: ~ps,~nsearch ~p times per second,~nuse ~p micro second per search~n", - [IpCount, Sec, IpCount / Sec, Sec * 1000000/IpCount]). + 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). +trim(Str) -> string:trim(Str).