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