re PR middle-end/91603 (Unaligned access in expand_assignment)
[official-gcc.git] / gcc / mem-stats.h
blob9ceb9ccc55b3d3c302e1908e119f655f41b8be54
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 class mem_location
36 public:
37 /* Default constructor. */
38 inline
39 mem_location () {}
41 /* Constructor. */
42 inline
43 mem_location (mem_alloc_origin origin, bool ggc,
44 const char *filename = NULL, int line = 0,
45 const char *function = NULL):
46 m_filename (filename), m_function (function), m_line (line), m_origin
47 (origin), m_ggc (ggc) {}
49 /* Copy constructor. */
50 inline
51 mem_location (mem_location &other): m_filename (other.m_filename),
52 m_function (other.m_function), m_line (other.m_line),
53 m_origin (other.m_origin), m_ggc (other.m_ggc) {}
55 /* Compute hash value based on file name, function name and line in
56 source code. As there is just a single pointer registered for every
57 constant that points to e.g. the same file name, we can use hash
58 of the pointer. */
59 hashval_t
60 hash ()
62 inchash::hash hash;
64 hash.add_ptr (m_filename);
65 hash.add_ptr (m_function);
66 hash.add_int (m_line);
68 return hash.end ();
71 /* Return true if the memory location is equal to OTHER. */
72 int
73 equal (mem_location &other)
75 return m_filename == other.m_filename && m_function == other.m_function
76 && m_line == other.m_line;
79 /* Return trimmed filename for the location. */
80 inline const char *
81 get_trimmed_filename ()
83 const char *s1 = m_filename;
84 const char *s2;
86 while ((s2 = strstr (s1, "gcc/")))
87 s1 = s2 + 4;
89 return s1;
92 inline char *
93 to_string ()
95 unsigned l = strlen (get_trimmed_filename ()) + strlen (m_function)
96 + LOCATION_LINE_EXTRA_SPACE;
98 char *s = XNEWVEC (char, l);
99 sprintf (s, "%s:%i (%s)", get_trimmed_filename (),
100 m_line, m_function);
102 s[MIN (LOCATION_LINE_WIDTH, l - 1)] = '\0';
104 return s;
107 /* Return display name associated to ORIGIN type. */
108 static const char *
109 get_origin_name (mem_alloc_origin origin)
111 return mem_alloc_origin_names[(unsigned) origin];
114 /* File name of source code. */
115 const char *m_filename;
116 /* Funcation name. */
117 const char *m_function;
118 /* Line number in source code. */
119 int m_line;
120 /* Origin type. */
121 mem_alloc_origin m_origin;
122 /* Flag if used by GGC allocation. */
123 bool m_ggc;
126 /* Memory usage register to a memory location. */
127 class mem_usage
129 public:
130 /* Default constructor. */
131 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
133 /* Constructor. */
134 mem_usage (size_t allocated, size_t times, size_t peak, size_t instances = 0):
135 m_allocated (allocated), m_times (times), m_peak (peak),
136 m_instances (instances) {}
138 /* Register overhead of SIZE bytes. */
139 inline void
140 register_overhead (size_t size)
142 m_allocated += size;
143 m_times++;
145 if (m_peak < m_allocated)
146 m_peak = m_allocated;
149 /* Release overhead of SIZE bytes. */
150 inline void
151 release_overhead (size_t size)
153 gcc_assert (size <= m_allocated);
155 m_allocated -= size;
158 /* Sum the usage with SECOND usage. */
159 mem_usage
160 operator+ (const mem_usage &second)
162 return mem_usage (m_allocated + second.m_allocated,
163 m_times + second.m_times,
164 m_peak + second.m_peak,
165 m_instances + second.m_instances);
168 /* Equality operator. */
169 inline bool
170 operator== (const mem_usage &second) const
172 return (m_allocated == second.m_allocated
173 && m_peak == second.m_peak
174 && m_times == second.m_times);
177 /* Comparison operator. */
178 inline bool
179 operator< (const mem_usage &second) const
181 if (*this == second)
182 return false;
184 return (m_allocated == second.m_allocated ?
185 (m_peak == second.m_peak ? m_times < second.m_times
186 : m_peak < second.m_peak) : m_allocated < second.m_allocated);
189 /* Compare wrapper used by qsort method. */
190 static int
191 compare (const void *first, const void *second)
193 typedef std::pair<mem_location *, mem_usage *> mem_pair_t;
195 const mem_pair_t f = *(const mem_pair_t *)first;
196 const mem_pair_t s = *(const mem_pair_t *)second;
198 if (*f.second == *s.second)
199 return 0;
201 return *f.second < *s.second ? 1 : -1;
204 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
205 inline void
206 dump (mem_location *loc, mem_usage &total) const
208 char *location_string = loc->to_string ();
210 fprintf (stderr, "%-48s " PRsa (9) ":%5.1f%%"
211 PRsa (9) PRsa (9) ":%5.1f%%%10s\n",
212 location_string, SIZE_AMOUNT (m_allocated),
213 get_percent (m_allocated, total.m_allocated),
214 SIZE_AMOUNT (m_peak), SIZE_AMOUNT (m_times),
215 get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap");
217 free (location_string);
220 /* Dump footer. */
221 inline void
222 dump_footer () const
224 fprintf (stderr, "%s" PRsa (53) PRsa (26) "\n", "Total",
225 SIZE_AMOUNT (m_allocated), SIZE_AMOUNT (m_times));
228 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */
229 static inline float
230 get_percent (size_t nominator, size_t denominator)
232 return denominator == 0 ? 0.0f : nominator * 100.0 / denominator;
235 /* Print line made of dashes. */
236 static inline void
237 print_dash_line (size_t count = 140)
239 while (count--)
240 fputc ('-', stderr);
241 fputc ('\n', stderr);
244 /* Dump header with NAME. */
245 static inline void
246 dump_header (const char *name)
248 fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak",
249 "Times", "Type");
252 /* Current number of allocated bytes. */
253 size_t m_allocated;
254 /* Number of allocations. */
255 size_t m_times;
256 /* Peak allocation in bytes. */
257 size_t m_peak;
258 /* Number of container instances. */
259 size_t m_instances;
262 /* Memory usage pair that connectes memory usage and number
263 of allocated bytes. */
264 template <class T>
265 class mem_usage_pair
267 public:
268 mem_usage_pair (T *usage_, size_t allocated_): usage (usage_),
269 allocated (allocated_) {}
271 T *usage;
272 size_t allocated;
275 /* Memory allocation description. */
276 template <class T>
277 class mem_alloc_description
279 public:
280 struct mem_location_hash : nofree_ptr_hash <mem_location>
282 static hashval_t
283 hash (value_type l)
285 inchash::hash hstate;
287 hstate.add_ptr ((const void *)l->m_filename);
288 hstate.add_ptr (l->m_function);
289 hstate.add_int (l->m_line);
291 return hstate.end ();
294 static bool
295 equal (value_type l1, value_type l2)
297 return (l1->m_filename == l2->m_filename
298 && l1->m_function == l2->m_function
299 && l1->m_line == l2->m_line);
303 /* Internal class type definitions. */
304 typedef hash_map <mem_location_hash, T *> mem_map_t;
305 typedef hash_map <const void *, mem_usage_pair<T> > reverse_mem_map_t;
306 typedef hash_map <const void *, std::pair<T *, size_t> > reverse_object_map_t;
307 typedef std::pair <mem_location *, T *> mem_list_t;
309 /* Default contructor. */
310 mem_alloc_description ();
312 /* Default destructor. */
313 ~mem_alloc_description ();
315 /* Returns true if instance PTR is registered by the memory description. */
316 bool contains_descriptor_for_instance (const void *ptr);
318 /* Return descriptor for instance PTR. */
319 T *get_descriptor_for_instance (const void *ptr);
321 /* Register memory allocation descriptor for container PTR which is
322 described by a memory LOCATION. */
323 T *register_descriptor (const void *ptr, mem_location *location);
325 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
326 type of container and GGC identifes if the allocation is handled in GGC
327 memory. Each location is identified by file NAME, LINE in source code and
328 FUNCTION name. */
329 T *register_descriptor (const void *ptr, mem_alloc_origin origin,
330 bool ggc, const char *name, int line,
331 const char *function);
333 /* Register instance overhead identified by PTR pointer. Allocation takes
334 SIZE bytes. */
335 T *register_instance_overhead (size_t size, const void *ptr);
337 /* For containers (and GGC) where we want to track every instance object,
338 we register allocation of SIZE bytes, identified by PTR pointer, belonging
339 to USAGE descriptor. */
340 void register_object_overhead (T *usage, size_t size, const void *ptr);
342 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
343 remove the instance from reverse map. Return memory usage that belongs
344 to this memory description. */
345 T *release_instance_overhead (void *ptr, size_t size,
346 bool remove_from_map = false);
348 /* Release instance object identified by PTR pointer. */
349 void release_object_overhead (void *ptr);
351 /* Unregister a memory allocation descriptor registered with
352 register_descriptor (remove from reverse map), unless it is
353 unregistered through release_instance_overhead with
354 REMOVE_FROM_MAP = true. */
355 void unregister_descriptor (void *ptr);
357 /* Get sum value for ORIGIN type of allocation for the descriptor. */
358 T get_sum (mem_alloc_origin origin);
360 /* Get all tracked instances registered by the description. Items
361 are filtered by ORIGIN type, LENGTH is return value where we register
362 the number of elements in the list. If we want to process custom order,
363 CMP comparator can be provided. */
364 mem_list_t *get_list (mem_alloc_origin origin, unsigned *length,
365 int (*cmp) (const void *first,
366 const void *second) = NULL);
368 /* Dump all tracked instances of type ORIGIN. If we want to process custom
369 order, CMP comparator can be provided. */
370 void dump (mem_alloc_origin origin,
371 int (*cmp) (const void *first, const void *second) = NULL);
373 /* Reverse object map used for every object allocation mapping. */
374 reverse_object_map_t *m_reverse_object_map;
376 private:
377 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
378 in NAME source file, at LINE in source code, in FUNCTION. */
379 T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
380 int line, const char *function, const void *ptr);
382 /* Allocation location coupled to the description. */
383 mem_location m_location;
385 /* Location to usage mapping. */
386 mem_map_t *m_map;
388 /* Reverse pointer to usage mapping. */
389 reverse_mem_map_t *m_reverse_map;
392 /* Returns true if instance PTR is registered by the memory description. */
394 template <class T>
395 inline bool
396 mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
398 return m_reverse_map->get (ptr);
401 /* Return descriptor for instance PTR. */
403 template <class T>
404 inline T*
405 mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
407 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
410 /* Register memory allocation descriptor for container PTR which is
411 described by a memory LOCATION. */
413 template <class T>
414 inline T*
415 mem_alloc_description<T>::register_descriptor (const void *ptr,
416 mem_location *location)
418 T *usage = NULL;
420 T **slot = m_map->get (location);
421 if (slot)
423 delete location;
424 usage = *slot;
425 usage->m_instances++;
427 else
429 usage = new T ();
430 m_map->put (location, usage);
433 if (!m_reverse_map->get (ptr))
434 m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
436 return usage;
439 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
440 type of container and GGC identifes if the allocation is handled in GGC
441 memory. Each location is identified by file NAME, LINE in source code and
442 FUNCTION name. */
444 template <class T>
445 inline T*
446 mem_alloc_description<T>::register_descriptor (const void *ptr,
447 mem_alloc_origin origin,
448 bool ggc,
449 const char *filename,
450 int line,
451 const char *function)
453 mem_location *l = new mem_location (origin, ggc, filename, line, function);
454 return register_descriptor (ptr, l);
457 /* Register instance overhead identified by PTR pointer. Allocation takes
458 SIZE bytes. */
460 template <class T>
461 inline T*
462 mem_alloc_description<T>::register_instance_overhead (size_t size,
463 const void *ptr)
465 mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
466 if (!slot)
468 /* Due to PCH, it can really happen. */
469 return NULL;
472 T *usage = (*slot).usage;
473 usage->register_overhead (size);
475 return usage;
478 /* For containers (and GGC) where we want to track every instance object,
479 we register allocation of SIZE bytes, identified by PTR pointer, belonging
480 to USAGE descriptor. */
482 template <class T>
483 void
484 mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
485 const void *ptr)
487 /* In case of GGC, it is possible to have already occupied the memory
488 location. */
489 m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
492 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
493 in NAME source file, at LINE in source code, in FUNCTION. */
495 template <class T>
496 inline T*
497 mem_alloc_description<T>::register_overhead (size_t size,
498 mem_alloc_origin origin,
499 const char *filename,
500 int line,
501 const char *function,
502 const void *ptr)
504 T *usage = register_descriptor (ptr, origin, filename, line, function);
505 usage->register_overhead (size);
507 return usage;
510 /* Release PTR pointer of SIZE bytes. */
512 template <class T>
513 inline T *
514 mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size,
515 bool remove_from_map)
517 mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
519 if (!slot)
521 /* Due to PCH, it can really happen. */
522 return NULL;
525 T *usage = (*slot).usage;
526 usage->release_overhead (size);
528 if (remove_from_map)
529 m_reverse_map->remove (ptr);
531 return usage;
534 /* Release instance object identified by PTR pointer. */
536 template <class T>
537 inline void
538 mem_alloc_description<T>::release_object_overhead (void *ptr)
540 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
541 if (entry)
543 entry->first->release_overhead (entry->second);
544 m_reverse_object_map->remove (ptr);
548 /* Unregister a memory allocation descriptor registered with
549 register_descriptor (remove from reverse map), unless it is
550 unregistered through release_instance_overhead with
551 REMOVE_FROM_MAP = true. */
552 template <class T>
553 inline void
554 mem_alloc_description<T>::unregister_descriptor (void *ptr)
556 m_reverse_map->remove (ptr);
559 /* Default contructor. */
561 template <class T>
562 inline
563 mem_alloc_description<T>::mem_alloc_description ()
565 m_map = new mem_map_t (13, false, false, false);
566 m_reverse_map = new reverse_mem_map_t (13, false, false, false);
567 m_reverse_object_map = new reverse_object_map_t (13, false, false, false);
570 /* Default destructor. */
572 template <class T>
573 inline
574 mem_alloc_description<T>::~mem_alloc_description ()
576 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
577 ++it)
579 delete (*it).first;
580 delete (*it).second;
583 delete m_map;
584 delete m_reverse_map;
585 delete m_reverse_object_map;
588 /* Get all tracked instances registered by the description. Items are filtered
589 by ORIGIN type, LENGTH is return value where we register the number of
590 elements in the list. If we want to process custom order, CMP comparator
591 can be provided. */
593 template <class T>
594 inline
595 typename mem_alloc_description<T>::mem_list_t *
596 mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length,
597 int (*cmp) (const void *first,
598 const void *second))
600 /* vec data structure is not used because all vectors generate memory
601 allocation info a it would create a cycle. */
602 size_t element_size = sizeof (mem_list_t);
603 mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ());
604 unsigned i = 0;
606 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
607 ++it)
608 if ((*it).first->m_origin == origin)
609 list[i++] = std::pair<mem_location*, T*> (*it);
611 qsort (list, i, element_size, cmp == NULL ? T::compare : cmp);
612 *length = i;
614 return list;
617 /* Get sum value for ORIGIN type of allocation for the descriptor. */
619 template <class T>
620 inline T
621 mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
623 unsigned length;
624 mem_list_t *list = get_list (origin, &length);
625 T sum;
627 for (unsigned i = 0; i < length; i++)
628 sum = sum + *list[i].second;
630 XDELETEVEC (list);
632 return sum;
635 /* Dump all tracked instances of type ORIGIN. If we want to process custom
636 order, CMP comparator can be provided. */
638 template <class T>
639 inline void
640 mem_alloc_description<T>::dump (mem_alloc_origin origin,
641 int (*cmp) (const void *first,
642 const void *second))
644 unsigned length;
646 fprintf (stderr, "\n");
648 mem_list_t *list = get_list (origin, &length, cmp);
649 T total = get_sum (origin);
651 T::print_dash_line ();
652 T::dump_header (mem_location::get_origin_name (origin));
653 T::print_dash_line ();
654 for (int i = length - 1; i >= 0; i--)
655 list[i].second->dump (list[i].first, total);
656 T::print_dash_line ();
658 T::dump_header (mem_location::get_origin_name (origin));
659 T::print_dash_line ();
660 total.dump_footer ();
661 T::print_dash_line ();
663 XDELETEVEC (list);
665 fprintf (stderr, "\n");
668 #endif // GCC_MEM_STATS_H