#define _POSIX_C_SOURCE 199309L #define X86_INTRIN #include #include // If using threads #include #include #include #include #include #include #include #include #ifdef __x86_64__ // Check if running on x86_64 architecture #ifdef X86_INTRIN #include #include #endif #endif #include #include #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wvariadic-macros" #define __diag(...) \ do { \ fprintf(stderr, "%s:%d:%s(): ", __FILE__, __LINE__, __func__); \ fprintf(stderr, __VA_ARGS__); \ } while (0) #pragma GCC diagnostic pop uint64_t tsc(void) { #ifdef __x86_64__ // Check if running on x86_64 architecture #ifdef X86_INTRIN return __rdtsc(); #else uint32_t low, high; __asm__ volatile("rdtsc" : "=a"(low), "=d"(high)); return ((uint64_t)high << 32) | low; #endif #ifdef __arm__ // Check if compiling for ARM architecture uint64_t result; __asm__ volatile("mrs %0, pmccntr_el0" : "=r"(result)); return result; } #endif #endif return 0; } // TODO remove me, this is only used for debugging. #ifdef SPARSEMAP_TESTING char *QCC_showSparsemap(void *value, int len); char *QCC_showChunk(void *value, int len); #endif // get microsecond timestamp uint64_t msts() { #ifdef _SC_MONOTONIC_CLOCK struct timespec ts; if (sysconf(_SC_MONOTONIC_CLOCK) > 0) { /* A monotonic clock presents */ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) return (uint64_t)(ts.tv_sec * 1000000 + ts.tv_nsec / 1000); else return 0; } return 0; #else struct timeval tv; if (gettimeofday(&tv, NULL) == 0) return (uint64_t)(tv.tv_sec * 1000000 + tv.tv_usec); else return 0; #endif } double nsts(void) { struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) == -1) { perror("clock_gettime"); return -1.0; // Return -1.0 on error } return ts.tv_sec + ts.tv_nsec / 1e9; } int __xorshift32_state = 0; // Xorshift algorithm for PRNG uint32_t xorshift32(void) { uint32_t x = __xorshift32_state; if (x == 0) { x = 123456789; } x ^= x << 13; x ^= x >> 17; x ^= x << 5; __xorshift32_state = x; return x; } void xorshift32_seed(void) { __xorshift32_state = XORSHIFT_SEED_VALUE; } void shuffle(int *array, size_t n) { for (size_t i = n - 1; i > 0; --i) { size_t j = xorshift32() % (i + 1); if (i != j) { array[i] ^= array[j]; array[j] ^= array[i]; array[i] ^= array[j]; } } } static int compare_ints(const void *a, const void *b) { return *(const int *)a - *(const int *)b; } // Check if there's already a sequence of 'r' sequential integers int has_sequential_set(int a[], int l, int r) { // Start with a count of 1 for the first number int count = 1; for (int i = 1; i < l; ++i) { // Check if the current and previous elements are sequential if (a[i] - a[i - 1] == 1) { count++; if (count >= r) { // Found a sequential set of length 'r' starting at 'i' return i; } } else { // Reset count if the sequence breaks count = 1; } } // No sequential set of length 'r' found return -1; } // Function to ensure an array contains a set of 'r' sequential integers int ensure_sequential_set(int a[], int l, int r) { if (!a || l == 0 || r < 1 || r > l - 1) { return 0; } // Sort the array to check for existing sequences qsort(a, l, sizeof(int), compare_ints); // Check if a sequential set of length 'r' already exists int offset = has_sequential_set(a, l, r); if (offset >= 0) { return offset; // Sequence already exists, no modification needed } // Find the minimum and maximum values in the array int min_value = a[0]; int max_value = a[l - 1]; // Generate a random value between min_value and max_value int value = random_uint32() % (max_value - min_value - r + 1); // Generate a random location between 0 and l - r int d = l - r - 1; offset = d == 0 ? 0 : random_uint32() % d; // Adjust the array to include a sequential set of 'r' integers at the random offset for (int i = 0; i < r; ++i) { a[i + offset] = value + i; } return value; } void print_array(int *array, int l) { int a[l]; memcpy(a, array, sizeof(int) * l); qsort(a, l, sizeof(int), compare_ints); fprintf(stderr, "int a[] = {"); for (int i = 0; i < l; i++) { fprintf(stderr, "%d", a[i]); if (i != l - 1) { fprintf(stderr, ", "); } } fprintf(stderr, "};\n"); } bool has_span(sparsemap_t *map, int *array, int l, int n) { if (n == 0 || l == 0 || n > l) { return false; } int sorted[l]; memcpy(sorted, array, sizeof(int) * l); qsort(sorted, l, sizeof(int), compare_ints); for (int i = 0; i <= l - n; i++) { if (sorted[i] + n - 1 == sorted[i + n - 1]) { for (int j = 0; j < n; j++) { size_t pos = sorted[j + i]; bool set = sparsemap_is_set(map, pos); assert(set); } __diag("Found span: [%d, %d], length: %d\n", sorted[i], sorted[i + n - 1], n); return true; } } return false; } bool is_span(int *array, int n, int x, int l) { if (n == 0 || l < 0) { return false; } int a[n]; memcpy(a, array, sizeof(int) * n); qsort(a, n, sizeof(int), compare_ints); // Iterate through the array to find a span starting at x of length l for (int i = 0; i < n; i++) { if (a[i] == x) { // Check if the span can fit in the array if (i + l - 1 < n && a[i + l - 1] == x + l - 1) { return true; // Found the span } } } return false; // Span not found } void print_spans(int *array, int n) { int a[n]; size_t start = 0, end = 0; if (n == 0) { fprintf(stderr, "Array is empty\n"); return; } memcpy(a, array, sizeof(int) * n); qsort(a, n, sizeof(int), compare_ints); for (int i = 1; i < n; i++) { if (a[i] == a[i - 1] + 1) { end = i; // Extend the span } else { // Print the current span if (start == end) { fprintf(stderr, "[%d] ", a[start]); } else { fprintf(stderr, "[%d, %d] ", a[start], a[end]); } // Move to the next span start = i; end = i; } } // Print the last span if needed if (start == end) { fprintf(stderr, "[%d]\n", a[start]); } else { fprintf(stderr, "[%d, %d]\n", a[start], a[end]); } } bool is_set(const int array[], int bit) { for (int i = 0; i < 1024; i++) { if (array[i] == bit) { return true; } } return false; } int whats_set_uint64(uint64_t number, int pos[64]) { int length = 0; for (int i = 0; i < 64; i++) { if (number & ((uint64_t)1 << i)) { pos[length++] = i; } } return length; } /** @brief Fills an array with unique random values between 0 and max_value. * * @param[in] a The array to fill. * @param[in] l The length of the array to fill. * @param[in] max_value The maximum value for the random numbers. */ void setup_test_array(int a[], int l, int max_value) { // Create a set to store the unique values. int unique_values[max_value + 1]; for (int i = 0; i <= max_value; ++i) { unique_values[i] = 0; } // Keep generating random numbers until we have l unique values. int count = 0; while (count < l) { int random_number = random_uint32() % (max_value + 1); if (unique_values[random_number] == 0) { unique_values[random_number] = 1; a[count] = random_number; count++; } } } void bitmap_from_uint32(sparsemap_t *map, uint32_t number) { for (int i = 0; i < 32; i++) { bool bit = number & (1 << i); sparsemap_assign(map, i, bit); } } uint32_t rank_uint64(uint64_t number, int n, int p) { if (p < n || p > 63) { return 0; } /* Create a mask for the range between n and p. This works by shifting 1 to the left (p+1) times, subtracting 1 to have a sequence of p 1's, then shifting n times to the left to position it starting at n. Finally, subtracting (1 << n) - 1 removes the bits below n from the mask. */ uint64_t mask = ((uint64_t)1 << (p + 1)) - 1 - (((uint64_t)1 << n) - 1); /* Apply the mask and count the set bits in the result. */ uint64_t maskedNumber = number & mask; /* Count the bits set in maskedNumber. */ uint32_t count = 0; while (maskedNumber) { count += maskedNumber & 1; maskedNumber >>= 1; } return count; } void print_bits(char *name, uint64_t value) { if (name) { printf("%s\t", name); } for (int i = 63; i >= 0; i--) { printf("%lu", (value >> i) & 1); if (i % 8 == 0) { printf(" "); // Add space for better readability } } printf("\n"); } void sm_bitmap_from_uint64(sparsemap_t *map, int offset, uint64_t number) { for (int i = offset; i < 64; i++) { bool bit = number & ((uint64_t)1 << i); sparsemap_assign(map, i, bit); } } sparsemap_idx_t sm_add_span(sparsemap_t *map, int map_size, int span_length) { int attempts = map_size / span_length; sparsemap_idx_t placed_at; do { placed_at = random_uint32() % (map_size - span_length - 1); if (sm_occupied(map, placed_at, span_length, true)) { attempts--; } else { break; } } while (attempts); for (sparsemap_idx_t i = placed_at; i < placed_at + span_length; i++) { if (sparsemap_set(map, i) != i) { return placed_at; // TODO error? } } return placed_at; } void sm_whats_set(sparsemap_t *map, int off, int len) { printf("what's set in the range [%d, %d): ", off, off + len); for (int i = off; i < off + len; i++) { if (sparsemap_is_set(map, i)) { printf("%d ", i); } } printf("\n"); } bool sm_is_span(sparsemap_t *map, sparsemap_idx_t m, int len, bool value) { for (sparsemap_idx_t i = m; i < m + len; i++) { if (sparsemap_is_set(map, i) != value) { return false; } } return true; } bool sm_occupied(sparsemap_t *map, sparsemap_idx_t m, int len, bool value) { for (sparsemap_idx_t i = m; i < (sparsemap_idx_t)len; i++) { if (sparsemap_is_set(map, i) == value) { return true; } } return false; } char * bytes_as(double bytes, char *s, size_t size) { const char *units[] = { "b", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" }; size_t i = 0; while (bytes >= 1024 && i < sizeof(units) / sizeof(units[0]) - 1) { bytes /= 1024; i++; } snprintf(s, size, "%.2f %s", bytes, units[i]); return s; }