target-supports.exp (check_effective_target_weak_undefined): Return 0 on hppa*-*...
[official-gcc.git] / gcc / mem-stats.h
blob7612e7de3d2fd5d4005c5f97a53276a2fe76d281
1 /* A memory statistics tracking infrastructure.
2 Copyright (C) 2015-2019 Free Software Foundation, Inc.
3 Contributed by Martin Liska <mliska@suse.cz>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #ifndef GCC_MEM_STATS_H
22 #define GCC_MEM_STATS_H
24 /* Forward declaration. */
25 template<typename Key, typename Value,
26 typename Traits = simple_hashmap_traits<default_hash_traits<Key>,
27 Value> >
28 class hash_map;
30 #define LOCATION_LINE_EXTRA_SPACE 30
31 #define LOCATION_LINE_WIDTH 48
33 /* Memory allocation location. */
34 struct mem_location
36 /* Default constructor. */
37 inline
38 mem_location () {}
40 /* Constructor. */
41 inline
42 mem_location (mem_alloc_origin origin, bool ggc,
43 const char *filename = NULL, int line = 0,
44 const char *function = NULL):
45 m_filename (filename), m_function (function), m_line (line), m_origin
46 (origin), m_ggc (ggc) {}
48 /* Copy constructor. */
49 inline
50 mem_location (mem_location &other): m_filename (other.m_filename),
51 m_function (other.m_function), m_line (other.m_line),
52 m_origin (other.m_origin), m_ggc (other.m_ggc) {}
54 /* Compute hash value based on file name, function name and line in
55 source code. As there is just a single pointer registered for every
56 constant that points to e.g. the same file name, we can use hash
57 of the pointer. */
58 hashval_t
59 hash ()
61 inchash::hash hash;
63 hash.add_ptr (m_filename);
64 hash.add_ptr (m_function);
65 hash.add_int (m_line);
67 return hash.end ();
70 /* Return true if the memory location is equal to OTHER. */
71 int
72 equal (mem_location &other)
74 return m_filename == other.m_filename && m_function == other.m_function
75 && m_line == other.m_line;
78 /* Return trimmed filename for the location. */
79 inline const char *
80 get_trimmed_filename ()
82 const char *s1 = m_filename;
83 const char *s2;
85 while ((s2 = strstr (s1, "gcc/")))
86 s1 = s2 + 4;
88 return s1;
91 inline char *
92 to_string ()
94 unsigned l = strlen (get_trimmed_filename ()) + strlen (m_function)
95 + LOCATION_LINE_EXTRA_SPACE;
97 char *s = XNEWVEC (char, l);
98 sprintf (s, "%s:%i (%s)", get_trimmed_filename (),
99 m_line, m_function);
101 s[MIN (LOCATION_LINE_WIDTH, l - 1)] = '\0';
103 return s;
106 /* Return display name associated to ORIGIN type. */
107 static const char *
108 get_origin_name (mem_alloc_origin origin)
110 return mem_alloc_origin_names[(unsigned) origin];
113 /* File name of source code. */
114 const char *m_filename;
115 /* Funcation name. */
116 const char *m_function;
117 /* Line number in source code. */
118 int m_line;
119 /* Origin type. */
120 mem_alloc_origin m_origin;
121 /* Flag if used by GGC allocation. */
122 bool m_ggc;
125 /* Memory usage register to a memory location. */
126 struct mem_usage
128 /* Default constructor. */
129 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
131 /* Constructor. */
132 mem_usage (size_t allocated, size_t times, size_t peak, size_t instances = 0):
133 m_allocated (allocated), m_times (times), m_peak (peak),
134 m_instances (instances) {}
136 /* Register overhead of SIZE bytes. */
137 inline void
138 register_overhead (size_t size)
140 m_allocated += size;
141 m_times++;
143 if (m_peak < m_allocated)
144 m_peak = m_allocated;
147 /* Release overhead of SIZE bytes. */
148 inline void
149 release_overhead (size_t size)
151 gcc_assert (size <= m_allocated);
153 m_allocated -= size;
156 /* Sum the usage with SECOND usage. */
157 mem_usage
158 operator+ (const mem_usage &second)
160 return mem_usage (m_allocated + second.m_allocated,
161 m_times + second.m_times,
162 m_peak + second.m_peak,
163 m_instances + second.m_instances);
166 /* Equality operator. */
167 inline bool
168 operator== (const mem_usage &second) const
170 return (m_allocated == second.m_allocated
171 && m_peak == second.m_peak
172 && m_times == second.m_times);
175 /* Comparison operator. */
176 inline bool
177 operator< (const mem_usage &second) const
179 if (*this == second)
180 return false;
182 return (m_allocated == second.m_allocated ?
183 (m_peak == second.m_peak ? m_times < second.m_times
184 : m_peak < second.m_peak) : m_allocated < second.m_allocated);
187 /* Compare wrapper used by qsort method. */
188 static int
189 compare (const void *first, const void *second)
191 typedef std::pair<mem_location *, mem_usage *> mem_pair_t;
193 const mem_pair_t f = *(const mem_pair_t *)first;
194 const mem_pair_t s = *(const mem_pair_t *)second;
196 if (*f.second == *s.second)
197 return 0;
199 return *f.second < *s.second ? 1 : -1;
202 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
203 inline void
204 dump (mem_location *loc, mem_usage &total) const
206 char *location_string = loc->to_string ();
208 fprintf (stderr, "%-48s " PRsa (9) ":%5.1f%%"
209 PRsa (9) PRsa (9) ":%5.1f%%%10s\n",
210 location_string, SIZE_AMOUNT (m_allocated),
211 get_percent (m_allocated, total.m_allocated),
212 SIZE_AMOUNT (m_peak), SIZE_AMOUNT (m_times),
213 get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap");
215 free (location_string);
218 /* Dump footer. */
219 inline void
220 dump_footer () const
222 fprintf (stderr, "%s" PRsa (53) PRsa (26) "\n", "Total",
223 SIZE_AMOUNT (m_allocated), SIZE_AMOUNT (m_times));
226 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */
227 static inline float
228 get_percent (size_t nominator, size_t denominator)
230 return denominator == 0 ? 0.0f : nominator * 100.0 / denominator;
233 /* Print line made of dashes. */
234 static inline void
235 print_dash_line (size_t count = 140)
237 while (count--)
238 fputc ('-', stderr);
239 fputc ('\n', stderr);
242 /* Dump header with NAME. */
243 static inline void
244 dump_header (const char *name)
246 fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak",
247 "Times", "Type");
250 /* Current number of allocated bytes. */
251 size_t m_allocated;
252 /* Number of allocations. */
253 size_t m_times;
254 /* Peak allocation in bytes. */
255 size_t m_peak;
256 /* Number of container instances. */
257 size_t m_instances;
260 /* Memory usage pair that connectes memory usage and number
261 of allocated bytes. */
262 template <class T>
263 struct mem_usage_pair
265 mem_usage_pair (T *usage_, size_t allocated_): usage (usage_),
266 allocated (allocated_) {}
268 T *usage;
269 size_t allocated;
272 /* Memory allocation description. */
273 template <class T>
274 class mem_alloc_description
276 public:
277 struct mem_location_hash : nofree_ptr_hash <mem_location>
279 static hashval_t
280 hash (value_type l)
282 inchash::hash hstate;
284 hstate.add_ptr ((const void *)l->m_filename);
285 hstate.add_ptr (l->m_function);
286 hstate.add_int (l->m_line);
288 return hstate.end ();
291 static bool
292 equal (value_type l1, value_type l2)
294 return (l1->m_filename == l2->m_filename
295 && l1->m_function == l2->m_function
296 && l1->m_line == l2->m_line);
300 /* Internal class type definitions. */
301 typedef hash_map <mem_location_hash, T *> mem_map_t;
302 typedef hash_map <const void *, mem_usage_pair<T> > reverse_mem_map_t;
303 typedef hash_map <const void *, std::pair<T *, size_t> > reverse_object_map_t;
304 typedef std::pair <mem_location *, T *> mem_list_t;
306 /* Default contructor. */
307 mem_alloc_description ();
309 /* Default destructor. */
310 ~mem_alloc_description ();
312 /* Returns true if instance PTR is registered by the memory description. */
313 bool contains_descriptor_for_instance (const void *ptr);
315 /* Return descriptor for instance PTR. */
316 T *get_descriptor_for_instance (const void *ptr);
318 /* Register memory allocation descriptor for container PTR which is
319 described by a memory LOCATION. */
320 T *register_descriptor (const void *ptr, mem_location *location);
322 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
323 type of container and GGC identifes if the allocation is handled in GGC
324 memory. Each location is identified by file NAME, LINE in source code and
325 FUNCTION name. */
326 T *register_descriptor (const void *ptr, mem_alloc_origin origin,
327 bool ggc, const char *name, int line,
328 const char *function);
330 /* Register instance overhead identified by PTR pointer. Allocation takes
331 SIZE bytes. */
332 T *register_instance_overhead (size_t size, const void *ptr);
334 /* For containers (and GGC) where we want to track every instance object,
335 we register allocation of SIZE bytes, identified by PTR pointer, belonging
336 to USAGE descriptor. */
337 void register_object_overhead (T *usage, size_t size, const void *ptr);
339 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
340 remove the instance from reverse map. Return memory usage that belongs
341 to this memory description. */
342 T *release_instance_overhead (void *ptr, size_t size,
343 bool remove_from_map = false);
345 /* Release intance object identified by PTR pointer. */
346 void release_object_overhead (void *ptr);
348 /* Get sum value for ORIGIN type of allocation for the descriptor. */
349 T get_sum (mem_alloc_origin origin);
351 /* Get all tracked instances registered by the description. Items
352 are filtered by ORIGIN type, LENGTH is return value where we register
353 the number of elements in the list. If we want to process custom order,
354 CMP comparator can be provided. */
355 mem_list_t *get_list (mem_alloc_origin origin, unsigned *length,
356 int (*cmp) (const void *first,
357 const void *second) = NULL);
359 /* Dump all tracked instances of type ORIGIN. If we want to process custom
360 order, CMP comparator can be provided. */
361 void dump (mem_alloc_origin origin,
362 int (*cmp) (const void *first, const void *second) = NULL);
364 /* Reverse object map used for every object allocation mapping. */
365 reverse_object_map_t *m_reverse_object_map;
367 private:
368 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
369 in NAME source file, at LINE in source code, in FUNCTION. */
370 T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
371 int line, const char *function, const void *ptr);
373 /* Allocation location coupled to the description. */
374 mem_location m_location;
376 /* Location to usage mapping. */
377 mem_map_t *m_map;
379 /* Reverse pointer to usage mapping. */
380 reverse_mem_map_t *m_reverse_map;
383 /* Returns true if instance PTR is registered by the memory description. */
385 template <class T>
386 inline bool
387 mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
389 return m_reverse_map->get (ptr);
392 /* Return descriptor for instance PTR. */
394 template <class T>
395 inline T*
396 mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
398 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
401 /* Register memory allocation descriptor for container PTR which is
402 described by a memory LOCATION. */
404 template <class T>
405 inline T*
406 mem_alloc_description<T>::register_descriptor (const void *ptr,
407 mem_location *location)
409 T *usage = NULL;
411 T **slot = m_map->get (location);
412 if (slot)
414 delete location;
415 usage = *slot;
416 usage->m_instances++;
418 else
420 usage = new T ();
421 m_map->put (location, usage);
424 if (!m_reverse_map->get (ptr))
425 m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
427 return usage;
430 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
431 type of container and GGC identifes if the allocation is handled in GGC
432 memory. Each location is identified by file NAME, LINE in source code and
433 FUNCTION name. */
435 template <class T>
436 inline T*
437 mem_alloc_description<T>::register_descriptor (const void *ptr,
438 mem_alloc_origin origin,
439 bool ggc,
440 const char *filename,
441 int line,
442 const char *function)
444 mem_location *l = new mem_location (origin, ggc, filename, line, function);
445 return register_descriptor (ptr, l);
448 /* Register instance overhead identified by PTR pointer. Allocation takes
449 SIZE bytes. */
451 template <class T>
452 inline T*
453 mem_alloc_description<T>::register_instance_overhead (size_t size,
454 const void *ptr)
456 mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
457 if (!slot)
459 /* Due to PCH, it can really happen. */
460 return NULL;
463 T *usage = (*slot).usage;
464 usage->register_overhead (size);
466 return usage;
469 /* For containers (and GGC) where we want to track every instance object,
470 we register allocation of SIZE bytes, identified by PTR pointer, belonging
471 to USAGE descriptor. */
473 template <class T>
474 void
475 mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
476 const void *ptr)
478 /* In case of GGC, it is possible to have already occupied the memory
479 location. */
480 m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
483 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
484 in NAME source file, at LINE in source code, in FUNCTION. */
486 template <class T>
487 inline T*
488 mem_alloc_description<T>::register_overhead (size_t size,
489 mem_alloc_origin origin,
490 const char *filename,
491 int line,
492 const char *function,
493 const void *ptr)
495 T *usage = register_descriptor (ptr, origin, filename, line, function);
496 usage->register_overhead (size);
498 return usage;
501 /* Release PTR pointer of SIZE bytes. */
503 template <class T>
504 inline T *
505 mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size,
506 bool remove_from_map)
508 mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
510 if (!slot)
512 /* Due to PCH, it can really happen. */
513 return NULL;
516 T *usage = (*slot).usage;
517 usage->release_overhead (size);
519 if (remove_from_map)
520 m_reverse_map->remove (ptr);
522 return usage;
525 /* Release intance object identified by PTR pointer. */
527 template <class T>
528 inline void
529 mem_alloc_description<T>::release_object_overhead (void *ptr)
531 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
532 if (entry)
534 entry->first->release_overhead (entry->second);
535 m_reverse_object_map->remove (ptr);
539 /* Default contructor. */
541 template <class T>
542 inline
543 mem_alloc_description<T>::mem_alloc_description ()
545 m_map = new mem_map_t (13, false, false);
546 m_reverse_map = new reverse_mem_map_t (13, false, false);
547 m_reverse_object_map = new reverse_object_map_t (13, false, false);
550 /* Default destructor. */
552 template <class T>
553 inline
554 mem_alloc_description<T>::~mem_alloc_description ()
556 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
557 ++it)
559 delete (*it).first;
560 delete (*it).second;
563 delete m_map;
564 delete m_reverse_map;
565 delete m_reverse_object_map;
568 /* Get all tracked instances registered by the description. Items are filtered
569 by ORIGIN type, LENGTH is return value where we register the number of
570 elements in the list. If we want to process custom order, CMP comparator
571 can be provided. */
573 template <class T>
574 inline
575 typename mem_alloc_description<T>::mem_list_t *
576 mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length,
577 int (*cmp) (const void *first,
578 const void *second))
580 /* vec data structure is not used because all vectors generate memory
581 allocation info a it would create a cycle. */
582 size_t element_size = sizeof (mem_list_t);
583 mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ());
584 unsigned i = 0;
586 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
587 ++it)
588 if ((*it).first->m_origin == origin)
589 list[i++] = std::pair<mem_location*, T*> (*it);
591 qsort (list, i, element_size, cmp == NULL ? T::compare : cmp);
592 *length = i;
594 return list;
597 /* Get sum value for ORIGIN type of allocation for the descriptor. */
599 template <class T>
600 inline T
601 mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
603 unsigned length;
604 mem_list_t *list = get_list (origin, &length);
605 T sum;
607 for (unsigned i = 0; i < length; i++)
608 sum = sum + *list[i].second;
610 XDELETEVEC (list);
612 return sum;
615 /* Dump all tracked instances of type ORIGIN. If we want to process custom
616 order, CMP comparator can be provided. */
618 template <class T>
619 inline void
620 mem_alloc_description<T>::dump (mem_alloc_origin origin,
621 int (*cmp) (const void *first,
622 const void *second))
624 unsigned length;
626 fprintf (stderr, "\n");
628 mem_list_t *list = get_list (origin, &length, cmp);
629 T total = get_sum (origin);
631 T::print_dash_line ();
632 T::dump_header (mem_location::get_origin_name (origin));
633 T::print_dash_line ();
634 for (int i = length - 1; i >= 0; i--)
635 list[i].second->dump (list[i].first, total);
636 T::print_dash_line ();
638 T::dump_header (mem_location::get_origin_name (origin));
639 T::print_dash_line ();
640 total.dump_footer ();
641 T::print_dash_line ();
643 XDELETEVEC (list);
645 fprintf (stderr, "\n");
648 #endif // GCC_MEM_STATS_H