diff options
author | José Valim <jose.valim@dashbit.co> | 2021-03-22 17:35:46 +0100 |
---|---|---|
committer | Sverker Eriksson <sverker@erlang.org> | 2021-04-09 14:17:35 +0200 |
commit | 8609f5cd9d6820f058693294e9d4433ce2922243 (patch) | |
tree | c9be93f61fe341c4c8ed7928159f503ed9c3a1e4 | |
parent | 4e1660e7ff93334ef8ce3ae740e0886e4483bf30 (diff) | |
download | erlang-8609f5cd9d6820f058693294e9d4433ce2922243.tar.gz |
Do not allocate large map when value is the same
This is the same as 6007bf0f8 but applied to large maps.
-rw-r--r-- | erts/emulator/beam/erl_map.c | 26 | ||||
-rw-r--r-- | erts/emulator/beam/erl_map.h | 2 | ||||
-rw-r--r-- | 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) -> |