samba-allocs.c (8595B)
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 }