Browse Source
In particular, this gets some MacOS fixes from #1327. It also includes a major intmap update which fixes corner cases in traversals, and requires ccan/bitops. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
Rusty Russell
7 years ago
committed by
Christian Decker
22 changed files with 1148 additions and 81 deletions
@ -1,3 +1,3 @@ |
|||
CCAN imported from http://ccodearchive.net. |
|||
|
|||
CCAN version: init-2405-g41a0af50 |
|||
CCAN version: init-2419-g9bdb4be8 |
|||
|
@ -0,0 +1 @@ |
|||
../../licenses/CC0 |
@ -0,0 +1,43 @@ |
|||
#include "config.h" |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
/** |
|||
* bitops - bit counting routines |
|||
* |
|||
* These offer convenience wrappers around (and, as necessary, |
|||
* replacements for) the builtin bit testing/counting routines. |
|||
* |
|||
* Example: |
|||
* #include <ccan/bitops/bitops.h> |
|||
* #include <stdio.h> |
|||
* |
|||
* int main(int argc, char *argv[]) |
|||
* { |
|||
* unsigned int v = atoi(argv[1]); |
|||
* |
|||
* printf("Number of 1 bits: %i\n", bitops_weight32(v)); |
|||
* if (v != 0) { |
|||
* printf("Least-significant set bit: %i\n", bitops_ls32(v)); |
|||
* printf("Most-significant set bit: %i\n", bitops_hs32(v)); |
|||
* printf("Least-significant clear bit: %i\n", bitops_lc32(v)); |
|||
* printf("Most-significant clear bit: %i\n", bitops_hc32(v)); |
|||
* } |
|||
* return 0; |
|||
* } |
|||
* |
|||
* License: CC0 (Public Domain) |
|||
* Author: Rusty Russell <rusty@rustcorp.com.au> |
|||
*/ |
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
/* Expect exactly one argument */ |
|||
if (argc != 2) |
|||
return 1; |
|||
|
|||
if (strcmp(argv[1], "depends") == 0) { |
|||
return 0; |
|||
} |
|||
|
|||
return 1; |
|||
} |
@ -0,0 +1,79 @@ |
|||
/* CC0 license (public domain) - see LICENSE file for details */ |
|||
#include <ccan/bitops/bitops.h> |
|||
#include <stdlib.h> |
|||
|
|||
/* We do naive replacement versions: good for testing, and really your
|
|||
* compiler should do better. */ |
|||
#ifdef BITOPS_NEED_FFS |
|||
int bitops_ffs32(uint32_t u) |
|||
{ |
|||
int i; |
|||
for (i = 0; i < 32; i++) |
|||
if (u & ((uint32_t)1 << i)) |
|||
return i + 1; |
|||
return 0; |
|||
} |
|||
|
|||
int bitops_ffs64(uint64_t u) |
|||
{ |
|||
int i; |
|||
for (i = 0; i < 64; i++) |
|||
if (u & ((uint64_t)1 << i)) |
|||
return i + 1; |
|||
return 0; |
|||
} |
|||
#endif |
|||
|
|||
#ifdef BITOPS_NEED_CLZ |
|||
int bitops_clz32(uint32_t u) |
|||
{ |
|||
int i; |
|||
for (i = 0; i < 32; i++) |
|||
if (u & ((uint32_t)1 << (31 - i))) |
|||
return i; |
|||
abort(); |
|||
} |
|||
|
|||
int bitops_clz64(uint64_t u) |
|||
{ |
|||
int i; |
|||
for (i = 0; i < 64; i++) |
|||
if (u & ((uint64_t)1 << (63 - i))) |
|||
return i; |
|||
abort(); |
|||
} |
|||
#endif |
|||
|
|||
#ifdef BITOPS_NEED_CTZ |
|||
int bitops_ctz32(uint32_t u) |
|||
{ |
|||
BITOPS_ASSERT_NONZERO(u); |
|||
return bitops_ffs32(u) - 1; |
|||
} |
|||
|
|||
int bitops_ctz64(uint64_t u) |
|||
{ |
|||
BITOPS_ASSERT_NONZERO(u); |
|||
return bitops_ffs64(u) - 1; |
|||
} |
|||
#endif |
|||
|
|||
#ifdef BITOPS_NEED_WEIGHT |
|||
int bitops_weight32(uint32_t u) |
|||
{ |
|||
int i, num = 0; |
|||
for (i = 0; i < 32; i++) |
|||
if (u & ((uint32_t)1 << i)) |
|||
num++; |
|||
return num; |
|||
} |
|||
|
|||
int bitops_weight64(uint64_t u) |
|||
{ |
|||
int i, num = 0; |
|||
for (i = 0; i < 64; i++) |
|||
if (u & ((uint64_t)1 << i)) |
|||
num++; |
|||
return num; |
|||
} |
|||
#endif |
@ -0,0 +1,223 @@ |
|||
/* CC0 license (public domain) - see LICENSE file for details */ |
|||
#ifndef CCAN_BITOPS_H |
|||
#define CCAN_BITOPS_H |
|||
#include "config.h" |
|||
#include <stdint.h> |
|||
|
|||
#if defined(CCAN_DEBUG) || defined(CCAN_BITOPS_DEBUG) |
|||
#include <assert.h> |
|||
#define BITOPS_ASSERT_NONZERO(u) assert((u) != 0) |
|||
#else |
|||
#define BITOPS_ASSERT_NONZERO(u) |
|||
#endif |
|||
|
|||
#if HAVE_BUILTIN_FFS && HAVE_BUILTIN_FFSL && HAVE_BUILTIN_FFSLL |
|||
/**
|
|||
* bitops_ffs32: find first set bit in a uint32_t |
|||
* |
|||
* Returns 1 for least signficant bit, 32 for most significant bit, 0 |
|||
* for no bits set. |
|||
*/ |
|||
static inline int bitops_ffs32(uint32_t u) |
|||
{ |
|||
return __builtin_ffs(u); |
|||
} |
|||
|
|||
/**
|
|||
* bitops_ffs64: find lowest set bit in a uint64_t |
|||
* |
|||
* Returns 1 for least signficant bit, 32 for most significant bit, 0 |
|||
* for no bits set. |
|||
*/ |
|||
static inline int bitops_ffs64(uint64_t u) |
|||
{ |
|||
if (sizeof(u) == sizeof(long)) |
|||
return __builtin_ffsl(u); |
|||
else |
|||
return __builtin_ffsll(u); |
|||
} |
|||
#else |
|||
int bitops_ffs32(uint32_t u); |
|||
int bitops_ffs64(uint64_t u); |
|||
#define BITOPS_NEED_FFS 1 |
|||
#endif |
|||
|
|||
#if HAVE_BUILTIN_CLZ && HAVE_BUILTIN_CLZL && HAVE_BUILTIN_CLZLL |
|||
/**
|
|||
* bitops_clz32: count leading zeros in a uint32_t (must not be 0) |
|||
* |
|||
* Returns 0 if most signficant bit is set, 31 if only least |
|||
* signficant bit is set. |
|||
*/ |
|||
static inline int bitops_clz32(uint32_t u) |
|||
{ |
|||
BITOPS_ASSERT_NONZERO(u); |
|||
return __builtin_clz(u); |
|||
} |
|||
|
|||
/**
|
|||
* bitops_clz64: count leading zeros in a uint64_t (must not be 0) |
|||
* |
|||
* Returns 0 if most signficant bit is set, 63 if only least |
|||
* signficant bit is set. |
|||
*/ |
|||
static inline int bitops_clz64(uint64_t u) |
|||
{ |
|||
BITOPS_ASSERT_NONZERO(u); |
|||
if (sizeof(u) == sizeof(long)) |
|||
return __builtin_clzl(u); |
|||
else |
|||
return __builtin_clzll(u); |
|||
} |
|||
#else |
|||
int bitops_clz32(uint32_t u); |
|||
int bitops_clz64(uint64_t u); |
|||
#define BITOPS_NEED_CLZ 1 |
|||
#endif |
|||
|
|||
#if HAVE_BUILTIN_CTZ && HAVE_BUILTIN_CTZL && HAVE_BUILTIN_CTZLL |
|||
/**
|
|||
* bitops_ctz32: count trailing zeros in a uint32_t (must not be 0) |
|||
* |
|||
* Returns 0 if least signficant bit is set, 31 if only most |
|||
* signficant bit is set. |
|||
*/ |
|||
static inline int bitops_ctz32(uint32_t u) |
|||
{ |
|||
BITOPS_ASSERT_NONZERO(u); |
|||
return __builtin_ctz(u); |
|||
} |
|||
|
|||
/**
|
|||
* bitops_ctz64: count trailing zeros in a uint64_t (must not be 0) |
|||
* |
|||
* Returns 0 if least signficant bit is set, 63 if only most |
|||
* signficant bit is set. |
|||
*/ |
|||
static inline int bitops_ctz64(uint64_t u) |
|||
{ |
|||
BITOPS_ASSERT_NONZERO(u); |
|||
if (sizeof(u) == sizeof(long)) |
|||
return __builtin_ctzl(u); |
|||
else |
|||
return __builtin_ctzll(u); |
|||
} |
|||
#else |
|||
int bitops_ctz32(uint32_t u); |
|||
int bitops_ctz64(uint64_t u); |
|||
#define BITOPS_NEED_CTZ 1 |
|||
#endif |
|||
|
|||
/**
|
|||
* bitops_ls32: find lowest set bit in a uint32_t (must not be zero) |
|||
* |
|||
* Returns 0 for least signficant bit, 31 for most significant bit. |
|||
*/ |
|||
static inline int bitops_ls32(uint32_t u) |
|||
{ |
|||
BITOPS_ASSERT_NONZERO(u); |
|||
return bitops_ffs32(u) - 1; |
|||
} |
|||
|
|||
/**
|
|||
* bitops_ls64: find lowest set bit in a uint64_t (must not be zero) |
|||
* |
|||
* Returns 0 for least signficant bit, 63 for most significant bit. |
|||
*/ |
|||
static inline int bitops_ls64(uint64_t u) |
|||
{ |
|||
BITOPS_ASSERT_NONZERO(u); |
|||
return bitops_ffs64(u) - 1; |
|||
} |
|||
|
|||
/**
|
|||
* bitops_hs32: find highest set bit in a uint32_t (must not be zero) |
|||
* |
|||
* Returns 0 for least signficant bit, 31 for most significant bit. |
|||
*/ |
|||
static inline int bitops_hs32(uint32_t u) |
|||
{ |
|||
BITOPS_ASSERT_NONZERO(u); |
|||
return 31 - bitops_clz32(u); |
|||
} |
|||
|
|||
/**
|
|||
* bitops_hs64: find highest set bit in a uint64_t (must not be zero) |
|||
* |
|||
* Returns 0 for least signficant bit, 63 for most significant bit. |
|||
*/ |
|||
static inline int bitops_hs64(uint64_t u) |
|||
{ |
|||
BITOPS_ASSERT_NONZERO(u); |
|||
return 63 - bitops_clz64(u); |
|||
} |
|||
|
|||
/**
|
|||
* bitops_lc32: find lowest clear bit in a uint32_t (must not be 0xFFFFFFFF) |
|||
* |
|||
* Returns 0 for least signficant bit, 31 for most significant bit. |
|||
*/ |
|||
static inline int bitops_lc32(uint32_t u) |
|||
{ |
|||
return bitops_ctz32(~u); |
|||
} |
|||
|
|||
/**
|
|||
* bitops_lc64: find lowest clear bit in a uint64_t (must not be 0xFFFFFFFFFFFFFFFF) |
|||
* |
|||
* Returns 0 for least signficant bit, 63 for most significant bit. |
|||
*/ |
|||
static inline int bitops_lc64(uint64_t u) |
|||
{ |
|||
return bitops_ctz64(~u); |
|||
} |
|||
|
|||
/**
|
|||
* bitops_hc32: find highest clear bit in a uint32_t (must not be 0xFFFFFFFF) |
|||
* |
|||
* Returns 0 for least signficant bit, 31 for most significant bit. |
|||
*/ |
|||
static inline int bitops_hc32(uint32_t u) |
|||
{ |
|||
return 31 - bitops_clz32(~u); |
|||
} |
|||
|
|||
/**
|
|||
* bitops_hc64: find highest clear bit in a uint64_t (must not be 0xFFFFFFFFFFFFFFFF) |
|||
* |
|||
* Returns 0 for least signficant bit, 63 for most significant bit. |
|||
*/ |
|||
static inline int bitops_hc64(uint64_t u) |
|||
{ |
|||
return 63 - bitops_clz64(~u); |
|||
} |
|||
|
|||
#if HAVE_BUILTIN_POPCOUNT && HAVE_BUILTIN_POPCOUNTL && HAVE_BUILTIN_POPCOUNTLL |
|||
/**
|
|||
* bitops_weight32: count number of bits set in a uint32_t |
|||
* |
|||
* Returns 0 to 32. |
|||
*/ |
|||
static inline int bitops_weight32(uint32_t u) |
|||
{ |
|||
return __builtin_popcount(u); |
|||
} |
|||
|
|||
/**
|
|||
* bitops_weight64: count number of bits set in a uint64_t |
|||
* |
|||
* Returns 0 to 64. |
|||
*/ |
|||
static inline int bitops_weight64(uint64_t u) |
|||
{ |
|||
if (sizeof(u) == sizeof(long)) |
|||
return __builtin_popcountl(u); |
|||
else |
|||
return __builtin_popcountll(u); |
|||
} |
|||
#else |
|||
int bitops_weight32(uint32_t u); |
|||
int bitops_weight64(uint64_t u); |
|||
#define BITOPS_NEED_WEIGHT 1 |
|||
#endif |
|||
#endif /* CCAN_BITOPS_H */ |
@ -0,0 +1,89 @@ |
|||
#include <ccan/bitops/bitops.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
/* Get naive versions */ |
|||
#ifndef BITOPS_NEED_FFS |
|||
#define BITOPS_NEED_FFS |
|||
#endif |
|||
|
|||
#ifndef BITOPS_NEED_CLZ |
|||
#define BITOPS_NEED_CLZ |
|||
#endif |
|||
|
|||
#ifndef BITOPS_NEED_CTZ |
|||
#define BITOPS_NEED_CTZ |
|||
#endif |
|||
|
|||
#ifndef BITOPS_NEED_WEIGHT |
|||
#define BITOPS_NEED_WEIGHT |
|||
#endif |
|||
|
|||
int naive_bitops_ffs32(uint32_t u); |
|||
int naive_bitops_ffs64(uint64_t u); |
|||
int naive_bitops_clz32(uint32_t u); |
|||
int naive_bitops_clz64(uint64_t u); |
|||
int naive_bitops_ctz32(uint32_t u); |
|||
int naive_bitops_ctz64(uint64_t u); |
|||
int naive_bitops_weight32(uint32_t u); |
|||
int naive_bitops_weight64(uint64_t u); |
|||
|
|||
#define bitops_ffs32 naive_bitops_ffs32 |
|||
#define bitops_ffs64 naive_bitops_ffs64 |
|||
#define bitops_clz32 naive_bitops_clz32 |
|||
#define bitops_clz64 naive_bitops_clz64 |
|||
#define bitops_ctz32 naive_bitops_ctz32 |
|||
#define bitops_ctz64 naive_bitops_ctz64 |
|||
#define bitops_weight32 naive_bitops_weight32 |
|||
#define bitops_weight64 naive_bitops_weight64 |
|||
#include <ccan/bitops/bitops.c> |
|||
|
|||
static void test_against_naive32(uint32_t v) |
|||
{ |
|||
ok1(bitops_ffs32(v) == naive_bitops_ffs32(v)); |
|||
ok1(bitops_clz32(v) == naive_bitops_clz32(v)); |
|||
ok1(bitops_ctz32(v) == naive_bitops_ctz32(v)); |
|||
ok1(bitops_weight32(v) == naive_bitops_weight32(v)); |
|||
} |
|||
|
|||
static void test_against_naive64(uint64_t v) |
|||
{ |
|||
ok1(bitops_ffs64(v) == naive_bitops_ffs64(v)); |
|||
ok1(bitops_clz64(v) == naive_bitops_clz64(v)); |
|||
ok1(bitops_ctz64(v) == naive_bitops_ctz64(v)); |
|||
ok1(bitops_weight64(v) == naive_bitops_weight64(v)); |
|||
} |
|||
|
|||
int main(void) |
|||
{ |
|||
int i, j; |
|||
uint64_t v; |
|||
|
|||
/* This is how many tests you plan to run */ |
|||
plan_tests(32 * 32 * 8 + (64 * 64) * 8 + 4 + 4); |
|||
|
|||
/* Various comparisons with any one or two bits set */ |
|||
for (i = 0; i < 32; i++) { |
|||
for (j = 0; j < 32; j++) { |
|||
v = ((uint64_t)1 << i) | ((uint64_t)1 << j); |
|||
test_against_naive32(v); |
|||
test_against_naive32(~v); |
|||
} |
|||
} |
|||
|
|||
for (i = 0; i < 64; i++) { |
|||
for (j = 0; j < 64; j++) { |
|||
v = ((uint64_t)1 << i) | ((uint64_t)1 << j); |
|||
test_against_naive64(v); |
|||
test_against_naive64(~v); |
|||
} |
|||
} |
|||
|
|||
test_against_naive64(0xFFFFFFFFFFFFFFFFULL); |
|||
ok1(bitops_ffs32(0) == naive_bitops_ffs32(0)); |
|||
ok1(bitops_ffs64(0) == naive_bitops_ffs64(0)); |
|||
ok1(bitops_weight32(0) == naive_bitops_weight32(0)); |
|||
ok1(bitops_weight64(0) == naive_bitops_weight64(0)); |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,113 @@ |
|||
#define CCAN_BITOPS_DEBUG 1 |
|||
#include <ccan/bitops/bitops.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
int i; |
|||
|
|||
/* This is how many tests you plan to run */ |
|||
plan_tests(68 + 6 * (31 + 63)); |
|||
|
|||
for (i = 0; i < 32; i++) |
|||
ok1(bitops_ffs32(1 << i) == i+1); |
|||
ok1(bitops_ffs32(0) == 0); |
|||
for (i = 0; i < 64; i++) |
|||
ok1(bitops_ffs64((uint64_t)1 << i) == i+1); |
|||
ok1(bitops_ffs64(0) == 0); |
|||
|
|||
/* Higher bits don't affect result */ |
|||
for (i = 0; i < 32; i++) |
|||
ok1(bitops_ffs32(0xFFFFFFFFFFFFFFFFULL << i) == i+1); |
|||
ok1(bitops_ffs32(0) == 0); |
|||
for (i = 0; i < 64; i++) |
|||
ok1(bitops_ffs64(0xFFFFFFFFFFFFFFFFULL << i) == i+1); |
|||
ok1(bitops_ffs64(0) == 0); |
|||
|
|||
for (i = 0; i < 32; i++) |
|||
ok1(bitops_clz32(1 << i) == 31 - i); |
|||
for (i = 0; i < 64; i++) |
|||
ok1(bitops_clz64((uint64_t)1 << i) == 63 - i); |
|||
|
|||
/* Lower bits don't effect results */ |
|||
for (i = 0; i < 32; i++) |
|||
ok1(bitops_clz32((1 << i) + (1 << i)-1) == 31 - i); |
|||
for (i = 0; i < 64; i++) |
|||
ok1(bitops_clz64(((uint64_t)1 << i) + ((uint64_t)1 << i)-1) |
|||
== 63 - i); |
|||
|
|||
for (i = 0; i < 32; i++) |
|||
ok1(bitops_ctz32(1 << i) == i); |
|||
for (i = 0; i < 64; i++) |
|||
ok1(bitops_ctz64((uint64_t)1 << i) == i); |
|||
|
|||
/* Higher bits don't affect result */ |
|||
for (i = 0; i < 32; i++) |
|||
ok1(bitops_ctz32(0xFFFFFFFFFFFFFFFFULL << i) == i); |
|||
for (i = 0; i < 64; i++) |
|||
ok1(bitops_ctz64(0xFFFFFFFFFFFFFFFFULL << i) == i); |
|||
|
|||
/* Now we've tested low-level, test higher ones */ |
|||
ok1(bitops_ls32(1U) == 0); |
|||
ok1(bitops_ls32(0xFFFFFFFF) == 0); |
|||
ok1(bitops_ls32(1U << 31) == 31); |
|||
ok1(bitops_ls32(0xFFFF0000) == 16); |
|||
|
|||
ok1(bitops_ls64(1U) == 0); |
|||
ok1(bitops_ls64(0xFFFFFFFF) == 0); |
|||
ok1(bitops_ls64(1U << 31) == 31); |
|||
ok1(bitops_ls64(0xFFFF0000) == 16); |
|||
ok1(bitops_ls64((uint64_t)1 << 32) == 32); |
|||
ok1(bitops_ls64((uint64_t)1 << 63) == 63); |
|||
ok1(bitops_ls64(0xFFFFFFFFFFFF0000ULL) == 16); |
|||
ok1(bitops_ls64(0xFFFF000000000000ULL) == 48); |
|||
|
|||
ok1(bitops_hs32(1U) == 0); |
|||
ok1(bitops_hs32(0xFFFFFFFF) == 31); |
|||
ok1(bitops_hs32(1U << 31) == 31); |
|||
ok1(bitops_hs32(0xFFFF0000) == 31); |
|||
ok1(bitops_hs32(0x0000FFFF) == 15); |
|||
|
|||
ok1(bitops_hs64(1U) == 0); |
|||
ok1(bitops_hs64(0xFFFFFFFF) == 31); |
|||
ok1(bitops_hs64(1U << 31) == 31); |
|||
ok1(bitops_hs64(0xFFFF0000) == 31); |
|||
ok1(bitops_hs32(0x0000FFFF) == 15); |
|||
ok1(bitops_hs64((uint64_t)1 << 32) == 32); |
|||
ok1(bitops_hs64((uint64_t)1 << 63) == 63); |
|||
ok1(bitops_hs64(0xFFFFFFFFFFFF0000ULL) == 63); |
|||
ok1(bitops_hs64(0x0000FFFF00000000ULL) == 47); |
|||
|
|||
ok1(bitops_lc32(~(1U)) == 0); |
|||
ok1(bitops_lc32(~(0xFFFFFFFF)) == 0); |
|||
ok1(bitops_lc32(~(1U << 31)) == 31); |
|||
ok1(bitops_lc32(~(0xFFFF0000)) == 16); |
|||
|
|||
ok1(bitops_lc64(~(1U)) == 0); |
|||
ok1(bitops_lc64(~(0xFFFFFFFF)) == 0); |
|||
ok1(bitops_lc64(~(1U << 31)) == 31); |
|||
ok1(bitops_lc64(~(0xFFFF0000)) == 16); |
|||
ok1(bitops_lc64(~((uint64_t)1 << 32)) == 32); |
|||
ok1(bitops_lc64(~((uint64_t)1 << 63)) == 63); |
|||
ok1(bitops_lc64(~(0xFFFFFFFFFFFF0000ULL)) == 16); |
|||
ok1(bitops_lc64(~(0xFFFF000000000000ULL)) == 48); |
|||
|
|||
ok1(bitops_hc32(~(1U)) == 0); |
|||
ok1(bitops_hc32(~(0xFFFFFFFF)) == 31); |
|||
ok1(bitops_hc32(~(1U << 31)) == 31); |
|||
ok1(bitops_hc32(~(0xFFFF0000)) == 31); |
|||
ok1(bitops_hc32(~(0x0000FFFF)) == 15); |
|||
|
|||
ok1(bitops_hc64(~(1ULL)) == 0); |
|||
ok1(bitops_hc64(~(0xFFFFFFFFULL)) == 31); |
|||
ok1(bitops_hc64(~(1ULL << 31)) == 31); |
|||
ok1(bitops_hc64(~(0xFFFF0000ULL)) == 31); |
|||
ok1(bitops_hc64(~(0x0000FFFFULL)) == 15); |
|||
ok1(bitops_hc64(~((uint64_t)1 << 32)) == 32); |
|||
ok1(bitops_hc64(~((uint64_t)1 << 63)) == 63); |
|||
ok1(bitops_hc64(~(0xFFFFFFFFFFFF0000ULL)) == 63); |
|||
ok1(bitops_hc64(~(0x0000FFFF00000000ULL)) == 47); |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,24 @@ |
|||
CCANDIR=../../.. |
|||
CFLAGS=-Wall -Werror -O3 -I$(CCANDIR) -flto |
|||
#CFLAGS=-Wall -Werror -g3 -I$(CCANDIR)
|
|||
LDFLAGS := -flto -O3 |
|||
|
|||
all: speed |
|||
|
|||
CCAN_OBJS:=ccan-intmap.o ccan-time.o ccan-isaac64.o ccan-htable.o ccan-siphash24.o |
|||
|
|||
speed: speed.o $(CCAN_OBJS) |
|||
|
|||
clean: |
|||
rm -f speed *.o |
|||
|
|||
ccan-time.o: $(CCANDIR)/ccan/time/time.c |
|||
$(CC) $(CFLAGS) -c -o $@ $< |
|||
ccan-intmap.o: $(CCANDIR)/ccan/intmap/intmap.c |
|||
$(CC) $(CFLAGS) -c -o $@ $< |
|||
ccan-isaac64.o: $(CCANDIR)/ccan/isaac/isaac64.c |
|||
$(CC) $(CFLAGS) -c -o $@ $< |
|||
ccan-htable.o: $(CCANDIR)/ccan/htable/htable.c |
|||
$(CC) $(CFLAGS) -c -o $@ $< |
|||
ccan-siphash24.o: $(CCANDIR)/ccan/crypto/siphash24/siphash24.c |
|||
$(CC) $(CFLAGS) -c -o $@ $< |
@ -0,0 +1,246 @@ |
|||
/* Test speed of intmap */ |
|||
#include <ccan/time/time.h> |
|||
#include <ccan/intmap/intmap.h> |
|||
#include <ccan/isaac/isaac64.h> |
|||
#include <ccan/htable/htable_type.h> |
|||
#include <ccan/crypto/siphash24/siphash24.h> |
|||
#include <stdlib.h> |
|||
#include <stdio.h> |
|||
#include <assert.h> |
|||
#include <inttypes.h> |
|||
|
|||
/* hack to let us gather span. */ |
|||
struct node { |
|||
/* These point to strings or nodes. */ |
|||
struct intmap child[2]; |
|||
/* Encoding both prefix and critbit: 1 is appended to prefix. */ |
|||
intmap_index_t prefix_and_critbit; |
|||
}; |
|||
|
|||
static void update_span(const void *p, size_t s, uintptr_t *min, uintptr_t *max) |
|||
{ |
|||
if ((uintptr_t)p < *min) |
|||
*min = (uintptr_t)p; |
|||
if ((uintptr_t)p + s > *max) |
|||
*max = (uintptr_t)p + s; |
|||
} |
|||
|
|||
static void getspan(const struct intmap *m, uintptr_t *min, uintptr_t *max) |
|||
{ |
|||
struct node *n; |
|||
/* Leaf node? */ |
|||
if (m->v) |
|||
return; |
|||
|
|||
n = m->u.n; |
|||
update_span(n, sizeof(*n), min, max); |
|||
getspan(&n->child[0], min, max); |
|||
getspan(&n->child[1], min, max); |
|||
} |
|||
|
|||
struct htable_elem { |
|||
uint64_t index; |
|||
uint64_t *v; |
|||
}; |
|||
|
|||
static struct siphash_seed sipseed; |
|||
|
|||
static uint64_t keyof(const struct htable_elem *elem) |
|||
{ |
|||
return elem->index; |
|||
} |
|||
|
|||
static size_t hashfn(const uint64_t index) |
|||
{ |
|||
return siphash24(&sipseed, &index, sizeof(index)); |
|||
} |
|||
|
|||
static bool eqfn(const struct htable_elem *elem, const uint64_t index) |
|||
{ |
|||
return elem->index == index; |
|||
} |
|||
HTABLE_DEFINE_TYPE(struct htable_elem, keyof, hashfn, eqfn, hash); |
|||
|
|||
static bool check_val(intmap_index_t i, uint64_t *v, uint64_t *expected) |
|||
{ |
|||
if (v != expected) |
|||
abort(); |
|||
return true; |
|||
} |
|||
|
|||
int main(int argc, char *argv[]) |
|||
{ |
|||
uint64_t i, total = 0, seed, *v; |
|||
size_t max = argv[1] ? atol(argv[1]) : 100000000; |
|||
isaac64_ctx isaac; |
|||
struct timeabs start, end; |
|||
UINTMAP(uint64_t *) map; |
|||
struct hash hash; |
|||
struct htable_elem *e; |
|||
struct hash_iter it; |
|||
uintptr_t span_min, span_max; |
|||
|
|||
uintmap_init(&map); |
|||
hash_init(&hash); |
|||
|
|||
/* We don't want our randomness function to dominate the time,
|
|||
* nor deal with duplicates (just abort, that's v. unlikely) */ |
|||
seed = time_now().ts.tv_sec + time_now().ts.tv_nsec; |
|||
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
|||
|
|||
start = time_now(); |
|||
for (i = 0; i < max; i++) |
|||
total += isaac64_next_uint64(&isaac); |
|||
end = time_now(); |
|||
printf("%zu,random generation (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
|||
start = time_now(); |
|||
for (i = 0; i < max; i++) { |
|||
if (!uintmap_add(&map, isaac64_next_uint64(&isaac), &i)) |
|||
abort(); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,critbit insert (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
|||
start = time_now(); |
|||
for (i = 0; i < max; i++) { |
|||
if (uintmap_get(&map, isaac64_next_uint64(&isaac)) != &i) |
|||
abort(); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,critbit successful lookup (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
start = time_now(); |
|||
for (i = 0; i < max; i++) { |
|||
if (uintmap_get(&map, isaac64_next_uint64(&isaac))) |
|||
abort(); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,critbit failed lookup (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
|||
start = time_now(); |
|||
for (v = uintmap_first(&map, &i); v; v = uintmap_after(&map, &i)) { |
|||
if (v != &i) |
|||
abort(); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,critbit iteration (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
start = time_now(); |
|||
uintmap_iterate(&map, check_val, &i); |
|||
end = time_now(); |
|||
printf("%zu,critbit callback iteration (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
span_min = -1ULL; |
|||
span_max = 0; |
|||
getspan(uintmap_unwrap_(&map), &span_min, &span_max); |
|||
printf("%zu,critbit memory (bytes),%zu\n", |
|||
max, (size_t)(span_max - span_min + max / 2) / max); |
|||
|
|||
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
|||
start = time_now(); |
|||
for (i = 0; i < max; i++) { |
|||
if (!uintmap_del(&map, isaac64_next_uint64(&isaac))) |
|||
abort(); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,critbit delete (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
/* Fill with consecutive values */ |
|||
for (i = 0; i < max; i++) { |
|||
if (!uintmap_add(&map, i, &i)) |
|||
abort(); |
|||
} |
|||
start = time_now(); |
|||
for (v = uintmap_first(&map, &i); v; v = uintmap_after(&map, &i)) { |
|||
if (v != &i) |
|||
abort(); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,critbit consecutive iteration (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
start = time_now(); |
|||
uintmap_iterate(&map, check_val, &i); |
|||
end = time_now(); |
|||
printf("%zu,critbit consecutive callback iteration (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
sipseed.u.u64[0] = isaac64_next_uint64(&isaac); |
|||
sipseed.u.u64[1] = isaac64_next_uint64(&isaac); |
|||
|
|||
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
|||
start = time_now(); |
|||
for (i = 0; i < max; i++) { |
|||
e = malloc(sizeof(*e)); |
|||
e->v = &i; |
|||
e->index = isaac64_next_uint64(&isaac); |
|||
hash_add(&hash, e); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,hash insert (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
|||
start = time_now(); |
|||
for (i = 0; i < max; i++) { |
|||
if (hash_get(&hash, isaac64_next_uint64(&isaac))->v != &i) |
|||
abort(); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,hash successful lookup (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
start = time_now(); |
|||
for (i = 0; i < max; i++) { |
|||
if (hash_get(&hash, isaac64_next_uint64(&isaac))) |
|||
abort(); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,hash failed lookup (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
|||
start = time_now(); |
|||
for (e = hash_first(&hash, &it); e; e = hash_next(&hash, &it)) { |
|||
if (e->v != &i) |
|||
abort(); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,hash iteration (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
span_min = -1ULL; |
|||
span_max = 0; |
|||
for (e = hash_first(&hash, &it); e; e = hash_next(&hash, &it)) |
|||
update_span(e, sizeof(*e), &span_min, &span_max); |
|||
/* table itself tends to be allocated in separate memory. */ |
|||
span_max += (sizeof(uintptr_t) << hash.raw.bits); |
|||
printf("%zu,hash memory (bytes),%zu\n", |
|||
max, (size_t)(span_max - span_min + max / 2) / max); |
|||
|
|||
isaac64_init(&isaac, (unsigned char *)&seed, sizeof(seed)); |
|||
start = time_now(); |
|||
for (i = 0; i < max; i++) { |
|||
e = hash_get(&hash, isaac64_next_uint64(&isaac)); |
|||
if (!hash_del(&hash, e)) |
|||
abort(); |
|||
free(e); |
|||
} |
|||
end = time_now(); |
|||
printf("%zu,hash delete (nsec),%"PRIu64"\n", max, |
|||
time_to_nsec(time_divide(time_between(end, start), max))); |
|||
|
|||
/* Use total, but "never happens". */ |
|||
return (total == 0); |
|||
} |
@ -0,0 +1,41 @@ |
|||
#include <ccan/bitops/bitops.h> |
|||
#include <ccan/intmap/intmap.c> |
|||
#include <ccan/tap/tap.h> |
|||
#include <stdio.h> |
|||
|
|||
#define ELEMENTS 8 |
|||
|
|||
int main(void) |
|||
{ |
|||
UINTMAP(void *) umap; |
|||
|
|||
plan_tests((1 << ELEMENTS) * ELEMENTS); |
|||
|
|||
/* Run through every combination of elements */ |
|||
for (int i = 0; i < (1 << ELEMENTS); i++) { |
|||
/* Set up map */ |
|||
uintmap_init(&umap); |
|||
for (int j = 0; j < ELEMENTS; j++) { |
|||
if ((1 << j) & i) |
|||
uintmap_add(&umap, j, &umap); |
|||
} |
|||
|
|||
/* Try each uintmap_after value */ |
|||
for (int j = 0; j < ELEMENTS; j++) { |
|||
intmap_index_t idx = j, next; |
|||
|
|||
if ((i >> (j + 1)) == 0) |
|||
next = 0; |
|||
else |
|||
next = j + 1 + bitops_ls32(i >> (j + 1)); |
|||
|
|||
if (!uintmap_after(&umap, &idx)) |
|||
idx = 0; |
|||
ok1(idx == next); |
|||
} |
|||
uintmap_clear(&umap); |
|||
} |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
@ -0,0 +1,26 @@ |
|||
#include <ccan/intmap/intmap.h> |
|||
#include <ccan/intmap/intmap.c> |
|||
#include <ccan/tap/tap.h> |
|||
|
|||
int main(void) |
|||
{ |
|||
UINTMAP(const char *) map; |
|||
u64 idx; |
|||
|
|||
/* This is how many tests you plan to run */ |
|||
plan_tests(2); |
|||
|
|||
uintmap_init(&map); |
|||
assert(uintmap_add(&map, 0x103, "103")); |
|||
assert(uintmap_add(&map, 0x10b, "10b")); |
|||
|
|||
uintmap_first(&map, &idx); |
|||
ok1(idx > 0xF); |
|||
idx = 0xF; |
|||
ok1(strcmp(uintmap_after(&map, &idx), "103") == 0); |
|||
|
|||
uintmap_clear(&map); |
|||
|
|||
/* This exits depending on whether all tests passed */ |
|||
return exit_status(); |
|||
} |
Loading…
Reference in new issue