-> 3.17.0 final.
[valgrind.git] / perf / many-loss-records.c
blob5296e3149d0c75276390e4847d4c3b9a24629fb1
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
11 #include <stdlib.h>
12 #include <strings.h>
13 #include <stdio.h>
14 #include <math.h>
16 /* parameters */
18 /* we will create stack_fan_out ^ stack_depth different call stacks */
19 int stack_fan_out = 15;
20 int stack_depth = 4;
22 /* for each call stack, allocate malloc_fan blocks */
23 int malloc_fan = 4;
25 /* for each call stack, allocate data structures having malloc_depth
26 indirection at each malloc-ed level */
27 int malloc_depth = 2;
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;
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;
37 /* every n release block operation, 1 block and its children will be leaked */
38 int leak_every_n = 250;
42 struct Chunk {
43 struct Chunk* child;
44 char s[];
47 struct Chunk** topblocks;
48 int freetop = 0;
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;
58 void free_chunks (struct Chunk ** mem)
60 if (*mem == 0)
61 return;
63 free_chunks ((&(*mem)->child));
65 blockfreed++;
66 free (*mem);
67 *mem = 0;
70 void release (struct Chunk ** mem)
72 releaseop++;
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);
82 void call_stack (int level)
84 int call_fan_out = 1;
86 if (level == stack_depth) {
87 int sz = sizeof(struct Chunk*) + malloc_data;
88 int d;
89 int f;
91 for (f = 0; f < malloc_fan; f++) {
92 struct Chunk *new = NULL; // shut gcc up
93 struct Chunk *prev = NULL;
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;
102 topblocks[freetop] = new;
104 if (freetop % free_every_n == 0) {
105 release (&topblocks[freetop]);
107 freetop++;
110 total_stacks++;
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++;
119 call_stack (level + 1);
120 if (call_fan_out == stack_fan_out) return;
121 call_fan_out++;
123 call_stack (level + 1);
124 if (call_fan_out == stack_fan_out) return;
125 call_fan_out++;
127 call_stack (level + 1);
128 if (call_fan_out == stack_fan_out) return;
129 call_fan_out++;
131 call_stack (level + 1);
132 if (call_fan_out == stack_fan_out) return;
133 call_fan_out++;
135 call_stack (level + 1);
136 if (call_fan_out == stack_fan_out) return;
137 call_fan_out++;
139 call_stack (level + 1);
140 if (call_fan_out == stack_fan_out) return;
141 call_fan_out++;
143 call_stack (level + 1);
144 if (call_fan_out == stack_fan_out) return;
145 call_fan_out++;
147 call_stack (level + 1);
148 if (call_fan_out == stack_fan_out) return;
149 call_fan_out++;
151 call_stack (level + 1);
152 if (call_fan_out == stack_fan_out) return;
153 call_fan_out++;
155 call_stack (level + 1);
156 if (call_fan_out == stack_fan_out) return;
157 call_fan_out++;
159 call_stack (level + 1);
160 if (call_fan_out == stack_fan_out) return;
161 call_fan_out++;
163 call_stack (level + 1);
164 if (call_fan_out == stack_fan_out) return;
165 call_fan_out++;
167 call_stack (level + 1);
168 if (call_fan_out == stack_fan_out) return;
169 call_fan_out++;
171 call_stack (level + 1);
172 if (call_fan_out == stack_fan_out) return;
173 call_fan_out++;
175 call_stack (level + 1);
176 if (call_fan_out == stack_fan_out) return;
177 call_fan_out++;
179 call_stack (level + 1);
180 if (call_fan_out == stack_fan_out) return;
181 call_fan_out++;
183 call_stack (level + 1);
184 if (call_fan_out == stack_fan_out) return;
185 call_fan_out++;
187 call_stack (level + 1);
188 if (call_fan_out == stack_fan_out) return;
189 call_fan_out++;
191 call_stack (level + 1);
192 if (call_fan_out == stack_fan_out) return;
193 call_fan_out++;
195 printf ("maximum stack_fan_out exceeded\n");
199 int main()
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;