iilyak commented on code in PR #4812:
URL: https://github.com/apache/couchdb/pull/4812#discussion_r1731576347


##########
src/rexi/src/rexi.erl:
##########
@@ -328,3 +336,23 @@ drain_acks(Count) ->
     after 0 ->
         {ok, Count}
     end.
+
+get_delta() ->
+    {delta, couch_stats_resource_tracker:make_delta()}.
+
+maybe_add_delta(T) ->
+    case couch_stats_resource_tracker:is_enabled() of
+        false ->
+            T;
+        true ->
+            add_delta(T, get_delta())
+    end.
+
+add_delta({A}, Delta) -> {A, Delta};

Review Comment:
   There is also https://www.erlang.org/doc/apps/erts/erlang#append_element/2. 
However in the way it is written there might be an opportunity for structural 
sharing. Since in this case the new tuple is constructed from existing 
pointers. I am not sure whether VM would eliminate copying in this case.
   
   I did a quick experiment just to see what gets emited.
    
   ```erlang
   % erlc +time +to_core add_delta.erl
   -module(add_delta).
   
   -export([test/0]).
   
   add_delta0({A}, Delta) -> {A, Delta};
   add_delta0({A, B}, Delta) -> {A, B, Delta}.
   
   add_delta1(T, Delta) when 0 < erlang:size(T), erlang:size(T) < 8 ->
       erlang:insert_element(erlang:size(T) + 1, T, Delta);
   add_delta1(T, _Delta) -> T.
   
   add_delta2(T, Delta) -> erlang:append_element(T, Delta).
   
   test() ->
       {1,2,3, {delta, 4}} = add_delta0({1,2,3}, {delta, 4}),
       {1,2,3, {delta, 4}} = add_delta1({1,2,3}, {delta, 4}),
       {1,2,3, {delta, 4}} = add_delta2({1,2,3}, {delta, 4}),
       ok.
   
   
   ```
   
   The resulting core erlang is
   
   ```
   module 'add_delta' ['module_info'/0,
                    'module_info'/1,
                    'test'/0]
       attributes [%% Line 1
                'file' =
                    %% Line 1
                    
[{[97|[100|[100|[95|[100|[101|[108|[116|[97|[46|[101|[114|[108]]]]]]]]]]]]],1}]]
   'add_delta0'/2 =
       %% Line 6
       ( fun (_0,_1) ->
          ( case <_0,_1> of
              <{A},Delta> when 'true' ->
                  {A,Delta}
              %% Line 7
              <{A,B},Delta> when 'true' ->
                  {A,B,Delta}
              ( <_3,_2> when 'true' ->
                    ( primop 'match_fail'
                          (( {'function_clause',_3,_2}
                             -| [{'function',{'add_delta0',2}}] ))
                      -| [{'function',{'add_delta0',2}}] )
                -| ['compiler_generated'] )
            end
            -| [{'function',{'add_delta0',2}}] )
         -| [{'function',{'add_delta0',2}}] )
   'add_delta1'/2 =
       %% Line 9
       ( fun (_0,_1) ->
          ( case <_0,_1> of
              <T,Delta>
                  when try
                        let <_2> =
                            call 'erlang':'size'
                                (T)
                        in  let <_3> =
                                call 'erlang':'<'
                                    (0, _2)
                            in  let <_4> =
                                    call 'erlang':'size'
                                        (T)
                                in  let <_5> =
                                        call 'erlang':'<'
                                            (_4, 8)
                                    in  call 'erlang':'and'
                                            (_3, _5)
                    of <Try> ->
                        Try
                    catch <T,R> ->
                        'false' ->
                  let <_6> =
                      call %% Line 10
                           'erlang':%% Line 10
                                    'size'
                          (%% Line 10
                           T)
                  in  let <_7> =
                          call %% Line 10
                               'erlang':%% Line 10
                                        '+'
                              (%% Line 10
                               _6, %% Line 10
                                   1)
                      in  %% Line 10
                          call 'erlang':'insert_element'
                              (_7, T, Delta)
              %% Line 11
              <T,_X_Delta> when 'true' ->
                  T
            end
            -| [{'function',{'add_delta1',2}}] )
         -| [{'function',{'add_delta1',2}}] )
   'add_delta2'/2 =
       %% Line 13
       ( fun (_0,_1) ->
          call 'erlang':'append_element'
              (_0, _1)
         -| [{'function',{'add_delta2',2}}] )
   'test'/0 =
       %% Line 15
       ( fun () ->
          %% Line 16
          case apply 'add_delta0'/2
                   ({1,2,3}, {'delta',4}) of
            <{1,2,3,{'delta',4}}> when 'true' ->
                %% Line 17
                case apply 'add_delta1'/2
                         ({1,2,3}, {'delta',4}) of
                  <{1,2,3,{'delta',4}}> when 'true' ->
                      %% Line 18
                      case apply 'add_delta2'/2
                               ({1,2,3}, {'delta',4}) of
                        <{1,2,3,{'delta',4}}> when 'true' ->
                            %% Line 19
                            'ok'
                        ( <_2> when 'true' ->
                              primop 'match_fail'
                                  ({'badmatch',_2})
                          -| ['compiler_generated'] )
                      end
                  ( <_1> when 'true' ->
                        primop 'match_fail'
                            ({'badmatch',_1})
                    -| ['compiler_generated'] )
                end
            ( <_0> when 'true' ->
                  primop 'match_fail'
                      ({'badmatch',_0})
              -| ['compiler_generated'] )
          end
         -| [{'function',{'test',0}}] )
   'module_info'/0 =
       ( fun () ->
          call 'erlang':'get_module_info'
              ('add_delta')
         -| [{'function',{'module_info',0}}] )
   'module_info'/1 =
       ( fun (_0) ->
          call 'erlang':'get_module_info'
              ('add_delta', ( _0
                              -| [{'function',{'module_info',1}}] ))
         -| [{'function',{'module_info',1}}] )
   end
   ```
   
   In the first case there is a direct reuse of tuple elements. Most likely no 
data copying.
   
   In the second case there are calls to size, construction of a new frame in 
try/catch and `'erlang':'insert_element'`. AFAIK the 
`'erlang':'insert_element'`(BIF written in C)  copies the values 
https://github.com/erlang/otp/blob/1afaa459eaae8d51585acc2a363dd2714b98c9c2/erts/emulator/beam/bif.c#L2866.
   
   In the third case `'erlang':'append_element'` which is a call to BIF written 
in C. This BIF copies the values 
https://github.com/erlang/otp/blob/1afaa459eaae8d51585acc2a363dd2714b98c9c2/erts/emulator/beam/bif.c#L2833
   
   I think the way it is written would be the fastest. I think Russell wanted 
to optimize this code path. If I am right Russell could you add a comment about 
it. Something like "The tuple match is used to enable subterm sharing and avoid 
data copying.".
   
   Also there might be a middle ground.
   
   ```erlang
   add_delta({A, B}, Delta) -> {A, B, Delta};
   add_delta({A, B, C}, Delta) -> {A, B, C, Delta};
   add_delta({A, B, C, D}, Delta) -> {A, B, C, D, Delta};
   add_delta({A, B, C, D, E}, Delta) -> {A, B, C, D, E, Delta};
   add_delta({A, B, C, D, E, F}, Delta) -> {A, B, C, D, E, F, Delta};
   add_delta({A, B, C, D, E, F, G}, Delta) -> {A, B, C, D, E, F, G, Delta};
   add_delta(T, Delta) when is_tuple(T) -> erlang:append_element(T, Delta).
   ```



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to