mirror of
https://github.com/lionsoul2014/ip2region.git
synced 2025-12-08 19:25:22 +00:00
增加单元测试及基准测试
This commit is contained in:
parent
4efa1b36b2
commit
de4f5c0c22
1
.gitignore
vendored
1
.gitignore
vendored
@ -84,3 +84,4 @@ target
|
||||
|
||||
#erlang
|
||||
/binding/erlang/_build
|
||||
/binding/erlang/doc
|
||||
|
||||
@ -22,3 +22,78 @@ $ rebar3 shell
|
||||
region => <<>>}
|
||||
2>
|
||||
```
|
||||
|
||||
### 使用方法
|
||||
* 在rebar.config中引入依赖
|
||||
```
|
||||
{deps, [
|
||||
ip2region
|
||||
]}.
|
||||
|
||||
```
|
||||
* 启动ip2region Application
|
||||
```
|
||||
......
|
||||
|
||||
application:ensure_started(ip2region),
|
||||
|
||||
......
|
||||
```
|
||||
|
||||
* 调用ip2region:search/1接口查询IP信息
|
||||
```
|
||||
......
|
||||
|
||||
ip2region:search("1.0.8.0"),
|
||||
|
||||
......
|
||||
```
|
||||
|
||||
### 单元测试
|
||||
|
||||
```
|
||||
$ rebar3 eunit
|
||||
===> Verifying dependencies...
|
||||
===> Analyzing applications...
|
||||
===> Compiling ip2region
|
||||
===> Performing EUnit tests...
|
||||
=INFO REPORT==== 13-Jan-2023::21:26:15.137021 ===
|
||||
XdbFile:/home/admin/erl-workspace/ip2region/binding/erlang/_build/test/lib/ip2region/priv/ip2region.xdb
|
||||
...
|
||||
Finished in 0.085 seconds
|
||||
3 tests, 0 failures
|
||||
|
||||
```
|
||||
|
||||
### 基准测试
|
||||
```
|
||||
$ cd benchmarks/
|
||||
$ sh ip2region-benchmark.sh
|
||||
CPU info:
|
||||
model name : AMD EPYC 7K62 48-Core Processor
|
||||
cache size : 512 KB
|
||||
cpu MHz : 2595.124
|
||||
bogomips : 5190.24
|
||||
cores/threads : 2
|
||||
|
||||
Erlang info:
|
||||
system_version:Erlang/OTP 24 [erts-12.3.2.2] [source] [64-bit] [smp:2:2] [ds:2:2:10] [async-threads:1] [jit]
|
||||
load test data use 2.724344s
|
||||
|
||||
start run benchmark tests
|
||||
|
||||
search from file:
|
||||
ip count:683844,
|
||||
total time: 25.56304s,
|
||||
search 26751.27840820184 times per second,
|
||||
use 37.381391077497206 micro second per search
|
||||
|
||||
search from cache:
|
||||
ip count:683844,
|
||||
total time: 0.670307s,
|
||||
search 1020195.2239794602 times per second,
|
||||
use 0.9802045495756342 micro second per search
|
||||
|
||||
benchmark test finish
|
||||
|
||||
```
|
||||
|
||||
7
binding/erlang/benchmarks/ip2region-benchmark.sh
Executable file
7
binding/erlang/benchmarks/ip2region-benchmark.sh
Executable file
@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
awk -v FS='|' '{print $1}' ../../../data/ip.merge.txt > test_data.txt
|
||||
|
||||
cd ..
|
||||
|
||||
rebar3 shell --eval="ip2region_benchmark:main(\"./benchmarks/test_data.txt\"), init:stop()."
|
||||
683844
binding/erlang/benchmarks/test_data.txt
Normal file
683844
binding/erlang/benchmarks/test_data.txt
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,13 @@
|
||||
{erl_opts, [debug_info, export_all, nowarn_export_all]}.
|
||||
{erl_opts, [
|
||||
debug_info,
|
||||
export_all,
|
||||
nowarn_export_all
|
||||
]}.
|
||||
|
||||
{plugins, [rebar3_hex, rebar3_ex_doc]}.
|
||||
|
||||
{deps, [
|
||||
poolboy
|
||||
poolboy
|
||||
]}.
|
||||
|
||||
{shell, [
|
||||
@ -8,3 +15,10 @@
|
||||
{apps, [ip2region]}
|
||||
]}.
|
||||
|
||||
{ex_doc, [
|
||||
{extras, ["README.md"]},
|
||||
{main, "README.md"},
|
||||
{source_url, "https://github.com/leihua996/ip2region/tree/master/binding/erlang"}
|
||||
]}.
|
||||
|
||||
{hex, [{doc, ex_doc}]}.
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{application, ip2region,
|
||||
[{description, "An OTP application"},
|
||||
[{description, "ip2region xdb client application"},
|
||||
{vsn, "0.1.0"},
|
||||
{registered, []},
|
||||
{mod, {ip2region_app, []}},
|
||||
@ -16,5 +16,5 @@
|
||||
{modules, []},
|
||||
|
||||
{licenses, ["Apache-2.0"]},
|
||||
{links, []}
|
||||
{links, [{"Github", "https://github.com/leihua996/ip2region/tree/master/binding/erlang"}]}
|
||||
]}.
|
||||
|
||||
@ -1,3 +1,11 @@
|
||||
|
||||
%%%===============================================================
|
||||
%%% @author leihua <leihua918@sina.com>
|
||||
%%% @doc
|
||||
%%% ip2region xdb 查询客户端
|
||||
%%% Created: 2023-1-13 16:53
|
||||
%%% @end
|
||||
%%%===============================================================
|
||||
-module(ip2region).
|
||||
-include("ip2region.hrl").
|
||||
|
||||
@ -5,23 +13,18 @@
|
||||
|
||||
-spec search(Ip :: tuple() | list() | binary()) -> Result :: {error, Reason::atom()} | map().
|
||||
search(Ip) ->
|
||||
case check_ip(Ip) of
|
||||
{false, Reason} -> {error, Reason};
|
||||
_ ->
|
||||
Worker = poolboy:checkout(?IP2REGION_POOL, true, infinity),
|
||||
try
|
||||
ip2region_worker:search(Worker, Ip)
|
||||
after
|
||||
poolboy:checkin(?IP2REGION_POOL, Worker)
|
||||
end
|
||||
end.
|
||||
|
||||
check_ip({_A, _B, _C, _D}) -> true;
|
||||
check_ip(Ip) when is_list(Ip); is_binary(Ip) ->
|
||||
IpRegx = "^((\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])\.){3}(\\d|[1-9]\\d|1\\d\\d|2[0-4]\\d|25[0-5])$",
|
||||
case re:run(Ip, IpRegx) of
|
||||
{match, _Captured} ->
|
||||
ok;
|
||||
case util:ipv4_to_n(Ip) of
|
||||
IntIp when is_integer(IntIp) ->
|
||||
case ets:lookup(?IP2REGION_CACHE, IntIp) of
|
||||
[{_IntIp, Region}] -> Region;
|
||||
_ ->
|
||||
{false, bad_ip_format}
|
||||
end.
|
||||
Worker = poolboy:checkout(?IP2REGION_POOL, true, infinity),
|
||||
try
|
||||
ip2region_worker:search(Worker, IntIp)
|
||||
after
|
||||
poolboy:checkin(?IP2REGION_POOL, Worker)
|
||||
end
|
||||
end;
|
||||
Ret ->
|
||||
Ret
|
||||
end.
|
||||
|
||||
68
binding/erlang/src/ip2region_benchmark.erl
Normal file
68
binding/erlang/src/ip2region_benchmark.erl
Normal file
@ -0,0 +1,68 @@
|
||||
%%%===============================================================
|
||||
%%% @author leihua <leihua918@sina.com>
|
||||
%%% @doc
|
||||
%%% ip2region性能基准测试
|
||||
%%% Created: 2023-1-13 17:46
|
||||
%%% @end
|
||||
%%%===============================================================
|
||||
-module(ip2region_benchmark).
|
||||
-export([main/1]).
|
||||
|
||||
main(DataFile) ->
|
||||
application:ensure_started(ip2region),
|
||||
show_hw_sw_info(),
|
||||
IpList = load_test_data(DataFile),
|
||||
run(IpList).
|
||||
|
||||
show_hw_sw_info() ->
|
||||
io:format("CPU info:~n", []),
|
||||
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")]),
|
||||
io:format("Erlang info:~n", []),
|
||||
io:format("system_version:~s", [erlang:system_info(system_version)]),
|
||||
ok.
|
||||
|
||||
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("load test data use ~ps~n", [Sec]),
|
||||
IpList.
|
||||
|
||||
load_test_data(Fd, IpList) ->
|
||||
case file:read_line(Fd) of
|
||||
{ok, Ip} ->
|
||||
load_test_data(Fd, [string:trim(Ip)| IpList]);
|
||||
_ ->
|
||||
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", []).
|
||||
|
||||
run_test(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]).
|
||||
|
||||
run_test_aux([]) -> ok;
|
||||
run_test_aux([Ip | Tail]) ->
|
||||
#{} = ip2region:search(Ip),
|
||||
run_test_aux(Tail).
|
||||
|
||||
@ -1,8 +1,14 @@
|
||||
%%%===============================================================
|
||||
%%% @author leihua <leihua918@sina.com>
|
||||
%%% @doc
|
||||
%%% ip2region工作进程
|
||||
%%% Created: 2023-1-13 16:53
|
||||
%%% @end
|
||||
%%%===============================================================
|
||||
-module(ip2region_worker).
|
||||
-behaviour(gen_server).
|
||||
-include("ip2region.hrl").
|
||||
|
||||
|
||||
%% API
|
||||
-export([start/1, stop/1, start_link/1]).
|
||||
-export([search/2]).
|
||||
@ -31,7 +37,12 @@ search(Pid, Ip) ->
|
||||
%% gen_server callbacks
|
||||
%% =========================================
|
||||
init(_Args) ->
|
||||
PrivDir = code:priv_dir(?APP_NAME),
|
||||
AppName =
|
||||
case application:get_application() of
|
||||
{ok, AName} -> AName;
|
||||
_ -> ?APP_NAME
|
||||
end,
|
||||
PrivDir = code:priv_dir(AppName),
|
||||
XdbFileName = filename:join([PrivDir, "ip2region.xdb"]),
|
||||
error_logger:info_report(io_lib:format("XdbFile:~s~n", [XdbFileName])),
|
||||
{ok, IoDevice} = file:open(XdbFileName, [read, binary]),
|
||||
|
||||
@ -2,15 +2,16 @@
|
||||
-export([ipv4_to_n/1]).
|
||||
|
||||
|
||||
ip_aton(Ip) ->
|
||||
{ok, Addr} = inet_parse:address(Ip),
|
||||
Addr.
|
||||
|
||||
ipv4_to_n(IntIp) when is_integer(IntIp) -> IntIp;
|
||||
ipv4_to_n({A, B, C, D}) ->
|
||||
<<N:32>> = <<A, B, C, D>>,
|
||||
N;
|
||||
ipv4_to_n(Ip) when is_binary(Ip) ->
|
||||
ipv4_to_n(binary_to_list(Ip));
|
||||
ipv4_to_n(Ip) when is_list(Ip) ->
|
||||
Addr = ip_aton(Ip),
|
||||
ipv4_to_n(Addr).
|
||||
case inet_parse:address(Ip) of
|
||||
{ok, Addr} ->
|
||||
ipv4_to_n(Addr);
|
||||
_ ->
|
||||
{error, bad_ip_format}
|
||||
end.
|
||||
22
binding/erlang/test/ip2region_test.erl
Normal file
22
binding/erlang/test/ip2region_test.erl
Normal file
@ -0,0 +1,22 @@
|
||||
-module(ip2region_test).
|
||||
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
|
||||
search_test_() ->
|
||||
application:ensure_started(ip2region),
|
||||
A = #{
|
||||
city => <<"广州市"/utf8>>,
|
||||
country => <<"中国"/utf8>>,
|
||||
isp => <<"电信"/utf8>>,
|
||||
province => <<"广东省"/utf8>>,
|
||||
region => <<>>
|
||||
},
|
||||
Region1 = ip2region:search("1.0.8.0"),
|
||||
Region2 = ip2region:search({1,0,8,0}),
|
||||
Region3 = ip2region:search("xxx.0.8.0"),
|
||||
[
|
||||
?_assert(A =:= Region1),
|
||||
?_assert(A =:= Region2),
|
||||
?_assert({error, bad_ip_format} =:= Region3)
|
||||
|
||||
].
|
||||
Loading…
x
Reference in New Issue
Block a user