[erlang-questions] per function/process locals

Ulf Wiger ulf@REDACTED
Thu May 10 13:42:20 CEST 2007


2007/5/3, ok <ok@REDACTED>:
>
> On 2 May 2007, at 11:21 pm, Ulf Wiger (TN/EAB) wrote
> [that instead of doing]
> > init_state(L) ->
> >   lists:foldl(
> >     fun({a, A}, S) -> S#st{a = A};
> >        ({b, B}, S) -> S#st{b = B};
> >        ...
> >     end, #st{}, L).
> [he tends to do]
> >   [A, B, C, D] =
> >     [proplists:get_value(K,L) ||
> >       K <- [a, b, c, d]],
> >   #st{a = A, b = B, c = C, d = D}
>
> This is a rather interesting example, because it shows a clear trade-
> off.
> Suppose there are V "variables".  We expect that the list will contain
> each at most once; the worst case is when they all appear.


Just to  give some concrete input, we are currently looking at how to
best populate a fairly large record, consisting of 42 attributes.

I'm thinking that the exprecs contrib (that I've posted in the trapexit
User Contributions forum) could try to output code that gives a reasonable
tradeoff based on size of record and (possibly) length of list.

Currently, it lays out the following code:

-record(dia_base_DPR,
        {'Origin-Host' = undefined, 'Origin-Realm' = undefined,
         'Disconnect-Cause' = undefined}).

'#set-dia_base_DPR'(Vals, Rec) ->
    F = fun ([], R, _F1) -> R;
            ([{'Origin-Host', V} | T], R, F1) ->
                F1(T, R#dia_base_DPR{'Origin-Host' = V}, F1);
            ([{'Origin-Realm', V} | T], R, F1) ->
                F1(T, R#dia_base_DPR{'Origin-Realm' = V}, F1);
            ([{'Disconnect-Cause', V} | T], R, F1) ->
                F1(T, R#dia_base_DPR{'Disconnect-Cause' = V}, F1)
        end,
    F(Vals, Rec, F).

... but for a record of size 44, this is not desirable.

Timing the two functions available for creating a new record:

-module(test4).

-compile(export_all).
-compile({parse_transform, exprecs}).

-export_records([r]).

-record(r, {a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,
        a11,a12,a13,a14,a15,a16,a17,a18,
        a19,a20,a21,a22,a23,a24,a25,a26,
        a27,a28,a29,a30,a31,a32,a33,a34,
        a35,a36,a37,a38,a39,a40,a41,a42,
        a43,a44,a45,a46,a47,a48,a49,a50}).

3> timer:tc(test4,'#new-r',[]).
{5, {r,undefined,...}}
4> Attrs = test4:'#info-r'(fields).
[a1, a2, a3, a4,...]
5> Vals = [{A,1} || A <- Attrs].
[{a1,1}, {a2,1}, {a3,1}, {a4,1},...]
6> timer:tc(test4,'#new-r',[Vals]).
{98,{r,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,...}}


I wrote a version basically doing this:

-module(recgen).
-export(['#new-r'/1]).
'#new-r'(L) ->
    mk_rec(L, undefined, undefined).
mk_rec([{Attr,Val}|T], X1, X2) ->
    X1 = if Attr == a1 -> Val; true -> X1 end,
    X2 = if Attr == a2 -> Val; true -> X2 end,
    mk_rec(T, X1, X2);
mk_rec([], X1, X2) ->
    '#new-r'(X1, X2).
'#new-r'(X1, X2) ->
    {r,X1,X2}.

...but for a record with 50 attributes, this was twice as slow
when setting all 50 attributes. Obviously, wielding functions
of arity 51 is not for free. (:

BR,
Ulf W
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20070510/a0d9c464/attachment.htm>


More information about the erlang-questions mailing list