diff options
author | Sverker Eriksson <sverker@erlang.org> | 2021-04-09 15:02:23 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-09 15:02:23 +0200 |
commit | 8727d3e5892f34cca9267b65ccac0d05071a5922 (patch) | |
tree | 2c4d6e9f2d42a3dc7904547c0a69c5988991d955 /erts | |
parent | 47f356348ee334192aae9c4035f2a7affb8ebbb7 (diff) | |
parent | 24d7fa01c67dd00b134cc5f8c5779d8513f8dd0f (diff) | |
download | erlang-8727d3e5892f34cca9267b65ccac0d05071a5922.tar.gz |
Merge PR-4656 from josevalim/jv-large-map-opt OTP-17310
Do not allocate large map when value is the same
Diffstat (limited to 'erts')
-rw-r--r-- | erts/emulator/beam/erl_map.c | 39 | ||||
-rw-r--r-- | erts/emulator/beam/erl_map.h | 4 |
2 files changed, 27 insertions, 16 deletions
diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index 9b1762e299..4f9d9ce287 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -2370,39 +2370,53 @@ 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; Uint32 ix, cix, bp, hval, chx; Uint slot, lvl = 0, clvl; Uint size = 0, n = 0; - DeclareTmpHeapNoproc(th,2); + Eterm th[2]; *update_size = 1; - UseTmpHeapNoproc(2); for (;;) { switch(primary_tag(node)) { case TAG_PRIMARY_LIST: /* LEAF NODE [K|V] */ 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; } if (is_update) { - UnUseTmpHeapNoproc(2); return 0; } goto insert_subnodes; @@ -2435,7 +2449,6 @@ int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz, if (!(bp & hval)) { /* not occupied */ if (is_update) { - UnUseTmpHeapNoproc(2); return 0; } size += HAMT_NODE_BITMAP_SZ(n+1); @@ -2467,7 +2480,6 @@ int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz, } /* not occupied */ if (is_update) { - UnUseTmpHeapNoproc(2); return 0; } size += HAMT_HEAD_BITMAP_SZ(n+1); @@ -2501,12 +2513,11 @@ insert_subnodes: unroll: *sz = size + /* res cons */ 2; - UnUseTmpHeapNoproc(2); return 1; } Eterm erts_hashmap_insert_up(Eterm *hp, Eterm key, Eterm value, - Uint *update_size, ErtsEStack *sp) { + Uint update_size, ErtsEStack *sp) { Eterm node, *ptr, hdr; Eterm res; Eterm *nhp = NULL; @@ -2551,7 +2562,7 @@ Eterm erts_hashmap_insert_up(Eterm *hp, Eterm key, Eterm value, nhp = hp; n = HAMT_HEAD_ARRAY_SZ - 2; *hp++ = MAP_HEADER_HAMT_HEAD_ARRAY; ptr++; - *hp++ = (*ptr++) + *update_size; + *hp++ = (*ptr++) + update_size; while(n--) { *hp++ = *ptr++; } nhp[slot+2] = res; res = make_hashmap(nhp); @@ -2579,7 +2590,7 @@ Eterm erts_hashmap_insert_up(Eterm *hp, Eterm key, Eterm value, hval = MAP_HEADER_VAL(hdr); nhp = hp; *hp++ = MAP_HEADER_HAMT_HEAD_BITMAP(hval | bp); ptr++; - *hp++ = (*ptr++) + *update_size; + *hp++ = (*ptr++) + update_size; n -= slot; while(slot--) { *hp++ = *ptr++; } diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h index 718d400e22..980cf246c4 100644 --- a/erts/emulator/beam/erl_map.h +++ b/erts/emulator/beam/erl_map.h @@ -85,10 +85,10 @@ 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); + Uint upsz, struct ErtsEStack_ *sp); int erts_validate_and_sort_flatmap(flatmap_t* map); void hashmap_iterator_init(struct ErtsWStack_* s, Eterm node, int reverse); |