2015-08-24 François Dumont <fdumont@gcc.gnu.org>
[official-gcc.git] / gcc / mem-stats.h
bloba6489b500686767b410fb32bfbde84e7e213c545
1 #ifndef GCC_MEM_STATS_H
2 #define GCC_MEM_STATS_H
4 /* Forward declaration. */
5 template<typename Key, typename Value,
6 typename Traits = simple_hashmap_traits<default_hash_traits<Key> > >
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_location_hash : nofree_ptr_hash <mem_location>
243 static hashval_t
244 hash (value_type 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 (value_type l1, value_type 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_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;
270 /* Default contructor. */
271 mem_alloc_description ();
273 /* Default destructor. */
274 ~mem_alloc_description ();
276 /* Returns true if instance PTR is registered by the memory description. */
277 bool
278 contains_descriptor_for_instance (const void *ptr);
280 /* Return descriptor for instance PTR. */
282 get_descriptor_for_instance (const void *ptr);
284 /* Register memory allocation descriptor for container PTR which is
285 described by a memory LOCATION. */
287 register_descriptor (const void *ptr, mem_location *location);
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. */
294 register_descriptor (const void *ptr, mem_alloc_origin origin,
295 bool ggc, const char *name, int line,
296 const char *function);
298 /* Register instance overhead identified by PTR pointer. Allocation takes
299 SIZE bytes. */
301 register_instance_overhead (size_t size, const void *ptr);
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);
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);
315 /* Release intance object identified by PTR pointer. */
316 void
317 release_object_overhead (void *ptr);
319 /* Get sum value for ORIGIN type of allocation for the descriptor. */
321 get_sum (mem_alloc_origin origin);
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);
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);
336 /* Reverse object map used for every object allocation mapping. */
337 reverse_object_map_t *m_reverse_object_map;
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);
345 /* Allocation location coupled to the description. */
346 mem_location m_location;
348 /* Location to usage mapping. */
349 mem_map_t *m_map;
351 /* Reverse pointer to usage mapping. */
352 reverse_mem_map_t *m_reverse_map;
356 /* Returns true if instance PTR is registered by the memory description. */
358 template <class T>
359 inline bool
360 mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
362 return m_reverse_map->get (ptr);
365 /* Return descriptor for instance PTR. */
367 template <class T>
368 inline T*
369 mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
371 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
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)
382 T *usage = NULL;
384 T **slot = m_map->get (location);
385 if (slot)
387 delete location;
388 usage = *slot;
389 usage->m_instances++;
391 else
393 usage = new T ();
394 m_map->put (location, usage);
397 if (!m_reverse_map->get (ptr))
398 m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
400 return usage;
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. */
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)
417 mem_location *l = new mem_location (origin, ggc, filename, line, function);
418 return register_descriptor (ptr, l);
421 /* Register instance overhead identified by PTR pointer. Allocation takes
422 SIZE bytes. */
424 template <class T>
425 inline T*
426 mem_alloc_description<T>::register_instance_overhead (size_t size,
427 const void *ptr)
429 mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
430 if (!slot)
432 /* Due to PCH, it can really happen. */
433 return NULL;
436 T *usage = (*slot).usage;
437 usage->register_overhead (size);
439 return usage;
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. */
446 template <class T>
447 void
448 mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
449 const void *ptr)
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));
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. */
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)
468 T *usage = register_descriptor (ptr, origin, filename, line, function);
469 usage->register_overhead (size);
471 return usage;
474 /* Release PTR pointer of SIZE bytes. */
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)
481 mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
483 if (!slot)
485 /* Due to PCH, it can really happen. */
486 return;
489 mem_usage_pair<T> usage_pair = *slot;
490 usage_pair.usage->release_overhead (size);
492 if (remove_from_map)
493 m_reverse_map->remove (ptr);
496 /* Release intance object identified by PTR pointer. */
498 template <class T>
499 inline void
500 mem_alloc_description<T>::release_object_overhead (void *ptr)
502 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
503 if (entry)
505 entry->first->release_overhead (entry->second);
506 m_reverse_object_map->remove (ptr);
510 /* Default contructor. */
512 template <class T>
513 inline
514 mem_alloc_description<T>::mem_alloc_description ()
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);
521 /* Default destructor. */
523 template <class T>
524 inline
525 mem_alloc_description<T>::~mem_alloc_description ()
527 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
528 ++it)
530 delete (*it).first;
531 delete (*it).second;
534 delete m_map;
535 delete m_reverse_map;
536 delete m_reverse_object_map;
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. */
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))
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;
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);
561 qsort (list, i, element_size, cmp == NULL ? T::compare : cmp);
562 *length = i;
564 return list;
567 /* Get sum value for ORIGIN type of allocation for the descriptor. */
569 template <class T>
570 inline T
571 mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
573 unsigned length;
574 mem_list_t *list = get_list (origin, &length);
575 T sum;
577 for (unsigned i = 0; i < length; i++)
578 sum = sum + *list[i].second;
580 XDELETEVEC (list);
582 return sum;
585 /* Dump all tracked instances of type ORIGIN. If we want to process custom
586 order, CMP comparator can be provided. */
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))
594 unsigned length;
596 fprintf (stderr, "\n");
598 mem_list_t *list = get_list (origin, &length, cmp);
599 T total = get_sum (origin);
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);
605 total.dump_footer ();
607 XDELETEVEC (list);
609 fprintf (stderr, "\n");
612 #endif // GCC_MEM_STATS_H