WIP
This commit is contained in:
parent
e0c79c9348
commit
5afb6c6f0d
1 changed files with 159 additions and 31 deletions
190
tests/soak.c
190
tests/soak.c
|
@ -17,8 +17,6 @@
|
|||
|
||||
#define INITIAL_AMOUNT 1024 * 2
|
||||
|
||||
bool recording = true;
|
||||
|
||||
typedef size_t pgno_t;
|
||||
|
||||
typedef enum { SM, ML, RB } container_impl_t;
|
||||
|
@ -133,6 +131,8 @@ typedef struct container {
|
|||
|
||||
} container_t;
|
||||
|
||||
#define digest(name) containers[type].name##_stats.td
|
||||
|
||||
char *
|
||||
bytes_as(double bytes, char *s, size_t size)
|
||||
{
|
||||
|
@ -316,6 +316,8 @@ b64_decode(const char *in, unsigned char *out, size_t outlen)
|
|||
|
||||
/* recording ------------------------------------------------------------- */
|
||||
|
||||
bool recording = false;
|
||||
|
||||
static void
|
||||
record_set_mutation(FILE *out, pgno_t pg)
|
||||
{
|
||||
|
@ -871,7 +873,9 @@ __roar_validate(void *handle)
|
|||
return true;
|
||||
}
|
||||
|
||||
/* histogram ------------------------------------------------------------- */
|
||||
/* statistics ------------------------------------------------------------ */
|
||||
|
||||
bool statistics = false;
|
||||
|
||||
typedef struct sw {
|
||||
struct timespec t1; /* start time */
|
||||
|
@ -892,7 +896,7 @@ elapsed(struct timespec *s, struct timespec *e)
|
|||
long sec, nanos;
|
||||
|
||||
sec = e->tv_sec - s->tv_sec;
|
||||
nanos = e->tv_nsec - e->tv_nsec;
|
||||
nanos = e->tv_nsec - s->tv_nsec;
|
||||
if (nanos < 0) {
|
||||
nanos += 1e9;
|
||||
sec--;
|
||||
|
@ -1102,7 +1106,8 @@ container_t containers[] = {
|
|||
|
||||
void *handles[(sizeof((containers)) / sizeof((containers)[0]))];
|
||||
void *new_handles[(sizeof((containers)) / sizeof((containers)[0]))];
|
||||
FILE *fp;
|
||||
FILE *record_fp;
|
||||
FILE *stats_fp;
|
||||
|
||||
#define alloc(type, size) containers[type].alloc(size);
|
||||
#define cast(type, fn, ...) \
|
||||
|
@ -1110,15 +1115,15 @@ FILE *fp;
|
|||
containers[type].fn(handles[type], ##__VA_ARGS__)
|
||||
|
||||
#define invoke(type, fn, ...) __stats_##fn(containers[type].fn##_stats.td, containers[type].fn##_stats.fn, handles[type], __VA_ARGS__)
|
||||
#define mutate(type, fn, ...) \
|
||||
(type == 0) ? record_##fn##_mutation(fp, __VA_ARGS__) : (void)0, \
|
||||
#define mutate(type, fn, ...) \
|
||||
(type == 0) ? record_##fn##_mutation(record_fp, __VA_ARGS__) : (void)0, \
|
||||
__stats_##fn(containers[type].fn##_stats.td, containers[type].fn##_stats.fn, &handles[type], __VA_ARGS__)
|
||||
#define foreach(set) for (unsigned type = 0; type < (sizeof((set)) / sizeof((set)[0])); type++)
|
||||
#define checkpoint(set) \
|
||||
for (unsigned type = 1; type < (sizeof((set)) / sizeof((set)[0])); type++) { \
|
||||
verify_eq(0, handles[0], type, handles[type]); \
|
||||
} \
|
||||
record_checkpoint(fp, handles[0])
|
||||
record_checkpoint(record_fp, handles[0])
|
||||
|
||||
bool
|
||||
verify_sm_eq_rb(sparsemap_t *map, roaring_bitmap_t *rbm)
|
||||
|
@ -1186,36 +1191,39 @@ verify_eq(unsigned a, void *ad, unsigned b, void *bd)
|
|||
return ret;
|
||||
}
|
||||
|
||||
#define SHORT_OPT "r:fa:bh"
|
||||
#define LONG_OPT "record:,force,amount:,buffer,help"
|
||||
|
||||
void
|
||||
print_usage(const char *program_name)
|
||||
{
|
||||
printf("Usage: %s [OPTIONS]\n", program_name);
|
||||
printf(" -r, --record <file> Path to the file for recording (optional)\n");
|
||||
printf(" -f, --force Force overwrite of existing file (optional)\n");
|
||||
printf(" -b, --buffer Disable buffering writes to stdout/err (optional)\n");
|
||||
printf(" -a, --amount <number> Specify the number of entries to record (must be positive, optional)\n");
|
||||
printf(" -h, --help Print this help message\n");
|
||||
printf(" -r <file> Path to the file for recording (optional)\n");
|
||||
printf(" -s <file> Path to the file for statistics (optional)\n");
|
||||
printf(" -f Force overwrite of existing file (optional)\n");
|
||||
printf(" -b Disable buffering writes to stdout/err (optional)\n");
|
||||
printf(" -a <number> Specify the number of entries to record (must be positive, optional)\n");
|
||||
printf(" -h Print this help message\n");
|
||||
}
|
||||
#define SHORT_OPT "r:s:fa:bh"
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int opt;
|
||||
const char *record_file = NULL;
|
||||
const char *stats_file = NULL;
|
||||
int force_flag = 0;
|
||||
size_t left, iteration = 0, amt = INITIAL_AMOUNT;
|
||||
bool buffer = true;
|
||||
|
||||
fp = stdout;
|
||||
|
||||
while ((opt = getopt(argc, argv, SHORT_OPT LONG_OPT)) != -1) {
|
||||
while ((opt = getopt(argc, argv, SHORT_OPT)) != -1) {
|
||||
switch (opt) {
|
||||
case 'r':
|
||||
recording = true;
|
||||
record_file = optarg;
|
||||
break;
|
||||
case 's':
|
||||
statistics = true;
|
||||
stats_file = optarg;
|
||||
break;
|
||||
case 'f':
|
||||
force_flag = 1;
|
||||
break;
|
||||
|
@ -1240,10 +1248,9 @@ main(int argc, char *argv[])
|
|||
}
|
||||
}
|
||||
|
||||
// Check if record file is specified
|
||||
if (record_file == NULL) {
|
||||
recording = false;
|
||||
} else {
|
||||
if (recording) {
|
||||
record_fp = stdout;
|
||||
|
||||
// Check for existing file without force flag
|
||||
if (access(record_file, F_OK) == 0 && !force_flag) {
|
||||
fprintf(stderr, "Warning: File '%s' already exists. Use -f or --force to overwrite.\n", record_file);
|
||||
|
@ -1251,17 +1258,38 @@ main(int argc, char *argv[])
|
|||
}
|
||||
|
||||
// Open the file for writing (truncate if force flag is set)
|
||||
fp = fopen(record_file, force_flag ? "w" : "a");
|
||||
if (fp == NULL) {
|
||||
record_fp = fopen(record_file, force_flag ? "w" : "a");
|
||||
if (record_fp == NULL) {
|
||||
perror("Error opening file");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if statistics file is specified
|
||||
if (statistics) {
|
||||
if (stats_file[0] == '-') {
|
||||
stats_fp = stdout;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
} else {
|
||||
// Check for existing file without force flag
|
||||
if (access(stats_file, F_OK) == 0 && !force_flag) {
|
||||
fprintf(stderr, "Warning: File '%s' already exists. Use -f or --force to overwrite.\n", stats_file);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Open the file for writing (truncate if force flag is set)
|
||||
stats_fp = fopen(stats_file, force_flag ? "w" : "a");
|
||||
if (stats_fp == NULL) {
|
||||
perror("Error opening file");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// disable buffering
|
||||
if (!buffer) {
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
setvbuf(fp, NULL, _IONBF, 0);
|
||||
setvbuf(record_fp, NULL, _IONBF, 0);
|
||||
setvbuf(stats_fp, NULL, _IONBF, 0);
|
||||
}
|
||||
unsigned types[] = { SM, ML, RB };
|
||||
unsigned num_types = (sizeof((types)) / sizeof((types)[0]));
|
||||
|
@ -1280,9 +1308,6 @@ main(int argc, char *argv[])
|
|||
containers[type].is_empty_stats.td = NULL;
|
||||
containers[type].is_first_stats.td = NULL;
|
||||
containers[type].merge_stats.td = td_new(100);
|
||||
containers[type].size = NULL;
|
||||
containers[type].count = NULL;
|
||||
containers[type].validate = NULL;
|
||||
}
|
||||
|
||||
/* Setup: add an amt of bits to each container. */
|
||||
|
@ -1299,6 +1324,77 @@ main(int argc, char *argv[])
|
|||
checkpoint(types);
|
||||
left = amt;
|
||||
|
||||
if (statistics) {
|
||||
const char *names[] = { "sm", "ml", "rb" };
|
||||
const char *dists[] = { "p50", "p75", "p90", "p99", "p999" };
|
||||
fprintf(stats_fp, "timestamp,iterations,");
|
||||
foreach(types)
|
||||
{
|
||||
fprintf(stats_fp, "%s_size,%s_bytes,", names[type], names[type]);
|
||||
if (digest(alloc) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_alloc_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(free) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_free_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(set) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_set_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(is_set) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_is_set_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(clear) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_clear_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(find_span) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_find_span_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(take_span) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_take_span_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(release_span) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_release_span_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(is_span) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_is_span_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(is_empty) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_is_empty_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(is_first) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_is_first_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
if (digest(merge) != NULL) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
fprintf(stats_fp, "%s_merge_%s,", names[type], dists[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stats_fp, "\n");
|
||||
}
|
||||
|
||||
while (true) {
|
||||
iteration++;
|
||||
// the an amount [1, 16] of pages to find preferring smaller sizes
|
||||
|
@ -1395,7 +1491,39 @@ main(int argc, char *argv[])
|
|||
containers[type].free(new_handles[type]);
|
||||
}
|
||||
}
|
||||
if (statistics) {
|
||||
const float dists[] = { 0.5, 0.75, 0.90, 0.99, 0.999 };
|
||||
fprintf(stats_fp, "%f,%zu,", nsts(), iteration);
|
||||
foreach(types)
|
||||
{
|
||||
fprintf(stats_fp, "%zu,%zu,", containers[type].count(handles[type]), containers[type].size(handles[type]));
|
||||
// clang-format off
|
||||
td_histogram_t *td[] = {
|
||||
digest(alloc),
|
||||
digest(free),
|
||||
digest(set),
|
||||
digest(is_set),
|
||||
digest(clear),
|
||||
digest(find_span),
|
||||
digest(take_span),
|
||||
digest(release_span),
|
||||
digest(is_span),
|
||||
digest(is_empty),
|
||||
digest(is_first),
|
||||
digest(merge)
|
||||
};
|
||||
// clang-format on
|
||||
for (int i = 0; i < 12; i++) {
|
||||
if (td[i] != NULL) {
|
||||
td_compress(td[i]);
|
||||
for (int j = 0; j < 5; j++) {
|
||||
fprintf(stats_fp, "%.10f,", td_quantile(td[i], dists[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(stats_fp, "\n");
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue