aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMattias EngdegÄrd2024-01-10 11:50:19 +0100
committerMattias EngdegÄrd2024-01-12 15:06:14 +0100
commit8ec0e030b661ae50d1aef4723b4e83a03645e4ee (patch)
tree013ed1d65639596d06143173991250fc4a0e3af6
parent8884720dce883142965a958fc5a33071388ec2e1 (diff)
downloademacs-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.c16
-rw-r--r--src/fns.c52
-rw-r--r--src/lisp.h22
-rw-r--r--src/pdumper.c3
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;
diff --git a/src/fns.c b/src/fns.c
index 557853d42fb..a96ddad1683 100644
--- a/src/fns.c
+++ b/src/fns.c
@@ -4280,13 +4280,13 @@ static void
4280set_hash_next_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val) 4280set_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}
4285static void 4285static void
4286set_hash_hash_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, hash_hash_t val) 4286set_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}
4291static void 4291static void
4292set_hash_index_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val) 4292set_hash_index_slot (struct Lisp_Hash_Table *h, ptrdiff_t idx, ptrdiff_t val)
@@ -4383,7 +4383,7 @@ static ptrdiff_t
4383HASH_NEXT (struct Lisp_Hash_Table *h, ptrdiff_t idx) 4383HASH_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. */
2430typedef int32_t hash_idx_t; 2430typedef int32_t hash_idx_t;
2431 2431
2432struct 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
2432struct Lisp_Hash_Table 2437struct 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
2565HASH_HASH (const struct Lisp_Hash_Table *h, ptrdiff_t idx) 2563HASH_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
2717hash_table_freeze (struct Lisp_Hash_Table *h) 2717hash_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;