Skip to content

Instantly share code, notes, and snippets.

@alk
Last active December 23, 2020 20:47
Show Gist options
  • Save alk/e46cce07da5a5182dbc092815e2db546 to your computer and use it in GitHub Desktop.
Save alk/e46cce07da5a5182dbc092815e2db546 to your computer and use it in GitHub Desktop.
#include <errno.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define NUM_THREADS 8
long long allocs_count = 16 << 12;
int alloc_min = 10 << 20;
int alloc_max = 512 << 20;
long long iter_count = 0;
char **alloc_pointers;
inline uint64_t NextRandom(uint64_t rnd) {
const uint64_t prng_mult = 0x5DEECE66DULL;
const uint64_t prng_add = 0xB;
const uint64_t prng_mod_power = 48;
const uint64_t prng_mod_mask =
~((~(uint64_t)(0)) << prng_mod_power);
return (prng_mult * rnd + prng_add) & prng_mod_mask;
}
uint32_t rng() {
static __thread uint64_t state;
if (state == 0) {
state = (uint64_t)(&state);
state = state ^ ((state >> 32) | (state << 32));
for (int i = 10; i > 0; i--) {
state = NextRandom(state);
}
fprintf(stderr, "setup random %016zx\n", state);
}
state = NextRandom(state);
return (uint32_t)(state >> 16);
}
extern __attribute__((weak)) void DumpTCMallocStats(int level);
void* thread_body(void* dummy) {
int threadno = (int)(uintptr_t)dummy;
long long count = iter_count;
for (;count >= 0; count--) {
int idx = (int)(rng() % allocs_count);
int size;
char* old;
char* fresh;
if (!(count % 500000)) {
printf("%d: count = %lld\n", threadno, count);
}
old = __atomic_exchange_n(&alloc_pointers[idx], NULL, __ATOMIC_RELAXED);
if (!old) {
size = (int)(rng() % (alloc_max - alloc_min)) + alloc_min;
fresh = malloc(size);
if (!fresh) {
fprintf(stderr, "%d: failed to allocate %d. count = %lld\n",
threadno, size, count);
if (DumpTCMallocStats) {
DumpTCMallocStats(2);
}
return NULL;
/*
* abort();
*/
}
old = __atomic_exchange_n(&alloc_pointers[idx], fresh, __ATOMIC_RELAXED);
}
free(old);
}
return NULL;
}
int main(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "n:f:t:i:")) != -1) {
switch (opt) {
case 'n':
allocs_count = atoi(optarg);
break;
case 'f':
alloc_min = atoi(optarg);
break;
case 't':
alloc_max = atoi(optarg);
break;
default:
fprintf(stderr, "Usage: %s [-n <how many allocs>] [-f <smallest malloc>] [-t <largest malloc>] [-i <iterations>]\n",
argv[0]);
exit(EXIT_FAILURE);
}
}
if (!iter_count)
iter_count = allocs_count * 1024;
alloc_pointers = calloc(allocs_count, sizeof(char *));
if (!alloc_pointers) {
fprintf(stderr, "failed to allocate alloc_pointers\n");
exit(EXIT_FAILURE);
}
memset(alloc_pointers, 0, sizeof(char*)*allocs_count);
fprintf(stderr, "allocated alloc_pointers\n");
pthread_t threads[NUM_THREADS];
for (int i = 1; i < NUM_THREADS; i++) {
int rv = pthread_create(&threads[i], NULL, thread_body, (void*)(uintptr_t)i);
if (rv != 0) {
errno = rv;
perror("pthread_create");
abort();
}
}
thread_body(NULL);
for (int i = 1; i < NUM_THREADS; i++) {
pthread_join(threads[i], NULL);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment