]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/mem-stats.h
[6/6] Preprocessor forced macro location
[thirdparty/gcc.git] / gcc / mem-stats.h
CommitLineData
0b2e1bfa 1/* A memory statistics tracking infrastructure.
85ec4feb 2 Copyright (C) 2015-2018 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
43331dfb
RB
208 fprintf (stderr, "%-48s %10" PRIu64 ":%5.1f%%"
209 "%10" PRIu64 "%10" PRIu64 ":%5.1f%%%10s\n",
210 location_string, (uint64_t)m_allocated,
211 get_percent (m_allocated, total.m_allocated),
212 (uint64_t)m_peak, (uint64_t)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 ();
43331dfb
RB
223 fprintf (stderr, "%s%54" PRIu64 "%27" PRIu64 "\n", "Total",
224 (uint64_t)m_allocated, (uint64_t)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
ML
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
9654754b 295 equal (value_type l1, value_type l2)
2d44c7de
ML
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. */
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. */
80a4fe78
ML
316 bool
317 contains_descriptor_for_instance (const void *ptr);
2d44c7de
ML
318
319 /* Return descriptor for instance PTR. */
80a4fe78
ML
320 T *
321 get_descriptor_for_instance (const void *ptr);
2d44c7de 322
ac059261
ML
323 /* Register memory allocation descriptor for container PTR which is
324 described by a memory LOCATION. */
80a4fe78
ML
325 T *
326 register_descriptor (const void *ptr, mem_location *location);
ac059261
ML
327
328 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
2d44c7de 329 type of container and GGC identifes if the allocation is handled in GGC
ac059261 330 memory. Each location is identified by file NAME, LINE in source code and
2d44c7de 331 FUNCTION name. */
80a4fe78
ML
332 T *
333 register_descriptor (const void *ptr, mem_alloc_origin origin,
2d44c7de
ML
334 bool ggc, const char *name, int line,
335 const char *function);
336
337 /* Register instance overhead identified by PTR pointer. Allocation takes
338 SIZE bytes. */
80a4fe78
ML
339 T *
340 register_instance_overhead (size_t size, const void *ptr);
2d44c7de
ML
341
342 /* For containers (and GGC) where we want to track every instance object,
343 we register allocation of SIZE bytes, identified by PTR pointer, belonging
344 to USAGE descriptor. */
80a4fe78
ML
345 void
346 register_object_overhead (T *usage, size_t size, const void *ptr);
2d44c7de
ML
347
348 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
349 remove the instance from reverse map. */
80a4fe78
ML
350 void
351 release_instance_overhead (void *ptr, size_t size,
2d44c7de
ML
352 bool remove_from_map = false);
353
354 /* Release intance object identified by PTR pointer. */
80a4fe78
ML
355 void
356 release_object_overhead (void *ptr);
2d44c7de
ML
357
358 /* Get sum value for ORIGIN type of allocation for the descriptor. */
80a4fe78
ML
359 T
360 get_sum (mem_alloc_origin origin);
2d44c7de
ML
361
362 /* Get all tracked instances registered by the description. Items
363 are filtered by ORIGIN type, LENGTH is return value where we register
364 the number of elements in the list. If we want to process custom order,
365 CMP comparator can be provided. */
80a4fe78
ML
366 mem_list_t *
367 get_list (mem_alloc_origin origin, unsigned *length,
368 int (*cmp) (const void *first, const void *second) = NULL);
2d44c7de
ML
369
370 /* Dump all tracked instances of type ORIGIN. If we want to process custom
371 order, CMP comparator can be provided. */
372 void dump (mem_alloc_origin origin,
373 int (*cmp) (const void *first, const void *second) = NULL);
374
375 /* Reverse object map used for every object allocation mapping. */
376 reverse_object_map_t *m_reverse_object_map;
377
378private:
379 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
380 in NAME source file, at LINE in source code, in FUNCTION. */
381 T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
382 int line, const char *function, const void *ptr);
383
384 /* Allocation location coupled to the description. */
385 mem_location m_location;
386
387 /* Location to usage mapping. */
388 mem_map_t *m_map;
389
390 /* Reverse pointer to usage mapping. */
391 reverse_mem_map_t *m_reverse_map;
392};
393
2d44c7de
ML
394
395/* Returns true if instance PTR is registered by the memory description. */
396
397template <class T>
398inline bool
399mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
400{
401 return m_reverse_map->get (ptr);
402}
403
404/* Return descriptor for instance PTR. */
405
406template <class T>
407inline T*
408mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
409{
410 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
411}
412
2d44c7de 413
ac059261
ML
414 /* Register memory allocation descriptor for container PTR which is
415 described by a memory LOCATION. */
2d44c7de
ML
416template <class T>
417inline T*
418mem_alloc_description<T>::register_descriptor (const void *ptr,
ac059261 419 mem_location *location)
2d44c7de 420{
2d44c7de
ML
421 T *usage = NULL;
422
ac059261 423 T **slot = m_map->get (location);
2d44c7de
ML
424 if (slot)
425 {
ac059261 426 delete location;
2d44c7de 427 usage = *slot;
ac059261 428 usage->m_instances++;
2d44c7de
ML
429 }
430 else
431 {
432 usage = new T ();
ac059261 433 m_map->put (location, usage);
2d44c7de
ML
434 }
435
436 if (!m_reverse_map->get (ptr))
437 m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
438
439 return usage;
440}
441
ac059261
ML
442/* Register memory allocation descriptor for container PTR. ORIGIN identifies
443 type of container and GGC identifes if the allocation is handled in GGC
444 memory. Each location is identified by file NAME, LINE in source code and
445 FUNCTION name. */
446
447template <class T>
448inline T*
449mem_alloc_description<T>::register_descriptor (const void *ptr,
450 mem_alloc_origin origin,
451 bool ggc,
452 const char *filename,
453 int line,
454 const char *function)
455{
456 mem_location *l = new mem_location (origin, ggc, filename, line, function);
457 return register_descriptor (ptr, l);
458}
459
2d44c7de
ML
460/* Register instance overhead identified by PTR pointer. Allocation takes
461 SIZE bytes. */
462
463template <class T>
464inline T*
465mem_alloc_description<T>::register_instance_overhead (size_t size,
466 const void *ptr)
467{
468 mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
469 if (!slot)
470 {
471 /* Due to PCH, it can really happen. */
472 return NULL;
473 }
474
475 T *usage = (*slot).usage;
476 usage->register_overhead (size);
477
478 return usage;
479}
480
481/* For containers (and GGC) where we want to track every instance object,
482 we register allocation of SIZE bytes, identified by PTR pointer, belonging
483 to USAGE descriptor. */
484
485template <class T>
486void
487mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
488 const void *ptr)
489{
490 /* In case of GGC, it is possible to have already occupied the memory
491 location. */
492 m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
493}
494
495/* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
496 in NAME source file, at LINE in source code, in FUNCTION. */
497
498template <class T>
499inline T*
500mem_alloc_description<T>::register_overhead (size_t size,
501 mem_alloc_origin origin,
502 const char *filename,
503 int line,
504 const char *function,
505 const void *ptr)
506{
507 T *usage = register_descriptor (ptr, origin, filename, line, function);
508 usage->register_overhead (size);
509
510 return usage;
511}
512
513/* Release PTR pointer of SIZE bytes. */
514
515template <class T>
516inline void
517mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size,
518 bool remove_from_map)
519{
520 mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
521
522 if (!slot)
523 {
524 /* Due to PCH, it can really happen. */
525 return;
526 }
527
528 mem_usage_pair<T> usage_pair = *slot;
529 usage_pair.usage->release_overhead (size);
530
531 if (remove_from_map)
532 m_reverse_map->remove (ptr);
533}
534
535/* Release intance object identified by PTR pointer. */
536
537template <class T>
538inline void
539mem_alloc_description<T>::release_object_overhead (void *ptr)
540{
541 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
542 if (entry)
543 {
544 entry->first->release_overhead (entry->second);
545 m_reverse_object_map->remove (ptr);
546 }
547}
548
549/* Default contructor. */
550
551template <class T>
552inline
553mem_alloc_description<T>::mem_alloc_description ()
554{
555 m_map = new mem_map_t (13, false, false);
556 m_reverse_map = new reverse_mem_map_t (13, false, false);
557 m_reverse_object_map = new reverse_object_map_t (13, false, false);
558}
559
560/* Default destructor. */
561
562template <class T>
563inline
564mem_alloc_description<T>::~mem_alloc_description ()
565{
566 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
567 ++it)
568 {
569 delete (*it).first;
570 delete (*it).second;
571 }
572
573 delete m_map;
574 delete m_reverse_map;
575 delete m_reverse_object_map;
576}
577
578/* Get all tracked instances registered by the description. Items are filtered
579 by ORIGIN type, LENGTH is return value where we register the number of
580 elements in the list. If we want to process custom order, CMP comparator
581 can be provided. */
582
583template <class T>
584inline
585typename mem_alloc_description<T>::mem_list_t *
586mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length,
587 int (*cmp) (const void *first, const void *second))
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, cmp == NULL ? T::compare : cmp);
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
610mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
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
629mem_alloc_description<T>::dump (mem_alloc_origin origin,
630 int (*cmp) (const void *first,
631 const void *second))
632{
633 unsigned length;
634
635 fprintf (stderr, "\n");
636
637 mem_list_t *list = get_list (origin, &length, cmp);
638 T total = get_sum (origin);
639
640 T::dump_header (mem_location::get_origin_name (origin));
641 for (int i = length - 1; i >= 0; i--)
642 list[i].second->dump (list[i].first, total);
643
644 total.dump_footer ();
645
646 XDELETEVEC (list);
647
648 fprintf (stderr, "\n");
649}
650
651#endif // GCC_MEM_STATS_H