2015-12-18 Ville Voutilainen <ville.voutilainen@gmail.com>
[official-gcc.git] / gcc / mem-stats.h
blob2c68ca752ebd5f712a64346dacd3196b6987676c
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 Value> >
8 class hash_map;
10 #define LOCATION_LINE_EXTRA_SPACE 30
11 #define LOCATION_LINE_WIDTH 48
13 /* Memory allocation location. */
14 struct mem_location
16 /* Default constructor. */
17 inline
18 mem_location () {}
20 /* Constructor. */
21 inline
22 mem_location (mem_alloc_origin origin, bool ggc,
23 const char *filename = NULL, int line = 0,
24 const char *function = NULL):
25 m_filename (filename), m_function (function), m_line (line), m_origin
26 (origin), m_ggc (ggc) {}
28 /* Copy constructor. */
29 inline
30 mem_location (mem_location &other): m_filename (other.m_filename),
31 m_function (other.m_function), m_line (other.m_line),
32 m_origin (other.m_origin), m_ggc (other.m_ggc) {}
34 /* Compute hash value based on file name, function name and line in
35 source code. As there is just a single pointer registered for every
36 constant that points to e.g. the same file name, we can use hash
37 of the pointer. */
38 hashval_t
39 hash ()
41 inchash::hash hash;
43 hash.add_ptr (m_filename);
44 hash.add_ptr (m_function);
45 hash.add_int (m_line);
47 return hash.end ();
50 /* Return true if the memory location is equal to OTHER. */
51 int
52 equal (mem_location &other)
54 return m_filename == other.m_filename && m_function == other.m_function
55 && m_line == other.m_line;
58 /* Return trimmed filename for the location. */
59 inline const char *
60 get_trimmed_filename ()
62 const char *s1 = m_filename;
63 const char *s2;
65 while ((s2 = strstr (s1, "gcc/")))
66 s1 = s2 + 4;
68 return s1;
71 inline char *
72 to_string ()
74 unsigned l = strlen (get_trimmed_filename ()) + strlen (m_function)
75 + LOCATION_LINE_EXTRA_SPACE;
77 char *s = XNEWVEC (char, l);
78 sprintf (s, "%s:%i (%s)", get_trimmed_filename (),
79 m_line, m_function);
81 s[MIN (LOCATION_LINE_WIDTH, l - 1)] = '\0';
83 return s;
86 /* Return display name associated to ORIGIN type. */
87 static const char *
88 get_origin_name (mem_alloc_origin origin)
90 return mem_alloc_origin_names[(unsigned) origin];
93 /* File name of source code. */
94 const char *m_filename;
95 /* Funcation name. */
96 const char *m_function;
97 /* Line number in source code. */
98 int m_line;
99 /* Origin type. */
100 mem_alloc_origin m_origin;
101 /* Flag if used by GGC allocation. */
102 bool m_ggc;
105 /* Memory usage register to a memory location. */
106 struct mem_usage
108 /* Default constructor. */
109 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
111 /* Constructor. */
112 mem_usage (size_t allocated, size_t times, size_t peak, size_t instances = 0):
113 m_allocated (allocated), m_times (times), m_peak (peak),
114 m_instances (instances) {}
116 /* Register overhead of SIZE bytes. */
117 inline void
118 register_overhead (size_t size)
120 m_allocated += size;
121 m_times++;
123 if (m_peak < m_allocated)
124 m_peak = m_allocated;
127 /* Release overhead of SIZE bytes. */
128 inline void
129 release_overhead (size_t size)
131 gcc_assert (size <= m_allocated);
133 m_allocated -= size;
136 /* Sum the usage with SECOND usage. */
137 mem_usage
138 operator+ (const mem_usage &second)
140 return mem_usage (m_allocated + second.m_allocated,
141 m_times + second.m_times,
142 m_peak + second.m_peak,
143 m_instances + second.m_instances);
146 /* Comparison operator. */
147 inline bool
148 operator< (const mem_usage &second) const
150 return (m_allocated == second.m_allocated ?
151 (m_peak == second.m_peak ? m_times < second.m_times
152 : m_peak < second.m_peak) : m_allocated < second.m_allocated);
155 /* Compare wrapper used by qsort method. */
156 static int
157 compare (const void *first, const void *second)
159 typedef std::pair<mem_location *, mem_usage *> mem_pair_t;
161 const mem_pair_t f = *(const mem_pair_t *)first;
162 const mem_pair_t s = *(const mem_pair_t *)second;
164 return (*f.second) < (*s.second);
167 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
168 inline void
169 dump (mem_location *loc, mem_usage &total) const
171 char *location_string = loc->to_string ();
173 fprintf (stderr, "%-48s %10li:%5.1f%%%10li%10li:%5.1f%%%10s\n",
174 location_string,
175 (long)m_allocated, get_percent (m_allocated, total.m_allocated),
176 (long)m_peak, (long)m_times,
177 get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap");
179 free (location_string);
182 /* Dump footer. */
183 inline void
184 dump_footer () const
186 print_dash_line ();
187 fprintf (stderr, "%s%54li%27li\n", "Total", (long)m_allocated,
188 (long)m_times);
189 print_dash_line ();
192 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */
193 static inline float
194 get_percent (size_t nominator, size_t denominator)
196 return denominator == 0 ? 0.0f : nominator * 100.0 / denominator;
199 /* Print line made of dashes. */
200 static inline void
201 print_dash_line (size_t count = 140)
203 fprintf (stderr, "%s\n", std::string (count, '-').c_str ());
206 /* Dump header with NAME. */
207 static inline void
208 dump_header (const char *name)
210 fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak",
211 "Times", "Type");
212 print_dash_line ();
215 /* Current number of allocated bytes. */
216 size_t m_allocated;
217 /* Number of allocations. */
218 size_t m_times;
219 /* Peak allocation in bytes. */
220 size_t m_peak;
221 /* Number of container instances. */
222 size_t m_instances;
225 /* Memory usage pair that connectes memory usage and number
226 of allocated bytes. */
227 template <class T>
228 struct mem_usage_pair
230 mem_usage_pair (T *usage_, size_t allocated_): usage (usage_),
231 allocated (allocated_) {}
233 T *usage;
234 size_t allocated;
237 /* Memory allocation description. */
238 template <class T>
239 class mem_alloc_description
241 public:
242 struct mem_location_hash : nofree_ptr_hash <mem_location>
244 static hashval_t
245 hash (value_type l)
247 inchash::hash hstate;
249 hstate.add_ptr ((const void *)l->m_filename);
250 hstate.add_ptr (l->m_function);
251 hstate.add_int (l->m_line);
253 return hstate.end ();
256 static bool
257 equal (value_type l1, value_type l2)
259 return l1->m_filename == l2->m_filename
260 && l1->m_function == l2->m_function
261 && l1->m_line == l2->m_line;
265 /* Internal class type definitions. */
266 typedef hash_map <mem_location_hash, T *> mem_map_t;
267 typedef hash_map <const void *, mem_usage_pair<T> > 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