Current section
Files
Jump to
Current section
Files
examples/bench_resource_pool.erl
#!/usr/bin/env escript
%% -*- erlang -*-
%%! -pa _build/default/lib/erlang_python/ebin
%%% @doc Benchmark script for py_resource_pool performance testing.
%%%
%%% Compares the new resource pool with the existing worker pool.
%%%
%%% Run with:
%%% rebar3 compile && escript examples/bench_resource_pool.erl
-mode(compile).
main(_Args) ->
io:format("~n=== py_resource_pool Benchmark ===~n~n"),
%% Start the application
{ok, _} = application:ensure_all_started(erlang_python),
%% Print system info
print_system_info(),
%% Benchmark the resource pool
io:format("~n--- Resource Pool Benchmarks ---~n~n"),
ok = py_resource_pool:start(),
Stats = py_resource_pool:stats(),
io:format("Pool stats: ~p~n~n", [Stats]),
%% Sequential calls
bench_resource_pool_sequential(1000),
%% Concurrent calls
bench_resource_pool_concurrent(10, 100),
bench_resource_pool_concurrent(50, 100),
bench_resource_pool_concurrent(100, 100),
%% Stop resource pool
ok = py_resource_pool:stop(),
%% Now benchmark the old worker pool for comparison
io:format("~n--- Old Worker Pool (py:call) Benchmarks ---~n~n"),
%% Sequential calls
bench_old_pool_sequential(1000),
%% Concurrent calls
bench_old_pool_concurrent(10, 100),
bench_old_pool_concurrent(50, 100),
bench_old_pool_concurrent(100, 100),
io:format("~n=== Benchmark Complete ===~n"),
halt(0).
print_system_info() ->
io:format("System Information:~n"),
io:format(" Erlang/OTP: ~s~n", [erlang:system_info(otp_release)]),
io:format(" Schedulers: ~p~n", [erlang:system_info(schedulers)]),
io:format(" Python: "),
{ok, PyVer} = py:version(),
io:format("~s~n", [PyVer]),
io:format(" Execution Mode: ~p~n", [py:execution_mode()]),
io:format("~n").
%% Resource pool benchmarks
bench_resource_pool_sequential(N) ->
io:format("Resource Pool: Sequential calls (math.sqrt)~n"),
io:format(" Iterations: ~p~n", [N]),
{Time, _} = timer:tc(fun() ->
lists:foreach(fun(I) ->
{ok, _} = py_resource_pool:call(math, sqrt, [I])
end, lists:seq(1, N))
end),
print_results(Time, N).
bench_resource_pool_concurrent(NumProcs, CallsPerProc) ->
TotalCalls = NumProcs * CallsPerProc,
io:format("Resource Pool: Concurrent calls~n"),
io:format(" Processes: ~p, Calls/process: ~p, Total: ~p~n",
[NumProcs, CallsPerProc, TotalCalls]),
Parent = self(),
{Time, _} = timer:tc(fun() ->
Pids = [spawn_link(fun() ->
lists:foreach(fun(I) ->
{ok, _} = py_resource_pool:call(math, sqrt, [I])
end, lists:seq(1, CallsPerProc)),
Parent ! {done, self()}
end) || _ <- lists:seq(1, NumProcs)],
[receive {done, Pid} -> ok end || Pid <- Pids]
end),
print_results(Time, TotalCalls).
%% Old pool benchmarks (py:call)
bench_old_pool_sequential(N) ->
io:format("Old Pool (py:call): Sequential calls (math.sqrt)~n"),
io:format(" Iterations: ~p~n", [N]),
{Time, _} = timer:tc(fun() ->
lists:foreach(fun(I) ->
{ok, _} = py:call(math, sqrt, [I])
end, lists:seq(1, N))
end),
print_results(Time, N).
bench_old_pool_concurrent(NumProcs, CallsPerProc) ->
TotalCalls = NumProcs * CallsPerProc,
io:format("Old Pool (py:call): Concurrent calls~n"),
io:format(" Processes: ~p, Calls/process: ~p, Total: ~p~n",
[NumProcs, CallsPerProc, TotalCalls]),
Parent = self(),
{Time, _} = timer:tc(fun() ->
Pids = [spawn_link(fun() ->
lists:foreach(fun(I) ->
{ok, _} = py:call(math, sqrt, [I])
end, lists:seq(1, CallsPerProc)),
Parent ! {done, self()}
end) || _ <- lists:seq(1, NumProcs)],
[receive {done, Pid} -> ok end || Pid <- Pids]
end),
print_results(Time, TotalCalls).
print_results(TimeUs, N) ->
TimeMs = TimeUs / 1000,
CallsPerSec = N / (TimeMs / 1000),
PerCall = TimeMs / N,
io:format(" Total time: ~.2f ms~n", [TimeMs]),
io:format(" Per call: ~.3f ms~n", [PerCall]),
io:format(" Throughput: ~p calls/sec~n~n", [round(CallsPerSec)]).