blob: 5296e3149d0c75276390e4847d4c3b9a24629fb1 [file] [log] [blame]
njn29a5c012009-05-06 06:15:55 +00001// 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
njn532b04b2009-05-06 06:27:19 +000011#include <stdlib.h>
njn29a5c012009-05-06 06:15:55 +000012#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 */
19int stack_fan_out = 15;
20int stack_depth = 4;
21
22/* for each call stack, allocate malloc_fan blocks */
23int malloc_fan = 4;
24
25/* for each call stack, allocate data structures having malloc_depth
26 indirection at each malloc-ed level */
27int 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 */
31int malloc_data = 5;
32
33/* every n top blocks, 1 block and all its children will be freed instead of
34 being kept */
35int free_every_n = 2;
36
37/* every n release block operation, 1 block and its children will be leaked */
38int leak_every_n = 250;
39
40
41
42struct Chunk {
43 struct Chunk* child;
44 char s[];
45};
46
47struct Chunk** topblocks;
48int freetop = 0;
49
50/* statistics */
51long total_malloced = 0;
52int blocknr = 0;
53int blockfreed = 0;
54int blockleaked = 0;
55int total_stacks = 0;
56int releaseop = 0;
57
58void 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
70void 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
82void 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
199int 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}