PR libstdc++/69450
[official-gcc.git] / gcc / mem-stats.h
blobcdf2885ec2a64803170e5ce47da59908beeaf433
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 while (count--)
204 fputc ('-', stderr);
205 fputc ('\n', stderr);
208 /* Dump header with NAME. */
209 static inline void
210 dump_header (const char *name)
212 fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak",
213 "Times", "Type");
214 print_dash_line ();
217 /* Current number of allocated bytes. */
218 size_t m_allocated;
219 /* Number of allocations. */
220 size_t m_times;
221 /* Peak allocation in bytes. */
222 size_t m_peak;
223 /* Number of container instances. */
224 size_t m_instances;
227 /* Memory usage pair that connectes memory usage and number
228 of allocated bytes. */
229 template <class T>
230 struct mem_usage_pair
232 mem_usage_pair (T *usage_, size_t allocated_): usage (usage_),
233 allocated (allocated_) {}
235 T *usage;
236 size_t allocated;
239 /* Memory allocation description. */
240 template <class T>
241 class mem_alloc_description
243 public:
244 struct mem_location_hash : nofree_ptr_hash <mem_location>
246 static hashval_t
247 hash (value_type l)
249 inchash::hash hstate;
251 hstate.add_ptr ((const void *)l->m_filename);
252 hstate.add_ptr (l->m_function);
253 hstate.add_int (l->m_line);
255 return hstate.end ();
258 static bool
259 equal (value_type l1, value_type l2)
261 return l1->m_filename == l2->m_filename
262 && l1->m_function == l2->m_function
263 && l1->m_line == l2->m_line;
267 /* Internal class type definitions. */
268 typedef hash_map <mem_location_hash, T *> mem_map_t;
269 typedef hash_map <const void *, mem_usage_pair<T> > reverse_mem_map_t;
270 typedef hash_map <const void *, std::pair<T *, size_t> > reverse_object_map_t;
271 typedef std::pair <mem_location *, T *> mem_list_t;
273 /* Default contructor. */
274 mem_alloc_description ();
276 /* Default destructor. */
277 ~mem_alloc_description ();
279 /* Returns true if instance PTR is registered by the memory description. */
280 bool
281 contains_descriptor_for_instance (const void *ptr);
283 /* Return descriptor for instance PTR. */
285 get_descriptor_for_instance (const void *ptr);
287 /* Register memory allocation descriptor for container PTR which is
288 described by a memory LOCATION. */
290 register_descriptor (const void *ptr, mem_location *location);
292 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
293 type of container and GGC identifes if the allocation is handled in GGC
294 memory. Each location is identified by file NAME, LINE in source code and
295 FUNCTION name. */
297 register_descriptor (const void *ptr, mem_alloc_origin origin,
298 bool ggc, const char *name, int line,
299 const char *function);
301 /* Register instance overhead identified by PTR pointer. Allocation takes
302 SIZE bytes. */
304 register_instance_overhead (size_t size, const void *ptr);
306 /* For containers (and GGC) where we want to track every instance object,
307 we register allocation of SIZE bytes, identified by PTR pointer, belonging
308 to USAGE descriptor. */
309 void
310 register_object_overhead (T *usage, size_t size, const void *ptr);
312 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
313 remove the instance from reverse map. */
314 void
315 release_instance_overhead (void *ptr, size_t size,
316 bool remove_from_map = false);
318 /* Release intance object identified by PTR pointer. */
319 void
320 release_object_overhead (void *ptr);
322 /* Get sum value for ORIGIN type of allocation for the descriptor. */
324 get_sum (mem_alloc_origin origin);
326 /* Get all tracked instances registered by the description. Items
327 are filtered by ORIGIN type, LENGTH is return value where we register
328 the number of elements in the list. If we want to process custom order,
329 CMP comparator can be provided. */
330 mem_list_t *
331 get_list (mem_alloc_origin origin, unsigned *length,
332 int (*cmp) (const void *first, const void *second) = NULL);
334 /* Dump all tracked instances of type ORIGIN. If we want to process custom
335 order, CMP comparator can be provided. */
336 void dump (mem_alloc_origin origin,
337 int (*cmp) (const void *first, const void *second) = NULL);
339 /* Reverse object map used for every object allocation mapping. */
340 reverse_object_map_t *m_reverse_object_map;
342 private:
343 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
344 in NAME source file, at LINE in source code, in FUNCTION. */
345 T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
346 int line, const char *function, const void *ptr);
348 /* Allocation location coupled to the description. */
349 mem_location m_location;
351 /* Location to usage mapping. */
352 mem_map_t *m_map;
354 /* Reverse pointer to usage mapping. */
355 reverse_mem_map_t *m_reverse_map;
359 /* Returns true if instance PTR is registered by the memory description. */
361 template <class T>
362 inline bool
363 mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
365 return m_reverse_map->get (ptr);
368 /* Return descriptor for instance PTR. */
370 template <class T>
371 inline T*
372 mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
374 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
378 /* Register memory allocation descriptor for container PTR which is
379 described by a memory LOCATION. */
380 template <class T>
381 inline T*
382 mem_alloc_description<T>::register_descriptor (const void *ptr,
383 mem_location *location)
385 T *usage = NULL;
387 T **slot = m_map->get (location);
388 if (slot)
390 delete location;
391 usage = *slot;
392 usage->m_instances++;
394 else
396 usage = new T ();
397 m_map->put (location, usage);
400 if (!m_reverse_map->get (ptr))
401 m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
403 return usage;
406 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
407 type of container and GGC identifes if the allocation is handled in GGC
408 memory. Each location is identified by file NAME, LINE in source code and
409 FUNCTION name. */
411 template <class T>
412 inline T*
413 mem_alloc_description<T>::register_descriptor (const void *ptr,
414 mem_alloc_origin origin,
415 bool ggc,
416 const char *filename,
417 int line,
418 const char *function)
420 mem_location *l = new mem_location (origin, ggc, filename, line, function);
421 return register_descriptor (ptr, l);
424 /* Register instance overhead identified by PTR pointer. Allocation takes
425 SIZE bytes. */
427 template <class T>
428 inline T*
429 mem_alloc_description<T>::register_instance_overhead (size_t size,
430 const void *ptr)
432 mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
433 if (!slot)
435 /* Due to PCH, it can really happen. */
436 return NULL;
439 T *usage = (*slot).usage;
440 usage->register_overhead (size);
442 return usage;
445 /* For containers (and GGC) where we want to track every instance object,
446 we register allocation of SIZE bytes, identified by PTR pointer, belonging
447 to USAGE descriptor. */
449 template <class T>
450 void
451 mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
452 const void *ptr)
454 /* In case of GGC, it is possible to have already occupied the memory
455 location. */
456 m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
459 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
460 in NAME source file, at LINE in source code, in FUNCTION. */
462 template <class T>
463 inline T*
464 mem_alloc_description<T>::register_overhead (size_t size,
465 mem_alloc_origin origin,
466 const char *filename,
467 int line,
468 const char *function,
469 const void *ptr)
471 T *usage = register_descriptor (ptr, origin, filename, line, function);
472 usage->register_overhead (size);
474 return usage;
477 /* Release PTR pointer of SIZE bytes. */
479 template <class T>
480 inline void
481 mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size,
482 bool remove_from_map)
484 mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
486 if (!slot)
488 /* Due to PCH, it can really happen. */
489 return;
492 mem_usage_pair<T> usage_pair = *slot;
493 usage_pair.usage->release_overhead (size);
495 if (remove_from_map)
496 m_reverse_map->remove (ptr);
499 /* Release intance object identified by PTR pointer. */
501 template <class T>
502 inline void
503 mem_alloc_description<T>::release_object_overhead (void *ptr)
505 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
506 if (entry)
508 entry->first->release_overhead (entry->second);
509 m_reverse_object_map->remove (ptr);
513 /* Default contructor. */
515 template <class T>
516 inline
517 mem_alloc_description<T>::mem_alloc_description ()
519 m_map = new mem_map_t (13, false, false);
520 m_reverse_map = new reverse_mem_map_t (13, false, false);
521 m_reverse_object_map = new reverse_object_map_t (13, false, false);
524 /* Default destructor. */
526 template <class T>
527 inline
528 mem_alloc_description<T>::~mem_alloc_description ()
530 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
531 ++it)
533 delete (*it).first;
534 delete (*it).second;
537 delete m_map;
538 delete m_reverse_map;
539 delete m_reverse_object_map;
542 /* Get all tracked instances registered by the description. Items are filtered
543 by ORIGIN type, LENGTH is return value where we register the number of
544 elements in the list. If we want to process custom order, CMP comparator
545 can be provided. */
547 template <class T>
548 inline
549 typename mem_alloc_description<T>::mem_list_t *
550 mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length,
551 int (*cmp) (const void *first, const void *second))
553 /* vec data structure is not used because all vectors generate memory
554 allocation info a it would create a cycle. */
555 size_t element_size = sizeof (mem_list_t);
556 mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ());
557 unsigned i = 0;
559 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
560 ++it)
561 if ((*it).first->m_origin == origin)
562 list[i++] = std::pair<mem_location*, T*> (*it);
564 qsort (list, i, element_size, cmp == NULL ? T::compare : cmp);
565 *length = i;
567 return list;
570 /* Get sum value for ORIGIN type of allocation for the descriptor. */
572 template <class T>
573 inline T
574 mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
576 unsigned length;
577 mem_list_t *list = get_list (origin, &length);
578 T sum;
580 for (unsigned i = 0; i < length; i++)
581 sum = sum + *list[i].second;
583 XDELETEVEC (list);
585 return sum;
588 /* Dump all tracked instances of type ORIGIN. If we want to process custom
589 order, CMP comparator can be provided. */
591 template <class T>
592 inline void
593 mem_alloc_description<T>::dump (mem_alloc_origin origin,
594 int (*cmp) (const void *first,
595 const void *second))
597 unsigned length;
599 fprintf (stderr, "\n");
601 mem_list_t *list = get_list (origin, &length, cmp);
602 T total = get_sum (origin);
604 T::dump_header (mem_location::get_origin_name (origin));
605 for (int i = length - 1; i >= 0; i--)
606 list[i].second->dump (list[i].first, total);
608 total.dump_footer ();
610 XDELETEVEC (list);
612 fprintf (stderr, "\n");
615 #endif // GCC_MEM_STATS_H