]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/mem-stats.h
Update copyright years.
[thirdparty/gcc.git] / gcc / mem-stats.h
CommitLineData
0b2e1bfa 1/* A memory statistics tracking infrastructure.
a5544970 2 Copyright (C) 2015-2019 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
ML
33/* Memory allocation location. */
34struct mem_location
35{
36 /* Default constructor. */
80a4fe78
ML
37 inline
38 mem_location () {}
2d44c7de
ML
39
40 /* Constructor. */
80a4fe78
ML
41 inline
42 mem_location (mem_alloc_origin origin, bool ggc,
ac059261
ML
43 const char *filename = NULL, int line = 0,
44 const char *function = NULL):
2d44c7de
ML
45 m_filename (filename), m_function (function), m_line (line), m_origin
46 (origin), m_ggc (ggc) {}
47
ac059261 48 /* Copy constructor. */
80a4fe78
ML
49 inline
50 mem_location (mem_location &other): m_filename (other.m_filename),
ac059261
ML
51 m_function (other.m_function), m_line (other.m_line),
52 m_origin (other.m_origin), m_ggc (other.m_ggc) {}
53
2d44c7de
ML
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. */
80a4fe78
ML
58 hashval_t
59 hash ()
2d44c7de
ML
60 {
61 inchash::hash hash;
62
63 hash.add_ptr (m_filename);
64 hash.add_ptr (m_function);
65 hash.add_int (m_line);
66
67 return hash.end ();
68 }
69
70 /* Return true if the memory location is equal to OTHER. */
80a4fe78
ML
71 int
72 equal (mem_location &other)
2d44c7de
ML
73 {
74 return m_filename == other.m_filename && m_function == other.m_function
75 && m_line == other.m_line;
76 }
77
78 /* Return trimmed filename for the location. */
80a4fe78
ML
79 inline const char *
80 get_trimmed_filename ()
2d44c7de
ML
81 {
82 const char *s1 = m_filename;
83 const char *s2;
84
85 while ((s2 = strstr (s1, "gcc/")))
86 s1 = s2 + 4;
87
88 return s1;
89 }
90
80a4fe78
ML
91 inline char *
92 to_string ()
ac059261
ML
93 {
94 unsigned l = strlen (get_trimmed_filename ()) + strlen (m_function)
95 + LOCATION_LINE_EXTRA_SPACE;
96
97 char *s = XNEWVEC (char, l);
98 sprintf (s, "%s:%i (%s)", get_trimmed_filename (),
99 m_line, m_function);
100
101 s[MIN (LOCATION_LINE_WIDTH, l - 1)] = '\0';
102
103 return s;
104 }
105
2d44c7de 106 /* Return display name associated to ORIGIN type. */
80a4fe78
ML
107 static const char *
108 get_origin_name (mem_alloc_origin origin)
2d44c7de
ML
109 {
110 return mem_alloc_origin_names[(unsigned) origin];
111 }
112
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;
123};
124
125/* Memory usage register to a memory location. */
126struct mem_usage
127{
128 /* Default constructor. */
ac059261 129 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
2d44c7de
ML
130
131 /* Constructor. */
ac059261
ML
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) {}
2d44c7de
ML
135
136 /* Register overhead of SIZE bytes. */
80a4fe78
ML
137 inline void
138 register_overhead (size_t size)
2d44c7de
ML
139 {
140 m_allocated += size;
141 m_times++;
142
143 if (m_peak < m_allocated)
144 m_peak = m_allocated;
145 }
146
147 /* Release overhead of SIZE bytes. */
80a4fe78
ML
148 inline void
149 release_overhead (size_t size)
2d44c7de
ML
150 {
151 gcc_assert (size <= m_allocated);
152
153 m_allocated -= size;
154 }
155
156 /* Sum the usage with SECOND usage. */
80a4fe78
ML
157 mem_usage
158 operator+ (const mem_usage &second)
2d44c7de
ML
159 {
160 return mem_usage (m_allocated + second.m_allocated,
161 m_times + second.m_times,
ac059261
ML
162 m_peak + second.m_peak,
163 m_instances + second.m_instances);
2d44c7de
ML
164 }
165
b27b31dc
ML
166 /* Equality operator. */
167 inline bool
168 operator== (const mem_usage &second) const
169 {
170 return (m_allocated == second.m_allocated
171 && m_peak == second.m_peak
2c2f8674 172 && m_times == second.m_times);
b27b31dc
ML
173 }
174
2d44c7de 175 /* Comparison operator. */
80a4fe78
ML
176 inline bool
177 operator< (const mem_usage &second) const
2d44c7de 178 {
b27b31dc
ML
179 if (*this == second)
180 return false;
181
2d44c7de
ML
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);
185 }
186
187 /* Compare wrapper used by qsort method. */
80a4fe78
ML
188 static int
189 compare (const void *first, const void *second)
2d44c7de
ML
190 {
191 typedef std::pair<mem_location *, mem_usage *> mem_pair_t;
192
193 const mem_pair_t f = *(const mem_pair_t *)first;
194 const mem_pair_t s = *(const mem_pair_t *)second;
195
b27b31dc
ML
196 if (*f.second == *s.second)
197 return 0;
198
199 return *f.second < *s.second ? 1 : -1;
2d44c7de
ML
200 }
201
202 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
80a4fe78
ML
203 inline void
204 dump (mem_location *loc, mem_usage &total) const
2d44c7de 205 {
ac059261 206 char *location_string = loc->to_string ();
2d44c7de 207
a0b48080
MM
208 fprintf (stderr, "%-48s " PRsa (9) ":%5.1f%%"
209 PRsa (9) PRsa (9) ":%5.1f%%%10s\n",
40ce7fa6 210 location_string, SIZE_AMOUNT (m_allocated),
43331dfb 211 get_percent (m_allocated, total.m_allocated),
40ce7fa6 212 SIZE_AMOUNT (m_peak), SIZE_AMOUNT (m_times),
2d44c7de 213 get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap");
ac059261
ML
214
215 free (location_string);
2d44c7de
ML
216 }
217
218 /* Dump footer. */
80a4fe78
ML
219 inline void
220 dump_footer () const
2d44c7de
ML
221 {
222 print_dash_line ();
a0b48080 223 fprintf (stderr, "%s" PRsa (53) PRsa (26) "\n", "Total",
40ce7fa6 224 SIZE_AMOUNT (m_allocated), SIZE_AMOUNT (m_times));
2d44c7de
ML
225 print_dash_line ();
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");
250 print_dash_line ();
251 }
252
253 /* Current number of allocated bytes. */
254 size_t m_allocated;
255 /* Number of allocations. */
256 size_t m_times;
257 /* Peak allocation in bytes. */
258 size_t m_peak;
ac059261
ML
259 /* Number of container instances. */
260 size_t m_instances;
2d44c7de
ML
261};
262
263/* Memory usage pair that connectes memory usage and number
264 of allocated bytes. */
265template <class T>
266struct mem_usage_pair
267{
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
ML
347
348 /* Release intance object identified by PTR pointer. */
93ef36dc 349 void release_object_overhead (void *ptr);
2d44c7de
ML
350
351 /* Get sum value for ORIGIN type of allocation for the descriptor. */
93ef36dc 352 T get_sum (mem_alloc_origin origin);
2d44c7de
ML
353
354 /* Get all tracked instances registered by the description. Items
355 are filtered by ORIGIN type, LENGTH is return value where we register
356 the number of elements in the list. If we want to process custom order,
357 CMP comparator can be provided. */
9cfc08c0
ML
358 mem_list_t *get_list (mem_alloc_origin origin, unsigned *length,
359 int (*cmp) (const void *first,
360 const void *second) = NULL);
2d44c7de
ML
361
362 /* Dump all tracked instances of type ORIGIN. If we want to process custom
363 order, CMP comparator can be provided. */
364 void dump (mem_alloc_origin origin,
365 int (*cmp) (const void *first, const void *second) = NULL);
366
367 /* Reverse object map used for every object allocation mapping. */
368 reverse_object_map_t *m_reverse_object_map;
369
370private:
371 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
372 in NAME source file, at LINE in source code, in FUNCTION. */
373 T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
374 int line, const char *function, const void *ptr);
375
376 /* Allocation location coupled to the description. */
377 mem_location m_location;
378
379 /* Location to usage mapping. */
380 mem_map_t *m_map;
381
382 /* Reverse pointer to usage mapping. */
383 reverse_mem_map_t *m_reverse_map;
384};
385
2d44c7de
ML
386/* Returns true if instance PTR is registered by the memory description. */
387
388template <class T>
389inline bool
390mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
391{
392 return m_reverse_map->get (ptr);
393}
394
395/* Return descriptor for instance PTR. */
396
397template <class T>
398inline T*
399mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
400{
401 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
402}
403
93ef36dc
ML
404/* Register memory allocation descriptor for container PTR which is
405 described by a memory LOCATION. */
2d44c7de
ML
406
407template <class T>
408inline T*
409mem_alloc_description<T>::register_descriptor (const void *ptr,
ac059261 410 mem_location *location)
2d44c7de 411{
2d44c7de
ML
412 T *usage = NULL;
413
ac059261 414 T **slot = m_map->get (location);
2d44c7de
ML
415 if (slot)
416 {
ac059261 417 delete location;
2d44c7de 418 usage = *slot;
ac059261 419 usage->m_instances++;
2d44c7de
ML
420 }
421 else
422 {
423 usage = new T ();
ac059261 424 m_map->put (location, usage);
2d44c7de
ML
425 }
426
427 if (!m_reverse_map->get (ptr))
428 m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
429
430 return usage;
431}
432
ac059261
ML
433/* Register memory allocation descriptor for container PTR. ORIGIN identifies
434 type of container and GGC identifes if the allocation is handled in GGC
435 memory. Each location is identified by file NAME, LINE in source code and
436 FUNCTION name. */
437
438template <class T>
439inline T*
440mem_alloc_description<T>::register_descriptor (const void *ptr,
441 mem_alloc_origin origin,
442 bool ggc,
443 const char *filename,
444 int line,
445 const char *function)
446{
447 mem_location *l = new mem_location (origin, ggc, filename, line, function);
448 return register_descriptor (ptr, l);
449}
450
2d44c7de
ML
451/* Register instance overhead identified by PTR pointer. Allocation takes
452 SIZE bytes. */
453
454template <class T>
455inline T*
456mem_alloc_description<T>::register_instance_overhead (size_t size,
457 const void *ptr)
458{
459 mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
460 if (!slot)
461 {
462 /* Due to PCH, it can really happen. */
463 return NULL;
464 }
465
466 T *usage = (*slot).usage;
467 usage->register_overhead (size);
468
469 return usage;
470}
471
472/* For containers (and GGC) where we want to track every instance object,
473 we register allocation of SIZE bytes, identified by PTR pointer, belonging
474 to USAGE descriptor. */
475
476template <class T>
477void
478mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
479 const void *ptr)
480{
481 /* In case of GGC, it is possible to have already occupied the memory
482 location. */
483 m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
484}
485
486/* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
487 in NAME source file, at LINE in source code, in FUNCTION. */
488
489template <class T>
490inline T*
491mem_alloc_description<T>::register_overhead (size_t size,
492 mem_alloc_origin origin,
493 const char *filename,
494 int line,
495 const char *function,
496 const void *ptr)
497{
498 T *usage = register_descriptor (ptr, origin, filename, line, function);
499 usage->register_overhead (size);
500
501 return usage;
502}
503
504/* Release PTR pointer of SIZE bytes. */
505
506template <class T>
00e6775a 507inline T *
2d44c7de
ML
508mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size,
509 bool remove_from_map)
510{
511 mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
512
513 if (!slot)
514 {
515 /* Due to PCH, it can really happen. */
00e6775a 516 return NULL;
2d44c7de
ML
517 }
518
00e6775a
ML
519 T *usage = (*slot).usage;
520 usage->release_overhead (size);
2d44c7de
ML
521
522 if (remove_from_map)
523 m_reverse_map->remove (ptr);
00e6775a
ML
524
525 return usage;
2d44c7de
ML
526}
527
528/* Release intance object identified by PTR pointer. */
529
530template <class T>
531inline void
532mem_alloc_description<T>::release_object_overhead (void *ptr)
533{
534 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
535 if (entry)
536 {
537 entry->first->release_overhead (entry->second);
538 m_reverse_object_map->remove (ptr);
539 }
540}
541
542/* Default contructor. */
543
544template <class T>
545inline
546mem_alloc_description<T>::mem_alloc_description ()
547{
548 m_map = new mem_map_t (13, false, false);
549 m_reverse_map = new reverse_mem_map_t (13, false, false);
550 m_reverse_object_map = new reverse_object_map_t (13, false, false);
551}
552
553/* Default destructor. */
554
555template <class T>
556inline
557mem_alloc_description<T>::~mem_alloc_description ()
558{
559 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
560 ++it)
561 {
562 delete (*it).first;
563 delete (*it).second;
564 }
565
566 delete m_map;
567 delete m_reverse_map;
568 delete m_reverse_object_map;
569}
570
571/* Get all tracked instances registered by the description. Items are filtered
572 by ORIGIN type, LENGTH is return value where we register the number of
573 elements in the list. If we want to process custom order, CMP comparator
574 can be provided. */
575
576template <class T>
577inline
578typename mem_alloc_description<T>::mem_list_t *
579mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length,
93ef36dc
ML
580 int (*cmp) (const void *first,
581 const void *second))
2d44c7de
ML
582{
583 /* vec data structure is not used because all vectors generate memory
584 allocation info a it would create a cycle. */
585 size_t element_size = sizeof (mem_list_t);
586 mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ());
587 unsigned i = 0;
588
589 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
590 ++it)
591 if ((*it).first->m_origin == origin)
592 list[i++] = std::pair<mem_location*, T*> (*it);
593
594 qsort (list, i, element_size, cmp == NULL ? T::compare : cmp);
595 *length = i;
596
597 return list;
598}
599
600/* Get sum value for ORIGIN type of allocation for the descriptor. */
601
602template <class T>
603inline T
604mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
605{
606 unsigned length;
607 mem_list_t *list = get_list (origin, &length);
608 T sum;
609
610 for (unsigned i = 0; i < length; i++)
611 sum = sum + *list[i].second;
612
613 XDELETEVEC (list);
614
615 return sum;
616}
617
618/* Dump all tracked instances of type ORIGIN. If we want to process custom
619 order, CMP comparator can be provided. */
620
621template <class T>
622inline void
623mem_alloc_description<T>::dump (mem_alloc_origin origin,
624 int (*cmp) (const void *first,
625 const void *second))
626{
627 unsigned length;
628
629 fprintf (stderr, "\n");
630
631 mem_list_t *list = get_list (origin, &length, cmp);
632 T total = get_sum (origin);
633
634 T::dump_header (mem_location::get_origin_name (origin));
635 for (int i = length - 1; i >= 0; i--)
636 list[i].second->dump (list[i].first, total);
637
638 total.dump_footer ();
639
640 XDELETEVEC (list);
641
642 fprintf (stderr, "\n");
643}
644
645#endif // GCC_MEM_STATS_H