Created
May 4, 2023 04:20
-
-
Save nickva/a911476907e1f1819d1aa56406609b6f to your computer and use it in GitHub Desktop.
Estone benchmark from Erlang/OTP source.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
-module(estone). | |
% Copied form OTP erts/emulator/test/estone_SUITE.erl | |
% run with estone:estone(). May take a few minutes to run. | |
% | |
-export([estone/0]). | |
%% Internal exports for EStone tests | |
-export([ | |
lists/1, | |
msgp/1, | |
msgp_medium/1, | |
msgp_huge/1, | |
pattern/1, | |
trav/1, | |
large_dataset_work/1, | |
large_local_dataset_work/1,mk_big_procs/1,big_proc/0, very_big/1, | |
alloc/1, | |
bif_dispatch/1, | |
binary_h/1,echo/1, | |
ets/1, | |
generic/1,req/2,gserv/4,handle_call/3, | |
int_arith/1, | |
float_arith/1, | |
fcalls/1,remote0/1,remote1/1,app0/1,app1/1, | |
timer/1, | |
links/1,lproc/1, | |
run_micro/2,p1/1,macro/1,micros/0 | |
]). | |
%% EStone defines | |
-define(BIGPROCS, 10). | |
-define(BIGPROC_SIZE, 500000). | |
-define(STONEFACTOR, 31000000). %% Factor to make the reference | |
%% implementation to make 1000 TS_ESTONES. | |
-record(micro, | |
{function, %% The name of the function implementing the micro | |
weight, %% How important is this in typical applications ?? | |
loops = 10000,%% initial data | |
tt1, %% time to do one round | |
str}). %% Header string | |
%% EStone Test | |
estone() -> | |
L = ?MODULE:macro(?MODULE:micros()), | |
{Total, Stones} = sum_micros(L, 0, 0), | |
pp(Total,Stones,L). | |
%% | |
%% Pretty Print EStone Result | |
%% | |
pp(Total,Stones,Ms) -> | |
io:format("EStone test completed~n",[]), | |
io:format("**** Total time ~w seconds ****~n", [Total / 1000000]), | |
io:format("**** ESTONES = ~w ****~n~n", [Stones]), | |
io:format("~-31s ~-12s ~-10s % ~-10s ~n~n", | |
[" Title", "Millis", "Estone", "Loops"]), | |
pp2(Ms). | |
sum_micros([], Tot, Stones) -> {Tot, Stones}; | |
sum_micros([H|T], Tot, Sto) -> | |
sum_micros(T, ks(microsecs, H) + Tot, ks(estones, H) + Sto). | |
pp2([]) -> ok; | |
pp2([R|Tail]) -> | |
io:format("~-35s ~-12w ~-10w ~-2w ~-10w ~n", | |
[ks(title,R), | |
round(ks(microsecs, R) / 1000), | |
ks(estones, R), | |
ks(weight_percentage, R), | |
ks(loops, R)]), | |
pp2(Tail). | |
ks(K, L) -> | |
{value, {_, V}} = lists:keysearch(K, 1, L), | |
V. | |
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% | |
%%% EStone test | |
micro(lists) -> | |
#micro{function = lists, | |
weight = 7, | |
loops = 64000, | |
str = "list manipulation"}; | |
micro(msgp) -> | |
#micro{function = msgp, | |
weight = 10, | |
loops = 15150, | |
str = "small messages"}; | |
micro(msgp_medium) -> | |
#micro{function = msgp_medium, | |
weight = 14, | |
loops = 15270, | |
str = "medium messages"}; | |
micro(msgp_huge) -> | |
#micro{function = msgp_huge, | |
weight = 4, | |
loops = 520, | |
str = "huge messages"}; | |
micro(pattern) -> | |
#micro{function = pattern, | |
weight = 5, | |
loops = 10460, | |
str = "pattern matching"}; | |
micro(trav) -> | |
#micro{function = trav, | |
weight = 4, | |
loops = 28340, | |
str = "traverse"}; | |
micro(large_dataset_work) -> | |
#micro{function = large_dataset_work, | |
weight = 3, | |
loops = 11930, | |
str = "Work with large dataset"}; | |
micro(large_local_dataset_work) -> | |
#micro{function = large_local_dataset_work, | |
weight = 3, | |
loops = 11740, | |
str = "Work with large local dataset"}; | |
micro(alloc) -> | |
#micro{function = alloc, | |
weight = 2, | |
loops = 37100, | |
str = "Alloc and dealloc"}; | |
micro(bif_dispatch) -> | |
#micro{function = bif_dispatch, | |
weight = 8, | |
loops = 56230, | |
str = "Bif dispatch"}; | |
micro(binary_h) -> | |
#micro{function = binary_h, | |
weight = 4, | |
loops = 5810, | |
str = "Binary handling"}; | |
micro(ets) -> | |
#micro{function = ets, | |
weight = 6, | |
loops = 3420, | |
str = "ets datadictionary"}; | |
micro(generic) -> | |
#micro{function = generic, | |
weight = 9, | |
loops = 797700, | |
str = "Generic server (with timeout)"}; | |
micro(int_arith) -> | |
#micro{function = int_arith, | |
weight = 3, | |
loops = 41570, | |
str = "Small Integer arithmetic"}; | |
micro(float_arith) -> | |
#micro{function = float_arith, | |
weight = 1, | |
loops = 55260, | |
str = "Float arithmetic"}; | |
micro(fcalls) -> | |
#micro{function = fcalls, | |
weight = 5, | |
loops = 88200, | |
str = "Function calls"}; | |
micro(timer) -> | |
#micro{function = timer, | |
weight = 2, | |
loops = 23120, | |
str = "Timers"}; | |
micro(links) -> | |
#micro{function = links, | |
weight = 1, | |
loops = 3000, | |
str = "Links"}. | |
%% Return a list of micro's | |
micros() -> | |
[ | |
micro(lists), | |
micro(msgp), | |
micro(msgp_medium), | |
micro(msgp_huge), | |
micro(pattern), | |
micro(trav), | |
micro(large_dataset_work), | |
micro(large_local_dataset_work), | |
micro(alloc), | |
micro(bif_dispatch), | |
micro(binary_h), | |
micro(ets), | |
micro(generic), | |
micro(int_arith), | |
micro(float_arith), | |
micro(fcalls), | |
micro(timer), | |
micro(links) | |
]. | |
macro(Ms) -> | |
statistics(reductions), | |
statistics(runtime), | |
lists(500), %% fixup cache on first round | |
run_micros(Ms). | |
run_micros([]) -> | |
io:nl(), | |
[]; | |
run_micros([H|T]) -> | |
R = run_micro(H), | |
[R| run_micros(T)]. | |
run_micro(M) -> | |
Pid = spawn(?MODULE, run_micro, [self(),M]), | |
receive {Pid, Reply} -> Reply end. | |
run_micro(Top, M) -> | |
Top ! {self(), apply_micro(M)}. | |
apply_micro(M) -> | |
{GC0, Words0, _} = statistics(garbage_collection), | |
statistics(reductions), | |
Before = monotonic_time(), | |
Compensate = apply_micro(M#micro.function, M#micro.loops), | |
After = monotonic_time(), | |
{GC1, Words1, _} = statistics(garbage_collection), | |
{_, Reds} = statistics(reductions), | |
Elapsed = subtr(Before, After), | |
MicroSecs = Elapsed - Compensate, | |
[{title, M#micro.str}, | |
{tt1, M#micro.tt1}, | |
{function, M#micro.function}, | |
{weight_percentage, M#micro.weight}, | |
{loops, M#micro.loops}, | |
{microsecs,MicroSecs}, | |
{estones, (M#micro.weight * M#micro.weight * ?STONEFACTOR) div max(1,MicroSecs)}, | |
{gcs, GC1 - GC0}, | |
{kilo_word_reclaimed, (Words1 - Words0) div 1000}, | |
{kilo_reductions, Reds div 1000}, | |
{gc_intensity, gci(max(1,Elapsed), GC1 - GC0, Words1 - Words0)}]. | |
monotonic_time() -> | |
erlang:monotonic_time(). | |
subtr(Before, After) when is_integer(Before), is_integer(After) -> | |
erlang:convert_time_unit(After-Before, native, 1000000); | |
subtr({_,_,_}=Before, {_,_,_}=After) -> | |
timer:now_diff(After, Before). | |
gci(Micros, Words, Gcs) -> | |
((256 * Gcs) / Micros) + (Words / Micros). | |
apply_micro(Name, Loops) -> | |
apply(?MODULE, Name, [Loops]). | |
%%%%%%%%%%%% micro bench manipulating lists. %%%%%%%%%%%%%%%%%%%%%%%%% | |
lists(I) -> | |
L1 = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", | |
L2 = "aaaaaaaaaa", | |
lists(I, L1, L2). | |
lists(0, _,_) -> | |
0; | |
lists(I, L1, L2) -> | |
revt(10, L1), | |
appt(10, L1, L2), | |
lists(I-1, L1, L2). | |
revt(0, _) -> | |
done; | |
revt(I, L) -> | |
reverse(L), | |
revt(I-1, L). | |
reverse(L) -> | |
reverse(L, []). | |
reverse([H|T], Ack) -> reverse(T, [H|Ack]); | |
reverse([], Ack) -> Ack. | |
append([H|T], L) -> | |
[H | append(T, L)]; | |
append([], L) -> | |
L. | |
appt(0, _L1, _L2) -> ok; | |
appt(I, L1, L2) -> | |
append(L1, L2), | |
appt(I-1, L1, L2). | |
%%%%%%%%%%%%%%% small message passing and ctxt switching %%%%%%% | |
msgp(I) -> | |
msgp(I, small()). | |
msgp(0, _) -> | |
0; | |
msgp(I, Msg) -> | |
P1 = spawn(?MODULE, p1, [self()]), | |
P2 = spawn(?MODULE, p1, [P1]), | |
P3 = spawn(?MODULE, p1, [P2]), | |
P4 = spawn(?MODULE, p1, [P3]), | |
msgp_loop(100, P4, Msg), | |
msgp(I-1, Msg). | |
p1(To) -> | |
receive | |
{_From, {message, X}} -> | |
To ! {self(), {message, X}}, | |
p1(To); | |
stop -> | |
To ! stop, | |
exit(normal) | |
end. | |
msgp_loop(0, P, _) -> | |
P ! stop, | |
receive | |
stop -> ok | |
end; | |
msgp_loop(I, P, Msg) -> | |
P ! {self(), {message, Msg}}, | |
receive | |
{_From, {message, _}} -> | |
msgp_loop(I-1, P, Msg) | |
end. | |
%%%%%%%%%%%% large massage passing and ctxt switching %%%%%%% | |
msgp_medium(I) -> | |
msgp_medium(I, big()). | |
msgp_medium(0, _) -> | |
0; | |
msgp_medium(I, Msg) -> | |
P1 = spawn(?MODULE , p1, [self()]), | |
P2 = spawn(?MODULE, p1, [P1]), | |
P3 = spawn(?MODULE, p1, [P2]), | |
P4 = spawn(?MODULE, p1, [P3]), | |
msgp_loop(100, P4, Msg), | |
msgp_medium(I-1, Msg). | |
%%%%%%%%%%%% huge massage passing and ctxt switching %%%%%%% | |
msgp_huge(I) -> | |
msgp_huge(I, very_big(15)). | |
msgp_huge(0, _) -> | |
0; | |
msgp_huge(I, Msg) -> | |
P1 = spawn(?MODULE , p1, [self()]), | |
P4 = spawn(?MODULE, p1, [P1]), | |
msgp_loop(100, P4, Msg), | |
msgp_huge(I-1, Msg). | |
%%%%%% typical protocol pattern matching %%%%%%% | |
pattern(0) -> | |
0; | |
pattern(I) -> | |
Tail = "aaabbaaababba", | |
P1 = [0, 1,2,3,4,5|Tail], | |
pat_loop1(100, P1), | |
pat_loop2(100, P1), | |
pat_loop3(100, P1), | |
pat_loop4(100, P1), | |
pat_loop5(100, P1), | |
pattern(I-1). | |
pat_loop1(0, _) -> | |
ok; | |
pat_loop1(_I, [_, _X, _Y, 0 |_T]) -> | |
ok; | |
pat_loop1(_I, [_, _X, _Y, 1| _T]) -> | |
ok; | |
pat_loop1(_I, [_, _X, _Y, 2 | _T]) -> | |
ok; | |
pat_loop1(I, [_, X, Y, 3 | T]) -> | |
pat_loop1(I-1, [0, X,Y,3|T]). | |
pat_loop2(0, _) -> | |
ok; | |
pat_loop2(_I, [_X, Y | _Tail]) when Y bsl 1 == 0 -> | |
ok; | |
pat_loop2(_I, [_X, Y | _Tail]) when Y bsl 2 == 0 -> | |
ok; | |
pat_loop2(I, [X, Y | Tail]) when Y bsl 2 == 4 -> | |
pat_loop2(I-1, [X, Y |Tail]). | |
pat_loop3(0, _) -> | |
ok; | |
pat_loop3(_I, [{c, h} | _Tail]) -> | |
ok; | |
pat_loop3(_I, [1, 0 |_T]) -> | |
ok; | |
pat_loop3(_I, [X, _Y |_Tail]) when is_binary(X), size(X) == 1 -> | |
ok; | |
pat_loop3(_I, [no, _Y|_Tail]) -> | |
ok; | |
pat_loop3(_I, []) -> | |
ok; | |
pat_loop3(_I, [X,_Y|_T]) when X /= 0 -> | |
ok; | |
pat_loop3(_I, [2,3|_T]) -> | |
ok; | |
pat_loop3(_I, [1, 2]) -> | |
ok; | |
pat_loop3(I, [0, 1 |T]) -> | |
pat_loop3(I-1, [0,1|T]). | |
pat_loop4(0, _) -> ok; | |
pat_loop4(_I, [20|_T]) -> ok; | |
pat_loop4(_I, [219|_T]) -> ok; | |
pat_loop4(_I, [18|_T]) -> ok; | |
pat_loop4(_I, [17|_T]) -> ok; | |
pat_loop4(_I, [16|_T]) -> ok; | |
pat_loop4(_I, [15|_T]) -> ok; | |
pat_loop4(_I, [14|_T]) -> ok; | |
pat_loop4(_I, [13|_T]) -> ok; | |
pat_loop4(_I, [12|_T]) -> ok; | |
pat_loop4(_I, [11|_T]) -> ok; | |
pat_loop4(_I, [10|_T]) -> ok; | |
pat_loop4(_I, [9|_T]) -> ok; | |
pat_loop4(_I, [8|_T]) -> ok; | |
pat_loop4(_I, [7|_T]) -> ok; | |
pat_loop4(_I, [6|_T]) -> ok; | |
pat_loop4(_I, [5|_T]) -> ok; | |
pat_loop4(_I, [4|_T]) -> ok; | |
pat_loop4(_I, [3|_T]) -> ok; | |
pat_loop4(_I, [1|_T]) -> ok; | |
pat_loop4(_I, [21|_T]) -> ok; | |
pat_loop4(_I, [22|_T]) -> ok; | |
pat_loop4(_I, [23|_T]) -> ok; | |
pat_loop4(_I, [24|_T]) -> ok; | |
pat_loop4(_I, [25|_T]) -> ok; | |
pat_loop4(_I, [26|_T]) -> ok; | |
pat_loop4(_I, [27|_T]) -> ok; | |
pat_loop4(I, [0|T]) -> | |
pat_loop4(I-1, [0|T]). | |
pat_loop5(0, _) -> ok; | |
pat_loop5(_I, [0, 20|_T]) -> ok; | |
pat_loop5(_I, [0, 19|_T]) -> ok; | |
pat_loop5(_I, [0, 18|_T]) -> ok; | |
pat_loop5(_I, [0, 17|_T]) -> ok; | |
pat_loop5(_I, [0, 16|_T]) -> ok; | |
pat_loop5(_I, [0, 15|_T]) -> ok; | |
pat_loop5(_I, [0, 14|_T]) -> ok; | |
pat_loop5(_I, [0, 13|_T]) -> ok; | |
pat_loop5(_I, [0, 12|_T]) -> ok; | |
pat_loop5(_I, [0, 11|_T]) -> ok; | |
pat_loop5(_I, [0, 10|_T]) -> ok; | |
pat_loop5(_I, [0, 9|_T]) -> ok; | |
pat_loop5(_I, [0, 8|_T]) -> ok; | |
pat_loop5(_I, [0, 7|_T]) -> ok; | |
pat_loop5(_I, [0, 6|_T]) -> ok; | |
pat_loop5(I, [0, 1|T]) -> | |
pat_loop5(I-1, [0,1|T]). | |
%%%%%%%%%% term traversal representing simple pattern matchhing %%% | |
%%%%%%%%% + some arith | |
trav(I) -> | |
X = very_big(10), | |
trav(I, X). | |
trav(0, _) -> 0; | |
trav(I, T) -> | |
do_trav(T), | |
trav(I-1, T). | |
do_trav(T) when is_tuple(T) -> | |
tup_trav(T, 1, 1 + size(T)); | |
do_trav([H|T]) -> | |
do_trav(H) + do_trav(T); | |
do_trav(X) when is_integer(X) -> 1; | |
do_trav(_X) -> 0. | |
tup_trav(_T, P, P) -> 0; | |
tup_trav(T, P, End) -> | |
do_trav(element(P, T)) + tup_trav(T, P+1, End). | |
%% Working with a very large non-working data set | |
%% where the passive data resides in remote processes | |
large_dataset_work(I) -> | |
{Minus, Ps} = timer:tc(?MODULE, mk_big_procs, [?BIGPROCS]), | |
trav(I), | |
lists(I), | |
send_procs(Ps, stop), | |
Minus. %% Don't count time to create the big procs. | |
mk_big_procs(0) -> []; | |
mk_big_procs(I) -> | |
[ mk_big_proc()| mk_big_procs(I-1)]. | |
mk_big_proc() -> | |
P = spawn(?MODULE, big_proc, []), | |
P ! {self(), running}, | |
receive | |
{P, yes} -> P | |
end. | |
big_proc() -> | |
X = very_big(?BIGPROC_SIZE), %% creates a big heap | |
Y = very_big(?BIGPROC_SIZE), | |
Z = very_big(?BIGPROC_SIZE), | |
receive | |
{From, running} -> | |
From ! {self(), yes} | |
end, | |
receive | |
stop -> | |
{X, Y, Z} %% Can't be garbed away now by very (not super) | |
%% smart compiler | |
end. | |
%% Working with a large non-working data set | |
%% where the data resides in the local process. | |
large_local_dataset_work(I) -> | |
{Minus, _Data} = timer:tc(?MODULE, very_big, [?BIGPROC_SIZE]), | |
trav(I), | |
lists(I), | |
Minus. | |
%% Fast allocation and also deallocation that is gc test | |
%% Important to not let variable linger on the stack un-necessarily | |
alloc(0) -> 0; | |
alloc(I) -> | |
_X11 = very_big(), | |
_X12 = very_big(), | |
_X13 = very_big(), | |
_Z = [_X14 = very_big(), | |
_X15 = very_big(), | |
_X16 = very_big()], | |
_X17 = very_big(), | |
_X18 = very_big(), | |
_X19 = very_big(), | |
_X20 = very_big(), | |
_X21 = very_big(), | |
_X22 = very_big(), | |
_X23 = very_big(), | |
_X24 = very_big(), | |
alloc(I-1). | |
%% Time to call bif's | |
%% This benchmark was updated in OTP-24. I've tried to keep the | |
%% number of stones is creates the same, but that is impossible | |
%% to achieve across all platforms. | |
bif_dispatch(0) -> | |
0; | |
bif_dispatch(I) -> | |
put(mon,erlang:monitor(process,self())), | |
disp(), disp(), disp(), disp(), disp(), disp(), | |
disp(), disp(), disp(), disp(), disp(), disp(), | |
bif_dispatch(I-1). | |
disp() -> | |
erts_debug:flat_size(true), | |
erts_debug:size_shared(true), | |
demonitor(get(mon)), | |
erts_debug:flat_size(true), | |
demonitor(get(mon)), | |
erts_debug:size_shared(true), | |
demonitor(get(mon)), | |
erts_debug:flat_size(true), | |
demonitor(get(mon)), | |
erts_debug:size_shared(true), | |
demonitor(get(mon)), | |
erts_debug:flat_size(true), | |
demonitor(get(mon)), | |
erts_debug:size_shared(true), | |
demonitor(get(mon)), | |
erts_debug:flat_size(true), | |
demonitor(get(mon)), | |
erts_debug:size_shared(true), | |
demonitor(get(mon)), | |
erts_debug:flat_size(true), | |
demonitor(get(mon)), | |
erts_debug:size_shared(true). | |
%% Generic server like behaviour | |
generic(I) -> | |
register(funky, spawn(?MODULE, gserv, [funky, ?MODULE, [], []])), | |
g_loop(I). | |
g_loop(0) -> | |
exit(whereis(funky), kill), | |
0; | |
g_loop(I) -> | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [xyz]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [xyz]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
?MODULE:req(funky, {call, [abc]}), | |
g_loop(I-1). | |
req(Name, Req) -> | |
R = make_ref(), | |
Name ! {self(), R, Req}, | |
receive | |
{Name, R, Reply} -> Reply | |
after 2000 -> | |
exit(timeout) | |
end. | |
gserv(Name, Mod, State, Debug) -> | |
receive | |
{From, Ref, {call, Req}} when Debug == [] -> | |
case catch apply(Mod, handle_call, [From, State, Req]) of | |
{reply, Reply, State2} -> | |
From ! {Name, Ref, Reply}, | |
gserv(Name, Mod, State2, Debug); | |
{noreply, State2} -> | |
gserv(Name, Mod, State2, Debug); | |
{'EXIT', Reason} -> | |
exit(Reason) | |
end; | |
{_From, _Ref, _Req} when Debug /= [] -> | |
exit(nodebug) | |
end. | |
handle_call(_From, _State, [xyz]) -> | |
R = atom_to_list(xyz), | |
{reply, R, []}; | |
handle_call(_From, State, [abc]) -> | |
R = 1 + 3, | |
{reply, R, [R | State]}. | |
%% Binary handling, creating, manipulating and sending binaries | |
binary_h(I) -> | |
Before = monotonic_time(), | |
P = spawn(?MODULE, echo, [self()]), | |
B = list_to_binary(lists:duplicate(2000, 5)), | |
After = monotonic_time(), | |
Compensate = subtr(Before, After), | |
binary_h_2(I, P, B), | |
Compensate. | |
binary_h_2(0, P, _B) -> | |
exit(P, kill); | |
binary_h_2(I, P, B) -> | |
echo_loop(P, 20, B), | |
split_loop(B, {abc,1,2222,self(),"ancnd"}, 100), | |
binary_h_2(I-1, P, B). | |
split_loop(_B, _, 0) -> | |
ok; | |
split_loop(B, Term, I) -> | |
{X, Y} = split_binary(B, I), | |
_ = size(X), | |
_ = binary_to_list(Y, 1, 2), | |
_ = binary_to_term(term_to_binary(Term)), | |
split_loop(B, Term, I-1). | |
echo_loop(_P, 0, _B) -> | |
k; | |
echo_loop(P, I, B) -> | |
P ! B, | |
P ! B, | |
P ! B, | |
P ! B, | |
P ! B, | |
P ! B, | |
P ! B, | |
P ! B, | |
P ! B, | |
P ! B, | |
receive _ -> ok end, | |
receive _ -> ok end, | |
receive _ -> ok end, | |
receive _ -> ok end, | |
receive _ -> ok end, | |
receive _ -> ok end, | |
receive _ -> ok end, | |
receive _ -> ok end, | |
receive _ -> ok end, | |
receive _ -> ok end, | |
echo_loop(P, I-1, B). | |
ets(0) -> | |
0; | |
ets(I) -> | |
T1 = ets:new(a, [set]), | |
T2 = ets:new(c, [bag, private]), | |
L = [T1, T2], | |
run_tabs(L, L, 1), | |
ets:delete(T1), | |
ets:delete(T2), | |
ets(I-1). | |
run_tabs(_, _, 0) -> | |
ok; | |
run_tabs([], L, I) -> | |
run_tabs(L, L, I-1); | |
run_tabs([Tab|Tail], L, I) -> | |
Begin = I * 20, | |
End = (I+1) * 20, | |
run_tab(Tab, Begin, End, I), | |
run_tabs(Tail, L, I). | |
run_tab(_Tab, X, X, _) -> | |
ok; | |
run_tab(Tab, Beg, End, J) -> | |
ets:insert(Tab, {Beg, J}), | |
ets:insert(Tab, {J, Beg}), | |
ets:insert(Tab, {{foo,Beg}, J}), | |
ets:insert(Tab, {{foo, J}, Beg}), | |
ets:delete(Tab, haha), | |
ets:match_delete(Tab, {k, j}), | |
ets:match(Tab, {Beg, '$1'}), | |
ets:match(Tab, {'$1', J}), | |
ets:delete(Tab, Beg), | |
K = ets:first(Tab), | |
_K2 = ets:next(Tab, K), | |
run_tab(Tab, Beg+1, End, J). | |
%%%% Integer arith %%%%% | |
int_arith(0) -> | |
0; | |
int_arith(I) -> | |
_ = do_arith(I) + | |
do_arith(I) + | |
do_arith(I) + | |
do_arith(I) + | |
do_arith(I) + | |
do_arith(I) + | |
do_arith(I) + | |
do_arith(I) + | |
do_arith(I) + | |
66, | |
int_arith(I-1). | |
do_arith(I) -> | |
do_arith2(I) - | |
do_arith2(I) - | |
do_arith2(I) - | |
do_arith2(I) - | |
do_arith2(I) - | |
do_arith2(I) - | |
do_arith2(I) - | |
99. | |
do_arith2(I) -> | |
X = 23, | |
_Y = 789 + I, | |
Z = I + 1, | |
U = (X bsl 1 bsr I) * X div 2 bsr 4, | |
U1 = Z + Z + Z + Z + X bsl 4 * 2 bsl 2, | |
Z - U + U1 div 2. | |
%%%% Float arith %%%%% | |
float_arith(0) -> | |
0; | |
float_arith(I) -> | |
_ = f_do_arith(I) + | |
f_do_arith(I) + | |
f_do_arith(I) + | |
f_do_arith(I) + | |
f_do_arith(I) + | |
f_do_arith(I) + | |
f_do_arith(I) + | |
f_do_arith(I) + | |
f_do_arith(I) + | |
66, | |
float_arith(I-1). | |
f_do_arith(I) -> | |
X = 23.4, | |
_Y = 789.99 + I, | |
Z = I + 1.88, | |
U = (X * 1 / I) * X / 2 * 4, | |
U1 = Z + Z + Z + Z + X * 4 * 2 / 2, | |
Z - U + U1 / 2. | |
%%%% time to do various function calls | |
fcalls(0) -> | |
0; | |
fcalls(I) -> | |
local0(400), | |
remote0(400), | |
app0(400), | |
local1(400), | |
remote1(400), | |
app1(400), | |
fcalls(I-1). | |
local0(0) -> 0; | |
local0(N) -> | |
local0(N-1). | |
local1(0) -> 0; | |
local1(N) -> | |
1+local1(N-1). | |
remote0(0) -> 0; | |
remote0(N) -> | |
?MODULE:remote0(N-1). | |
remote1(0) -> 0; | |
remote1(N) -> | |
1+?MODULE:remote1(N-1). | |
app0(0) -> 0; | |
app0(N) -> | |
apply(?MODULE, app0, [N-1]). | |
app1(0) -> 0; | |
app1(N) -> | |
1 + apply(?MODULE, app1, [N-1]). | |
%%%%%% jog the time queue implementation | |
timer(I) -> | |
L = [50, 50, 50, 100, 1000, 3000, 8000, 50000, 100000], | |
timer(I, L). | |
timer(0, _) -> 0; | |
timer(N, L) -> | |
send_self(100), | |
recv(100,L, L), | |
timer(N-1). | |
recv(0, _, _) -> | |
ok; | |
recv(N, [], L) -> | |
recv(N, L, L); | |
recv(N, [Timeout|Tail], L) -> | |
receive | |
hi_dude -> | |
recv(N-1, Tail, L) | |
after Timeout -> | |
io:format("XXXXX this wasn't supposed to happen???~n", []), | |
ok | |
end. | |
send_self(0) -> | |
ok; | |
send_self(N) -> | |
self() ! hi_dude, | |
send_self(N-1). | |
%%%%%%%%%%%% managing many links %%%%% | |
links(I) -> | |
L = mk_link_procs(100), | |
send_procs(L, {procs, L, I}), | |
wait_for_pids(L), | |
0. | |
mk_link_procs(0) -> | |
[]; | |
mk_link_procs(I) -> | |
[spawn_link(?MODULE, lproc, [self()]) | mk_link_procs(I-1)]. | |
lproc(Top) -> | |
process_flag(trap_exit,true), | |
receive | |
{procs, Procs, I} -> | |
Top ! {self(), lproc(Procs, Procs, link, I)} | |
end. | |
lproc(_, _, _, 0) -> | |
done; | |
lproc([], Procs, link, I) -> | |
lproc(Procs, Procs, unlink, I-1); | |
lproc([], Procs, unlink, I) -> | |
lproc(Procs, Procs, link, I-1); | |
lproc([Pid|Tail], Procs, unlink, I) -> | |
unlink(Pid), | |
lproc(Tail, Procs, unlink, I); | |
lproc([Pid|Tail], Procs, link, I) -> | |
link(Pid), | |
lproc(Tail, Procs, unlink, I). | |
%%%%%%%%%%% various utility functions %%%%%%% | |
echo(Pid) -> | |
receive | |
X -> Pid ! X, | |
echo(Pid) | |
end. | |
very_big() -> | |
very_big(2). | |
very_big(0) -> []; | |
very_big(I) -> | |
{1,2,3,a,v,f,r,t,y,u,self(), self(), self(), | |
"22222222222222222", {{"234", self()}}, | |
[[very_big(I-1)]]}. | |
big() -> | |
{self(), funky_stuff, baby, {1, [123, true,[]], "abcdef"}}. | |
small() -> {self(), true}. | |
%% Wait for a list of children to respond | |
wait_for_pids([]) -> | |
ok; | |
wait_for_pids([P|Tail]) -> | |
receive | |
{P, _Res} -> wait_for_pids(Tail) | |
end. | |
send_procs([P|Tail], Msg) -> P ! Msg, send_procs(Tail, Msg); | |
send_procs([], _) -> ok. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment