diff options
| author | William Casarin <jb55@jb55.com> | 2018-07-09 12:10:32 -0700 |
|---|---|---|
| committer | William Casarin <jb55@jb55.com> | 2018-07-09 12:10:32 -0700 |
| commit | 1b8fbbd843ddeb5fc81c9303db9c590a436d499b (patch) | |
| tree | a7227dfe8e4fbaee7b1e0b58b24994dce8078f3f /ccan/tal/benchmark/samba-allocs.c | |
| parent | 37a9cdd2e80386f2c94e14e4f511284ae14c745a (diff) | |
progress
Diffstat (limited to 'ccan/tal/benchmark/samba-allocs.c')
| -rw-r--r-- | ccan/tal/benchmark/samba-allocs.c | 381 |
1 files changed, 381 insertions, 0 deletions
diff --git a/ccan/tal/benchmark/samba-allocs.c b/ccan/tal/benchmark/samba-allocs.c new file mode 100644 index 0000000..f2259a4 --- /dev/null +++ b/ccan/tal/benchmark/samba-allocs.c @@ -0,0 +1,381 @@ +/* Grab dump of Samba4 talloc tree to do benchmarks on it. */ +#include <ccan/talloc/talloc.h> +#include <ccan/tal/tal.h> +#include <ccan/time/time.h> +#include <ccan/err/err.h> +#include <ccan/str/str.h> +#include <string.h> +#include <assert.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <inttypes.h> + +struct node { + void *n; + struct node *parent; + char *name; + bool destructor; + size_t len; + unsigned int num_children; + struct node *children[0]; +}; + +static int node_count; + +static struct node *new_node(void) +{ + node_count++; + return calloc(sizeof(struct node), 1); +} + +/* struct db_context contains 282 bytes in 5 blocks (ref 0) d=(nil) 0x1f64e70 */ +static struct node *parse(const char *line) +{ + struct node *n = new_node(); + const char *p; + + p = strstr(line, " contains "); + p += strlen(" contains "); + p += strspn(line, " "); + n->len = strtol(p, NULL, 0); + p = strstr(p, "d="); + if (p[2] != '(') + n->destructor = true; + return n; +} + +static void add_child(struct node *parent, struct node *child) +{ + unsigned int i; + struct node *oldp = parent; + + parent = realloc(parent, sizeof(*parent) + + sizeof(parent->children[0]) * (parent->num_children+1)); + parent->children[parent->num_children++] = child; + child->parent = parent; + + if (parent == oldp) + return; + + /* Fix up children's parent pointers. */ + for (i = 0; i < parent->num_children-1; i++) { + assert(parent->children[i]->parent == oldp); + parent->children[i]->parent = parent; + } + + /* Fix up parent's child pointer. */ + if (parent->parent) { + assert(parent->parent->children[parent->parent->num_children-1] + == oldp); + parent->parent->children[parent->parent->num_children-1] + = parent; + } +} + +/* Random string of required length */ +static char *namelen(int len) +{ + char *p = malloc(len); + memset(p, 'x', len-1); + p[len-1] = '\0'; + return p; +} + +static struct node *read_nodes(FILE *f) +{ + char line[4096]; + unsigned int curr_indent = 0, indent; + struct node *n, *curr = new_node(); + + /* Ignore first line */ + fgets(line, 4096, f); + + while (fgets(line, 4096, f)) { + bool is_name; + + indent = strspn(line, " "); + + /* Ignore references for now. */ + if (strstarts(line + indent, "reference to: ")) + continue; + + /* Blank name? Use offset of 'contains' to guess indent! */ + if (strstarts(line + indent, "contains ")) + indent -= 31; + + is_name = strstarts(line + indent, ".name "); + + n = parse(line + indent); + if (is_name) { + curr->name = namelen(n->len); + free(n); + } else { + if (indent > curr_indent) { + assert(indent == curr_indent + 4); + curr_indent += 4; + } else { + /* Go back up to parent. */ + for (curr_indent += 4; + curr_indent != indent; + curr_indent -= 4) + curr = curr->parent; + } + add_child(curr, n); + curr = n; + } + } + while (curr->parent) { + curr = curr->parent; + curr_indent -= 4; + } + assert(curr_indent == 0); + return curr; +} + +static int unused_talloc_destructor(void *p) +{ + return 0; +} + +static void do_tallocs(struct node *node) +{ + unsigned int i; + static int count; + + if (count++ % 16 == 0) + node->n = talloc_array(node->parent ? node->parent->n : NULL, + char, node->len); + else + node->n = talloc_size(node->parent ? node->parent->n : NULL, + node->len); + if (node->destructor) + talloc_set_destructor(node->n, unused_talloc_destructor); + if (node->name) + talloc_set_name(node->n, "%s", node->name); + + for (i = 0; i < node->num_children; i++) + do_tallocs(node->children[i]); +} + +static void free_tallocs(struct node *node) +{ + unsigned int i; + + for (i = 0; i < node->num_children; i++) + free_tallocs(node->children[i]); + + talloc_free(node->n); +} + +static void unused_tal_destructor(void *p) +{ +} + +static void do_tals(struct node *node) +{ + unsigned int i; + static int count; + + /* Tal pays a penalty for arrays, but we can't tell which is an array + * and which isn't. Grepping samba source gives 1221 talloc_array of + * 33137 talloc occurrences, so conservatively assume 1 in 16 */ + if (count++ % 16 == 0) + node->n = tal_arr(node->parent ? node->parent->n : NULL, + char, node->len); + else + node->n = tal_alloc_(node->parent ? node->parent->n : NULL, + node->len, false, false, TAL_LABEL(type, "")); + + if (node->destructor) + tal_add_destructor(node->n, unused_tal_destructor); + if (node->name) + tal_set_name(node->n, node->name); + + for (i = 0; i < node->num_children; i++) + do_tals(node->children[i]); +} + +static void free_tals(struct node *node) +{ + unsigned int i; + + for (i = 0; i < node->num_children; i++) + free_tals(node->children[i]); + + tal_free(node->n); +} + +static void do_mallocs(struct node *node) +{ + unsigned int i; + + node->n = malloc(node->len + (node->name ? strlen(node->name) + 1 : 1)); + + for (i = 0; i < node->num_children; i++) + do_mallocs(node->children[i]); +} + +static void free_mallocs(struct node *node) +{ + unsigned int i; + + for (i = 0; i < node->num_children; i++) + free_mallocs(node->children[i]); + + free(node->n); +} + +/* See proc(5): field 23 is vsize, 24 is rss (in pages) */ +static void dump_vsize(void) +{ + int fd, i; + char buf[1000], *p = buf; + + sprintf(buf, "/proc/%u/stat", getpid()); + fd = open(buf, O_RDONLY); + read(fd, buf, sizeof(buf)); + close(fd); + + for (i = 0; i < 22; i++) { + p += strcspn(p, " "); + p += strspn(p, " "); + } + i = atoi(p); + printf("Virtual size = %i, ", i); + p += strcspn(p, " "); + p += strspn(p, " "); + i = atoi(p); + printf("RSS = %i\n", i * getpagesize()); +} + +#define LOOPS 1000 + +int main(int argc, char *argv[]) +{ + struct timeabs start; + struct timerel alloc_time, free_time; + struct node *root; + unsigned int i; + FILE *f; + bool run_talloc = true, run_tal = true, run_malloc = true; + + f = argv[1] ? fopen(argv[1], "r") : stdin; + root = read_nodes(f); + fclose(f); + printf("Read %u nodes\n", node_count); + + if (argc > 2) { + if (streq(argv[2], "--talloc-size")) { + do_tallocs(root); + dump_vsize(); + exit(0); + } + if (streq(argv[2], "--tal-size")) { + do_tals(root); + dump_vsize(); + exit(0); + } + if (strcmp(argv[2], "--talloc") == 0) + run_tal = run_malloc = false; + else if (strcmp(argv[2], "--tal") == 0) + run_talloc = run_malloc = false; + else if (strcmp(argv[2], "--malloc") == 0) + run_talloc = run_tal = false; + else + errx(1, "Bad flag %s", argv[2]); + } + + if (!run_malloc) + goto after_malloc; + + alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0; + free_time.ts.tv_sec = free_time.ts.tv_nsec = 0; + for (i = 0; i < LOOPS; i++) { + start = time_now(); + do_mallocs(root); + alloc_time = timerel_add(alloc_time, + time_between(time_now(), start)); + + start = time_now(); + free_mallocs(root); + free_time = timerel_add(free_time, + time_between(time_now(), start)); + } + alloc_time = time_divide(alloc_time, i); + free_time = time_divide(free_time, i); + printf("Malloc time: %"PRIu64"ns\n", time_to_nsec(alloc_time)); + printf("Free time: %"PRIu64"ns\n", time_to_nsec(free_time)); + +after_malloc: + if (!run_talloc) + goto after_talloc; + + alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0; + free_time.ts.tv_sec = free_time.ts.tv_nsec = 0; + for (i = 0; i < LOOPS; i++) { + start = time_now(); + do_tallocs(root); + alloc_time = timerel_add(alloc_time, + time_between(time_now(), start)); + + start = time_now(); + free_tallocs(root); + free_time = timerel_add(free_time, + time_between(time_now(), start)); + } + alloc_time = time_divide(alloc_time, i); + free_time = time_divide(free_time, i); + printf("Talloc time: %"PRIu64"ns\n", time_to_nsec(alloc_time)); + printf("talloc_free time: %"PRIu64"ns\n", time_to_nsec(free_time)); + + free_time.ts.tv_sec = free_time.ts.tv_nsec = 0; + for (i = 0; i < LOOPS; i++) { + do_tallocs(root); + + start = time_now(); + talloc_free(root->n); + free_time = timerel_add(free_time, + time_between(time_now(), start)); + } + free_time = time_divide(free_time, i); + printf("Single talloc_free time: %"PRIu64"\n", time_to_nsec(free_time)); + +after_talloc: + if (!run_tal) + goto after_tal; + + alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0; + free_time.ts.tv_sec = free_time.ts.tv_nsec = 0; + for (i = 0; i < LOOPS; i++) { + start = time_now(); + do_tals(root); + alloc_time = timerel_add(alloc_time, + time_between(time_now(), start)); + + start = time_now(); + free_tals(root); + free_time = timerel_add(free_time, + time_between(time_now(), start)); + } + alloc_time = time_divide(alloc_time, i); + free_time = time_divide(free_time, i); + printf("Tal time: %"PRIu64"ns\n", time_to_nsec(alloc_time)); + printf("Tal_free time: %"PRIu64"ns\n", time_to_nsec(free_time)); + + free_time.ts.tv_sec = free_time.ts.tv_nsec = 0; + for (i = 0; i < LOOPS; i++) { + do_tals(root); + + start = time_now(); + tal_free(root->n); + free_time = timerel_add(free_time, + time_between(time_now(), start)); + } + free_time = time_divide(free_time, i); + printf("Single tal_free time: %"PRIu64"ns\n", time_to_nsec(free_time)); +after_tal: + + return 0; +} |
