From 8609f5cd9d6820f058693294e9d4433ce2922243 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 22 Mar 2021 17:35:46 +0100 Subject: 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) -> -- cgit v1.2.1