Skip to content

Instantly share code, notes, and snippets.

@RoadRunnr
Last active August 27, 2022 22:59
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save RoadRunnr/311a7679fff6fbdf367c455b960f1ba8 to your computer and use it in GitHub Desktop.
Save RoadRunnr/311a7679fff6fbdf367c455b960f1ba8 to your computer and use it in GitHub Desktop.
#!/usr/bin/env escript
%% -*- erlang -*-
%%! +sbtu +A1
-mode(compile).
-export([init_server/1]).
-define(UNIT, nanosecond).
%%-define(UNIT, millisecond).
main(_) ->
{ok, Server, SockAddr} = start_server(),
io:format("Server Pid ~p~nServer Addr ~p~n", [Server, SockAddr]),
{ok, Socket} = gen_udp:open(0, [binary, inet, {active, false}]),
Load = [proc_lib:spawn_link(fun busy_loop/0) ||
_ <- lists:seq(0, erlang:system_info(schedulers) * 2)],
Stats = ping(Server, Socket, SockAddr, 1000, []),
io:format(" round trip Clnt/Srvr Srvr/Clnt ProcPing~n"),
[io:format("~8w: ~8w ns, ~8w ns, ~8w ns, ~8w ns~n",
[Cnt, RecvTS - SendTS, RecvTS - SrvTS,
SrvTS - SendTS, PingTS - RecvTS]) ||
{Cnt, RecvTS, SendTS, SrvTS, PingTS} <- Stats],
[P ! stop || P <- Load],
Server ! stop.
ping(Server) ->
erlang:send(Server, {ping, self()}, [noconnect]),
receive
pong -> ok
after 2000 ->
io:format("ping timeout~n")
end.
ping(_Server, _Socket, _Dest, 0, Stats) ->
lists:reverse(Stats);
ping(Server, Socket, #{addr := Addr, port := Port} = Dest, Cnt, Stats0) ->
%%timer:sleep(rand:uniform(1000)),
%%timer:sleep(2000),
SendTS = erlang:monotonic_time(?UNIT),
Fill = binary:list_to_bin(lists:duplicate(1000, 0)),
Data = term_to_binary({Cnt, SendTS, Fill}),
ping(Server),
ok = gen_udp:send(Socket, Addr, Port, Data),
ping(Server),
{ok, {_, _, Answer}} = gen_udp:recv(Socket, 0, infinity),
erlang:send(Server, hi, [noconnect]),
RecvTS = erlang:monotonic_time(?UNIT),
Mref = erlang:monitor(process, Server),
ping(Server),
erlang:demonitor(Mref, [flush]),
PingTS = erlang:monotonic_time(?UNIT),
{Cnt, _, SrvTS, _} = binary_to_term(Answer),
Stats = [{Cnt, RecvTS, SendTS, SrvTS, PingTS}|Stats0],
ping(Server, Socket, Dest, Cnt - 1, Stats).
busy_loop() ->
receive
stop ->
ok
after
1 ->
busy_loop()
end.
start_server() ->
{ok, _, _} = proc_lib:start_link(?MODULE, init_server, [self()]).
init_server(Parent) ->
{ok, Socket} = socket:open(inet, dgram, udp),
{ok, _} = socket:bind(Socket, loopback),
{ok, SockAddr} = socket:sockname(Socket),
proc_lib:init_ack(Parent, {ok, self(), SockAddr}),
server_loop(Socket).
server_loop(Socket) ->
server_loop(Socket, 10).
server_loop(Socket, 0) ->
self() ! {'$socket', Socket, select, undefined},
select_loop(Socket);
server_loop(Socket, BusyCnt) ->
case socket:recvfrom(Socket, 0, [], nowait) of
{ok, {Source, Data}} ->
SrvTS = erlang:monotonic_time(?UNIT),
{Cnt, SendTS, Fill} = binary_to_term(Data),
Answer = term_to_binary({Cnt, SendTS, SrvTS, Fill}),
socket:sendto(Socket, Answer, Source, [], nowait),
server_loop(Socket, BusyCnt - 1);
{select, _} ->
select_loop(Socket);
{error, Reason} ->
exit(Reason)
end.
select_loop(Socket) ->
receive
hi ->
select_loop(Socket);
{ping, Pid} ->
Pid ! pong,
select_loop(Socket);
stop ->
ok;
{'$socket', Socket, abort, _} ->
io:format("Socket Error"),
ok;
{'$socket', Socket, select, _} ->
server_loop(Socket)
end.
@bmk
Copy link

bmk commented Oct 24, 2019

It looks like you have both proc's running in the same VM.
Have you tried it in different VMs?

/BMK

@RoadRunnr
Copy link
Author

RoadRunnr commented Oct 25, 2019

No. But why would it matter if it does or does not work with two VMs? Using socket.erl should not break Erlang message passing in either case, yet it clearly does.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment