Updating ccan to stricter htable revealed we were trying to put (void *)1 in the htable, which is forbidden: ``` topology: ccan/ccan/htable/htable.c:382: htable_add_: Assertion `entry_is_valid((uintptr_t)p)' failed. topology: FATAL SIGNAL 6 (version 1358d7f) 0x55f30c689c34 send_backtrace common/daemon.c:33 0x55f30c689ce0 crashdump common/daemon.c:46 0x7f5d150fe51f ??? ./signal/../sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c:0 0x7f5d15152828 __pthread_kill_implementation ./nptl/pthread_kill.c:44 0x7f5d15152828 __pthread_kill_internal ./nptl/pthread_kill.c:80 0x7f5d15152828 __GI___pthread_kill ./nptl/pthread_kill.c:91 0x7f5d150fe475 __GI_raise ../sysdeps/posix/raise.c:26 0x7f5d150e47b6 __GI_abort ./stdlib/abort.c:79 0x7f5d150e46da __assert_fail_base ./assert/assert.c:92 0x7f5d150f5e25 __GI___assert_fail ./assert/assert.c:101 0x55f30c6adbe4 htable_add_ ccan/ccan/htable/htable.c:382 0x55f30c65f303 chanidx_htable_add common/gossmap.c:35 0x55f30c6605ed new_channel common/gossmap.c:337 0x55f30c6609cf add_channel common/gossmap.c:425 0x55f30c661101 map_catchup common/gossmap.c:607 0x55f30c66221e gossmap_refresh common/gossmap.c:927 0x55f30c66e3e9 get_gossmap plugins/topology.c:27 0x55f30c66f939 listpeers_done plugins/topology.c:369 0x55f30c671f46 handle_rpc_reply plugins/libplugin.c:558 0x55f30c672a19 rpc_read_response_one plugins/libplugin.c:726 0x55f30c672b4f rpc_conn_read_response plugins/libplugin.c:746 0x55f30c6ae35e next_plan ccan/ccan/io/io.c:59 0x55f30c6aef93 do_plan ccan/ccan/io/io.c:407 0x55f30c6aefd5 io_ready ccan/ccan/io/io.c:417 0x55f30c6b1371 io_loop ccan/ccan/io/poll.c:453 0x55f30c67587c plugin_main plugins/libplugin.c:1559 0x55f30c6708eb main plugins/topology.c:701 0x7f5d150e5fcf __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58 0x7f5d150e607c __libc_start_main_impl ../csu/libc-start.c:409 0x55f30c65d894 ??? ???:0 0xffffffffffffffff ??? ???:0 ``` Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
108 lines
2.5 KiB
C
108 lines
2.5 KiB
C
/* Density measurements for hashtables. */
|
|
#include <ccan/err/err.h>
|
|
#include <ccan/htable/htable_type.h>
|
|
#include <ccan/htable/htable.c>
|
|
#include <ccan/hash/hash.h>
|
|
#include <ccan/ptrint/ptrint.h>
|
|
#include <ccan/time/time.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
/* We don't actually hash objects: we put values in as if they were ptrs */
|
|
static uintptr_t key(const ptrint_t *obj)
|
|
{
|
|
return ptr2int(obj);
|
|
}
|
|
|
|
static size_t hash_uintptr(uintptr_t key)
|
|
{
|
|
return hashl(&key, 1, 0);
|
|
}
|
|
|
|
static bool cmp(const ptrint_t *p, uintptr_t k)
|
|
{
|
|
return key(p) == k;
|
|
}
|
|
|
|
HTABLE_DEFINE_TYPE(ptrint_t, key, hash_uintptr, cmp, htable_ptrint);
|
|
|
|
/* Nanoseconds per operation */
|
|
static size_t normalize(const struct timeabs *start,
|
|
const struct timeabs *stop,
|
|
unsigned int num)
|
|
{
|
|
return time_to_nsec(time_divide(time_between(*stop, *start), num));
|
|
}
|
|
|
|
static size_t average_run(const struct htable_ptrint *ht, size_t count, size_t *longest)
|
|
{
|
|
size_t i, total = 0;
|
|
|
|
*longest = 0;
|
|
for (i = 0; i < count; i++) {
|
|
size_t h = hash_uintptr(i + 2);
|
|
size_t run = 1;
|
|
|
|
while (get_raw_ptr(&ht->raw, ht->raw.table[h % ((size_t)1 << ht->raw.bits)]) != int2ptr(i + 2)) {
|
|
h++;
|
|
run++;
|
|
}
|
|
total += run;
|
|
if (run > *longest)
|
|
*longest = run;
|
|
}
|
|
return total / count;
|
|
}
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
unsigned int i;
|
|
size_t num;
|
|
struct timeabs start, stop;
|
|
struct htable_ptrint ht;
|
|
|
|
if (argc != 2)
|
|
errx(1, "Usage: density <power-of-2-tablesize>");
|
|
|
|
num = atoi(argv[1]);
|
|
|
|
printf("Total buckets, buckets used, nanoseconds search time per element, avg run, longest run\n");
|
|
for (i = 1; i <= 99; i++) {
|
|
uintptr_t j;
|
|
struct htable_ptrint_iter it;
|
|
size_t count, avg_run, longest_run;
|
|
ptrint_t *p;
|
|
|
|
htable_ptrint_init_sized(&ht, num * 3 / 4);
|
|
assert((1 << ht.raw.bits) == num);
|
|
|
|
/* Can't put 0 or 1 in the hash table: multiply by a prime. */
|
|
for (j = 0; j < num * i / 100; j++) {
|
|
htable_ptrint_add(&ht, int2ptr(j + 2));
|
|
/* stop it from doubling! */
|
|
ht.raw.elems = num / 2;
|
|
}
|
|
/* Must not have changed! */
|
|
assert((1 << ht.raw.bits) == num);
|
|
|
|
/* Clean cache */
|
|
count = 0;
|
|
for (p = htable_ptrint_first(&ht, &it); p; p = htable_ptrint_next(&ht, &it))
|
|
count++;
|
|
assert(count == num * i / 100);
|
|
start = time_now();
|
|
for (j = 0; j < count; j++)
|
|
assert(htable_ptrint_get(&ht, j + 2));
|
|
stop = time_now();
|
|
avg_run = average_run(&ht, count, &longest_run);
|
|
printf("%zu,%zu,%zu,%zu,%zu\n",
|
|
num, count, normalize(&start, &stop, count), avg_run, longest_run);
|
|
fflush(stdout);
|
|
htable_ptrint_clear(&ht);
|
|
}
|
|
|
|
return 0;
|
|
}
|