File 3481-Do-not-allocate-large-map-when-value-is-the-same.patch of Package erlang

From 8609f5cd9d6820f058693294e9d4433ce2922243 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Valim?= <jose.valim@dashbit.co>
Date: Mon, 22 Mar 2021 17:35:46 +0100
Subject: [PATCH 1/3] Do not allocate large map when value is the same

This is the same as 6007bf0f8 but applied to large maps.
---
 erts/emulator/beam/erl_map.c   | 26 +++++++++++++++++++++-----
 erts/emulator/beam/erl_map.h   |  2 +-
 lib/stdlib/test/maps_SUITE.erl |  8 ++++++--
 3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c
index 9b1762e299..ce17cd9163 100644
--- a/erts/emulator/beam/erl_map.c
+++ b/erts/emulator/beam/erl_map.c
@@ -2370,17 +2370,29 @@ Eterm erts_hashmap_insert(Process *p, Uint32 hx, Eterm key, Eterm value,
     Uint size, upsz;
     Eterm *hp, res = THE_NON_VALUE;
     DECLARE_ESTACK(stack);
-    if (erts_hashmap_insert_down(hx, key, map, &size, &upsz, &stack, is_update)) {
-	hp  = HAlloc(p, size);
-	res = erts_hashmap_insert_up(hp, key, value, &upsz, &stack);
+    if (erts_hashmap_insert_down(hx, key, value, map, &size, &upsz, &stack,
+                                 is_update)) {
+        if (size) {
+            /* We are putting a new value (under a new or existing key) */
+	    hp  = HAlloc(p, size);
+	    res = erts_hashmap_insert_up(hp, key, value, &upsz, &stack);
+	}
+        else {
+            /* We are putting the same key-value */
+            res = map;
+        }
+    }
+    else {
+        /* We are updating and the key does not exist */
+        ASSERT(is_update);
     }
-    DESTROY_ESTACK(stack);
 
+    DESTROY_ESTACK(stack);
     return res;
 }
 
 
-int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz,
+int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm value, Eterm node, Uint *sz,
 			     Uint *update_size, ErtsEStack *sp, int is_update) {
     Eterm *ptr;
     Eterm hdr, ckey;
@@ -2398,6 +2410,10 @@ int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz,
 		ptr  = list_val(node);
 		ckey = CAR(ptr);
 		if (EQ(ckey, key)) {
+		    if (CDR(ptr) == value) {
+                        *sz = 0; /* same value, same map, no heap needed */
+                        return 1;
+                    }
 		    *update_size = 0;
 		    goto unroll;
 		}
diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h
index 718d400e22..d587273ec7 100644
--- a/erts/emulator/beam/erl_map.h
+++ b/erts/emulator/beam/erl_map.h
@@ -85,7 +85,7 @@ int    erts_maps_take(Process *p, Eterm key, Eterm map, Eterm *res, Eterm *value
 
 Eterm  erts_hashmap_insert(Process *p, Uint32 hx, Eterm key, Eterm value,
 			   Eterm node, int is_update);
-int    erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz,
+int    erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm value, Eterm node, Uint *sz,
 			        Uint *upsz, struct ErtsEStack_ *sp, int is_update);
 Eterm  erts_hashmap_insert_up(Eterm *hp, Eterm key, Eterm value,
 			      Uint *upsz, struct ErtsEStack_ *sp);
diff --git a/lib/stdlib/test/maps_SUITE.erl b/lib/stdlib/test/maps_SUITE.erl
index 4159ea6c3b..4860e39b70 100644
--- a/lib/stdlib/test/maps_SUITE.erl
+++ b/lib/stdlib/test/maps_SUITE.erl
@@ -495,8 +495,12 @@ iter_kv(I) ->
 
 t_put_opt(Config) when is_list(Config) ->
     Value = id(#{complex => map}),
-    Map = id(#{a => Value}),
-    true = erts_debug:same(maps:put(a, Value, Map), Map),
+    Small = id(#{a => Value}),
+    true = erts_debug:same(maps:put(a, Value, Small), Small),
+
+    LargeBase = maps:from_list([{I,I}||I<-lists:seq(1,200)]),
+    Large = LargeBase#{a => Value},
+    true = erts_debug:same(maps:put(a, Value, Large), Large),
     ok.
 
 t_merge_opt(Config) when is_list(Config) ->
-- 
2.26.2

openSUSE Build Service is sponsored by