]> git.ozlabs.org Git - ccan/blob - ccan/tal/benchmark/samba-allocs.c
base64: fix for unsigned chars (e.g. ARM).
[ccan] / ccan / tal / benchmark / samba-allocs.c
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>
7 #include <string.h>
8 #include <assert.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <inttypes.h>
14
15 struct node {
16         void *n;
17         struct node *parent;
18         char *name;
19         bool destructor;
20         size_t len;
21         unsigned int num_children;
22         struct node *children[0];
23 };
24
25 static int node_count;
26
27 static struct node *new_node(void)
28 {
29         node_count++;
30         return calloc(sizeof(struct node), 1);
31 }
32
33 /* struct db_context              contains    282 bytes in   5 blocks (ref 0) d=(nil) 0x1f64e70 */
34 static struct node *parse(const char *line)
35 {
36         struct node *n = new_node();
37         const char *p;
38
39         p = strstr(line, " contains ");
40         p += strlen(" contains ");
41         p += strspn(line, " ");
42         n->len = strtol(p, NULL, 0);
43         p = strstr(p, "d=");
44         if (p[2] != '(')
45                 n->destructor = true;
46         return n;
47 }
48
49 static void add_child(struct node *parent, struct node *child)
50 {
51         unsigned int i;
52         struct node *oldp = parent;
53
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;
58
59         if (parent == oldp)
60                 return;
61
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;
66         }
67
68         /* Fix up parent's child pointer. */
69         if (parent->parent) {
70                 assert(parent->parent->children[parent->parent->num_children-1]
71                        == oldp);
72                 parent->parent->children[parent->parent->num_children-1]
73                         = parent;
74         }
75 }
76
77 /* Random string of required length */
78 static char *namelen(int len)
79 {
80         char *p = malloc(len);
81         memset(p, 'x', len-1);
82         p[len-1] = '\0';
83         return p;
84 }
85
86 static struct node *read_nodes(FILE *f)
87 {
88         char line[4096];
89         unsigned int curr_indent = 0, indent;
90         struct node *n, *curr = new_node();
91
92         /* Ignore first line */
93         fgets(line, 4096, f);
94
95         while (fgets(line, 4096, f)) {
96                 bool is_name;
97
98                 indent = strspn(line, " ");
99
100                 /* Ignore references for now. */
101                 if (strstarts(line + indent, "reference to: "))
102                         continue;
103
104                 /* Blank name?  Use offset of 'contains' to guess indent! */
105                 if (strstarts(line + indent, "contains "))
106                         indent -= 31;
107
108                 is_name = strstarts(line + indent, ".name ");
109
110                 n = parse(line + indent);
111                 if (is_name) {
112                         curr->name = namelen(n->len);
113                         free(n);
114                 } else {
115                         if (indent > curr_indent) {
116                                 assert(indent == curr_indent + 4);
117                                 curr_indent += 4;
118                         } else {
119                                 /* Go back up to parent. */
120                                 for (curr_indent += 4;
121                                      curr_indent != indent;
122                                      curr_indent -= 4)
123                                         curr = curr->parent;
124                         }
125                         add_child(curr, n);
126                         curr = n;
127                 }
128         }
129         while (curr->parent) {
130                 curr = curr->parent;
131                 curr_indent -= 4;
132         }
133         assert(curr_indent == 0);
134         return curr;
135 }
136
137 static int unused_talloc_destructor(void *p)
138 {
139         return 0;
140 }
141
142 static void do_tallocs(struct node *node)
143 {
144         unsigned int i;
145         static int count;
146
147         if (count++ % 16 == 0)
148                 node->n = talloc_array(node->parent ? node->parent->n : NULL,
149                                        char, node->len);
150         else
151                 node->n = talloc_size(node->parent ? node->parent->n : NULL,
152                                       node->len);
153         if (node->destructor)
154                 talloc_set_destructor(node->n, unused_talloc_destructor);
155         if (node->name)
156                 talloc_set_name(node->n, "%s", node->name);
157
158         for (i = 0; i < node->num_children; i++)
159                 do_tallocs(node->children[i]);
160 }
161
162 static void free_tallocs(struct node *node)
163 {
164         unsigned int i;
165
166         for (i = 0; i < node->num_children; i++)
167                 free_tallocs(node->children[i]);
168
169         talloc_free(node->n);
170 }
171
172 static void unused_tal_destructor(void *p)
173 {
174 }
175
176 static void do_tals(struct node *node)
177 {
178         unsigned int i;
179         static int count;
180
181         node->n = tal_arr(node->parent ? node->parent->n : NULL,
182                           char, node->len);
183
184         if (node->destructor)
185                 tal_add_destructor(node->n, unused_tal_destructor);
186         if (node->name)
187                 tal_set_name(node->n, node->name);
188
189         for (i = 0; i < node->num_children; i++)
190                 do_tals(node->children[i]);
191 }
192
193 static void free_tals(struct node *node)
194 {
195         unsigned int i;
196
197         for (i = 0; i < node->num_children; i++)
198                 free_tals(node->children[i]);
199
200         tal_free(node->n);
201 }
202
203 static void do_mallocs(struct node *node)
204 {
205         unsigned int i;
206
207         node->n = malloc(node->len + (node->name ? strlen(node->name) + 1 : 1));
208
209         for (i = 0; i < node->num_children; i++)
210                 do_mallocs(node->children[i]);
211 }
212
213 static void free_mallocs(struct node *node)
214 {
215         unsigned int i;
216
217         for (i = 0; i < node->num_children; i++)
218                 free_mallocs(node->children[i]);
219
220         free(node->n);
221 }
222
223 /* See proc(5): field 23 is vsize, 24 is rss (in pages) */
224 static void dump_vsize(void)
225 {
226         int fd, i;
227         char buf[1000], *p = buf;
228
229         sprintf(buf, "/proc/%u/stat", getpid());
230         fd = open(buf, O_RDONLY);
231         read(fd, buf, sizeof(buf));
232         close(fd);
233
234         for (i = 0; i < 22; i++) {
235                 p += strcspn(p, " ");
236                 p += strspn(p, " ");
237         }
238         i = atoi(p);
239         printf("Virtual size = %i, ", i);
240         p += strcspn(p, " ");
241         p += strspn(p, " ");
242         i = atoi(p);
243         printf("RSS = %i\n", i * getpagesize());
244 }
245
246 #define LOOPS 1000
247
248 int main(int argc, char *argv[])
249 {
250         struct timeabs start;
251         struct timerel alloc_time, free_time;
252         struct node *root;
253         unsigned int i;
254         FILE *f;
255         bool run_talloc = true, run_tal = true, run_malloc = true;
256
257         f = argv[1] ? fopen(argv[1], "r") : stdin;
258         root = read_nodes(f);
259         fclose(f);
260         printf("Read %u nodes\n", node_count);
261
262         if (argc > 2) {
263                 if (streq(argv[2], "--talloc-size")) {
264                         do_tallocs(root);
265                         dump_vsize();
266                         exit(0);
267                 }
268                 if (streq(argv[2], "--tal-size")) {
269                         do_tals(root);
270                         dump_vsize();
271                         exit(0);
272                 }
273                 if (strcmp(argv[2], "--talloc") == 0)
274                         run_tal = run_malloc = false;
275                 else if (strcmp(argv[2], "--tal") == 0)
276                         run_talloc = run_malloc = false;
277                 else if (strcmp(argv[2], "--malloc") == 0)
278                         run_talloc = run_tal = false;
279                 else
280                         errx(1, "Bad flag %s", argv[2]);
281         }
282
283         if (!run_malloc)
284                 goto after_malloc;
285
286         alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0;
287         free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
288         for (i = 0; i < LOOPS; i++) {
289                 start = time_now();
290                 do_mallocs(root);
291                 alloc_time = timerel_add(alloc_time,
292                                          time_between(time_now(), start));
293
294                 start = time_now();
295                 free_mallocs(root);
296                 free_time = timerel_add(free_time,
297                                         time_between(time_now(), start));
298         }
299         alloc_time = time_divide(alloc_time, i);
300         free_time = time_divide(free_time, i);
301         printf("Malloc time:             %"PRIu64"ns\n", time_to_nsec(alloc_time));
302         printf("Free time:               %"PRIu64"ns\n", time_to_nsec(free_time));
303
304 after_malloc:
305         if (!run_talloc)
306                 goto after_talloc;
307
308         alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0;
309         free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
310         for (i = 0; i < LOOPS; i++) {
311                 start = time_now();
312                 do_tallocs(root);
313                 alloc_time = timerel_add(alloc_time,
314                                          time_between(time_now(), start));
315
316                 start = time_now();
317                 free_tallocs(root);
318                 free_time = timerel_add(free_time,
319                                         time_between(time_now(), start));
320         }
321         alloc_time = time_divide(alloc_time, i);
322         free_time = time_divide(free_time, i);
323         printf("Talloc time:             %"PRIu64"ns\n", time_to_nsec(alloc_time));
324         printf("talloc_free time:        %"PRIu64"ns\n", time_to_nsec(free_time));
325
326         free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
327         for (i = 0; i < LOOPS; i++) {
328                 do_tallocs(root);
329
330                 start = time_now();
331                 talloc_free(root->n);
332                 free_time = timerel_add(free_time,
333                                         time_between(time_now(), start));
334         }
335         free_time = time_divide(free_time, i);
336         printf("Single talloc_free time: %"PRIu64"\n", time_to_nsec(free_time));
337
338 after_talloc:
339         if (!run_tal)
340                 goto after_tal;
341
342         alloc_time.ts.tv_sec = alloc_time.ts.tv_nsec = 0;
343         free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
344         for (i = 0; i < LOOPS; i++) {
345                 start = time_now();
346                 do_tals(root);
347                 alloc_time = timerel_add(alloc_time,
348                                          time_between(time_now(), start));
349
350                 start = time_now();
351                 free_tals(root);
352                 free_time = timerel_add(free_time,
353                                         time_between(time_now(), start));
354         }
355         alloc_time = time_divide(alloc_time, i);
356         free_time = time_divide(free_time, i);
357         printf("Tal time:                %"PRIu64"ns\n", time_to_nsec(alloc_time));
358         printf("Tal_free time:           %"PRIu64"ns\n", time_to_nsec(free_time));
359
360         free_time.ts.tv_sec = free_time.ts.tv_nsec = 0;
361         for (i = 0; i < LOOPS; i++) {
362                 do_tals(root);
363
364                 start = time_now();
365                 tal_free(root->n);
366                 free_time = timerel_add(free_time,
367                                         time_between(time_now(), start));
368         }
369         free_time = time_divide(free_time, i);
370         printf("Single tal_free time:    %"PRIu64"ns\n", time_to_nsec(free_time));
371 after_tal:
372
373         return 0;
374 }