Home | History | Annotate | Download | only in perf
      1 // Performance test for the leak checker from bug #191182.
      2 // Nb: it must be run with --leak-resolution=high to show the quadratic
      3 // behaviour caused by the large number of loss records.
      4 // By Philippe Waroquiers.
      5 //
      6 // On my machine, before being fixed, building the loss record list took about
      7 // 36 seconds, and sorting + printing it took about 20 seconds.  After being
      8 // fixed it took about 2 seconds, and the leak checking was only a small
      9 // fraction of that. --njn
     10 
     11 #include <stdlib.h>
     12 #include <strings.h>
     13 #include <stdio.h>
     14 #include <math.h>
     15 
     16 /* parameters */
     17 
     18 /* we will create stack_fan_out ^ stack_depth different call stacks */
     19 int stack_fan_out = 15;
     20 int stack_depth = 4;
     21 
     22 /* for each call stack, allocate malloc_fan blocks */
     23 int malloc_fan = 4;
     24 
     25 /* for each call stack, allocate data structures having malloc_depth
     26    indirection at each malloc-ed level */
     27 int malloc_depth = 2;
     28 
     29 /* in addition to the pointer needed to maintain the levels; some more
     30    bytes are allocated simulating the data stored in the data structure */
     31 int malloc_data = 5;
     32 
     33 /* every n top blocks, 1 block and all its children will be freed instead of
     34    being kept */
     35 int free_every_n = 2;
     36 
     37 /* every n release block operation, 1 block and its children will be leaked */
     38 int leak_every_n = 250;
     39 
     40 
     41 
     42 struct Chunk {
     43    struct Chunk* child;
     44    char   s[];
     45 };
     46 
     47 struct Chunk** topblocks;
     48 int freetop = 0;
     49 
     50 /* statistics */
     51 long total_malloced = 0;
     52 int blocknr = 0;
     53 int blockfreed = 0;
     54 int blockleaked = 0;
     55 int total_stacks = 0;
     56 int releaseop = 0;
     57 
     58 void free_chunks (struct Chunk ** mem)
     59 {
     60    if (*mem == 0)
     61       return;
     62 
     63    free_chunks ((&(*mem)->child));
     64 
     65    blockfreed++;
     66    free (*mem);
     67    *mem = 0;
     68 }
     69 
     70 void release (struct Chunk ** mem)
     71 {
     72    releaseop++;
     73 
     74    if (releaseop % leak_every_n == 0) {
     75       blockleaked++;
     76       *mem = 0; // lose the pointer without free-ing the blocks
     77    } else {
     78       free_chunks (mem);
     79    }
     80 }
     81 
     82 void call_stack (int level)
     83 {
     84    int call_fan_out = 1;
     85 
     86    if (level == stack_depth) {
     87       int sz = sizeof(struct Chunk*) + malloc_data;
     88       int d;
     89       int f;
     90 
     91       for (f = 0; f < malloc_fan; f++) {
     92          struct Chunk *new  = NULL;    // shut gcc up
     93          struct Chunk *prev = NULL;
     94 
     95          for (d = 0; d < malloc_depth; d++) {
     96             new = malloc (sz);
     97             total_malloced += sz;
     98             blocknr++;
     99             new->child = prev;
    100             prev = new;
    101          }
    102          topblocks[freetop] = new;
    103 
    104          if (freetop % free_every_n == 0) {
    105                release (&topblocks[freetop]);
    106          }
    107          freetop++;
    108       }
    109 
    110       total_stacks++;
    111 
    112    } else {
    113       /* Nb: don't common these up into a loop!  We need different code
    114          locations to exercise the problem. */
    115       call_stack (level + 1);
    116       if (call_fan_out == stack_fan_out) return;
    117       call_fan_out++;
    118 
    119       call_stack (level + 1);
    120       if (call_fan_out == stack_fan_out) return;
    121       call_fan_out++;
    122 
    123       call_stack (level + 1);
    124       if (call_fan_out == stack_fan_out) return;
    125       call_fan_out++;
    126 
    127       call_stack (level + 1);
    128       if (call_fan_out == stack_fan_out) return;
    129       call_fan_out++;
    130 
    131       call_stack (level + 1);
    132       if (call_fan_out == stack_fan_out) return;
    133       call_fan_out++;
    134 
    135       call_stack (level + 1);
    136       if (call_fan_out == stack_fan_out) return;
    137       call_fan_out++;
    138 
    139       call_stack (level + 1);
    140       if (call_fan_out == stack_fan_out) return;
    141       call_fan_out++;
    142 
    143       call_stack (level + 1);
    144       if (call_fan_out == stack_fan_out) return;
    145       call_fan_out++;
    146 
    147       call_stack (level + 1);
    148       if (call_fan_out == stack_fan_out) return;
    149       call_fan_out++;
    150 
    151       call_stack (level + 1);
    152       if (call_fan_out == stack_fan_out) return;
    153       call_fan_out++;
    154 
    155       call_stack (level + 1);
    156       if (call_fan_out == stack_fan_out) return;
    157       call_fan_out++;
    158 
    159       call_stack (level + 1);
    160       if (call_fan_out == stack_fan_out) return;
    161       call_fan_out++;
    162 
    163       call_stack (level + 1);
    164       if (call_fan_out == stack_fan_out) return;
    165       call_fan_out++;
    166 
    167       call_stack (level + 1);
    168       if (call_fan_out == stack_fan_out) return;
    169       call_fan_out++;
    170 
    171       call_stack (level + 1);
    172       if (call_fan_out == stack_fan_out) return;
    173       call_fan_out++;
    174 
    175       call_stack (level + 1);
    176       if (call_fan_out == stack_fan_out) return;
    177       call_fan_out++;
    178 
    179       call_stack (level + 1);
    180       if (call_fan_out == stack_fan_out) return;
    181       call_fan_out++;
    182 
    183       call_stack (level + 1);
    184       if (call_fan_out == stack_fan_out) return;
    185       call_fan_out++;
    186 
    187       call_stack (level + 1);
    188       if (call_fan_out == stack_fan_out) return;
    189       call_fan_out++;
    190 
    191       call_stack (level + 1);
    192       if (call_fan_out == stack_fan_out) return;
    193       call_fan_out++;
    194 
    195       printf ("maximum stack_fan_out exceeded\n");
    196    }
    197 }
    198 
    199 int main()
    200 {
    201    int d;
    202    int stacks = 1;
    203    for (d = 0; d < stack_depth; d++)
    204       stacks *= stack_fan_out;
    205    printf ("will generate %d different stacks\n", stacks);
    206    topblocks = malloc(sizeof(struct Chunk*) * stacks * malloc_fan);
    207    call_stack (0);
    208    printf ("total stacks %d\n", total_stacks);
    209    printf ("total bytes malloc-ed: %ld\n", total_malloced);
    210    printf ("total blocks malloc-ed: %d\n", blocknr);
    211    printf ("total blocks free-ed: %d\n", blockfreed);
    212    printf ("total blocks leak-ed: %d\n", blockleaked);
    213    return 0;
    214 }
    215