LogoopenSUSE Build Service > Projects
Sign Up | Log In

View File 1112-erts-Optimize-erlang-put-2-for-immed-values.patch of Package erlang (Project home:Ledest:erlang:20)

From 4d547dfb2a012ba1cf8fb9dd3cdc4d9df933a37f Mon Sep 17 00:00:00 2001
From: Sverker Eriksson <sverker@erlang.org>
Date: Wed, 21 Feb 2018 22:05:10 +0100
Subject: [PATCH 2/3] erts: Optimize erlang:put/2 for immed values

Do destructive write of immed value if key exists.

This is an optimization at the expense of get/0
which must now copy all (mutable) key-value tuples.
---
 erts/emulator/beam/erl_process_dict.c | 41 +++++++++++++++++++++++++++++------
 lib/kernel/test/pdict_SUITE.erl       | 32 +++++++++++++++++++++++++++
 2 files changed, 66 insertions(+), 7 deletions(-)

diff --git a/erts/emulator/beam/erl_process_dict.c b/erts/emulator/beam/erl_process_dict.c
index 1ec81f50a3..87b440093b 100644
--- a/erts/emulator/beam/erl_process_dict.c
+++ b/erts/emulator/beam/erl_process_dict.c
@@ -92,7 +92,7 @@ static void pd_hash_erase_all(Process *p);
 static Eterm pd_hash_get_with_hval(Process *p, Eterm bucket, Eterm id);
 static Eterm pd_hash_get_keys(Process *p, Eterm value);
 static Eterm pd_hash_get_all_keys(Process *p, ProcDict *pd);
-static Eterm pd_hash_get_all(Process *p, ProcDict *pd);
+static Eterm pd_hash_get_all(Process *p, ProcDict *pd, int keep_dict);
 static Eterm pd_hash_put(Process *p, Eterm id, Eterm value);
 
 static void shrink(Process *p, Eterm* ret); 
@@ -281,7 +281,7 @@ BIF_RETTYPE get_0(BIF_ALIST_0)
 {
     Eterm ret;
     PD_CHECK(BIF_P->dictionary);
-    ret = pd_hash_get_all(BIF_P, BIF_P->dictionary);
+    ret = pd_hash_get_all(BIF_P, BIF_P->dictionary, 1);
     PD_CHECK(BIF_P->dictionary);
     BIF_RET(ret);
 }
@@ -329,7 +329,7 @@ BIF_RETTYPE erase_0(BIF_ALIST_0)
 {
     Eterm ret;
     PD_CHECK(BIF_P->dictionary);
-    ret = pd_hash_get_all(BIF_P, BIF_P->dictionary);
+    ret = pd_hash_get_all(BIF_P, BIF_P->dictionary, 0);
     pd_hash_erase_all(BIF_P);
     PD_CHECK(BIF_P->dictionary);
     BIF_RET(ret);
@@ -541,29 +541,46 @@ static Eterm pd_hash_get_keys(Process *p, Eterm value)
 	
 
 static Eterm
-pd_hash_get_all(Process *p, ProcDict *pd)
+pd_hash_get_all(Process *p, ProcDict *pd, int keep_dict)
 {
     Eterm* hp;
+    Eterm* tp;
     Eterm res = NIL;
     Eterm tmp, tmp2;
     unsigned int i;
     unsigned int num;
+    Uint need;
 
     if (pd == NULL) {
 	return res;
     }
     num = HASH_RANGE(pd);
-    hp = HAlloc(p, pd->numElements * 2);
-    
+
+    /*
+     * If this is not erase/0, then must copy all key-value tuples
+     * as they may be mutated by put/2.
+     */
+    need = pd->numElements * (keep_dict ? 2+3 : 2);
+    hp = HAlloc(p, need);
+
     for (i = 0; i < num; ++i) {
 	tmp = ARRAY_GET(pd, i);
 	if (is_boxed(tmp)) {
-	    ASSERT(is_tuple(tmp));
+            if (keep_dict) {
+                tp = tuple_val(tmp);
+                tmp = TUPLE2(hp, tp[1], tp[2]);
+                hp += 3;
+            }
 	    res = CONS(hp, tmp, res);
 	    hp += 2;
 	} else if (is_list(tmp)) {
 	    while (tmp != NIL) {
 		tmp2 = TCAR(tmp);
+                if (keep_dict) {
+                    tp = tuple_val(tmp2);
+                    tmp2 = TUPLE2(hp, tp[1], tp[2]);
+                    hp += 3;
+                }
 		res = CONS(hp, tmp2, res);
 		hp += 2;
 		tmp = TCDR(tmp);
@@ -607,6 +624,11 @@ static Eterm pd_hash_put(Process *p, Eterm id, Eterm value)
         ASSERT(is_tuple(old));
         tp = tuple_val(old);
         if (EQ(tp[1], id)) {
+            if (is_immed(value)) {
+                Eterm old_val = tp[2];
+                tp[2] = value;
+                return old_val;
+            }
             key_at = 1;
         }
         else {
@@ -619,6 +641,11 @@ static Eterm pd_hash_put(Process *p, Eterm id, Eterm value)
 	for (tmp = old; tmp != NIL; tmp = TCDR(tmp)) {
             tp = tuple_val(TCAR(tmp));
             if (EQ(tp[1], id)) {
+                if (is_immed(value)) {
+                    Eterm old_val = tp[2];
+                    tp[2] = value;
+                    return old_val;
+                }
                 key_at = i;
                 needed += 2*(key_at-1);
                 break;
diff --git a/lib/kernel/test/pdict_SUITE.erl b/lib/kernel/test/pdict_SUITE.erl
index d105952df9..a891451c82 100644
--- a/lib/kernel/test/pdict_SUITE.erl
+++ b/lib/kernel/test/pdict_SUITE.erl
@@ -33,6 +33,7 @@
 	 init_per_group/2,end_per_group/2,
 	 mixed/1,
          literals/1,
+         destructive/1,
 	 simple/1, complicated/1, heavy/1, simple_all_keys/1, info/1]).
 -export([init_per_testcase/2, end_per_testcase/2]).
 -export([other_process/2]).
@@ -52,6 +53,7 @@ suite() ->
 all() -> 
     [simple, complicated, heavy, simple_all_keys, info,
      literals,
+     destructive,
      mixed].
 
 groups() -> 
@@ -367,6 +369,36 @@ match_keys(All) ->
     ok.
 
 
+%% Test destructive put optimization of immed values
+%% does not affect get/0 or process_info.
+destructive(_Config) ->
+    Keys = lists:seq(1,100),
+    [put(Key, 17) || Key <- Keys],
+    Get1 = get(),
+    {dictionary,PI1} = process_info(self(), dictionary),
+
+    [begin
+         {Key, 17} = lists:keyfind(Key, 1, Get1),
+         {Key, 17} = lists:keyfind(Key, 1, PI1)
+     end
+     || Key <- Keys],
+
+    [17 = put(Key, 42) || Key <- Keys],   % Mutate
+
+    Get2 = get(),
+    {dictionary,PI2} = process_info(self(), dictionary),
+
+    [begin
+         {Key, 17} = lists:keyfind(Key, 1, Get1),
+         {Key, 17} = lists:keyfind(Key, 1, PI1),
+         {Key, 42} = lists:keyfind(Key, 1, Get2),
+         {Key, 42} = lists:keyfind(Key, 1, PI2)
+
+     end
+     || Key <- Keys],
+
+    ok.
+
 %% Do random mixed put/erase to test grow/shrink
 %% Written for a temporary bug in gc during shrink
 mixed(_Config) ->
-- 
2.16.2