1 /* Grab dump of Samba4 talloc tree to do benchmarks on it. */
2 #include <ccan/talloc/talloc.h>
3 #include <ccan/tal/tal.h>
4 #include <ccan/time/time.h>
5 #include <ccan/err/err.h>
6 #include <ccan/str/str.h>
21 unsigned int num_children;
22 struct node *children[0];
25 static int node_count;
27 static struct node *new_node(void)
30 return calloc(sizeof(struct node), 1);
33 /* struct db_context contains 282 bytes in 5 blocks (ref 0) d=(nil) 0x1f64e70 */
34 static struct node *parse(const char *line)
36 struct node *n = new_node();
39 p = strstr(line, " contains ");
40 p += strlen(" contains ");
41 p += strspn(line, " ");
42 n->len = strtol(p, NULL, 0);
49 static void add_child(struct node *parent, struct node *child)
52 struct node *oldp = parent;
54 parent = realloc(parent, sizeof(*parent)
55 + sizeof(parent->children[0]) * (parent->num_children+1));
56 parent->children[parent->num_children++] = child;
57 child->parent = parent;
62 /* Fix up children's parent pointers. */
63 for (i = 0; i < parent->num_children-1; i++) {
64 assert(parent->children[i]->parent == oldp);
65 parent->children[i]->parent = parent;
68 /* Fix up parent's child pointer. */
70 assert(parent->parent->children[parent->parent->num_children-1]
72 parent->parent->children[parent->parent->num_children-1]
77 /* Random string of required length */
78 static char *namelen(int len)
80 char *p = malloc(len);
81 memset(p, 'x', len-1);
86 static struct node *read_nodes(FILE *f)
89 unsigned int curr_indent = 0, indent;
90 struct node *n, *curr = new_node();
92 /* Ignore first line */
95 while (fgets(line, 4096, f)) {
98 indent = strspn(line, " ");
100 /* Ignore references for now. */
101 if (strstarts(line + indent, "reference to: "))
104 /* Blank name? Use offset of 'contains' to guess indent! */
105 if (strstarts(line + indent, "contains "))
108 is_name = strstarts(line + indent, ".name ");
110 n = parse(line + indent);
112 curr->name = namelen(n->len);
115 if (indent > curr_indent) {
116 assert(indent == curr_indent + 4);
119 /* Go back up to parent. */
120 for (curr_indent += 4;
121 curr_indent != indent;
129 while (curr->parent) {
133 assert(curr_indent == 0);
137 static int unused_talloc_destructor(void *p)
142 static void do_tallocs(struct node *node)
147 if (count++ % 16 == 0)
148 node->n = talloc_array(node->parent ? node->parent->n : NULL,
151 node->n = talloc_size(node->parent ? node->parent->n : NULL,
153 if (node->destructor)
154 talloc_set_destructor(node->n, unused_talloc_destructor);
156 talloc_set_name(node->n, "%s", node->name);
158 for (i = 0; i < node->num_children; i++)
159 do_tallocs(node->children[i]);
162 static void free_tallocs(struct node *node)
166 for (i = 0; i < node->num_children; i++)
167 free_tallocs(node->children[i]);
169 talloc_free(node->n);
172 static void unused_tal_destructor(void *p)
176 static void do_tals(struct node *node)
181 /* Tal pays a penalty for arrays, but we can't tell which is an array
182 * and which isn't. Grepping samba source gives 1221 talloc_array of
183 * 33137 talloc occurrences, so conservatively assume 1 in 16 */
184 if (count++ % 16 == 0)
185 node->n = tal_arr(node->parent ? node->parent->n : NULL,
188 node->n = tal_alloc_(node->parent ? node->parent->n : NULL,
189 node->len, false, false, TAL_LABEL(type, ""));
191 if (node->destructor)
192 tal_add_destructor(node->n, unused_tal_destructor);
194 tal_set_name(node->n, node->name);
196 for (i = 0; i < node->num_children; i++)
197 do_tals(node->children[i]);
200 static void free_tals(struct node *node)
204 for (i = 0; i < node->num_children; i++)
205 free_tals(node->children[i]);
210 static void do_mallocs(struct node *node)
214 node->n = malloc(node->len + (node->name ? strlen(node->name) + 1 : 1));
216 for (i = 0; i < node->num_children; i++)
217 do_mallocs(node->children[i]);
220 static void free_mallocs(struct node *node)
224 for (i = 0; i < node->num_children; i++)
225 free_mallocs(node->children[i]);
230 /* See proc(5): field 23 is vsize, 24 is rss (in pages) */
231 static void dump_vsize(void)
234 char buf[1000], *p = buf;
236 sprintf(buf, "/proc/%u/stat", getpid());
237 fd = open(buf, O_RDONLY);
238 read(fd, buf, sizeof(buf));
241 for (i = 0; i < 22; i++) {
242 p += strcspn(p, " ");
246 printf("Virtual size = %i, ", i);
247 p += strcspn(p, " ");
250 printf("RSS = %i\n", i * getpagesize());
255 int main(int argc, char *argv[])
257 struct timeabs start;
258 struct timerel alloc_time, free_time;
262 bool run_talloc = true, run_tal = true, run_malloc = true;
264 f = argv[1] ? fopen(argv[1], "r") : stdin;
265 root = read_nodes(f);
267 printf("Read %u nodes\n", node_count);
270 if (streq(argv[2], "--talloc-size")) {
275 if (streq(argv[2], "--tal-size")) {
280 if (strcmp(argv[2], "--talloc") == 0)
281 run_tal = run_malloc = false;
282 else if (strcmp(argv[2], "--tal") == 0)
283 run_talloc = run_malloc = false;
284 else if (strcmp(argv[2], "--malloc") == 0)
285 run_talloc = run_tal = false;
287 errx(1, "Bad flag %s", argv[2]);
293 alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0;
294 free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
295 for (i = 0; i < LOOPS; i++) {
298 alloc_time = timerel_add(alloc_time,
299 time_between(time_now(), start));
303 free_time = timerel_add(free_time,
304 time_between(time_now(), start));
306 alloc_time = time_divide(alloc_time, i);
307 free_time = time_divide(free_time, i);
308 printf("Malloc time: %"PRIu64"ns\n", time_to_nsec(alloc_time));
309 printf("Free time: %"PRIu64"ns\n", time_to_nsec(free_time));
315 alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0;
316 free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
317 for (i = 0; i < LOOPS; i++) {
320 alloc_time = timerel_add(alloc_time,
321 time_between(time_now(), start));
325 free_time = timerel_add(free_time,
326 time_between(time_now(), start));
328 alloc_time = time_divide(alloc_time, i);
329 free_time = time_divide(free_time, i);
330 printf("Talloc time: %"PRIu64"ns\n", time_to_nsec(alloc_time));
331 printf("talloc_free time: %"PRIu64"ns\n", time_to_nsec(free_time));
333 free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
334 for (i = 0; i < LOOPS; i++) {
338 talloc_free(root->n);
339 free_time = timerel_add(free_time,
340 time_between(time_now(), start));
342 free_time = time_divide(free_time, i);
343 printf("Single talloc_free time: %"PRIu64"\n", time_to_nsec(free_time));
349 alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0;
350 free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
351 for (i = 0; i < LOOPS; i++) {
354 alloc_time = timerel_add(alloc_time,
355 time_between(time_now(), start));
359 free_time = timerel_add(free_time,
360 time_between(time_now(), start));
362 alloc_time = time_divide(alloc_time, i);
363 free_time = time_divide(free_time, i);
364 printf("Tal time: %"PRIu64"ns\n", time_to_nsec(alloc_time));
365 printf("Tal_free time: %"PRIu64"ns\n", time_to_nsec(free_time));
367 free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
368 for (i = 0; i < LOOPS; i++) {
373 free_time = timerel_add(free_time,
374 time_between(time_now(), start));
376 free_time = time_divide(free_time, i);
377 printf("Single tal_free time: %"PRIu64"ns\n", time_to_nsec(free_time));