re PR debug/66691 (ICE on valid code at -O3 with -g enabled in simplify_subreg, at...
[gcc.git] / gcc / mem-stats.h
1 #ifndef GCC_MEM_STATS_H
2 #define GCC_MEM_STATS_H
3
4 /* Forward declaration. */
5 template<typename Key, typename Value,
6 typename Traits = simple_hashmap_traits<default_hash_traits<Key> > >
7 class hash_map;
8
9 #define LOCATION_LINE_EXTRA_SPACE 30
10 #define LOCATION_LINE_WIDTH 48
11
12 /* Memory allocation location. */
13 struct mem_location
14 {
15 /* Default constructor. */
16 inline
17 mem_location () {}
18
19 /* Constructor. */
20 inline
21 mem_location (mem_alloc_origin origin, bool ggc,
22 const char *filename = NULL, int line = 0,
23 const char *function = NULL):
24 m_filename (filename), m_function (function), m_line (line), m_origin
25 (origin), m_ggc (ggc) {}
26
27 /* Copy constructor. */
28 inline
29 mem_location (mem_location &other): m_filename (other.m_filename),
30 m_function (other.m_function), m_line (other.m_line),
31 m_origin (other.m_origin), m_ggc (other.m_ggc) {}
32
33 /* Compute hash value based on file name, function name and line in
34 source code. As there is just a single pointer registered for every
35 constant that points to e.g. the same file name, we can use hash
36 of the pointer. */
37 hashval_t
38 hash ()
39 {
40 inchash::hash hash;
41
42 hash.add_ptr (m_filename);
43 hash.add_ptr (m_function);
44 hash.add_int (m_line);
45
46 return hash.end ();
47 }
48
49 /* Return true if the memory location is equal to OTHER. */
50 int
51 equal (mem_location &other)
52 {
53 return m_filename == other.m_filename && m_function == other.m_function
54 && m_line == other.m_line;
55 }
56
57 /* Return trimmed filename for the location. */
58 inline const char *
59 get_trimmed_filename ()
60 {
61 const char *s1 = m_filename;
62 const char *s2;
63
64 while ((s2 = strstr (s1, "gcc/")))
65 s1 = s2 + 4;
66
67 return s1;
68 }
69
70 inline char *
71 to_string ()
72 {
73 unsigned l = strlen (get_trimmed_filename ()) + strlen (m_function)
74 + LOCATION_LINE_EXTRA_SPACE;
75
76 char *s = XNEWVEC (char, l);
77 sprintf (s, "%s:%i (%s)", get_trimmed_filename (),
78 m_line, m_function);
79
80 s[MIN (LOCATION_LINE_WIDTH, l - 1)] = '\0';
81
82 return s;
83 }
84
85 /* Return display name associated to ORIGIN type. */
86 static const char *
87 get_origin_name (mem_alloc_origin origin)
88 {
89 return mem_alloc_origin_names[(unsigned) origin];
90 }
91
92 /* File name of source code. */
93 const char *m_filename;
94 /* Funcation name. */
95 const char *m_function;
96 /* Line number in source code. */
97 int m_line;
98 /* Origin type. */
99 mem_alloc_origin m_origin;
100 /* Flag if used by GGC allocation. */
101 bool m_ggc;
102 };
103
104 /* Memory usage register to a memory location. */
105 struct mem_usage
106 {
107 /* Default constructor. */
108 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
109
110 /* Constructor. */
111 mem_usage (size_t allocated, size_t times, size_t peak, size_t instances = 0):
112 m_allocated (allocated), m_times (times), m_peak (peak),
113 m_instances (instances) {}
114
115 /* Register overhead of SIZE bytes. */
116 inline void
117 register_overhead (size_t size)
118 {
119 m_allocated += size;
120 m_times++;
121
122 if (m_peak < m_allocated)
123 m_peak = m_allocated;
124 }
125
126 /* Release overhead of SIZE bytes. */
127 inline void
128 release_overhead (size_t size)
129 {
130 gcc_assert (size <= m_allocated);
131
132 m_allocated -= size;
133 }
134
135 /* Sum the usage with SECOND usage. */
136 mem_usage
137 operator+ (const mem_usage &second)
138 {
139 return mem_usage (m_allocated + second.m_allocated,
140 m_times + second.m_times,
141 m_peak + second.m_peak,
142 m_instances + second.m_instances);
143 }
144
145 /* Comparison operator. */
146 inline bool
147 operator< (const mem_usage &second) const
148 {
149 return (m_allocated == second.m_allocated ?
150 (m_peak == second.m_peak ? m_times < second.m_times
151 : m_peak < second.m_peak) : m_allocated < second.m_allocated);
152 }
153
154 /* Compare wrapper used by qsort method. */
155 static int
156 compare (const void *first, const void *second)
157 {
158 typedef std::pair<mem_location *, mem_usage *> mem_pair_t;
159
160 const mem_pair_t f = *(const mem_pair_t *)first;
161 const mem_pair_t s = *(const mem_pair_t *)second;
162
163 return (*f.second) < (*s.second);
164 }
165
166 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
167 inline void
168 dump (mem_location *loc, mem_usage &total) const
169 {
170 char *location_string = loc->to_string ();
171
172 fprintf (stderr, "%-48s %10li:%5.1f%%%10li%10li:%5.1f%%%10s\n",
173 location_string,
174 (long)m_allocated, get_percent (m_allocated, total.m_allocated),
175 (long)m_peak, (long)m_times,
176 get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap");
177
178 free (location_string);
179 }
180
181 /* Dump footer. */
182 inline void
183 dump_footer () const
184 {
185 print_dash_line ();
186 fprintf (stderr, "%s%54li%27li\n", "Total", (long)m_allocated,
187 (long)m_times);
188 print_dash_line ();
189 }
190
191 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */
192 static inline float
193 get_percent (size_t nominator, size_t denominator)
194 {
195 return denominator == 0 ? 0.0f : nominator * 100.0 / denominator;
196 }
197
198 /* Print line made of dashes. */
199 static inline void
200 print_dash_line (size_t count = 140)
201 {
202 fprintf (stderr, "%s\n", std::string (count, '-').c_str ());
203 }
204
205 /* Dump header with NAME. */
206 static inline void
207 dump_header (const char *name)
208 {
209 fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak",
210 "Times", "Type");
211 print_dash_line ();
212 }
213
214 /* Current number of allocated bytes. */
215 size_t m_allocated;
216 /* Number of allocations. */
217 size_t m_times;
218 /* Peak allocation in bytes. */
219 size_t m_peak;
220 /* Number of container instances. */
221 size_t m_instances;
222 };
223
224 /* Memory usage pair that connectes memory usage and number
225 of allocated bytes. */
226 template <class T>
227 struct mem_usage_pair
228 {
229 mem_usage_pair (T *usage_, size_t allocated_): usage (usage_),
230 allocated (allocated_) {}
231
232 T *usage;
233 size_t allocated;
234 };
235
236 /* Memory allocation description. */
237 template <class T>
238 class mem_alloc_description
239 {
240 public:
241 struct mem_location_hash : nofree_ptr_hash <mem_location>
242 {
243 static hashval_t
244 hash (value_type l)
245 {
246 inchash::hash hstate;
247
248 hstate.add_ptr ((const void *)l->m_filename);
249 hstate.add_ptr (l->m_function);
250 hstate.add_int (l->m_line);
251
252 return hstate.end ();
253 }
254
255 static bool
256 equal (value_type l1, value_type l2)
257 {
258 return l1->m_filename == l2->m_filename
259 && l1->m_function == l2->m_function
260 && l1->m_line == l2->m_line;
261 }
262 };
263
264 /* Internal class type definitions. */
265 typedef hash_map <mem_location_hash, T *> mem_map_t;
266 typedef hash_map <const void *, mem_usage_pair<T> > reverse_mem_map_t;
267 typedef hash_map <const void *, std::pair<T *, size_t> > reverse_object_map_t;
268 typedef std::pair <mem_location *, T *> mem_list_t;
269
270 /* Default contructor. */
271 mem_alloc_description ();
272
273 /* Default destructor. */
274 ~mem_alloc_description ();
275
276 /* Returns true if instance PTR is registered by the memory description. */
277 bool
278 contains_descriptor_for_instance (const void *ptr);
279
280 /* Return descriptor for instance PTR. */
281 T *
282 get_descriptor_for_instance (const void *ptr);
283
284 /* Register memory allocation descriptor for container PTR which is
285 described by a memory LOCATION. */
286 T *
287 register_descriptor (const void *ptr, mem_location *location);
288
289 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
290 type of container and GGC identifes if the allocation is handled in GGC
291 memory. Each location is identified by file NAME, LINE in source code and
292 FUNCTION name. */
293 T *
294 register_descriptor (const void *ptr, mem_alloc_origin origin,
295 bool ggc, const char *name, int line,
296 const char *function);
297
298 /* Register instance overhead identified by PTR pointer. Allocation takes
299 SIZE bytes. */
300 T *
301 register_instance_overhead (size_t size, const void *ptr);
302
303 /* For containers (and GGC) where we want to track every instance object,
304 we register allocation of SIZE bytes, identified by PTR pointer, belonging
305 to USAGE descriptor. */
306 void
307 register_object_overhead (T *usage, size_t size, const void *ptr);
308
309 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
310 remove the instance from reverse map. */
311 void
312 release_instance_overhead (void *ptr, size_t size,
313 bool remove_from_map = false);
314
315 /* Release intance object identified by PTR pointer. */
316 void
317 release_object_overhead (void *ptr);
318
319 /* Get sum value for ORIGIN type of allocation for the descriptor. */
320 T
321 get_sum (mem_alloc_origin origin);
322
323 /* Get all tracked instances registered by the description. Items
324 are filtered by ORIGIN type, LENGTH is return value where we register
325 the number of elements in the list. If we want to process custom order,
326 CMP comparator can be provided. */
327 mem_list_t *
328 get_list (mem_alloc_origin origin, unsigned *length,
329 int (*cmp) (const void *first, const void *second) = NULL);
330
331 /* Dump all tracked instances of type ORIGIN. If we want to process custom
332 order, CMP comparator can be provided. */
333 void dump (mem_alloc_origin origin,
334 int (*cmp) (const void *first, const void *second) = NULL);
335
336 /* Reverse object map used for every object allocation mapping. */
337 reverse_object_map_t *m_reverse_object_map;
338
339 private:
340 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
341 in NAME source file, at LINE in source code, in FUNCTION. */
342 T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
343 int line, const char *function, const void *ptr);
344
345 /* Allocation location coupled to the description. */
346 mem_location m_location;
347
348 /* Location to usage mapping. */
349 mem_map_t *m_map;
350
351 /* Reverse pointer to usage mapping. */
352 reverse_mem_map_t *m_reverse_map;
353 };
354
355
356 /* Returns true if instance PTR is registered by the memory description. */
357
358 template <class T>
359 inline bool
360 mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
361 {
362 return m_reverse_map->get (ptr);
363 }
364
365 /* Return descriptor for instance PTR. */
366
367 template <class T>
368 inline T*
369 mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
370 {
371 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
372 }
373
374
375 /* Register memory allocation descriptor for container PTR which is
376 described by a memory LOCATION. */
377 template <class T>
378 inline T*
379 mem_alloc_description<T>::register_descriptor (const void *ptr,
380 mem_location *location)
381 {
382 T *usage = NULL;
383
384 T **slot = m_map->get (location);
385 if (slot)
386 {
387 delete location;
388 usage = *slot;
389 usage->m_instances++;
390 }
391 else
392 {
393 usage = new T ();
394 m_map->put (location, usage);
395 }
396
397 if (!m_reverse_map->get (ptr))
398 m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
399
400 return usage;
401 }
402
403 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
404 type of container and GGC identifes if the allocation is handled in GGC
405 memory. Each location is identified by file NAME, LINE in source code and
406 FUNCTION name. */
407
408 template <class T>
409 inline T*
410 mem_alloc_description<T>::register_descriptor (const void *ptr,
411 mem_alloc_origin origin,
412 bool ggc,
413 const char *filename,
414 int line,
415 const char *function)
416 {
417 mem_location *l = new mem_location (origin, ggc, filename, line, function);
418 return register_descriptor (ptr, l);
419 }
420
421 /* Register instance overhead identified by PTR pointer. Allocation takes
422 SIZE bytes. */
423
424 template <class T>
425 inline T*
426 mem_alloc_description<T>::register_instance_overhead (size_t size,
427 const void *ptr)
428 {
429 mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
430 if (!slot)
431 {
432 /* Due to PCH, it can really happen. */
433 return NULL;
434 }
435
436 T *usage = (*slot).usage;
437 usage->register_overhead (size);
438
439 return usage;
440 }
441
442 /* For containers (and GGC) where we want to track every instance object,
443 we register allocation of SIZE bytes, identified by PTR pointer, belonging
444 to USAGE descriptor. */
445
446 template <class T>
447 void
448 mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
449 const void *ptr)
450 {
451 /* In case of GGC, it is possible to have already occupied the memory
452 location. */
453 m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
454 }
455
456 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
457 in NAME source file, at LINE in source code, in FUNCTION. */
458
459 template <class T>
460 inline T*
461 mem_alloc_description<T>::register_overhead (size_t size,
462 mem_alloc_origin origin,
463 const char *filename,
464 int line,
465 const char *function,
466 const void *ptr)
467 {
468 T *usage = register_descriptor (ptr, origin, filename, line, function);
469 usage->register_overhead (size);
470
471 return usage;
472 }
473
474 /* Release PTR pointer of SIZE bytes. */
475
476 template <class T>
477 inline void
478 mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size,
479 bool remove_from_map)
480 {
481 mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
482
483 if (!slot)
484 {
485 /* Due to PCH, it can really happen. */
486 return;
487 }
488
489 mem_usage_pair<T> usage_pair = *slot;
490 usage_pair.usage->release_overhead (size);
491
492 if (remove_from_map)
493 m_reverse_map->remove (ptr);
494 }
495
496 /* Release intance object identified by PTR pointer. */
497
498 template <class T>
499 inline void
500 mem_alloc_description<T>::release_object_overhead (void *ptr)
501 {
502 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
503 if (entry)
504 {
505 entry->first->release_overhead (entry->second);
506 m_reverse_object_map->remove (ptr);
507 }
508 }
509
510 /* Default contructor. */
511
512 template <class T>
513 inline
514 mem_alloc_description<T>::mem_alloc_description ()
515 {
516 m_map = new mem_map_t (13, false, false);
517 m_reverse_map = new reverse_mem_map_t (13, false, false);
518 m_reverse_object_map = new reverse_object_map_t (13, false, false);
519 }
520
521 /* Default destructor. */
522
523 template <class T>
524 inline
525 mem_alloc_description<T>::~mem_alloc_description ()
526 {
527 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
528 ++it)
529 {
530 delete (*it).first;
531 delete (*it).second;
532 }
533
534 delete m_map;
535 delete m_reverse_map;
536 delete m_reverse_object_map;
537 }
538
539 /* Get all tracked instances registered by the description. Items are filtered
540 by ORIGIN type, LENGTH is return value where we register the number of
541 elements in the list. If we want to process custom order, CMP comparator
542 can be provided. */
543
544 template <class T>
545 inline
546 typename mem_alloc_description<T>::mem_list_t *
547 mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length,
548 int (*cmp) (const void *first, const void *second))
549 {
550 /* vec data structure is not used because all vectors generate memory
551 allocation info a it would create a cycle. */
552 size_t element_size = sizeof (mem_list_t);
553 mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ());
554 unsigned i = 0;
555
556 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
557 ++it)
558 if ((*it).first->m_origin == origin)
559 list[i++] = std::pair<mem_location*, T*> (*it);
560
561 qsort (list, i, element_size, cmp == NULL ? T::compare : cmp);
562 *length = i;
563
564 return list;
565 }
566
567 /* Get sum value for ORIGIN type of allocation for the descriptor. */
568
569 template <class T>
570 inline T
571 mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
572 {
573 unsigned length;
574 mem_list_t *list = get_list (origin, &length);
575 T sum;
576
577 for (unsigned i = 0; i < length; i++)
578 sum = sum + *list[i].second;
579
580 XDELETEVEC (list);
581
582 return sum;
583 }
584
585 /* Dump all tracked instances of type ORIGIN. If we want to process custom
586 order, CMP comparator can be provided. */
587
588 template <class T>
589 inline void
590 mem_alloc_description<T>::dump (mem_alloc_origin origin,
591 int (*cmp) (const void *first,
592 const void *second))
593 {
594 unsigned length;
595
596 fprintf (stderr, "\n");
597
598 mem_list_t *list = get_list (origin, &length, cmp);
599 T total = get_sum (origin);
600
601 T::dump_header (mem_location::get_origin_name (origin));
602 for (int i = length - 1; i >= 0; i--)
603 list[i].second->dump (list[i].first, total);
604
605 total.dump_footer ();
606
607 XDELETEVEC (list);
608
609 fprintf (stderr, "\n");
610 }
611
612 #endif // GCC_MEM_STATS_H