diff options
| author | Mattias EngdegÄrd | 2024-01-10 11:50:19 +0100 |
|---|---|---|
| committer | Mattias EngdegÄrd | 2024-01-12 15:06:14 +0100 |
| commit | 8ec0e030b661ae50d1aef4723b4e83a03645e4ee (patch) | |
| tree | 013ed1d65639596d06143173991250fc4a0e3af6 | |
| parent | 8884720dce883142965a958fc5a33071388ec2e1 (diff) | |
| download | emacs-scratch/hash-table-perf.tar.gz emacs-scratch/hash-table-perf.zip | |
Combine hash and next vector into a single arrayscratch/hash-table-perf
This shrinks the hash object by one word and should give better
locality since these values are often accessed at the same time.
| -rw-r--r-- | src/alloc.c | 16 | ||||
| -rw-r--r-- | src/fns.c | 52 | ||||
| -rw-r--r-- | src/lisp.h | 22 | ||||
| -rw-r--r-- | src/pdumper.c | 3 |
4 files changed, 34 insertions, 59 deletions
diff --git a/src/alloc.c b/src/alloc.c index 180b9995993..7f7e04415b4 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3473,11 +3473,9 @@ cleanup_vector (struct Lisp_Vector *vector) | |||
| 3473 | eassert (h->index_size > 1); | 3473 | eassert (h->index_size > 1); |
| 3474 | xfree (h->index); | 3474 | xfree (h->index); |
| 3475 | xfree (h->key_and_value); | 3475 | xfree (h->key_and_value); |
| 3476 | xfree (h->next); | 3476 | xfree (h->hash_next); |
| 3477 | xfree (h->hash); | ||
| 3478 | ptrdiff_t bytes = (h->table_size * (2 * sizeof *h->key_and_value | 3477 | ptrdiff_t bytes = (h->table_size * (2 * sizeof *h->key_and_value |
| 3479 | + sizeof *h->hash | 3478 | + sizeof *h->hash_next) |
| 3480 | + sizeof *h->next) | ||
| 3481 | + h->index_size * sizeof *h->index); | 3479 | + h->index_size * sizeof *h->index); |
| 3482 | hash_table_allocated_bytes -= bytes; | 3480 | hash_table_allocated_bytes -= bytes; |
| 3483 | } | 3481 | } |
| @@ -5974,13 +5972,9 @@ purecopy_hash_table (struct Lisp_Hash_Table *table) | |||
| 5974 | 5972 | ||
| 5975 | if (table->table_size > 0) | 5973 | if (table->table_size > 0) |
| 5976 | { | 5974 | { |
| 5977 | ptrdiff_t hash_bytes = table->table_size * sizeof *table->hash; | 5975 | ptrdiff_t hn_bytes = table->table_size * sizeof *table->hash_next; |
| 5978 | pure->hash = pure_alloc (hash_bytes, -(int)sizeof *table->hash); | 5976 | pure->hash_next = pure_alloc (hn_bytes, -(int)sizeof *table->hash_next); |
| 5979 | memcpy (pure->hash, table->hash, hash_bytes); | 5977 | memcpy (pure->hash_next, table->hash_next, hn_bytes); |
| 5980 | |||
| 5981 | ptrdiff_t next_bytes = table->table_size * sizeof *table->next; | ||
| 5982 | pure->next = pure_alloc (next_bytes, -(int)sizeof *table->next); | ||
| 5983 | memcpy (pure->next, table->next, next_bytes); | ||
| 5984 | 5978 | ||
| 5985 | ptrdiff_t nvalues = table->table_size * 2; | 5979 | ptrdiff_t nvalues = table->table_size * 2; |
| 5986 | ptrdiff_t kv_bytes = nvalues * sizeof *table->key_and_value; | 5980 | ptrdiff_t kv_bytes = nvalues * sizeof *table->key_and_value; |
| @@ -4280,13 +4280,13 @@ static void | |||
| 4280 | set_hash_next_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val) | 4280 | set_hash_next_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val) |
| 4281 | { | 4281 | { |
| 4282 | eassert (idx >= 0 && idx < h->table_size); | 4282 | eassert (idx >= 0 && idx < h->table_size); |
| 4283 | h->next[idx] = val; | 4283 | h->hash_next[idx].next = val; |
| 4284 | } | 4284 | } |
| 4285 | static void | 4285 | static void |
| 4286 | set_hash_hash_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, hash_hash_t val) | 4286 | set_hash_hash_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, hash_hash_t val) |
| 4287 | { | 4287 | { |
| 4288 | eassert (idx >= 0 && idx < h->table_size); | 4288 | eassert (idx >= 0 && idx < h->table_size); |
| 4289 | h->hash[idx] = val; | 4289 | h->hash_next[idx].hash = val; |
| 4290 | } | 4290 | } |
| 4291 | static void | 4291 | static void |
| 4292 | set_hash_index_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val) | 4292 | set_hash_index_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val) |
| @@ -4383,7 +4383,7 @@ static ptrdiff_t | |||
| 4383 | HASH_NEXT (struct Lisp_Hash_Table *h, ptrdiff_t idx) | 4383 | HASH_NEXT (struct Lisp_Hash_Table *h, ptrdiff_t idx) |
| 4384 | { | 4384 | { |
| 4385 | eassert (idx >= 0 && idx < h->table_size); | 4385 | eassert (idx >= 0 && idx < h->table_size); |
| 4386 | return h->next[idx]; | 4386 | return h->hash_next[idx].next; |
| 4387 | } | 4387 | } |
| 4388 | 4388 | ||
| 4389 | /* Return the index of the element in hash table H that is the start | 4389 | /* Return the index of the element in hash table H that is the start |
| @@ -4571,8 +4571,7 @@ make_hash_table (const struct hash_table_test *test, EMACS_INT size, | |||
| 4571 | if (size == 0) | 4571 | if (size == 0) |
| 4572 | { | 4572 | { |
| 4573 | h->key_and_value = NULL; | 4573 | h->key_and_value = NULL; |
| 4574 | h->hash = NULL; | 4574 | h->hash_next = NULL; |
| 4575 | h->next = NULL; | ||
| 4576 | eassert (index_size == 1); | 4575 | eassert (index_size == 1); |
| 4577 | h->index = (hash_idx_t *)empty_hash_index_vector; | 4576 | h->index = (hash_idx_t *)empty_hash_index_vector; |
| 4578 | h->next_free = -1; | 4577 | h->next_free = -1; |
| @@ -4584,12 +4583,10 @@ make_hash_table (const struct hash_table_test *test, EMACS_INT size, | |||
| 4584 | for (ptrdiff_t i = 0; i < 2 * size; i++) | 4583 | for (ptrdiff_t i = 0; i < 2 * size; i++) |
| 4585 | h->key_and_value[i] = HASH_UNUSED_ENTRY_KEY; | 4584 | h->key_and_value[i] = HASH_UNUSED_ENTRY_KEY; |
| 4586 | 4585 | ||
| 4587 | h->hash = hash_table_alloc_bytes (size * sizeof *h->hash); | 4586 | h->hash_next = hash_table_alloc_bytes (size * sizeof *h->hash_next); |
| 4588 | |||
| 4589 | h->next = hash_table_alloc_bytes (size * sizeof *h->next); | ||
| 4590 | for (ptrdiff_t i = 0; i < size - 1; i++) | 4587 | for (ptrdiff_t i = 0; i < size - 1; i++) |
| 4591 | h->next[i] = i + 1; | 4588 | h->hash_next[i].next = i + 1; |
| 4592 | h->next[size - 1] = -1; | 4589 | h->hash_next[size - 1].next = -1; |
| 4593 | 4590 | ||
| 4594 | h->index = hash_table_alloc_bytes (index_size * sizeof *h->index); | 4591 | h->index = hash_table_alloc_bytes (index_size * sizeof *h->index); |
| 4595 | for (ptrdiff_t i = 0; i < index_size; i++) | 4592 | for (ptrdiff_t i = 0; i < index_size; i++) |
| @@ -4630,13 +4627,9 @@ copy_hash_table (struct Lisp_Hash_Table *h1) | |||
| 4630 | h2->key_and_value = hash_table_alloc_bytes (kv_bytes); | 4627 | h2->key_and_value = hash_table_alloc_bytes (kv_bytes); |
| 4631 | memcpy (h2->key_and_value, h1->key_and_value, kv_bytes); | 4628 | memcpy (h2->key_and_value, h1->key_and_value, kv_bytes); |
| 4632 | 4629 | ||
| 4633 | ptrdiff_t hash_bytes = h1->table_size * sizeof *h1->hash; | 4630 | ptrdiff_t hn_bytes = h1->table_size * sizeof *h1->hash_next; |
| 4634 | h2->hash = hash_table_alloc_bytes (hash_bytes); | 4631 | h2->hash_next = hash_table_alloc_bytes (hn_bytes); |
| 4635 | memcpy (h2->hash, h1->hash, hash_bytes); | 4632 | memcpy (h2->hash_next, h1->hash_next, hn_bytes); |
| 4636 | |||
| 4637 | ptrdiff_t next_bytes = h1->table_size * sizeof *h1->next; | ||
| 4638 | h2->next = hash_table_alloc_bytes (next_bytes); | ||
| 4639 | memcpy (h2->next, h1->next, next_bytes); | ||
| 4640 | 4633 | ||
| 4641 | ptrdiff_t index_bytes = h1->index_size * sizeof *h1->index; | 4634 | ptrdiff_t index_bytes = h1->index_size * sizeof *h1->index; |
| 4642 | h2->index = hash_table_alloc_bytes (index_bytes); | 4635 | h2->index = hash_table_alloc_bytes (index_bytes); |
| @@ -4674,11 +4667,12 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) | |||
| 4674 | 4667 | ||
| 4675 | /* Allocate all the new vectors before updating *H, to | 4668 | /* Allocate all the new vectors before updating *H, to |
| 4676 | avoid problems if memory is exhausted. */ | 4669 | avoid problems if memory is exhausted. */ |
| 4677 | hash_idx_t *next = hash_table_alloc_bytes (new_size * sizeof *next); | 4670 | struct hash_next *hash_next |
| 4678 | memcpy (next, h->next, old_size * sizeof *next); | 4671 | = hash_table_alloc_bytes (new_size * sizeof *hash_next); |
| 4672 | memcpy (hash_next, h->hash_next, old_size * sizeof *hash_next); | ||
| 4679 | for (ptrdiff_t i = old_size; i < new_size - 1; i++) | 4673 | for (ptrdiff_t i = old_size; i < new_size - 1; i++) |
| 4680 | next[i] = i + 1; | 4674 | hash_next[i].next = i + 1; |
| 4681 | next[new_size - 1] = -1; | 4675 | hash_next[new_size - 1].next = -1; |
| 4682 | 4676 | ||
| 4683 | Lisp_Object *key_and_value | 4677 | Lisp_Object *key_and_value |
| 4684 | = hash_table_alloc_bytes (2 * new_size * sizeof *key_and_value); | 4678 | = hash_table_alloc_bytes (2 * new_size * sizeof *key_and_value); |
| @@ -4687,9 +4681,6 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) | |||
| 4687 | for (ptrdiff_t i = 2 * old_size; i < 2 * new_size; i++) | 4681 | for (ptrdiff_t i = 2 * old_size; i < 2 * new_size; i++) |
| 4688 | key_and_value[i] = HASH_UNUSED_ENTRY_KEY; | 4682 | key_and_value[i] = HASH_UNUSED_ENTRY_KEY; |
| 4689 | 4683 | ||
| 4690 | hash_hash_t *hash = hash_table_alloc_bytes (new_size * sizeof *hash); | ||
| 4691 | memcpy (hash, h->hash, old_size * sizeof *hash); | ||
| 4692 | |||
| 4693 | ptrdiff_t old_index_size = h->index_size; | 4684 | ptrdiff_t old_index_size = h->index_size; |
| 4694 | ptrdiff_t index_size = hash_index_size (new_size); | 4685 | ptrdiff_t index_size = hash_index_size (new_size); |
| 4695 | hash_idx_t *index = hash_table_alloc_bytes (index_size * sizeof *index); | 4686 | hash_idx_t *index = hash_table_alloc_bytes (index_size * sizeof *index); |
| @@ -4708,11 +4699,8 @@ maybe_resize_hash_table (struct Lisp_Hash_Table *h) | |||
| 4708 | 2 * old_size * sizeof *h->key_and_value); | 4699 | 2 * old_size * sizeof *h->key_and_value); |
| 4709 | h->key_and_value = key_and_value; | 4700 | h->key_and_value = key_and_value; |
| 4710 | 4701 | ||
| 4711 | hash_table_free_bytes (h->hash, old_size * sizeof *h->hash); | 4702 | hash_table_free_bytes (h->hash_next, old_size * sizeof *h->hash_next); |
| 4712 | h->hash = hash; | 4703 | h->hash_next = hash_next; |
| 4713 | |||
| 4714 | hash_table_free_bytes (h->next, old_size * sizeof *h->next); | ||
| 4715 | h->next = next; | ||
| 4716 | 4704 | ||
| 4717 | h->key_and_value = key_and_value; | 4705 | h->key_and_value = key_and_value; |
| 4718 | 4706 | ||
| @@ -4760,11 +4748,7 @@ hash_table_thaw (Lisp_Object hash_table) | |||
| 4760 | h->index_size = index_size; | 4748 | h->index_size = index_size; |
| 4761 | h->next_free = -1; | 4749 | h->next_free = -1; |
| 4762 | 4750 | ||
| 4763 | h->hash = hash_table_alloc_bytes (size * sizeof *h->hash); | 4751 | h->hash_next = hash_table_alloc_bytes (size * sizeof *h->hash_next); |
| 4764 | |||
| 4765 | h->next = hash_table_alloc_bytes (size * sizeof *h->next); | ||
| 4766 | for (ptrdiff_t i = 0; i < size; i++) | ||
| 4767 | h->next[i] = -1; | ||
| 4768 | 4752 | ||
| 4769 | h->index = hash_table_alloc_bytes (index_size * sizeof *h->index); | 4753 | h->index = hash_table_alloc_bytes (index_size * sizeof *h->index); |
| 4770 | for (ptrdiff_t i = 0; i < index_size; i++) | 4754 | for (ptrdiff_t i = 0; i < index_size; i++) |
diff --git a/src/lisp.h b/src/lisp.h index 64e8e0c11c3..30e452ffbb0 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -2429,6 +2429,11 @@ typedef enum { | |||
| 2429 | (hash) indices. It's signed and a subtype of ptrdiff_t. */ | 2429 | (hash) indices. It's signed and a subtype of ptrdiff_t. */ |
| 2430 | typedef int32_t hash_idx_t; | 2430 | typedef int32_t hash_idx_t; |
| 2431 | 2431 | ||
| 2432 | struct hash_next { | ||
| 2433 | hash_hash_t hash; /* Hash value for entry. Undefined for unused entries. */ | ||
| 2434 | hash_idx_t next; /* Next index in bucket or free list, or -1 if last. */ | ||
| 2435 | }; | ||
| 2436 | |||
| 2432 | struct Lisp_Hash_Table | 2437 | struct Lisp_Hash_Table |
| 2433 | { | 2438 | { |
| 2434 | union vectorlike_header header; | 2439 | union vectorlike_header header; |
| @@ -2455,11 +2460,11 @@ struct Lisp_Hash_Table | |||
| 2455 | | | 2460 | | |
| 2456 | next_free | 2461 | next_free |
| 2457 | 2462 | ||
| 2458 | The table is physically split into three vectors (hash, next, | 2463 | The table is physically split into two vectors (hash_next, |
| 2459 | key_and_value) which may or may not be beneficial. */ | 2464 | key_and_value) which may or may not be beneficial. */ |
| 2460 | 2465 | ||
| 2461 | hash_idx_t index_size; /* Size of the index vector. */ | 2466 | hash_idx_t index_size; /* Size of the index vector. */ |
| 2462 | hash_idx_t table_size; /* Size of the next and hash vectors. */ | 2467 | hash_idx_t table_size; /* Size of hash_next and key_and_value arrays. */ |
| 2463 | 2468 | ||
| 2464 | /* Bucket vector. An entry of -1 indicates no item is present, | 2469 | /* Bucket vector. An entry of -1 indicates no item is present, |
| 2465 | and a nonnegative entry is the index of the first item in | 2470 | and a nonnegative entry is the index of the first item in |
| @@ -2470,9 +2475,9 @@ struct Lisp_Hash_Table | |||
| 2470 | Otherwise it is heap-allocated. */ | 2475 | Otherwise it is heap-allocated. */ |
| 2471 | hash_idx_t *index; | 2476 | hash_idx_t *index; |
| 2472 | 2477 | ||
| 2473 | /* Vector of hash codes. Unused entries have undefined values. | 2478 | /* Vector of hash values and next indices. |
| 2474 | This vector is table_size entries long. */ | 2479 | This vector is table_size entries long. */ |
| 2475 | hash_hash_t *hash; | 2480 | struct hash_next *hash_next; |
| 2476 | 2481 | ||
| 2477 | /* Vector of keys and values. The key of item I is found at index | 2482 | /* Vector of keys and values. The key of item I is found at index |
| 2478 | 2 * I, the value is found at index 2 * I + 1. | 2483 | 2 * I, the value is found at index 2 * I + 1. |
| @@ -2484,13 +2489,6 @@ struct Lisp_Hash_Table | |||
| 2484 | /* The comparison and hash functions. */ | 2489 | /* The comparison and hash functions. */ |
| 2485 | const struct hash_table_test *test; | 2490 | const struct hash_table_test *test; |
| 2486 | 2491 | ||
| 2487 | /* Vector used to chain entries. If entry I is free, next[I] is the | ||
| 2488 | entry number of the next free item. If entry I is non-free, | ||
| 2489 | next[I] is the index of the next entry in the collision chain, | ||
| 2490 | or -1 if there is no such entry. | ||
| 2491 | This vector is table_size entries long. */ | ||
| 2492 | hash_idx_t *next; | ||
| 2493 | |||
| 2494 | /* Number of key/value entries in the table. */ | 2492 | /* Number of key/value entries in the table. */ |
| 2495 | hash_idx_t count; | 2493 | hash_idx_t count; |
| 2496 | 2494 | ||
| @@ -2565,7 +2563,7 @@ INLINE hash_hash_t | |||
| 2565 | HASH_HASH (const struct Lisp_Hash_Table *h, ptrdiff_t idx) | 2563 | HASH_HASH (const struct Lisp_Hash_Table *h, ptrdiff_t idx) |
| 2566 | { | 2564 | { |
| 2567 | eassert (idx >= 0 && idx < h->table_size); | 2565 | eassert (idx >= 0 && idx < h->table_size); |
| 2568 | return h->hash[idx]; | 2566 | return h->hash_next[idx].hash; |
| 2569 | } | 2567 | } |
| 2570 | 2568 | ||
| 2571 | /* Value is the size of hash table H. */ | 2569 | /* Value is the size of hash table H. */ |
diff --git a/src/pdumper.c b/src/pdumper.c index 0bc3a9bd958..83406343b98 100644 --- a/src/pdumper.c +++ b/src/pdumper.c | |||
| @@ -2717,8 +2717,7 @@ static void | |||
| 2717 | hash_table_freeze (struct Lisp_Hash_Table *h) | 2717 | hash_table_freeze (struct Lisp_Hash_Table *h) |
| 2718 | { | 2718 | { |
| 2719 | h->key_and_value = hash_table_contents (h); | 2719 | h->key_and_value = hash_table_contents (h); |
| 2720 | h->next = NULL; | 2720 | h->hash_next = NULL; |
| 2721 | h->hash = NULL; | ||
| 2722 | h->index = NULL; | 2721 | h->index = NULL; |
| 2723 | h->table_size = 0; | 2722 | h->table_size = 0; |
| 2724 | h->index_size = 0; | 2723 | h->index_size = 0; |