rs6000: fix power10_hw test
[platform/upstream/gcc.git] / gcc / mem-stats.h
1 /* A memory statistics tracking infrastructure.
2    Copyright (C) 2015-2020 Free Software Foundation, Inc.
3    Contributed by Martin Liska  <mliska@suse.cz>
4
5 This file is part of GCC.
6
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.
11
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.
16
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/>.  */
20
21 #ifndef GCC_MEM_STATS_H
22 #define GCC_MEM_STATS_H
23
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;
29
30 #define LOCATION_LINE_EXTRA_SPACE 30
31 #define LOCATION_LINE_WIDTH       48
32
33 /* Memory allocation location.  */
34 class mem_location
35 {
36 public:
37   /* Default constructor.  */
38   inline
39   mem_location () {}
40
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) {}
48
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) {}
54
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 ()
61   {
62     inchash::hash hash;
63
64     hash.add_ptr (m_filename);
65     hash.add_ptr (m_function);
66     hash.add_int (m_line);
67
68     return hash.end ();
69   }
70
71   /* Return true if the memory location is equal to OTHER.  */
72   int
73   equal (const mem_location &other)
74   {
75     return m_filename == other.m_filename && m_function == other.m_function
76       && m_line == other.m_line;
77   }
78
79   /* Return trimmed filename for the location.  */
80   inline const char *
81   get_trimmed_filename ()
82   {
83     const char *s1 = m_filename;
84     const char *s2;
85
86     while ((s2 = strstr (s1, "gcc/")))
87       s1 = s2 + 4;
88
89     return s1;
90   }
91
92   inline char *
93   to_string ()
94   {
95     unsigned l = strlen (get_trimmed_filename ()) + strlen (m_function)
96       + LOCATION_LINE_EXTRA_SPACE;
97
98     char *s = XNEWVEC (char, l);
99     sprintf (s, "%s:%i (%s)", get_trimmed_filename (),
100              m_line, m_function);
101
102     s[MIN (LOCATION_LINE_WIDTH, l - 1)] = '\0';
103
104     return s;
105   }
106
107   /* Return display name associated to ORIGIN type.  */
108   static const char *
109   get_origin_name (mem_alloc_origin origin)
110   {
111     return mem_alloc_origin_names[(unsigned) origin];
112   }
113
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;
124 };
125
126 /* Memory usage register to a memory location.  */
127 class mem_usage
128 {
129 public:
130   /* Default constructor.  */
131   mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
132
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) {}
137
138   /* Register overhead of SIZE bytes.  */
139   inline void
140   register_overhead (size_t size)
141   {
142     m_allocated += size;
143     m_times++;
144
145     if (m_peak < m_allocated)
146       m_peak = m_allocated;
147   }
148
149   /* Release overhead of SIZE bytes.  */
150   inline void
151   release_overhead (size_t size)
152   {
153     gcc_assert (size <= m_allocated);
154
155     m_allocated -= size;
156   }
157
158   /* Sum the usage with SECOND usage.  */
159   mem_usage
160   operator+ (const mem_usage &second)
161   {
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);
166   }
167
168   /* Equality operator.  */
169   inline bool
170   operator== (const mem_usage &second) const
171   {
172     return (m_allocated == second.m_allocated
173             && m_peak == second.m_peak
174             && m_times == second.m_times);
175   }
176
177   /* Comparison operator.  */
178   inline bool
179   operator< (const mem_usage &second) const
180   {
181     if (*this == second)
182       return false;
183
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);
187   }
188
189   /* Compare wrapper used by qsort method.  */
190   static int
191   compare (const void *first, const void *second)
192   {
193     typedef std::pair<mem_location *, mem_usage *> mem_pair_t;
194
195     const mem_pair_t f = *(const mem_pair_t *)first;
196     const mem_pair_t s = *(const mem_pair_t *)second;
197
198     if (*f.second == *s.second)
199       return 0;
200
201     return *f.second < *s.second ? 1 : -1;
202   }
203
204   /* Dump usage coupled to LOC location, where TOTAL is sum of all rows.  */
205   inline void
206   dump (mem_location *loc, const mem_usage &total) const
207   {
208     char *location_string = loc->to_string ();
209
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");
216
217     free (location_string);
218   }
219
220   /* Dump footer.  */
221   inline void
222   dump_footer () const
223   {
224     fprintf (stderr, "%s" PRsa (53) PRsa (26) "\n", "Total",
225              SIZE_AMOUNT (m_allocated), SIZE_AMOUNT (m_times));
226   }
227
228   /* Return fraction of NOMINATOR and DENOMINATOR in percent.  */
229   static inline float
230   get_percent (size_t nominator, size_t denominator)
231   {
232     return denominator == 0 ? 0.0f : nominator * 100.0 / denominator;
233   }
234
235   /* Print line made of dashes.  */
236   static inline void
237   print_dash_line (size_t count = 140)
238   {
239     while (count--)
240       fputc ('-', stderr);
241     fputc ('\n', stderr);
242   }
243
244   /* Dump header with NAME.  */
245   static inline void
246   dump_header (const char *name)
247   {
248     fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak",
249              "Times", "Type");
250   }
251
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;
260 };
261
262 /* Memory usage pair that connectes memory usage and number
263    of allocated bytes.  */
264 template <class T>
265 class mem_usage_pair
266 {
267 public:
268   mem_usage_pair (T *usage_, size_t allocated_): usage (usage_),
269   allocated (allocated_) {}
270
271   T *usage;
272   size_t allocated;
273 };
274
275 /* Memory allocation description.  */
276 template <class T>
277 class mem_alloc_description
278 {
279 public:
280   struct mem_location_hash : nofree_ptr_hash <mem_location>
281   {
282     static hashval_t
283     hash (value_type l)
284     {
285       inchash::hash hstate;
286
287       hstate.add_ptr ((const void *)l->m_filename);
288       hstate.add_ptr (l->m_function);
289       hstate.add_int (l->m_line);
290
291       return hstate.end ();
292     }
293
294     static bool
295     equal (value_type l1, value_type l2)
296     {
297       return (l1->m_filename == l2->m_filename
298               && l1->m_function == l2->m_function
299               && l1->m_line == l2->m_line);
300     }
301   };
302
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;
308
309   /* Default contructor.  */
310   mem_alloc_description ();
311
312   /* Default destructor.  */
313   ~mem_alloc_description ();
314
315   /* Returns true if instance PTR is registered by the memory description.  */
316   bool contains_descriptor_for_instance (const void *ptr);
317
318   /* Return descriptor for instance PTR.  */
319   T *get_descriptor_for_instance (const void *ptr);
320
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);
324
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);
332
333   /* Register instance overhead identified by PTR pointer. Allocation takes
334      SIZE bytes.  */
335   T *register_instance_overhead (size_t size, const void *ptr);
336
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);
341
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);
347
348   /* Release instance object identified by PTR pointer.  */
349   void release_object_overhead (void *ptr);
350
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);
356
357   /* Get sum value for ORIGIN type of allocation for the descriptor.  */
358   T get_sum (mem_alloc_origin origin);
359
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
366   /* Dump all tracked instances of type ORIGIN. If we want to process custom
367      order, CMP comparator can be provided.  */
368   void dump (mem_alloc_origin origin);
369
370   /* Reverse object map used for every object allocation mapping.  */
371   reverse_object_map_t *m_reverse_object_map;
372
373 private:
374   /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
375      in NAME source file, at LINE in source code, in FUNCTION.  */
376   T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
377                         int line, const char *function, const void *ptr);
378
379   /* Allocation location coupled to the description.  */
380   mem_location m_location;
381
382   /* Location to usage mapping.  */
383   mem_map_t *m_map;
384
385   /* Reverse pointer to usage mapping.  */
386   reverse_mem_map_t *m_reverse_map;
387 };
388
389 /* Returns true if instance PTR is registered by the memory description.  */
390
391 template <class T>
392 inline bool
393 mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
394 {
395   return m_reverse_map->get (ptr);
396 }
397
398 /* Return descriptor for instance PTR.  */
399
400 template <class T>
401 inline T*
402 mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
403 {
404   return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
405 }
406
407 /* Register memory allocation descriptor for container PTR which is
408    described by a memory LOCATION.  */
409
410 template <class T>
411 inline T*
412 mem_alloc_description<T>::register_descriptor (const void *ptr,
413                                                mem_location *location)
414 {
415   T *usage = NULL;
416
417   T **slot = m_map->get (location);
418   if (slot)
419     {
420       delete location;
421       usage = *slot;
422       usage->m_instances++;
423     }
424   else
425     {
426       usage = new T ();
427       m_map->put (location, usage);
428     }
429
430   if (!m_reverse_map->get (ptr))
431     m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
432
433   return usage;
434 }
435
436 /* Register memory allocation descriptor for container PTR.  ORIGIN identifies
437    type of container and GGC identifes if the allocation is handled in GGC
438    memory.  Each location is identified by file NAME, LINE in source code and
439    FUNCTION name.  */
440
441 template <class T>
442 inline T*
443 mem_alloc_description<T>::register_descriptor (const void *ptr,
444                                                mem_alloc_origin origin,
445                                                bool ggc,
446                                                const char *filename,
447                                                int line,
448                                                const char *function)
449 {
450   mem_location *l = new mem_location (origin, ggc, filename, line, function);
451   return register_descriptor (ptr, l);
452 }
453
454 /* Register instance overhead identified by PTR pointer. Allocation takes
455    SIZE bytes.  */
456
457 template <class T>
458 inline T*
459 mem_alloc_description<T>::register_instance_overhead (size_t size,
460                                                       const void *ptr)
461 {
462   mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
463   if (!slot)
464     {
465       /* Due to PCH, it can really happen.  */
466       return NULL;
467     }
468
469   T *usage = (*slot).usage;
470   usage->register_overhead (size);
471
472   return usage;
473 }
474
475 /* For containers (and GGC) where we want to track every instance object,
476    we register allocation of SIZE bytes, identified by PTR pointer, belonging
477    to USAGE descriptor.  */
478
479 template <class T>
480 void
481 mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
482                                                     const void *ptr)
483 {
484   /* In case of GGC, it is possible to have already occupied the memory
485      location.  */
486   m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
487 }
488
489 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
490    in NAME source file, at LINE in source code, in FUNCTION.  */
491
492 template <class T>
493 inline T*
494 mem_alloc_description<T>::register_overhead (size_t size,
495                                              mem_alloc_origin origin,
496                                              const char *filename,
497                                              int line,
498                                              const char *function,
499                                              const void *ptr)
500 {
501   T *usage = register_descriptor (ptr, origin, filename, line, function);
502   usage->register_overhead (size);
503
504   return usage;
505 }
506
507 /* Release PTR pointer of SIZE bytes.  */
508
509 template <class T>
510 inline T *
511 mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size,
512                                                      bool remove_from_map)
513 {
514   mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
515
516   if (!slot)
517     {
518       /* Due to PCH, it can really happen.  */
519       return NULL;
520     }
521
522   T *usage = (*slot).usage;
523   usage->release_overhead (size);
524
525   if (remove_from_map)
526     m_reverse_map->remove (ptr);
527
528   return usage;
529 }
530
531 /* Release instance object identified by PTR pointer.  */
532
533 template <class T>
534 inline void
535 mem_alloc_description<T>::release_object_overhead (void *ptr)
536 {
537   std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
538   entry->first->release_overhead (entry->second);
539   m_reverse_object_map->remove (ptr);
540 }
541
542 /* Unregister a memory allocation descriptor registered with
543    register_descriptor (remove from reverse map), unless it is
544    unregistered through release_instance_overhead with
545    REMOVE_FROM_MAP = true.  */
546 template <class T>
547 inline void
548 mem_alloc_description<T>::unregister_descriptor (void *ptr)
549 {
550   m_reverse_map->remove (ptr);
551 }
552
553 /* Default contructor.  */
554
555 template <class T>
556 inline
557 mem_alloc_description<T>::mem_alloc_description ()
558 {
559   m_map = new mem_map_t (13, false, false, false);
560   m_reverse_map = new reverse_mem_map_t (13, false, false, false);
561   m_reverse_object_map = new reverse_object_map_t (13, false, false, false);
562 }
563
564 /* Default destructor.  */
565
566 template <class T>
567 inline
568 mem_alloc_description<T>::~mem_alloc_description ()
569 {
570   for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
571        ++it)
572     {
573       delete (*it).first;
574       delete (*it).second;
575     }
576
577   delete m_map;
578   delete m_reverse_map;
579   delete m_reverse_object_map;
580 }
581
582 /* Get all tracked instances registered by the description. Items are filtered
583    by ORIGIN type, LENGTH is return value where we register the number of
584    elements in the list. If we want to process custom order, CMP comparator
585    can be provided.  */
586
587 template <class T>
588 inline
589 typename mem_alloc_description<T>::mem_list_t *
590 mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length)
591 {
592   /* vec data structure is not used because all vectors generate memory
593      allocation info a it would create a cycle.  */
594   size_t element_size = sizeof (mem_list_t);
595   mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ());
596   unsigned i = 0;
597
598   for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
599        ++it)
600     if ((*it).first->m_origin == origin)
601       list[i++] = std::pair<mem_location*, T*> (*it);
602
603   qsort (list, i, element_size, T::compare);
604   *length = i;
605
606   return list;
607 }
608
609 /* Get sum value for ORIGIN type of allocation for the descriptor.  */
610
611 template <class T>
612 inline T
613 mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
614 {
615   unsigned length;
616   mem_list_t *list = get_list (origin, &length);
617   T sum;
618
619   for (unsigned i = 0; i < length; i++)
620     sum = sum + *list[i].second;
621
622   XDELETEVEC (list);
623
624   return sum;
625 }
626
627 /* Dump all tracked instances of type ORIGIN. If we want to process custom
628    order, CMP comparator can be provided.  */
629
630 template <class T>
631 inline void
632 mem_alloc_description<T>::dump (mem_alloc_origin origin)
633 {
634   unsigned length;
635
636   fprintf (stderr, "\n");
637
638   mem_list_t *list = get_list (origin, &length);
639   T total = get_sum (origin);
640
641   T::print_dash_line ();
642   T::dump_header (mem_location::get_origin_name (origin));
643   T::print_dash_line ();
644   for (int i = length - 1; i >= 0; i--)
645     list[i].second->dump (list[i].first, total);
646   T::print_dash_line ();
647
648   T::dump_header (mem_location::get_origin_name (origin));
649   T::print_dash_line ();
650   total.dump_footer ();
651   T::print_dash_line ();
652
653   XDELETEVEC (list);
654
655   fprintf (stderr, "\n");
656 }
657
658 #endif // GCC_MEM_STATS_H