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-2024 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
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. */
61 {
63
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 /* Funcation 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),
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",
215 get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap");
216
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 connectes memory usage and number
263 of allocated bytes. */
264template <class T>
266{
267public:
270
272 size_t allocated;
273};
274
275/* Memory allocation description. */
276template <class T>
278{
279public:
280 struct mem_location_hash : nofree_ptr_hash <mem_location>
281 {
282 static hashval_t
284 {
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
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. */
307 typedef std::pair <mem_location *, T *> mem_list_t;
308
309 /* Default contructor. */
311
312 /* Default destructor. */
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. */
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. */
381
382 /* Location to usage mapping. */
384
385 /* Reverse pointer to usage mapping. */
387};
388
389/* Returns true if instance PTR is registered by the memory description. */
390
391template <class T>
392inline bool
394{
395 return m_reverse_map->get (ptr);
396}
397
398/* Return descriptor for instance PTR. */
399
400template <class T>
401inline T*
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
410template <class T>
411inline T*
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
441template <class T>
442inline T*
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
457template <class T>
458inline T*
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
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*
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>
510inline T *
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
533template <class T>
534inline void
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. */
546template <class T>
547inline void
549{
550 m_reverse_map->remove (ptr);
551}
552
553/* Default contructor. */
554
555template <class T>
556inline
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
566template <class T>
567inline
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
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
611template <class T>
612inline T
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
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
Definition hash-map.h:255
Definition hash-map.h:40
Value * get(const Key &k)
Definition hash-map.h:189
Definition inchash.h:38
void add_ptr(const void *ptr)
Definition inchash.h:94
Definition mem-stats.h:278
T get_sum(mem_alloc_origin origin)
Definition mem-stats.h:613
void dump(mem_alloc_origin origin)
Definition mem-stats.h:632
hash_map< const void *, std::pair< T *, size_t > > reverse_object_map_t
Definition mem-stats.h:306
void register_object_overhead(T *usage, size_t size, const void *ptr)
Definition mem-stats.h:481
hash_map< mem_location_hash, T * > mem_map_t
Definition mem-stats.h:304
std::pair< mem_location *, T * > mem_list_t
Definition mem-stats.h:307
T * register_descriptor(const void *ptr, mem_location *location)
Definition mem-stats.h:412
~mem_alloc_description()
Definition mem-stats.h:568
void unregister_descriptor(void *ptr)
Definition mem-stats.h:548
reverse_object_map_t * m_reverse_object_map
Definition mem-stats.h:371
mem_location m_location
Definition mem-stats.h:380
reverse_mem_map_t * m_reverse_map
Definition mem-stats.h:386
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:494
T * register_instance_overhead(size_t size, const void *ptr)
Definition mem-stats.h:459
void release_object_overhead(void *ptr)
Definition mem-stats.h:535
bool contains_descriptor_for_instance(const void *ptr)
Definition mem-stats.h:393
T * release_instance_overhead(void *ptr, size_t size, bool remove_from_map=false)
Definition mem-stats.h:511
mem_map_t * m_map
Definition mem-stats.h:383
hash_map< const void *, mem_usage_pair< T > > reverse_mem_map_t
Definition mem-stats.h:305
mem_alloc_description()
Definition mem-stats.h:557
mem_list_t * get_list(mem_alloc_origin origin, unsigned *length)
Definition mem-stats.h:590
T * get_descriptor_for_instance(const void *ptr)
Definition mem-stats.h:402
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)
T * ggc_alloc(ALONE_CXX_MEM_STAT_INFO)
Definition ggc.h:184
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:772
fputc('\n', stderr)
Definition function.h:249
static hashval_t hash(value_type l)
Definition mem-stats.h:283
static bool equal(value_type l1, value_type l2)
Definition mem-stats.h:295
Definition hash-traits.h:303
Type * value_type
Definition hash-traits.h:169
Definition hash-map-traits.h:33
#define NULL
Definition system.h:50
#define gcc_assert(EXPR)
Definition system.h:821
#define qsort(...)
Definition system.h:1263
#define SIZE_AMOUNT(size)
Definition system.h:1289
#define MIN(X, Y)
Definition system.h:392
#define PRsa(n)
Definition system.h:1293