2015-06-11 Paul Thomas <pault@gcc.gnu.org>
[official-gcc.git] / gcc / mem-stats.h
blob6d3d79c7f10fff3b9a78cea006fbdc9324494245
1 #ifndef GCC_MEM_STATS_H
2 #define GCC_MEM_STATS_H
4 /* Forward declaration. */
5 template<typename Key, typename Value,
6 typename Traits = default_hashmap_traits>
7 class hash_map;
9 #define LOCATION_LINE_EXTRA_SPACE 30
10 #define LOCATION_LINE_WIDTH 48
12 /* Memory allocation location. */
13 struct mem_location
15 /* Default constructor. */
16 inline
17 mem_location () {}
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) {}
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) {}
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 ()
40 inchash::hash hash;
42 hash.add_ptr (m_filename);
43 hash.add_ptr (m_function);
44 hash.add_int (m_line);
46 return hash.end ();
49 /* Return true if the memory location is equal to OTHER. */
50 int
51 equal (mem_location &other)
53 return m_filename == other.m_filename && m_function == other.m_function
54 && m_line == other.m_line;
57 /* Return trimmed filename for the location. */
58 inline const char *
59 get_trimmed_filename ()
61 const char *s1 = m_filename;
62 const char *s2;
64 while ((s2 = strstr (s1, "gcc/")))
65 s1 = s2 + 4;
67 return s1;
70 inline char *
71 to_string ()
73 unsigned l = strlen (get_trimmed_filename ()) + strlen (m_function)
74 + LOCATION_LINE_EXTRA_SPACE;
76 char *s = XNEWVEC (char, l);
77 sprintf (s, "%s:%i (%s)", get_trimmed_filename (),
78 m_line, m_function);
80 s[MIN (LOCATION_LINE_WIDTH, l - 1)] = '\0';
82 return s;
85 /* Return display name associated to ORIGIN type. */
86 static const char *
87 get_origin_name (mem_alloc_origin origin)
89 return mem_alloc_origin_names[(unsigned) origin];
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;
104 /* Memory usage register to a memory location. */
105 struct mem_usage
107 /* Default constructor. */
108 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
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) {}
115 /* Register overhead of SIZE bytes. */
116 inline void
117 register_overhead (size_t size)
119 m_allocated += size;
120 m_times++;
122 if (m_peak < m_allocated)
123 m_peak = m_allocated;
126 /* Release overhead of SIZE bytes. */
127 inline void
128 release_overhead (size_t size)
130 gcc_assert (size <= m_allocated);
132 m_allocated -= size;
135 /* Sum the usage with SECOND usage. */
136 mem_usage
137 operator+ (const mem_usage &second)
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);
145 /* Comparison operator. */
146 inline bool
147 operator< (const mem_usage &second) const
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);
154 /* Compare wrapper used by qsort method. */
155 static int
156 compare (const void *first, const void *second)
158 typedef std::pair<mem_location *, mem_usage *> mem_pair_t;
160 const mem_pair_t f = *(const mem_pair_t *)first;
161 const mem_pair_t s = *(const mem_pair_t *)second;
163 return (*f.second) < (*s.second);
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
170 char *location_string = loc->to_string ();
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");
178 free (location_string);
181 /* Dump footer. */
182 inline void
183 dump_footer () const
185 print_dash_line ();
186 fprintf (stderr, "%s%54li%27li\n", "Total", (long)m_allocated,
187 (long)m_times);
188 print_dash_line ();
191 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */
192 static inline float
193 get_percent (size_t nominator, size_t denominator)
195 return denominator == 0 ? 0.0f : nominator * 100.0 / denominator;
198 /* Print line made of dashes. */
199 static inline void
200 print_dash_line (size_t count = 140)
202 fprintf (stderr, "%s\n", std::string (count, '-').c_str ());
205 /* Dump header with NAME. */
206 static inline void
207 dump_header (const char *name)
209 fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak",
210 "Times", "Type");
211 print_dash_line ();
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;
224 /* Memory usage pair that connectes memory usage and number
225 of allocated bytes. */
226 template <class T>
227 struct mem_usage_pair
229 mem_usage_pair (T *usage_, size_t allocated_): usage (usage_),
230 allocated (allocated_) {}
232 T *usage;
233 size_t allocated;
236 /* Memory allocation description. */
237 template <class T>
238 class mem_alloc_description
240 public:
241 struct mem_alloc_hashmap_traits: default_hashmap_traits
243 static hashval_t
244 hash (const mem_location *l)
246 inchash::hash hstate;
248 hstate.add_ptr ((const void *)l->m_filename);
249 hstate.add_ptr (l->m_function);
250 hstate.add_int (l->m_line);
252 return hstate.end ();
255 static bool
256 equal_keys (const mem_location *l1, const mem_location *l2)
258 return l1->m_filename == l2->m_filename
259 && l1->m_function == l2->m_function
260 && l1->m_line == l2->m_line;
264 /* Internal class type definitions. */
265 typedef hash_map <mem_location *, T *, mem_alloc_hashmap_traits> mem_map_t;
266 typedef hash_map <const void *, mem_usage_pair<T>, default_hashmap_traits>
267 reverse_mem_map_t;
268 typedef hash_map <const void *, std::pair<T *, size_t> > reverse_object_map_t;
269 typedef std::pair <mem_location *, T *> mem_list_t;
271 /* Default contructor. */
272 mem_alloc_description ();
274 /* Default destructor. */
275 ~mem_alloc_description ();
277 /* Returns true if instance PTR is registered by the memory description. */
278 bool
279 contains_descriptor_for_instance (const void *ptr);
281 /* Return descriptor for instance PTR. */
283 get_descriptor_for_instance (const void *ptr);
285 /* Register memory allocation descriptor for container PTR which is
286 described by a memory LOCATION. */
288 register_descriptor (const void *ptr, mem_location *location);
290 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
291 type of container and GGC identifes if the allocation is handled in GGC
292 memory. Each location is identified by file NAME, LINE in source code and
293 FUNCTION name. */
295 register_descriptor (const void *ptr, mem_alloc_origin origin,
296 bool ggc, const char *name, int line,
297 const char *function);
299 /* Register instance overhead identified by PTR pointer. Allocation takes
300 SIZE bytes. */
302 register_instance_overhead (size_t size, const void *ptr);
304 /* For containers (and GGC) where we want to track every instance object,
305 we register allocation of SIZE bytes, identified by PTR pointer, belonging
306 to USAGE descriptor. */
307 void
308 register_object_overhead (T *usage, size_t size, const void *ptr);
310 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
311 remove the instance from reverse map. */
312 void
313 release_instance_overhead (void *ptr, size_t size,
314 bool remove_from_map = false);
316 /* Release intance object identified by PTR pointer. */
317 void
318 release_object_overhead (void *ptr);
320 /* Get sum value for ORIGIN type of allocation for the descriptor. */
322 get_sum (mem_alloc_origin origin);
324 /* Get all tracked instances registered by the description. Items
325 are filtered by ORIGIN type, LENGTH is return value where we register
326 the number of elements in the list. If we want to process custom order,
327 CMP comparator can be provided. */
328 mem_list_t *
329 get_list (mem_alloc_origin origin, unsigned *length,
330 int (*cmp) (const void *first, const void *second) = NULL);
332 /* Dump all tracked instances of type ORIGIN. If we want to process custom
333 order, CMP comparator can be provided. */
334 void dump (mem_alloc_origin origin,
335 int (*cmp) (const void *first, const void *second) = NULL);
337 /* Reverse object map used for every object allocation mapping. */
338 reverse_object_map_t *m_reverse_object_map;
340 private:
341 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
342 in NAME source file, at LINE in source code, in FUNCTION. */
343 T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
344 int line, const char *function, const void *ptr);
346 /* Allocation location coupled to the description. */
347 mem_location m_location;
349 /* Location to usage mapping. */
350 mem_map_t *m_map;
352 /* Reverse pointer to usage mapping. */
353 reverse_mem_map_t *m_reverse_map;
357 /* Returns true if instance PTR is registered by the memory description. */
359 template <class T>
360 inline bool
361 mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
363 return m_reverse_map->get (ptr);
366 /* Return descriptor for instance PTR. */
368 template <class T>
369 inline T*
370 mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
372 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
376 /* Register memory allocation descriptor for container PTR which is
377 described by a memory LOCATION. */
378 template <class T>
379 inline T*
380 mem_alloc_description<T>::register_descriptor (const void *ptr,
381 mem_location *location)
383 T *usage = NULL;
385 T **slot = m_map->get (location);
386 if (slot)
388 delete location;
389 usage = *slot;
390 usage->m_instances++;
392 else
394 usage = new T ();
395 m_map->put (location, usage);
398 if (!m_reverse_map->get (ptr))
399 m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
401 return usage;
404 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
405 type of container and GGC identifes if the allocation is handled in GGC
406 memory. Each location is identified by file NAME, LINE in source code and
407 FUNCTION name. */
409 template <class T>
410 inline T*
411 mem_alloc_description<T>::register_descriptor (const void *ptr,
412 mem_alloc_origin origin,
413 bool ggc,
414 const char *filename,
415 int line,
416 const char *function)
418 mem_location *l = new mem_location (origin, ggc, filename, line, function);
419 return register_descriptor (ptr, l);
422 /* Register instance overhead identified by PTR pointer. Allocation takes
423 SIZE bytes. */
425 template <class T>
426 inline T*
427 mem_alloc_description<T>::register_instance_overhead (size_t size,
428 const void *ptr)
430 mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
431 if (!slot)
433 /* Due to PCH, it can really happen. */
434 return NULL;
437 T *usage = (*slot).usage;
438 usage->register_overhead (size);
440 return usage;
443 /* For containers (and GGC) where we want to track every instance object,
444 we register allocation of SIZE bytes, identified by PTR pointer, belonging
445 to USAGE descriptor. */
447 template <class T>
448 void
449 mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
450 const void *ptr)
452 /* In case of GGC, it is possible to have already occupied the memory
453 location. */
454 m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
457 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
458 in NAME source file, at LINE in source code, in FUNCTION. */
460 template <class T>
461 inline T*
462 mem_alloc_description<T>::register_overhead (size_t size,
463 mem_alloc_origin origin,
464 const char *filename,
465 int line,
466 const char *function,
467 const void *ptr)
469 T *usage = register_descriptor (ptr, origin, filename, line, function);
470 usage->register_overhead (size);
472 return usage;
475 /* Release PTR pointer of SIZE bytes. */
477 template <class T>
478 inline void
479 mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size,
480 bool remove_from_map)
482 mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
484 if (!slot)
486 /* Due to PCH, it can really happen. */
487 return;
490 mem_usage_pair<T> usage_pair = *slot;
491 usage_pair.usage->release_overhead (size);
493 if (remove_from_map)
494 m_reverse_map->remove (ptr);
497 /* Release intance object identified by PTR pointer. */
499 template <class T>
500 inline void
501 mem_alloc_description<T>::release_object_overhead (void *ptr)
503 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
504 if (entry)
506 entry->first->release_overhead (entry->second);
507 m_reverse_object_map->remove (ptr);
511 /* Default contructor. */
513 template <class T>
514 inline
515 mem_alloc_description<T>::mem_alloc_description ()
517 m_map = new mem_map_t (13, false, false);
518 m_reverse_map = new reverse_mem_map_t (13, false, false);
519 m_reverse_object_map = new reverse_object_map_t (13, false, false);
522 /* Default destructor. */
524 template <class T>
525 inline
526 mem_alloc_description<T>::~mem_alloc_description ()
528 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
529 ++it)
531 delete (*it).first;
532 delete (*it).second;
535 delete m_map;
536 delete m_reverse_map;
537 delete m_reverse_object_map;
540 /* Get all tracked instances registered by the description. Items are filtered
541 by ORIGIN type, LENGTH is return value where we register the number of
542 elements in the list. If we want to process custom order, CMP comparator
543 can be provided. */
545 template <class T>
546 inline
547 typename mem_alloc_description<T>::mem_list_t *
548 mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length,
549 int (*cmp) (const void *first, const void *second))
551 /* vec data structure is not used because all vectors generate memory
552 allocation info a it would create a cycle. */
553 size_t element_size = sizeof (mem_list_t);
554 mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ());
555 unsigned i = 0;
557 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
558 ++it)
559 if ((*it).first->m_origin == origin)
560 list[i++] = std::pair<mem_location*, T*> (*it);
562 qsort (list, i, element_size, cmp == NULL ? T::compare : cmp);
563 *length = i;
565 return list;
568 /* Get sum value for ORIGIN type of allocation for the descriptor. */
570 template <class T>
571 inline T
572 mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
574 unsigned length;
575 mem_list_t *list = get_list (origin, &length);
576 T sum;
578 for (unsigned i = 0; i < length; i++)
579 sum = sum + *list[i].second;
581 XDELETEVEC (list);
583 return sum;
586 /* Dump all tracked instances of type ORIGIN. If we want to process custom
587 order, CMP comparator can be provided. */
589 template <class T>
590 inline void
591 mem_alloc_description<T>::dump (mem_alloc_origin origin,
592 int (*cmp) (const void *first,
593 const void *second))
595 unsigned length;
597 fprintf (stderr, "\n");
599 mem_list_t *list = get_list (origin, &length, cmp);
600 T total = get_sum (origin);
602 T::dump_header (mem_location::get_origin_name (origin));
603 for (int i = length - 1; i >= 0; i--)
604 list[i].second->dump (list[i].first, total);
606 total.dump_footer ();
608 XDELETEVEC (list);
610 fprintf (stderr, "\n");
613 #endif // GCC_MEM_STATS_H