rts/linker/ElfTypes.h: restore powerps (and others) support
[ghc.git] / rts / RetainerSet.c
1 /* -----------------------------------------------------------------------------
2 *
3 * (c) The GHC Team, 2001
4 * Author: Sungwoo Park
5 *
6 * Retainer set implementation for retainer profiling (see RetainerProfile.c)
7 *
8 * ---------------------------------------------------------------------------*/
9
10 #if defined(PROFILING)
11
12 #include "PosixSource.h"
13 #include "Rts.h"
14
15 #include "Stats.h"
16 #include "RtsUtils.h"
17 #include "RetainerSet.h"
18 #include "Arena.h"
19 #include "Profiling.h"
20
21 #include <string.h>
22
23 #define HASH_TABLE_SIZE 255
24 #define hash(hk) (hk % HASH_TABLE_SIZE)
25 static RetainerSet *hashTable[HASH_TABLE_SIZE];
26
27 static Arena *arena; // arena in which we store retainer sets
28
29 static int nextId; // id of next retainer set
30
31 /* -----------------------------------------------------------------------------
32 * rs_MANY is a distinguished retainer set, such that
33 *
34 * isMember(e, rs_MANY) = True
35 *
36 * addElement(e, rs) = rs_MANY, if rs->num >= maxRetainerSetSize
37 * addElement(e, rs_MANY) = rs_MANY
38 *
39 * The point of rs_MANY is to keep the total number of retainer sets
40 * from growing too large.
41 * -------------------------------------------------------------------------- */
42 RetainerSet rs_MANY = {
43 .num = 0,
44 .hashKey = 0,
45 .link = NULL,
46 .id = 1,
47 .element = {}
48 };
49
50 /* -----------------------------------------------------------------------------
51 * calculate the size of a RetainerSet structure
52 * -------------------------------------------------------------------------- */
53 STATIC_INLINE size_t
54 sizeofRetainerSet( int elems )
55 {
56 return (sizeof(RetainerSet) + elems * sizeof(retainer));
57 }
58
59 /* -----------------------------------------------------------------------------
60 * Creates the first pool and initializes hashTable[].
61 * Frees all pools if any.
62 * -------------------------------------------------------------------------- */
63 void
64 initializeAllRetainerSet(void)
65 {
66 int i;
67
68 arena = newArena();
69
70 for (i = 0; i < HASH_TABLE_SIZE; i++)
71 hashTable[i] = NULL;
72 nextId = 2; // Initial value must be positive, 2 is MANY.
73 }
74
75 /* -----------------------------------------------------------------------------
76 * Refreshes all pools for reuse and initializes hashTable[].
77 * -------------------------------------------------------------------------- */
78 void
79 refreshAllRetainerSet(void)
80 {
81 #if defined(FIRST_APPROACH)
82 int i;
83
84 // first approach: completely refresh
85 arenaFree(arena);
86 arena = newArena();
87
88 for (i = 0; i < HASH_TABLE_SIZE; i++)
89 hashTable[i] = NULL;
90 nextId = 2;
91 #endif /* FIRST_APPROACH */
92 }
93
94 /* -----------------------------------------------------------------------------
95 * Frees all pools.
96 * -------------------------------------------------------------------------- */
97 void
98 closeAllRetainerSet(void)
99 {
100 arenaFree(arena);
101 }
102
103 /* -----------------------------------------------------------------------------
104 * Finds or creates if needed a singleton retainer set.
105 * -------------------------------------------------------------------------- */
106 RetainerSet *
107 singleton(retainer r)
108 {
109 RetainerSet *rs;
110 StgWord hk;
111
112 hk = hashKeySingleton(r);
113 for (rs = hashTable[hash(hk)]; rs != NULL; rs = rs->link)
114 if (rs->num == 1 && rs->element[0] == r) return rs; // found it
115
116 // create it
117 rs = arenaAlloc( arena, sizeofRetainerSet(1) );
118 rs->num = 1;
119 rs->hashKey = hk;
120 rs->link = hashTable[hash(hk)];
121 rs->id = nextId++;
122 rs->element[0] = r;
123
124 // The new retainer set is placed at the head of the linked list.
125 hashTable[hash(hk)] = rs;
126
127 return rs;
128 }
129
130 /* -----------------------------------------------------------------------------
131 * Finds or creates a retainer set *rs augmented with r.
132 * Invariants:
133 * r is not a member of rs, i.e., isMember(r, rs) returns false.
134 * rs is not NULL.
135 * Note:
136 * We could check if rs is NULL, in which case this function call
137 * reverts to singleton(). We do not choose this strategy because
138 * in most cases addElement() is invoked with non-NULL rs.
139 * -------------------------------------------------------------------------- */
140 RetainerSet *
141 addElement(retainer r, RetainerSet *rs)
142 {
143 uint32_t i;
144 uint32_t nl; // Number of retainers in *rs Less than r
145 RetainerSet *nrs; // New Retainer Set
146 StgWord hk; // Hash Key
147
148 #if defined(DEBUG_RETAINER)
149 // debugBelch("addElement(%p, %p) = ", r, rs);
150 #endif
151
152 ASSERT(rs != NULL);
153 ASSERT(rs->num <= RtsFlags.ProfFlags.maxRetainerSetSize);
154
155 if (rs == &rs_MANY || rs->num == RtsFlags.ProfFlags.maxRetainerSetSize) {
156 return &rs_MANY;
157 }
158
159 ASSERT(!isMember(r, rs));
160
161 for (nl = 0; nl < rs->num; nl++)
162 if (r < rs->element[nl]) break;
163 // Now nl is the index for r into the new set.
164 // Also it denotes the number of retainers less than r in *rs.
165 // Thus, compare the first nl retainers, then r itself, and finally the
166 // remaining (rs->num - nl) retainers.
167
168 hk = hashKeyAddElement(r, rs);
169 for (nrs = hashTable[hash(hk)]; nrs != NULL; nrs = nrs->link) {
170 // test *rs and *nrs for equality
171
172 // check their size
173 if (rs->num + 1 != nrs->num) continue;
174
175 // compare the first nl retainers and find the first non-matching one.
176 for (i = 0; i < nl; i++)
177 if (rs->element[i] != nrs->element[i]) break;
178 if (i < nl) continue;
179
180 // compare r itself
181 if (r != nrs->element[i]) continue; // i == nl
182
183 // compare the remaining retainers
184 for (; i < rs->num; i++)
185 if (rs->element[i] != nrs->element[i + 1]) break;
186 if (i < rs->num) continue;
187
188 #if defined(DEBUG_RETAINER)
189 // debugBelch("%p\n", nrs);
190 #endif
191 // The set we are seeking already exists!
192 return nrs;
193 }
194
195 // create a new retainer set
196 nrs = arenaAlloc( arena, sizeofRetainerSet(rs->num + 1) );
197 nrs->num = rs->num + 1;
198 nrs->hashKey = hk;
199 nrs->link = hashTable[hash(hk)];
200 nrs->id = nextId++;
201 for (i = 0; i < nl; i++) { // copy the first nl retainers
202 nrs->element[i] = rs->element[i];
203 }
204 nrs->element[i] = r; // copy r
205 for (; i < rs->num; i++) { // copy the remaining retainers
206 nrs->element[i + 1] = rs->element[i];
207 }
208
209 hashTable[hash(hk)] = nrs;
210
211 #if defined(DEBUG_RETAINER)
212 // debugBelch("%p\n", nrs);
213 #endif
214 return nrs;
215 }
216
217 /* -----------------------------------------------------------------------------
218 * printRetainer() prints the full information on a given retainer,
219 * not a retainer set.
220 * -------------------------------------------------------------------------- */
221 #if defined(RETAINER_SCHEME_INFO)
222 // Retainer scheme 1: retainer = info table
223 static void
224 printRetainer(FILE *f, retainer itbl)
225 {
226 fprintf(f, "%s[%s]", GET_PROF_DESC(itbl), itbl->prof.closure_type);
227 }
228 #elif defined(RETAINER_SCHEME_CCS)
229 // Retainer scheme 2: retainer = cost centre stack
230 static void
231 printRetainer(FILE *f, retainer ccs)
232 {
233 fprintCCS(f, ccs);
234 }
235 #elif defined(RETAINER_SCHEME_CC)
236 // Retainer scheme 3: retainer = cost centre
237 static void
238 printRetainer(FILE *f, retainer cc)
239 {
240 fprintf(f,"%s.%s", cc->module, cc->label);
241 }
242 #endif
243
244 /* -----------------------------------------------------------------------------
245 * printRetainerSetShort() should always display the same output for
246 * a given retainer set regardless of the time of invocation.
247 * -------------------------------------------------------------------------- */
248 #if defined(SECOND_APPROACH)
249 #if defined(RETAINER_SCHEME_INFO)
250 // Retainer scheme 1: retainer = info table
251 void
252 printRetainerSetShort(FILE *f, RetainerSet *rs, uint32_t max_length)
253 {
254 char tmp[max_length + 1];
255 int size;
256 uint32_t j;
257
258 ASSERT(rs->id < 0);
259
260 tmp[max_length] = '\0';
261
262 // No blank characters are allowed.
263 sprintf(tmp + 0, "(%d)", -(rs->id));
264 size = strlen(tmp);
265 ASSERT(size < max_length);
266
267 for (j = 0; j < rs->num; j++) {
268 if (j < rs->num - 1) {
269 strncpy(tmp + size, GET_PROF_DESC(rs->element[j]), max_length - size);
270 size = strlen(tmp);
271 if (size == max_length)
272 break;
273 strncpy(tmp + size, ",", max_length - size);
274 size = strlen(tmp);
275 if (size == max_length)
276 break;
277 }
278 else {
279 strncpy(tmp + size, GET_PROF_DESC(rs->element[j]), max_length - size);
280 // size = strlen(tmp);
281 }
282 }
283 fprintf(f, tmp);
284 }
285 #elif defined(RETAINER_SCHEME_CC)
286 // Retainer scheme 3: retainer = cost centre
287 void
288 printRetainerSetShort(FILE *f, RetainerSet *rs, uint32_t max_length)
289 {
290 char tmp[max_length + 1];
291 int size;
292 uint32_t j;
293
294 }
295 #elif defined(RETAINER_SCHEME_CCS)
296 // Retainer scheme 2: retainer = cost centre stack
297 void
298 printRetainerSetShort(FILE *f, RetainerSet *rs, uint32_t max_length)
299 {
300 char tmp[max_length + 1];
301 uint32_t size;
302 uint32_t j;
303
304 ASSERT(rs->id < 0);
305
306 tmp[max_length] = '\0';
307
308 // No blank characters are allowed.
309 sprintf(tmp + 0, "(%d)", -(rs->id));
310 size = strlen(tmp);
311 ASSERT(size < max_length);
312
313 for (j = 0; j < rs->num; j++) {
314 if (j < rs->num - 1) {
315 strncpy(tmp + size, rs->element[j]->cc->label, max_length - size);
316 size = strlen(tmp);
317 if (size == max_length)
318 break;
319 strncpy(tmp + size, ",", max_length - size);
320 size = strlen(tmp);
321 if (size == max_length)
322 break;
323 }
324 else {
325 strncpy(tmp + size, rs->element[j]->cc->label, max_length - size);
326 // size = strlen(tmp);
327 }
328 }
329 fputs(tmp, f);
330 }
331 #elif defined(RETAINER_SCHEME_CC)
332 // Retainer scheme 3: retainer = cost centre
333 static void
334 printRetainerSetShort(FILE *f, retainerSet *rs, uint32_t max_length)
335 {
336 char tmp[max_length + 1];
337 int size;
338 uint32_t j;
339
340 ASSERT(rs->id < 0);
341
342 tmp[max_length] = '\0';
343
344 // No blank characters are allowed.
345 sprintf(tmp + 0, "(%d)", -(rs->id));
346 size = strlen(tmp);
347 ASSERT(size < max_length);
348
349 for (j = 0; j < rs->num; j++) {
350 if (j < rs->num - 1) {
351 strncpy(tmp + size, rs->element[j]->label,
352 max_length - size);
353 size = strlen(tmp);
354 if (size == max_length)
355 break;
356 strncpy(tmp + size, ",", max_length - size);
357 size = strlen(tmp);
358 if (size == max_length)
359 break;
360 }
361 else {
362 strncpy(tmp + size, rs->element[j]->label,
363 max_length - size);
364 // size = strlen(tmp);
365 }
366 }
367 fprintf(f, tmp);
368 /*
369 #define DOT_NUMBER 3
370 // 1. 32 > max_length + 1 (1 for '\0')
371 // 2. (max_length - DOT_NUMBER ) characters should be enough for
372 // printing one natural number (plus '(' and ')').
373 char tmp[32];
374 int size, ts;
375 uint32_t j;
376
377 ASSERT(rs->id < 0);
378
379 // No blank characters are allowed.
380 sprintf(tmp + 0, "(%d)", -(rs->id));
381 size = strlen(tmp);
382 ASSERT(size < max_length - DOT_NUMBER);
383
384 for (j = 0; j < rs->num; j++) {
385 ts = strlen(rs->element[j]->label);
386 if (j < rs->num - 1) {
387 if (size + ts + 1 > max_length - DOT_NUMBER) {
388 sprintf(tmp + size, "...");
389 break;
390 }
391 sprintf(tmp + size, "%s,", rs->element[j]->label);
392 size += ts + 1;
393 }
394 else {
395 if (size + ts > max_length - DOT_NUMBER) {
396 sprintf(tmp + size, "...");
397 break;
398 }
399 sprintf(tmp + size, "%s", rs->element[j]->label);
400 size += ts;
401 }
402 }
403 fprintf(f, tmp);
404 */
405 }
406 #endif /* RETAINER_SCHEME_CC */
407 #endif /* SECOND_APPROACH */
408
409 /* -----------------------------------------------------------------------------
410 * Dump the contents of each retainer set into the log file at the end
411 * of the run, so the user can find out for a given retainer set ID
412 * the full contents of that set.
413 * -------------------------------------------------------------------------- */
414 #if defined(SECOND_APPROACH)
415 void
416 outputAllRetainerSet(FILE *prof_file)
417 {
418 uint32_t i, j;
419 uint32_t numSet;
420 RetainerSet *rs, **rsArray, *tmp;
421
422 // find out the number of retainer sets which have had a non-zero cost at
423 // least once during retainer profiling
424 numSet = 0;
425 for (i = 0; i < HASH_TABLE_SIZE; i++)
426 for (rs = hashTable[i]; rs != NULL; rs = rs->link) {
427 if (rs->id < 0)
428 numSet++;
429 }
430
431 if (numSet == 0) // retainer profiling was not done at all.
432 return;
433
434 // allocate memory
435 rsArray = stgMallocBytes(numSet * sizeof(RetainerSet *),
436 "outputAllRetainerSet()");
437
438 // prepare for sorting
439 j = 0;
440 for (i = 0; i < HASH_TABLE_SIZE; i++)
441 for (rs = hashTable[i]; rs != NULL; rs = rs->link) {
442 if (rs->id < 0) {
443 rsArray[j] = rs;
444 j++;
445 }
446 }
447
448 ASSERT(j == numSet);
449
450 // sort rsArray[] according to the id of each retainer set
451 for (i = numSet - 1; i > 0; i--) {
452 for (j = 0; j <= i - 1; j++) {
453 // if (-(rsArray[j]->id) < -(rsArray[j + 1]->id))
454 if (rsArray[j]->id < rsArray[j + 1]->id) {
455 tmp = rsArray[j];
456 rsArray[j] = rsArray[j + 1];
457 rsArray[j + 1] = tmp;
458 }
459 }
460 }
461
462 fprintf(prof_file, "\nRetainer sets created during profiling:\n");
463 for (i = 0;i < numSet; i++) {
464 fprintf(prof_file, "SET %u = {", -(rsArray[i]->id));
465 for (j = 0; j < rsArray[i]->num - 1; j++) {
466 printRetainer(prof_file, rsArray[i]->element[j]);
467 fprintf(prof_file, ", ");
468 }
469 printRetainer(prof_file, rsArray[i]->element[j]);
470 fprintf(prof_file, "}\n");
471 }
472
473 stgFree(rsArray);
474 }
475 #endif /* SECOND_APPROACH */
476
477 #endif /* PROFILING */