]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/mem-stats.h
[Ada] Improved support for aspect alignment in CCG
[thirdparty/gcc.git] / gcc / mem-stats.h
CommitLineData
0b2e1bfa 1/* A memory statistics tracking infrastructure.
8d9254fc 2 Copyright (C) 2015-2020 Free Software Foundation, Inc.
0b2e1bfa
ML
3 Contributed by Martin Liska <mliska@suse.cz>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 3, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING3. If not see
19<http://www.gnu.org/licenses/>. */
20
2d44c7de
ML
21#ifndef GCC_MEM_STATS_H
22#define GCC_MEM_STATS_H
23
2d44c7de
ML
24/* Forward declaration. */
25template<typename Key, typename Value,
76b6ddbf
TS
26 typename Traits = simple_hashmap_traits<default_hash_traits<Key>,
27 Value> >
2d44c7de
ML
28class hash_map;
29
ac059261
ML
30#define LOCATION_LINE_EXTRA_SPACE 30
31#define LOCATION_LINE_WIDTH 48
32
2d44c7de 33/* Memory allocation location. */
6c1dae73 34class mem_location
2d44c7de 35{
6c1dae73 36public:
2d44c7de 37 /* Default constructor. */
80a4fe78
ML
38 inline
39 mem_location () {}
2d44c7de
ML
40
41 /* Constructor. */
80a4fe78
ML
42 inline
43 mem_location (mem_alloc_origin origin, bool ggc,
ac059261
ML
44 const char *filename = NULL, int line = 0,
45 const char *function = NULL):
2d44c7de
ML
46 m_filename (filename), m_function (function), m_line (line), m_origin
47 (origin), m_ggc (ggc) {}
48
ac059261 49 /* Copy constructor. */
80a4fe78
ML
50 inline
51 mem_location (mem_location &other): m_filename (other.m_filename),
ac059261
ML
52 m_function (other.m_function), m_line (other.m_line),
53 m_origin (other.m_origin), m_ggc (other.m_ggc) {}
54
2d44c7de
ML
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. */
80a4fe78
ML
59 hashval_t
60 hash ()
2d44c7de
ML
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. */
80a4fe78 72 int
d73d45f1 73 equal (const mem_location &other)
2d44c7de
ML
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. */
80a4fe78
ML
80 inline const char *
81 get_trimmed_filename ()
2d44c7de
ML
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
80a4fe78
ML
92 inline char *
93 to_string ()
ac059261
ML
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
2d44c7de 107 /* Return display name associated to ORIGIN type. */
80a4fe78
ML
108 static const char *
109 get_origin_name (mem_alloc_origin origin)
2d44c7de
ML
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. */
6c1dae73 127class mem_usage
2d44c7de 128{
6c1dae73 129public:
2d44c7de 130 /* Default constructor. */
ac059261 131 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
2d44c7de
ML
132
133 /* Constructor. */
ac059261
ML
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) {}
2d44c7de
ML
137
138 /* Register overhead of SIZE bytes. */
80a4fe78
ML
139 inline void
140 register_overhead (size_t size)
2d44c7de
ML
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. */
80a4fe78
ML
150 inline void
151 release_overhead (size_t size)
2d44c7de
ML
152 {
153 gcc_assert (size <= m_allocated);
154
155 m_allocated -= size;
156 }
157
158 /* Sum the usage with SECOND usage. */
80a4fe78
ML
159 mem_usage
160 operator+ (const mem_usage &second)
2d44c7de
ML
161 {
162 return mem_usage (m_allocated + second.m_allocated,
163 m_times + second.m_times,
ac059261
ML
164 m_peak + second.m_peak,
165 m_instances + second.m_instances);
2d44c7de
ML
166 }
167
b27b31dc
ML
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
2c2f8674 174 && m_times == second.m_times);
b27b31dc
ML
175 }
176
2d44c7de 177 /* Comparison operator. */
80a4fe78
ML
178 inline bool
179 operator< (const mem_usage &second) const
2d44c7de 180 {
b27b31dc
ML
181 if (*this == second)
182 return false;
183
2d44c7de
ML
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. */
80a4fe78
ML
190 static int
191 compare (const void *first, const void *second)
2d44c7de
ML
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
b27b31dc
ML
198 if (*f.second == *s.second)
199 return 0;
200
201 return *f.second < *s.second ? 1 : -1;
2d44c7de
ML
202 }
203
204 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
80a4fe78 205 inline void
d73d45f1 206 dump (mem_location *loc, const mem_usage &total) const
2d44c7de 207 {
ac059261 208 char *location_string = loc->to_string ();
2d44c7de 209
a0b48080
MM
210 fprintf (stderr, "%-48s " PRsa (9) ":%5.1f%%"
211 PRsa (9) PRsa (9) ":%5.1f%%%10s\n",
40ce7fa6 212 location_string, SIZE_AMOUNT (m_allocated),
43331dfb 213 get_percent (m_allocated, total.m_allocated),
40ce7fa6 214 SIZE_AMOUNT (m_peak), SIZE_AMOUNT (m_times),
2d44c7de 215 get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap");
ac059261
ML
216
217 free (location_string);
2d44c7de
ML
218 }
219
220 /* Dump footer. */
80a4fe78
ML
221 inline void
222 dump_footer () const
2d44c7de 223 {
a0b48080 224 fprintf (stderr, "%s" PRsa (53) PRsa (26) "\n", "Total",
40ce7fa6 225 SIZE_AMOUNT (m_allocated), SIZE_AMOUNT (m_times));
2d44c7de
ML
226 }
227
228 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */
80a4fe78
ML
229 static inline float
230 get_percent (size_t nominator, size_t denominator)
2d44c7de
ML
231 {
232 return denominator == 0 ? 0.0f : nominator * 100.0 / denominator;
233 }
234
235 /* Print line made of dashes. */
80a4fe78
ML
236 static inline void
237 print_dash_line (size_t count = 140)
2d44c7de 238 {
01736018
MM
239 while (count--)
240 fputc ('-', stderr);
241 fputc ('\n', stderr);
2d44c7de
ML
242 }
243
244 /* Dump header with NAME. */
80a4fe78
ML
245 static inline void
246 dump_header (const char *name)
2d44c7de
ML
247 {
248 fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak",
249 "Times", "Type");
2d44c7de
ML
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;
ac059261
ML
258 /* Number of container instances. */
259 size_t m_instances;
2d44c7de
ML
260};
261
262/* Memory usage pair that connectes memory usage and number
263 of allocated bytes. */
264template <class T>
6c1dae73 265class mem_usage_pair
2d44c7de 266{
6c1dae73 267public:
2d44c7de
ML
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. */
276template <class T>
277class mem_alloc_description
278{
279public:
9654754b 280 struct mem_location_hash : nofree_ptr_hash <mem_location>
2d44c7de
ML
281 {
282 static hashval_t
9654754b 283 hash (value_type l)
2d44c7de 284 {
93ef36dc 285 inchash::hash hstate;
2d44c7de 286
93ef36dc
ML
287 hstate.add_ptr ((const void *)l->m_filename);
288 hstate.add_ptr (l->m_function);
289 hstate.add_int (l->m_line);
2d44c7de 290
93ef36dc 291 return hstate.end ();
2d44c7de
ML
292 }
293
294 static bool
9654754b 295 equal (value_type l1, value_type l2)
2d44c7de 296 {
93ef36dc
ML
297 return (l1->m_filename == l2->m_filename
298 && l1->m_function == l2->m_function
299 && l1->m_line == l2->m_line);
2d44c7de
ML
300 }
301 };
302
303 /* Internal class type definitions. */
fb5c464a 304 typedef hash_map <mem_location_hash, T *> mem_map_t;
9654754b 305 typedef hash_map <const void *, mem_usage_pair<T> > reverse_mem_map_t;
2d44c7de
ML
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. */
93ef36dc 316 bool contains_descriptor_for_instance (const void *ptr);
2d44c7de
ML
317
318 /* Return descriptor for instance PTR. */
9cfc08c0 319 T *get_descriptor_for_instance (const void *ptr);
2d44c7de 320
ac059261
ML
321 /* Register memory allocation descriptor for container PTR which is
322 described by a memory LOCATION. */
9cfc08c0 323 T *register_descriptor (const void *ptr, mem_location *location);
ac059261
ML
324
325 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
2d44c7de 326 type of container and GGC identifes if the allocation is handled in GGC
ac059261 327 memory. Each location is identified by file NAME, LINE in source code and
2d44c7de 328 FUNCTION name. */
9cfc08c0
ML
329 T *register_descriptor (const void *ptr, mem_alloc_origin origin,
330 bool ggc, const char *name, int line,
331 const char *function);
2d44c7de
ML
332
333 /* Register instance overhead identified by PTR pointer. Allocation takes
334 SIZE bytes. */
9cfc08c0 335 T *register_instance_overhead (size_t size, const void *ptr);
2d44c7de
ML
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. */
93ef36dc 340 void register_object_overhead (T *usage, size_t size, const void *ptr);
2d44c7de
ML
341
342 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
00e6775a
ML
343 remove the instance from reverse map. Return memory usage that belongs
344 to this memory description. */
9cfc08c0
ML
345 T *release_instance_overhead (void *ptr, size_t size,
346 bool remove_from_map = false);
2d44c7de 347
a6f36166 348 /* Release instance object identified by PTR pointer. */
93ef36dc 349 void release_object_overhead (void *ptr);
2d44c7de 350
a6f36166
JM
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
2d44c7de 357 /* Get sum value for ORIGIN type of allocation for the descriptor. */
93ef36dc 358 T get_sum (mem_alloc_origin origin);
2d44c7de
ML
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. */
c5281d50 364 mem_list_t *get_list (mem_alloc_origin origin, unsigned *length);
2d44c7de
ML
365
366 /* Dump all tracked instances of type ORIGIN. If we want to process custom
367 order, CMP comparator can be provided. */
c5281d50 368 void dump (mem_alloc_origin origin);
2d44c7de
ML
369
370 /* Reverse object map used for every object allocation mapping. */
371 reverse_object_map_t *m_reverse_object_map;
372
373private:
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
2d44c7de
ML
389/* Returns true if instance PTR is registered by the memory description. */
390
391template <class T>
392inline bool
393mem_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
400template <class T>
401inline T*
402mem_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
93ef36dc
ML
407/* Register memory allocation descriptor for container PTR which is
408 described by a memory LOCATION. */
2d44c7de
ML
409
410template <class T>
411inline T*
412mem_alloc_description<T>::register_descriptor (const void *ptr,
ac059261 413 mem_location *location)
2d44c7de 414{
2d44c7de
ML
415 T *usage = NULL;
416
ac059261 417 T **slot = m_map->get (location);
2d44c7de
ML
418 if (slot)
419 {
ac059261 420 delete location;
2d44c7de 421 usage = *slot;
ac059261 422 usage->m_instances++;
2d44c7de
ML
423 }
424 else
425 {
426 usage = new T ();
ac059261 427 m_map->put (location, usage);
2d44c7de
ML
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
ac059261
ML
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
441template <class T>
442inline T*
443mem_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
2d44c7de
ML
454/* Register instance overhead identified by PTR pointer. Allocation takes
455 SIZE bytes. */
456
457template <class T>
458inline T*
459mem_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
479template <class T>
480void
481mem_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
492template <class T>
493inline T*
494mem_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
509template <class T>
00e6775a 510inline T *
2d44c7de
ML
511mem_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. */
00e6775a 519 return NULL;
2d44c7de
ML
520 }
521
00e6775a
ML
522 T *usage = (*slot).usage;
523 usage->release_overhead (size);
2d44c7de
ML
524
525 if (remove_from_map)
526 m_reverse_map->remove (ptr);
00e6775a
ML
527
528 return usage;
2d44c7de
ML
529}
530
a6f36166 531/* Release instance object identified by PTR pointer. */
2d44c7de
ML
532
533template <class T>
534inline void
535mem_alloc_description<T>::release_object_overhead (void *ptr)
536{
537 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
5d24b4f2
JH
538 entry->first->release_overhead (entry->second);
539 m_reverse_object_map->remove (ptr);
2d44c7de
ML
540}
541
a6f36166
JM
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. */
546template <class T>
547inline void
548mem_alloc_description<T>::unregister_descriptor (void *ptr)
549{
550 m_reverse_map->remove (ptr);
551}
552
2d44c7de
ML
553/* Default contructor. */
554
555template <class T>
556inline
557mem_alloc_description<T>::mem_alloc_description ()
558{
ff7b3aa5
ML
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);
2d44c7de
ML
562}
563
564/* Default destructor. */
565
566template <class T>
567inline
568mem_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
587template <class T>
588inline
589typename mem_alloc_description<T>::mem_list_t *
c5281d50 590mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length)
2d44c7de
ML
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
c5281d50 603 qsort (list, i, element_size, T::compare);
2d44c7de
ML
604 *length = i;
605
606 return list;
607}
608
609/* Get sum value for ORIGIN type of allocation for the descriptor. */
610
611template <class T>
612inline T
613mem_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
630template <class T>
631inline void
c5281d50 632mem_alloc_description<T>::dump (mem_alloc_origin origin)
2d44c7de
ML
633{
634 unsigned length;
635
636 fprintf (stderr, "\n");
637
c5281d50 638 mem_list_t *list = get_list (origin, &length);
2d44c7de
ML
639 T total = get_sum (origin);
640
60448173 641 T::print_dash_line ();
2d44c7de 642 T::dump_header (mem_location::get_origin_name (origin));
60448173 643 T::print_dash_line ();
2d44c7de
ML
644 for (int i = length - 1; i >= 0; i--)
645 list[i].second->dump (list[i].first, total);
60448173 646 T::print_dash_line ();
2d44c7de 647
60448173
ML
648 T::dump_header (mem_location::get_origin_name (origin));
649 T::print_dash_line ();
2d44c7de 650 total.dump_footer ();
60448173 651 T::print_dash_line ();
2d44c7de
ML
652
653 XDELETEVEC (list);
654
655 fprintf (stderr, "\n");
656}
657
658#endif // GCC_MEM_STATS_H