GCC Middle and Back End API Reference
mem-stats.h
Go to the documentation of this file.
1/* A memory statistics tracking infrastructure.
2 Copyright (C) 2015-2026 Free Software Foundation, Inc.
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
21#ifndef GCC_MEM_STATS_H
22#define GCC_MEM_STATS_H
23
24/* Forward declaration. */
25template<typename Key, typename Value,
27 Value> >
28class hash_map;
29
30#define LOCATION_LINE_EXTRA_SPACE 30
31#define LOCATION_LINE_WIDTH 48
32
33/* Memory allocation location. */
35{
36public:
37 /* Default constructor. */
38 inline
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
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
61 {
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 *
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 *
94 {
95 unsigned l = strlen (get_trimmed_filename ()) + strlen (m_function)
97
98 char *s = XNEWVEC (char, l);
99 sprintf (s, "%s:%i (%s)", get_trimmed_filename (),
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 *
110 {
111 return mem_alloc_origin_names[(unsigned) origin];
112 }
113
114 /* File name of source code. */
115 const char *m_filename;
116 /* Function name. */
117 const char *m_function;
118 /* Line number in source code. */
120 /* Origin type. */
122 /* Flag if used by GGC allocation. */
123 bool m_ggc;
124};
125
126/* Memory usage register to a memory location. */
128{
129public:
130 /* Default constructor. */
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)
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. */
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),
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",
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. */
254 /* Number of allocations. */
255 size_t m_times;
256 /* Peak allocation in bytes. */
257 size_t m_peak;
258 /* Number of container instances. */
260};
261
262/* Memory usage pair that connects memory usage and number
263 of allocated bytes. */
264template <class T>
266{
267public:
268 mem_usage_pair (T *usage_, size_t allocated_): usage (usage_),
269 allocated (allocated_) {}
270
272 size_t allocated;
273};
274
275/* Memory allocation description. */
276template <class T>
278{
279
280 /* Constructor is private to enforce singleton. */
282
283 /* Destruction is not allowed, since we might be tracking
284 static objects with undefined destruction order. */
286
287public:
288
289 template<mem_alloc_origin>
290 static auto &instance ()
291 {
292 static const auto self = new mem_alloc_description;
293 return *self;
294 }
295
296 struct mem_location_hash : nofree_ptr_hash <mem_location>
297 {
298 static hashval_t
300 {
301 inchash::hash hstate;
302
303 hstate.add_ptr ((const void *)l->m_filename);
304 hstate.add_ptr (l->m_function);
305 hstate.add_int (l->m_line);
306
307 return hstate.end ();
308 }
309
310 static bool
312 {
313 return (l1->m_filename == l2->m_filename
314 && l1->m_function == l2->m_function
315 && l1->m_line == l2->m_line);
316 }
317 };
318
319 /* Internal class type definitions. */
320 typedef hash_map <mem_location_hash, T *> mem_map_t;
321 typedef hash_map <const void *, mem_usage_pair<T> > reverse_mem_map_t;
322 typedef hash_map <const void *, std::pair<T *, size_t> > reverse_object_map_t;
323 typedef std::pair <mem_location *, T *> mem_list_t;
324
325
326 /* Returns true if instance PTR is registered by the memory description. */
327 bool contains_descriptor_for_instance (const void *ptr);
328
329 /* Return descriptor for instance PTR. */
330 T *get_descriptor_for_instance (const void *ptr);
331
332 /* Register memory allocation descriptor for container PTR which is
333 described by a memory LOCATION. */
334 T *register_descriptor (const void *ptr, mem_location *location);
335
336 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
337 type of container and GGC identifies if the allocation is handled in GGC
338 memory. Each location is identified by file NAME, LINE in source code and
339 FUNCTION name. */
340 T *register_descriptor (const void *ptr, mem_alloc_origin origin,
341 bool ggc, const char *name, int line,
342 const char *function);
343
344 /* Register instance overhead identified by PTR pointer. Allocation takes
345 SIZE bytes. */
346 T *register_instance_overhead (size_t size, const void *ptr);
347
348 /* For containers (and GGC) where we want to track every instance object,
349 we register allocation of SIZE bytes, identified by PTR pointer, belonging
350 to USAGE descriptor. */
351 void register_object_overhead (T *usage, size_t size, const void *ptr);
352
353 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
354 remove the instance from reverse map. Return memory usage that belongs
355 to this memory description. */
356 T *release_instance_overhead (void *ptr, size_t size,
357 bool remove_from_map = false);
358
359 /* Release instance object identified by PTR pointer. */
360 void release_object_overhead (void *ptr);
361
362 /* Unregister a memory allocation descriptor registered with
363 register_descriptor (remove from reverse map), unless it is
364 unregistered through release_instance_overhead with
365 REMOVE_FROM_MAP = true. */
366 void unregister_descriptor (void *ptr);
367
368 /* Get sum value for ORIGIN type of allocation for the descriptor. */
369 T get_sum (mem_alloc_origin origin);
370
371 /* Get all tracked instances registered by the description. Items
372 are filtered by ORIGIN type, LENGTH is return value where we register
373 the number of elements in the list. If we want to process custom order,
374 CMP comparator can be provided. */
375 mem_list_t *get_list (mem_alloc_origin origin, unsigned *length);
376
377 /* Dump all tracked instances of type ORIGIN. If we want to process custom
378 order, CMP comparator can be provided. */
379 void dump (mem_alloc_origin origin);
380
381 /* Reverse object map used for every object allocation mapping. */
383
384private:
385 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
386 in NAME source file, at LINE in source code, in FUNCTION. */
387 T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
388 int line, const char *function, const void *ptr);
389
390 /* Allocation location coupled to the description. */
392
393 /* Location to usage mapping. */
395
396 /* Reverse pointer to usage mapping. */
398};
399
400/* Returns true if instance PTR is registered by the memory description. */
401
402template <class T>
403inline bool
405{
406 return m_reverse_map->get (ptr);
407}
408
409/* Return descriptor for instance PTR. */
410
411template <class T>
412inline T*
414{
415 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
416}
417
418/* Register memory allocation descriptor for container PTR which is
419 described by a memory LOCATION. */
420
421template <class T>
422inline T*
424 mem_location *location)
425{
426 T *usage = NULL;
427
428 T **slot = m_map->get (location);
429 if (slot)
430 {
431 delete location;
432 usage = *slot;
433 usage->m_instances++;
434 }
435 else
436 {
437 usage = new T ();
438 m_map->put (location, usage);
439 }
440
441 if (!m_reverse_map->get (ptr))
442 m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
443
444 return usage;
445}
446
447/* Register memory allocation descriptor for container PTR. ORIGIN identifies
448 type of container and GGC identifies if the allocation is handled in GGC
449 memory. Each location is identified by file NAME, LINE in source code and
450 FUNCTION name. */
451
452template <class T>
453inline T*
455 mem_alloc_origin origin,
456 bool ggc,
457 const char *filename,
458 int line,
459 const char *function)
460{
461 mem_location *l = new mem_location (origin, ggc, filename, line, function);
462 return register_descriptor (ptr, l);
463}
464
465/* Register instance overhead identified by PTR pointer. Allocation takes
466 SIZE bytes. */
467
468template <class T>
469inline T*
471 const void *ptr)
472{
473 mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
474 if (!slot)
475 {
476 /* Due to PCH, it can really happen. */
477 return NULL;
478 }
479
480 T *usage = (*slot).usage;
481 usage->register_overhead (size);
482
483 return usage;
484}
485
486/* For containers (and GGC) where we want to track every instance object,
487 we register allocation of SIZE bytes, identified by PTR pointer, belonging
488 to USAGE descriptor. */
489
490template <class T>
491void
493 const void *ptr)
494{
495 /* In case of GGC, it is possible to have already occupied the memory
496 location. */
497 m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
498}
499
500/* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
501 in NAME source file, at LINE in source code, in FUNCTION. */
502
503template <class T>
504inline T*
506 mem_alloc_origin origin,
507 const char *filename,
508 int line,
509 const char *function,
510 const void *ptr)
511{
512 T *usage = register_descriptor (ptr, origin, filename, line, function);
513 usage->register_overhead (size);
514
515 return usage;
516}
517
518/* Release PTR pointer of SIZE bytes. */
519
520template <class T>
521inline T *
523 bool remove_from_map)
524{
526
527 if (!slot)
528 {
529 /* Due to PCH, it can really happen. */
530 return NULL;
531 }
532
533 T *usage = (*slot).usage;
534 usage->release_overhead (size);
535
536 if (remove_from_map)
537 m_reverse_map->remove (ptr);
538
539 return usage;
540}
541
542/* Release instance object identified by PTR pointer. */
543
544template <class T>
545inline void
547{
548 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
549 if (!entry)
550 return;
551 entry->first->release_overhead (entry->second);
552 m_reverse_object_map->remove (ptr);
553}
554
555/* Unregister a memory allocation descriptor registered with
556 register_descriptor (remove from reverse map), unless it is
557 unregistered through release_instance_overhead with
558 REMOVE_FROM_MAP = true. */
559template <class T>
560inline void
562{
563 m_reverse_map->remove (ptr);
564}
565
566/* Default constructor. */
567
568template <class T>
569inline
571{
572 /* Note it is important to pass false for the 4th argument (GATHER_MEM_STATS)
573 to avoid infinite recursion in instance (). */
574 m_map = new mem_map_t (13, false, false, false);
575 m_reverse_map = new reverse_mem_map_t (13, false, false, false);
576 m_reverse_object_map = new reverse_object_map_t (13, false, false, false);
577}
578
579/* Get all tracked instances registered by the description. Items are filtered
580 by ORIGIN type, LENGTH is return value where we register the number of
581 elements in the list. If we want to process custom order, CMP comparator
582 can be provided. */
583
584template <class T>
585inline
588{
589 /* vec data structure is not used because all vectors generate memory
590 allocation info a it would create a cycle. */
591 size_t element_size = sizeof (mem_list_t);
592 mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ());
593 unsigned i = 0;
594
595 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
596 ++it)
597 if ((*it).first->m_origin == origin)
598 list[i++] = std::pair<mem_location*, T*> (*it);
599
600 qsort (list, i, element_size, T::compare);
601 *length = i;
602
603 return list;
604}
605
606/* Get sum value for ORIGIN type of allocation for the descriptor. */
607
608template <class T>
609inline T
611{
612 unsigned length;
613 mem_list_t *list = get_list (origin, &length);
614 T sum;
615
616 for (unsigned i = 0; i < length; i++)
617 sum = sum + *list[i].second;
618
619 XDELETEVEC (list);
620
621 return sum;
622}
623
624/* Dump all tracked instances of type ORIGIN. If we want to process custom
625 order, CMP comparator can be provided. */
626
627template <class T>
628inline void
630{
631 unsigned length;
632
633 fprintf (stderr, "\n");
634
635 mem_list_t *list = get_list (origin, &length);
636 T total = get_sum (origin);
637
638 T::print_dash_line ();
639 T::dump_header (mem_location::get_origin_name (origin));
640 T::print_dash_line ();
641 for (int i = length - 1; i >= 0; i--)
642 list[i].second->dump (list[i].first, total);
643 T::print_dash_line ();
644
645 T::dump_header (mem_location::get_origin_name (origin));
646 T::print_dash_line ();
647 total.dump_footer ();
648 T::print_dash_line ();
649
650 XDELETEVEC (list);
651
652 fprintf (stderr, "\n");
653}
654
655#endif // GCC_MEM_STATS_H
Definition hash-map.h:40
Definition inchash.h:38
void add_int(unsigned v)
Definition inchash.h:55
hashval_t end() const
Definition inchash.h:49
void add_ptr(const void *ptr)
Definition inchash.h:94
T get_sum(mem_alloc_origin origin)
Definition mem-stats.h:610
void dump(mem_alloc_origin origin)
Definition mem-stats.h:629
hash_map< const void *, std::pair< T *, size_t > > reverse_object_map_t
Definition mem-stats.h:322
void register_object_overhead(T *usage, size_t size, const void *ptr)
Definition mem-stats.h:492
static auto & instance()
Definition mem-stats.h:290
hash_map< mem_location_hash, T * > mem_map_t
Definition mem-stats.h:320
std::pair< mem_location *, T * > mem_list_t
Definition mem-stats.h:323
T * register_descriptor(const void *ptr, mem_location *location)
Definition mem-stats.h:423
void unregister_descriptor(void *ptr)
Definition mem-stats.h:561
reverse_object_map_t * m_reverse_object_map
Definition mem-stats.h:382
mem_location m_location
Definition mem-stats.h:391
reverse_mem_map_t * m_reverse_map
Definition mem-stats.h:397
~mem_alloc_description()=delete
T * register_overhead(size_t size, mem_alloc_origin origin, const char *name, int line, const char *function, const void *ptr)
Definition mem-stats.h:505
T * register_instance_overhead(size_t size, const void *ptr)
Definition mem-stats.h:470
void release_object_overhead(void *ptr)
Definition mem-stats.h:546
bool contains_descriptor_for_instance(const void *ptr)
Definition mem-stats.h:404
T * release_instance_overhead(void *ptr, size_t size, bool remove_from_map=false)
Definition mem-stats.h:522
mem_map_t * m_map
Definition mem-stats.h:394
hash_map< const void *, mem_usage_pair< T > > reverse_mem_map_t
Definition mem-stats.h:321
mem_alloc_description()
Definition mem-stats.h:570
mem_list_t * get_list(mem_alloc_origin origin, unsigned *length)
Definition mem-stats.h:587
T * get_descriptor_for_instance(const void *ptr)
Definition mem-stats.h:413
Definition mem-stats.h:35
char * to_string()
Definition mem-stats.h:93
const char * m_filename
Definition mem-stats.h:115
int equal(const mem_location &other)
Definition mem-stats.h:73
int m_line
Definition mem-stats.h:119
static const char * get_origin_name(mem_alloc_origin origin)
Definition mem-stats.h:109
mem_location()
Definition mem-stats.h:39
mem_location(mem_location &other)
Definition mem-stats.h:51
hashval_t hash()
Definition mem-stats.h:60
mem_alloc_origin m_origin
Definition mem-stats.h:121
bool m_ggc
Definition mem-stats.h:123
const char * m_function
Definition mem-stats.h:117
const char * get_trimmed_filename()
Definition mem-stats.h:81
mem_location(mem_alloc_origin origin, bool ggc, const char *filename=NULL, int line=0, const char *function=NULL)
Definition mem-stats.h:43
Definition mem-stats.h:266
size_t allocated
Definition mem-stats.h:272
T * usage
Definition mem-stats.h:271
mem_usage_pair(T *usage_, size_t allocated_)
Definition mem-stats.h:268
Definition mem-stats.h:128
mem_usage(size_t allocated, size_t times, size_t peak, size_t instances=0)
Definition mem-stats.h:134
static void dump_header(const char *name)
Definition mem-stats.h:246
bool operator==(const mem_usage &second) const
Definition mem-stats.h:170
static void print_dash_line(size_t count=140)
Definition mem-stats.h:237
void dump_footer() const
Definition mem-stats.h:222
void register_overhead(size_t size)
Definition mem-stats.h:140
static int compare(const void *first, const void *second)
Definition mem-stats.h:191
mem_usage()
Definition mem-stats.h:131
size_t m_allocated
Definition mem-stats.h:253
size_t m_peak
Definition mem-stats.h:257
mem_usage operator+(const mem_usage &second)
Definition mem-stats.h:160
bool operator<(const mem_usage &second) const
Definition mem-stats.h:179
size_t m_instances
Definition mem-stats.h:259
void dump(mem_location *loc, const mem_usage &total) const
Definition mem-stats.h:206
size_t m_times
Definition mem-stats.h:255
void release_overhead(size_t size)
Definition mem-stats.h:151
static float get_percent(size_t nominator, size_t denominator)
Definition mem-stats.h:230
Definition lra-spills.cc:101
static unsigned int count[debug_counter_number_of_counters]
Definition dbgcnt.cc:50
static void usage(void)
Definition gencheck.cc:39
static struct token T
Definition gengtype-parse.cc:45
free(str)
mem_alloc_origin
Definition mem-stats-traits.h:26
static const char * mem_alloc_origin_names[]
Definition mem-stats-traits.h:38
#define LOCATION_LINE_EXTRA_SPACE
Definition mem-stats.h:30
#define LOCATION_LINE_WIDTH
Definition mem-stats.h:31
i
Definition poly-int.h:776
fputc('\n', stderr)
Definition function.h:249
static hashval_t hash(value_type l)
Definition mem-stats.h:299
static bool equal(value_type l1, value_type l2)
Definition mem-stats.h:311
Definition hash-traits.h:303
mem_location * value_type
Definition hash-traits.h:169
Definition hash-map-traits.h:33
#define NULL
Definition system.h:58
#define gcc_assert(EXPR)
Definition system.h:828
#define qsort(...)
Definition system.h:1221
#define SIZE_AMOUNT(size)
Definition system.h:1247
#define MIN(X, Y)
Definition system.h:410
#define PRsa(n)
Definition system.h:1251