[erlang-questions] mochiglobal vs ets vs registered process

35 views
Skip to first unread message

Garrett Smith

unread,
May 22, 2012, 2:39:23 PM5/22/12
to Erlang Questions
This is a followup on a recent question I had about "meta programming"
in Erlang. The gist of the post was on a best practice for extending
functionality in Erlang without using registered processes.

This is a short hand of the sort of use case:

-module(foo).

do_something(Value) ->
foo_impl:lookup(do_something)(Value).

It led me to experiment with some options for storing/retrieving the
"pluggable" functionality:

- mochiglobal
- ets
- registered process running under proc_lib

The source code for the tests is pasted at the end of this email.

The test was to simply read a "global" value 1M times, after having
first initialized the facility. Times are of the "run" portion only
and do not include the "init" time.

Summary:

- ets was the fastest, baseline of 1x
- mochiglobal was 1.8x slower than ets
- registered process was 7.8x slower than ets

The registered process call (slowest) was, on average, ~2 microseconds
per call slower than ets (fastest). Note that's *micro* seconds.

My conclusion:

Provided the process doesn't block unnecessarily, using a process to
lookup "pluggable" functionality (e.g. an implementation module) is
perfectly good for almost any application. IMO it doesn't warrant the
use of ets.

This may not apply to systems under heavy load, where message passing
overhead could grow non-linearly. A number of tests could be run in
parallel to get a better feel for this.

mochiglobal's use of dynamically generated Erlang modules to serve
"global" values is novel, but it doesn't appear warranted on
performance grounds alone.

The raw test results:

26> timer:tc(tests, run_ets, []).
{307550,ok}
27> timer:tc(tests, run_ets, []).
{302596,ok}
28> timer:tc(tests, run_ets, []).
{313182,ok}
29> timer:tc(tests, run_ets, []).
{300729,ok}

30> timer:tc(tests, run_mochiglobal, []).
{576356,ok}
31> timer:tc(tests, run_mochiglobal, []).
{567248,ok}
32> timer:tc(tests, run_mochiglobal, []).
{541281,ok}
33> timer:tc(tests, run_mochiglobal, []).
{574178,ok}

34> timer:tc(tests, run_server, []).
{2358793,ok}
35> timer:tc(tests, run_server, []).
{2425085,ok}
36> timer:tc(tests, run_server, []).
{2394177,ok}
37> timer:tc(tests, run_server, []).
{2383787,ok}

The test code:

-module(tests).

-export([init_mochiglobal/0,
run_mochiglobal/0,
init_ets/0,
run_ets/0,
init_server/0,
run_server/0]).

-define(KEY, mykey).
-define(VALUE, "My Value").
-define(READS, 1000000).

init_mochiglobal() ->
mochiglobal:put(?KEY, ?VALUE).

run_mochiglobal() ->
run_mochiglobal(?READS).

run_mochiglobal(0) -> ok;
run_mochiglobal(N) when N > 0 ->
?VALUE = mochiglobal:get(mykey),
run_mochiglobal(N - 1).

init_ets() ->
ets:new(tests_ets, [named_table]),
ets:insert(tests_ets, {?KEY, ?VALUE}).

run_ets() ->
run_ets(?READS).

run_ets(0) -> ok;
run_ets(N) when N > 0 ->
[{_, ?VALUE}] = ets:lookup(tests_ets, ?KEY),
run_ets(N - 1).

init_server() ->
Server = proc_lib:spawn(fun() -> server_loop(?VALUE) end),
register(server, Server).

server_loop(Value) ->
receive
{get, ?KEY, Src} ->
Src ! {ok, Value},
server_loop(Value);
_ ->
server_loop(Value)
end.

server_get(Key) ->
server ! {get, Key, self()},
receive
{ok, Value} -> Value
after
3000 -> error(timeout)
end.

run_server() ->
run_server(?READS).

run_server(0) -> ok;
run_server(N) when N > 0 ->
?VALUE = server_get(?KEY),
run_server(N - 1).
_______________________________________________
erlang-questions mailing list
erlang-q...@erlang.org
http://erlang.org/mailman/listinfo/erlang-questions

Tomasz Maciejewski

unread,
May 22, 2012, 2:55:03 PM5/22/12
to Erlang Questions, Garrett Smith
Dnia 22-05-2012 o 20:39:23 Garrett Smith <g...@rre.tt> napisał(a):

> The test was to simply read a "global" value 1M times, after having
> first initialized the facility. Times are of the "run" portion only
> and do not include the "init" time.

I see your test reading 1M times *the same* value. I'd rather see the test when you write and read 1M random keys/values. The single value could be cached spoiling the test.

--
Tomasz Maciejewski

Garrett Smith

unread,
May 22, 2012, 3:02:20 PM5/22/12
to Tomasz Maciejewski, Erlang Questions
Hi Tomasz,

On Tue, May 22, 2012 at 1:55 PM, Tomasz Maciejewski <pon...@jabster.pl> wrote:
> Dnia 22-05-2012 o 20:39:23 Garrett Smith <g...@rre.tt> napisał(a):
>
>> The test was to simply read a "global" value 1M times, after having
>> first initialized the facility. Times are of the "run" portion only
>> and do not include the "init" time.
>
> I see your test reading 1M times *the same* value. I'd rather see the test
> when you write and read 1M random keys/values. The single value could be
> cached spoiling the test.

Whatever caches are in play here, I *want* to test them.

This is not a data problem, it's an extensibility problem. This use
would only ever be reading a small number of values.

Garrett

Bob Ippolito

unread,
May 22, 2012, 3:06:54 PM5/22/12
to Tomasz Maciejewski, Erlang Questions
On Tue, May 22, 2012 at 11:55 AM, Tomasz Maciejewski <pon...@jabster.pl> wrote:
Dnia 22-05-2012 o 20:39:23 Garrett Smith <g...@rre.tt> napisał(a):


The test was to simply read a "global" value 1M times, after having
first initialized the facility. Times are of the "run" portion only
and do not include the "init" time.

I see your test reading 1M times *the same* value. I'd rather see the test when you write and read 1M random keys/values. The single value could be cached spoiling the test.

mochiglobal is unsuitable for writes at runtime, at least prior to R16, because loading new code blocks the whole VM (possibly for *seconds*). The (only) occasion where you'll see mochiglobal work better than ets is when you have a very large data structure that you need to read at runtime with high process concurrency. The goal is to share memory and avoid garbage collector churn. In the tests the given value is so small AND you're only reading it from one process, so of course that there's no benefit.

-bob
 

Garrett Smith

unread,
May 22, 2012, 3:15:32 PM5/22/12
to Bob Ippolito, Erlang Questions

This is good to know.

I included mochiglobal in the tests because it was suggested in the
prior thread as a possible approach. In this use case, the values are
quite small.

Garrett

Reply all
Reply to author
Forward
0 new messages