1*38fd1498Szrj /* A memory statistics tracking infrastructure.
2*38fd1498Szrj Copyright (C) 2015-2018 Free Software Foundation, Inc.
3*38fd1498Szrj Contributed by Martin Liska <mliska@suse.cz>
4*38fd1498Szrj
5*38fd1498Szrj This file is part of GCC.
6*38fd1498Szrj
7*38fd1498Szrj GCC is free software; you can redistribute it and/or modify it under
8*38fd1498Szrj the terms of the GNU General Public License as published by the Free
9*38fd1498Szrj Software Foundation; either version 3, or (at your option) any later
10*38fd1498Szrj version.
11*38fd1498Szrj
12*38fd1498Szrj GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13*38fd1498Szrj WARRANTY; without even the implied warranty of MERCHANTABILITY or
14*38fd1498Szrj FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15*38fd1498Szrj for more details.
16*38fd1498Szrj
17*38fd1498Szrj You should have received a copy of the GNU General Public License
18*38fd1498Szrj along with GCC; see the file COPYING3. If not see
19*38fd1498Szrj <http://www.gnu.org/licenses/>. */
20*38fd1498Szrj
21*38fd1498Szrj #ifndef GCC_MEM_STATS_H
22*38fd1498Szrj #define GCC_MEM_STATS_H
23*38fd1498Szrj
24*38fd1498Szrj /* Forward declaration. */
25*38fd1498Szrj template<typename Key, typename Value,
26*38fd1498Szrj typename Traits = simple_hashmap_traits<default_hash_traits<Key>,
27*38fd1498Szrj Value> >
28*38fd1498Szrj class hash_map;
29*38fd1498Szrj
30*38fd1498Szrj #define LOCATION_LINE_EXTRA_SPACE 30
31*38fd1498Szrj #define LOCATION_LINE_WIDTH 48
32*38fd1498Szrj
33*38fd1498Szrj /* Memory allocation location. */
34*38fd1498Szrj struct mem_location
35*38fd1498Szrj {
36*38fd1498Szrj /* Default constructor. */
37*38fd1498Szrj inline
mem_locationmem_location38*38fd1498Szrj mem_location () {}
39*38fd1498Szrj
40*38fd1498Szrj /* Constructor. */
41*38fd1498Szrj inline
42*38fd1498Szrj mem_location (mem_alloc_origin origin, bool ggc,
43*38fd1498Szrj const char *filename = NULL, int line = 0,
44*38fd1498Szrj const char *function = NULL):
m_filenamemem_location45*38fd1498Szrj m_filename (filename), m_function (function), m_line (line), m_origin
46*38fd1498Szrj (origin), m_ggc (ggc) {}
47*38fd1498Szrj
48*38fd1498Szrj /* Copy constructor. */
49*38fd1498Szrj inline
mem_locationmem_location50*38fd1498Szrj mem_location (mem_location &other): m_filename (other.m_filename),
51*38fd1498Szrj m_function (other.m_function), m_line (other.m_line),
52*38fd1498Szrj m_origin (other.m_origin), m_ggc (other.m_ggc) {}
53*38fd1498Szrj
54*38fd1498Szrj /* Compute hash value based on file name, function name and line in
55*38fd1498Szrj source code. As there is just a single pointer registered for every
56*38fd1498Szrj constant that points to e.g. the same file name, we can use hash
57*38fd1498Szrj of the pointer. */
58*38fd1498Szrj hashval_t
hashmem_location59*38fd1498Szrj hash ()
60*38fd1498Szrj {
61*38fd1498Szrj inchash::hash hash;
62*38fd1498Szrj
63*38fd1498Szrj hash.add_ptr (m_filename);
64*38fd1498Szrj hash.add_ptr (m_function);
65*38fd1498Szrj hash.add_int (m_line);
66*38fd1498Szrj
67*38fd1498Szrj return hash.end ();
68*38fd1498Szrj }
69*38fd1498Szrj
70*38fd1498Szrj /* Return true if the memory location is equal to OTHER. */
71*38fd1498Szrj int
equalmem_location72*38fd1498Szrj equal (mem_location &other)
73*38fd1498Szrj {
74*38fd1498Szrj return m_filename == other.m_filename && m_function == other.m_function
75*38fd1498Szrj && m_line == other.m_line;
76*38fd1498Szrj }
77*38fd1498Szrj
78*38fd1498Szrj /* Return trimmed filename for the location. */
79*38fd1498Szrj inline const char *
get_trimmed_filenamemem_location80*38fd1498Szrj get_trimmed_filename ()
81*38fd1498Szrj {
82*38fd1498Szrj const char *s1 = m_filename;
83*38fd1498Szrj const char *s2;
84*38fd1498Szrj
85*38fd1498Szrj while ((s2 = strstr (s1, "gcc/")))
86*38fd1498Szrj s1 = s2 + 4;
87*38fd1498Szrj
88*38fd1498Szrj return s1;
89*38fd1498Szrj }
90*38fd1498Szrj
91*38fd1498Szrj inline char *
to_stringmem_location92*38fd1498Szrj to_string ()
93*38fd1498Szrj {
94*38fd1498Szrj unsigned l = strlen (get_trimmed_filename ()) + strlen (m_function)
95*38fd1498Szrj + LOCATION_LINE_EXTRA_SPACE;
96*38fd1498Szrj
97*38fd1498Szrj char *s = XNEWVEC (char, l);
98*38fd1498Szrj sprintf (s, "%s:%i (%s)", get_trimmed_filename (),
99*38fd1498Szrj m_line, m_function);
100*38fd1498Szrj
101*38fd1498Szrj s[MIN (LOCATION_LINE_WIDTH, l - 1)] = '\0';
102*38fd1498Szrj
103*38fd1498Szrj return s;
104*38fd1498Szrj }
105*38fd1498Szrj
106*38fd1498Szrj /* Return display name associated to ORIGIN type. */
107*38fd1498Szrj static const char *
get_origin_namemem_location108*38fd1498Szrj get_origin_name (mem_alloc_origin origin)
109*38fd1498Szrj {
110*38fd1498Szrj return mem_alloc_origin_names[(unsigned) origin];
111*38fd1498Szrj }
112*38fd1498Szrj
113*38fd1498Szrj /* File name of source code. */
114*38fd1498Szrj const char *m_filename;
115*38fd1498Szrj /* Funcation name. */
116*38fd1498Szrj const char *m_function;
117*38fd1498Szrj /* Line number in source code. */
118*38fd1498Szrj int m_line;
119*38fd1498Szrj /* Origin type. */
120*38fd1498Szrj mem_alloc_origin m_origin;
121*38fd1498Szrj /* Flag if used by GGC allocation. */
122*38fd1498Szrj bool m_ggc;
123*38fd1498Szrj };
124*38fd1498Szrj
125*38fd1498Szrj /* Memory usage register to a memory location. */
126*38fd1498Szrj struct mem_usage
127*38fd1498Szrj {
128*38fd1498Szrj /* Default constructor. */
mem_usagemem_usage129*38fd1498Szrj mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
130*38fd1498Szrj
131*38fd1498Szrj /* Constructor. */
132*38fd1498Szrj mem_usage (size_t allocated, size_t times, size_t peak, size_t instances = 0):
m_allocatedmem_usage133*38fd1498Szrj m_allocated (allocated), m_times (times), m_peak (peak),
134*38fd1498Szrj m_instances (instances) {}
135*38fd1498Szrj
136*38fd1498Szrj /* Register overhead of SIZE bytes. */
137*38fd1498Szrj inline void
register_overheadmem_usage138*38fd1498Szrj register_overhead (size_t size)
139*38fd1498Szrj {
140*38fd1498Szrj m_allocated += size;
141*38fd1498Szrj m_times++;
142*38fd1498Szrj
143*38fd1498Szrj if (m_peak < m_allocated)
144*38fd1498Szrj m_peak = m_allocated;
145*38fd1498Szrj }
146*38fd1498Szrj
147*38fd1498Szrj /* Release overhead of SIZE bytes. */
148*38fd1498Szrj inline void
release_overheadmem_usage149*38fd1498Szrj release_overhead (size_t size)
150*38fd1498Szrj {
151*38fd1498Szrj gcc_assert (size <= m_allocated);
152*38fd1498Szrj
153*38fd1498Szrj m_allocated -= size;
154*38fd1498Szrj }
155*38fd1498Szrj
156*38fd1498Szrj /* Sum the usage with SECOND usage. */
157*38fd1498Szrj mem_usage
158*38fd1498Szrj operator+ (const mem_usage &second)
159*38fd1498Szrj {
160*38fd1498Szrj return mem_usage (m_allocated + second.m_allocated,
161*38fd1498Szrj m_times + second.m_times,
162*38fd1498Szrj m_peak + second.m_peak,
163*38fd1498Szrj m_instances + second.m_instances);
164*38fd1498Szrj }
165*38fd1498Szrj
166*38fd1498Szrj /* Equality operator. */
167*38fd1498Szrj inline bool
168*38fd1498Szrj operator== (const mem_usage &second) const
169*38fd1498Szrj {
170*38fd1498Szrj return (m_allocated == second.m_allocated
171*38fd1498Szrj && m_peak == second.m_peak
172*38fd1498Szrj && m_allocated == second.m_allocated);
173*38fd1498Szrj }
174*38fd1498Szrj
175*38fd1498Szrj /* Comparison operator. */
176*38fd1498Szrj inline bool
177*38fd1498Szrj operator< (const mem_usage &second) const
178*38fd1498Szrj {
179*38fd1498Szrj if (*this == second)
180*38fd1498Szrj return false;
181*38fd1498Szrj
182*38fd1498Szrj return (m_allocated == second.m_allocated ?
183*38fd1498Szrj (m_peak == second.m_peak ? m_times < second.m_times
184*38fd1498Szrj : m_peak < second.m_peak) : m_allocated < second.m_allocated);
185*38fd1498Szrj }
186*38fd1498Szrj
187*38fd1498Szrj /* Compare wrapper used by qsort method. */
188*38fd1498Szrj static int
comparemem_usage189*38fd1498Szrj compare (const void *first, const void *second)
190*38fd1498Szrj {
191*38fd1498Szrj typedef std::pair<mem_location *, mem_usage *> mem_pair_t;
192*38fd1498Szrj
193*38fd1498Szrj const mem_pair_t f = *(const mem_pair_t *)first;
194*38fd1498Szrj const mem_pair_t s = *(const mem_pair_t *)second;
195*38fd1498Szrj
196*38fd1498Szrj if (*f.second == *s.second)
197*38fd1498Szrj return 0;
198*38fd1498Szrj
199*38fd1498Szrj return *f.second < *s.second ? 1 : -1;
200*38fd1498Szrj }
201*38fd1498Szrj
202*38fd1498Szrj /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
203*38fd1498Szrj inline void
dumpmem_usage204*38fd1498Szrj dump (mem_location *loc, mem_usage &total) const
205*38fd1498Szrj {
206*38fd1498Szrj char *location_string = loc->to_string ();
207*38fd1498Szrj
208*38fd1498Szrj fprintf (stderr, "%-48s %10" PRIu64 ":%5.1f%%"
209*38fd1498Szrj "%10" PRIu64 "%10" PRIu64 ":%5.1f%%%10s\n",
210*38fd1498Szrj location_string, (uint64_t)m_allocated,
211*38fd1498Szrj get_percent (m_allocated, total.m_allocated),
212*38fd1498Szrj (uint64_t)m_peak, (uint64_t)m_times,
213*38fd1498Szrj get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap");
214*38fd1498Szrj
215*38fd1498Szrj free (location_string);
216*38fd1498Szrj }
217*38fd1498Szrj
218*38fd1498Szrj /* Dump footer. */
219*38fd1498Szrj inline void
dump_footermem_usage220*38fd1498Szrj dump_footer () const
221*38fd1498Szrj {
222*38fd1498Szrj print_dash_line ();
223*38fd1498Szrj fprintf (stderr, "%s%54" PRIu64 "%27" PRIu64 "\n", "Total",
224*38fd1498Szrj (uint64_t)m_allocated, (uint64_t)m_times);
225*38fd1498Szrj print_dash_line ();
226*38fd1498Szrj }
227*38fd1498Szrj
228*38fd1498Szrj /* Return fraction of NOMINATOR and DENOMINATOR in percent. */
229*38fd1498Szrj static inline float
get_percentmem_usage230*38fd1498Szrj get_percent (size_t nominator, size_t denominator)
231*38fd1498Szrj {
232*38fd1498Szrj return denominator == 0 ? 0.0f : nominator * 100.0 / denominator;
233*38fd1498Szrj }
234*38fd1498Szrj
235*38fd1498Szrj /* Print line made of dashes. */
236*38fd1498Szrj static inline void
237*38fd1498Szrj print_dash_line (size_t count = 140)
238*38fd1498Szrj {
239*38fd1498Szrj while (count--)
240*38fd1498Szrj fputc ('-', stderr);
241*38fd1498Szrj fputc ('\n', stderr);
242*38fd1498Szrj }
243*38fd1498Szrj
244*38fd1498Szrj /* Dump header with NAME. */
245*38fd1498Szrj static inline void
dump_headermem_usage246*38fd1498Szrj dump_header (const char *name)
247*38fd1498Szrj {
248*38fd1498Szrj fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak",
249*38fd1498Szrj "Times", "Type");
250*38fd1498Szrj print_dash_line ();
251*38fd1498Szrj }
252*38fd1498Szrj
253*38fd1498Szrj /* Current number of allocated bytes. */
254*38fd1498Szrj size_t m_allocated;
255*38fd1498Szrj /* Number of allocations. */
256*38fd1498Szrj size_t m_times;
257*38fd1498Szrj /* Peak allocation in bytes. */
258*38fd1498Szrj size_t m_peak;
259*38fd1498Szrj /* Number of container instances. */
260*38fd1498Szrj size_t m_instances;
261*38fd1498Szrj };
262*38fd1498Szrj
263*38fd1498Szrj /* Memory usage pair that connectes memory usage and number
264*38fd1498Szrj of allocated bytes. */
265*38fd1498Szrj template <class T>
266*38fd1498Szrj struct mem_usage_pair
267*38fd1498Szrj {
mem_usage_pairmem_usage_pair268*38fd1498Szrj mem_usage_pair (T *usage_, size_t allocated_): usage (usage_),
269*38fd1498Szrj allocated (allocated_) {}
270*38fd1498Szrj
271*38fd1498Szrj T *usage;
272*38fd1498Szrj size_t allocated;
273*38fd1498Szrj };
274*38fd1498Szrj
275*38fd1498Szrj /* Memory allocation description. */
276*38fd1498Szrj template <class T>
277*38fd1498Szrj class mem_alloc_description
278*38fd1498Szrj {
279*38fd1498Szrj public:
280*38fd1498Szrj struct mem_location_hash : nofree_ptr_hash <mem_location>
281*38fd1498Szrj {
282*38fd1498Szrj static hashval_t
hashmem_location_hash283*38fd1498Szrj hash (value_type l)
284*38fd1498Szrj {
285*38fd1498Szrj inchash::hash hstate;
286*38fd1498Szrj
287*38fd1498Szrj hstate.add_ptr ((const void *)l->m_filename);
288*38fd1498Szrj hstate.add_ptr (l->m_function);
289*38fd1498Szrj hstate.add_int (l->m_line);
290*38fd1498Szrj
291*38fd1498Szrj return hstate.end ();
292*38fd1498Szrj }
293*38fd1498Szrj
294*38fd1498Szrj static bool
equalmem_location_hash295*38fd1498Szrj equal (value_type l1, value_type l2)
296*38fd1498Szrj {
297*38fd1498Szrj return l1->m_filename == l2->m_filename
298*38fd1498Szrj && l1->m_function == l2->m_function
299*38fd1498Szrj && l1->m_line == l2->m_line;
300*38fd1498Szrj }
301*38fd1498Szrj };
302*38fd1498Szrj
303*38fd1498Szrj /* Internal class type definitions. */
304*38fd1498Szrj typedef hash_map <mem_location_hash, T *> mem_map_t;
305*38fd1498Szrj typedef hash_map <const void *, mem_usage_pair<T> > reverse_mem_map_t;
306*38fd1498Szrj typedef hash_map <const void *, std::pair<T *, size_t> > reverse_object_map_t;
307*38fd1498Szrj typedef std::pair <mem_location *, T *> mem_list_t;
308*38fd1498Szrj
309*38fd1498Szrj /* Default contructor. */
310*38fd1498Szrj mem_alloc_description ();
311*38fd1498Szrj
312*38fd1498Szrj /* Default destructor. */
313*38fd1498Szrj ~mem_alloc_description ();
314*38fd1498Szrj
315*38fd1498Szrj /* Returns true if instance PTR is registered by the memory description. */
316*38fd1498Szrj bool
317*38fd1498Szrj contains_descriptor_for_instance (const void *ptr);
318*38fd1498Szrj
319*38fd1498Szrj /* Return descriptor for instance PTR. */
320*38fd1498Szrj T *
321*38fd1498Szrj get_descriptor_for_instance (const void *ptr);
322*38fd1498Szrj
323*38fd1498Szrj /* Register memory allocation descriptor for container PTR which is
324*38fd1498Szrj described by a memory LOCATION. */
325*38fd1498Szrj T *
326*38fd1498Szrj register_descriptor (const void *ptr, mem_location *location);
327*38fd1498Szrj
328*38fd1498Szrj /* Register memory allocation descriptor for container PTR. ORIGIN identifies
329*38fd1498Szrj type of container and GGC identifes if the allocation is handled in GGC
330*38fd1498Szrj memory. Each location is identified by file NAME, LINE in source code and
331*38fd1498Szrj FUNCTION name. */
332*38fd1498Szrj T *
333*38fd1498Szrj register_descriptor (const void *ptr, mem_alloc_origin origin,
334*38fd1498Szrj bool ggc, const char *name, int line,
335*38fd1498Szrj const char *function);
336*38fd1498Szrj
337*38fd1498Szrj /* Register instance overhead identified by PTR pointer. Allocation takes
338*38fd1498Szrj SIZE bytes. */
339*38fd1498Szrj T *
340*38fd1498Szrj register_instance_overhead (size_t size, const void *ptr);
341*38fd1498Szrj
342*38fd1498Szrj /* For containers (and GGC) where we want to track every instance object,
343*38fd1498Szrj we register allocation of SIZE bytes, identified by PTR pointer, belonging
344*38fd1498Szrj to USAGE descriptor. */
345*38fd1498Szrj void
346*38fd1498Szrj register_object_overhead (T *usage, size_t size, const void *ptr);
347*38fd1498Szrj
348*38fd1498Szrj /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
349*38fd1498Szrj remove the instance from reverse map. */
350*38fd1498Szrj void
351*38fd1498Szrj release_instance_overhead (void *ptr, size_t size,
352*38fd1498Szrj bool remove_from_map = false);
353*38fd1498Szrj
354*38fd1498Szrj /* Release intance object identified by PTR pointer. */
355*38fd1498Szrj void
356*38fd1498Szrj release_object_overhead (void *ptr);
357*38fd1498Szrj
358*38fd1498Szrj /* Get sum value for ORIGIN type of allocation for the descriptor. */
359*38fd1498Szrj T
360*38fd1498Szrj get_sum (mem_alloc_origin origin);
361*38fd1498Szrj
362*38fd1498Szrj /* Get all tracked instances registered by the description. Items
363*38fd1498Szrj are filtered by ORIGIN type, LENGTH is return value where we register
364*38fd1498Szrj the number of elements in the list. If we want to process custom order,
365*38fd1498Szrj CMP comparator can be provided. */
366*38fd1498Szrj mem_list_t *
367*38fd1498Szrj get_list (mem_alloc_origin origin, unsigned *length,
368*38fd1498Szrj int (*cmp) (const void *first, const void *second) = NULL);
369*38fd1498Szrj
370*38fd1498Szrj /* Dump all tracked instances of type ORIGIN. If we want to process custom
371*38fd1498Szrj order, CMP comparator can be provided. */
372*38fd1498Szrj void dump (mem_alloc_origin origin,
373*38fd1498Szrj int (*cmp) (const void *first, const void *second) = NULL);
374*38fd1498Szrj
375*38fd1498Szrj /* Reverse object map used for every object allocation mapping. */
376*38fd1498Szrj reverse_object_map_t *m_reverse_object_map;
377*38fd1498Szrj
378*38fd1498Szrj private:
379*38fd1498Szrj /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
380*38fd1498Szrj in NAME source file, at LINE in source code, in FUNCTION. */
381*38fd1498Szrj T *register_overhead (size_t size, mem_alloc_origin origin, const char *name,
382*38fd1498Szrj int line, const char *function, const void *ptr);
383*38fd1498Szrj
384*38fd1498Szrj /* Allocation location coupled to the description. */
385*38fd1498Szrj mem_location m_location;
386*38fd1498Szrj
387*38fd1498Szrj /* Location to usage mapping. */
388*38fd1498Szrj mem_map_t *m_map;
389*38fd1498Szrj
390*38fd1498Szrj /* Reverse pointer to usage mapping. */
391*38fd1498Szrj reverse_mem_map_t *m_reverse_map;
392*38fd1498Szrj };
393*38fd1498Szrj
394*38fd1498Szrj
395*38fd1498Szrj /* Returns true if instance PTR is registered by the memory description. */
396*38fd1498Szrj
397*38fd1498Szrj template <class T>
398*38fd1498Szrj inline bool
contains_descriptor_for_instance(const void * ptr)399*38fd1498Szrj mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr)
400*38fd1498Szrj {
401*38fd1498Szrj return m_reverse_map->get (ptr);
402*38fd1498Szrj }
403*38fd1498Szrj
404*38fd1498Szrj /* Return descriptor for instance PTR. */
405*38fd1498Szrj
406*38fd1498Szrj template <class T>
407*38fd1498Szrj inline T*
get_descriptor_for_instance(const void * ptr)408*38fd1498Szrj mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr)
409*38fd1498Szrj {
410*38fd1498Szrj return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL;
411*38fd1498Szrj }
412*38fd1498Szrj
413*38fd1498Szrj
414*38fd1498Szrj /* Register memory allocation descriptor for container PTR which is
415*38fd1498Szrj described by a memory LOCATION. */
416*38fd1498Szrj template <class T>
417*38fd1498Szrj inline T*
register_descriptor(const void * ptr,mem_location * location)418*38fd1498Szrj mem_alloc_description<T>::register_descriptor (const void *ptr,
419*38fd1498Szrj mem_location *location)
420*38fd1498Szrj {
421*38fd1498Szrj T *usage = NULL;
422*38fd1498Szrj
423*38fd1498Szrj T **slot = m_map->get (location);
424*38fd1498Szrj if (slot)
425*38fd1498Szrj {
426*38fd1498Szrj delete location;
427*38fd1498Szrj usage = *slot;
428*38fd1498Szrj usage->m_instances++;
429*38fd1498Szrj }
430*38fd1498Szrj else
431*38fd1498Szrj {
432*38fd1498Szrj usage = new T ();
433*38fd1498Szrj m_map->put (location, usage);
434*38fd1498Szrj }
435*38fd1498Szrj
436*38fd1498Szrj if (!m_reverse_map->get (ptr))
437*38fd1498Szrj m_reverse_map->put (ptr, mem_usage_pair<T> (usage, 0));
438*38fd1498Szrj
439*38fd1498Szrj return usage;
440*38fd1498Szrj }
441*38fd1498Szrj
442*38fd1498Szrj /* Register memory allocation descriptor for container PTR. ORIGIN identifies
443*38fd1498Szrj type of container and GGC identifes if the allocation is handled in GGC
444*38fd1498Szrj memory. Each location is identified by file NAME, LINE in source code and
445*38fd1498Szrj FUNCTION name. */
446*38fd1498Szrj
447*38fd1498Szrj template <class T>
448*38fd1498Szrj inline T*
register_descriptor(const void * ptr,mem_alloc_origin origin,bool ggc,const char * filename,int line,const char * function)449*38fd1498Szrj mem_alloc_description<T>::register_descriptor (const void *ptr,
450*38fd1498Szrj mem_alloc_origin origin,
451*38fd1498Szrj bool ggc,
452*38fd1498Szrj const char *filename,
453*38fd1498Szrj int line,
454*38fd1498Szrj const char *function)
455*38fd1498Szrj {
456*38fd1498Szrj mem_location *l = new mem_location (origin, ggc, filename, line, function);
457*38fd1498Szrj return register_descriptor (ptr, l);
458*38fd1498Szrj }
459*38fd1498Szrj
460*38fd1498Szrj /* Register instance overhead identified by PTR pointer. Allocation takes
461*38fd1498Szrj SIZE bytes. */
462*38fd1498Szrj
463*38fd1498Szrj template <class T>
464*38fd1498Szrj inline T*
register_instance_overhead(size_t size,const void * ptr)465*38fd1498Szrj mem_alloc_description<T>::register_instance_overhead (size_t size,
466*38fd1498Szrj const void *ptr)
467*38fd1498Szrj {
468*38fd1498Szrj mem_usage_pair <T> *slot = m_reverse_map->get (ptr);
469*38fd1498Szrj if (!slot)
470*38fd1498Szrj {
471*38fd1498Szrj /* Due to PCH, it can really happen. */
472*38fd1498Szrj return NULL;
473*38fd1498Szrj }
474*38fd1498Szrj
475*38fd1498Szrj T *usage = (*slot).usage;
476*38fd1498Szrj usage->register_overhead (size);
477*38fd1498Szrj
478*38fd1498Szrj return usage;
479*38fd1498Szrj }
480*38fd1498Szrj
481*38fd1498Szrj /* For containers (and GGC) where we want to track every instance object,
482*38fd1498Szrj we register allocation of SIZE bytes, identified by PTR pointer, belonging
483*38fd1498Szrj to USAGE descriptor. */
484*38fd1498Szrj
485*38fd1498Szrj template <class T>
486*38fd1498Szrj void
register_object_overhead(T * usage,size_t size,const void * ptr)487*38fd1498Szrj mem_alloc_description<T>::register_object_overhead (T *usage, size_t size,
488*38fd1498Szrj const void *ptr)
489*38fd1498Szrj {
490*38fd1498Szrj /* In case of GGC, it is possible to have already occupied the memory
491*38fd1498Szrj location. */
492*38fd1498Szrj m_reverse_object_map->put (ptr, std::pair<T *, size_t> (usage, size));
493*38fd1498Szrj }
494*38fd1498Szrj
495*38fd1498Szrj /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
496*38fd1498Szrj in NAME source file, at LINE in source code, in FUNCTION. */
497*38fd1498Szrj
498*38fd1498Szrj template <class T>
499*38fd1498Szrj inline T*
register_overhead(size_t size,mem_alloc_origin origin,const char * filename,int line,const char * function,const void * ptr)500*38fd1498Szrj mem_alloc_description<T>::register_overhead (size_t size,
501*38fd1498Szrj mem_alloc_origin origin,
502*38fd1498Szrj const char *filename,
503*38fd1498Szrj int line,
504*38fd1498Szrj const char *function,
505*38fd1498Szrj const void *ptr)
506*38fd1498Szrj {
507*38fd1498Szrj T *usage = register_descriptor (ptr, origin, filename, line, function);
508*38fd1498Szrj usage->register_overhead (size);
509*38fd1498Szrj
510*38fd1498Szrj return usage;
511*38fd1498Szrj }
512*38fd1498Szrj
513*38fd1498Szrj /* Release PTR pointer of SIZE bytes. */
514*38fd1498Szrj
515*38fd1498Szrj template <class T>
516*38fd1498Szrj inline void
release_instance_overhead(void * ptr,size_t size,bool remove_from_map)517*38fd1498Szrj mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size,
518*38fd1498Szrj bool remove_from_map)
519*38fd1498Szrj {
520*38fd1498Szrj mem_usage_pair<T> *slot = m_reverse_map->get (ptr);
521*38fd1498Szrj
522*38fd1498Szrj if (!slot)
523*38fd1498Szrj {
524*38fd1498Szrj /* Due to PCH, it can really happen. */
525*38fd1498Szrj return;
526*38fd1498Szrj }
527*38fd1498Szrj
528*38fd1498Szrj mem_usage_pair<T> usage_pair = *slot;
529*38fd1498Szrj usage_pair.usage->release_overhead (size);
530*38fd1498Szrj
531*38fd1498Szrj if (remove_from_map)
532*38fd1498Szrj m_reverse_map->remove (ptr);
533*38fd1498Szrj }
534*38fd1498Szrj
535*38fd1498Szrj /* Release intance object identified by PTR pointer. */
536*38fd1498Szrj
537*38fd1498Szrj template <class T>
538*38fd1498Szrj inline void
release_object_overhead(void * ptr)539*38fd1498Szrj mem_alloc_description<T>::release_object_overhead (void *ptr)
540*38fd1498Szrj {
541*38fd1498Szrj std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr);
542*38fd1498Szrj if (entry)
543*38fd1498Szrj {
544*38fd1498Szrj entry->first->release_overhead (entry->second);
545*38fd1498Szrj m_reverse_object_map->remove (ptr);
546*38fd1498Szrj }
547*38fd1498Szrj }
548*38fd1498Szrj
549*38fd1498Szrj /* Default contructor. */
550*38fd1498Szrj
551*38fd1498Szrj template <class T>
552*38fd1498Szrj inline
mem_alloc_description()553*38fd1498Szrj mem_alloc_description<T>::mem_alloc_description ()
554*38fd1498Szrj {
555*38fd1498Szrj m_map = new mem_map_t (13, false, false);
556*38fd1498Szrj m_reverse_map = new reverse_mem_map_t (13, false, false);
557*38fd1498Szrj m_reverse_object_map = new reverse_object_map_t (13, false, false);
558*38fd1498Szrj }
559*38fd1498Szrj
560*38fd1498Szrj /* Default destructor. */
561*38fd1498Szrj
562*38fd1498Szrj template <class T>
563*38fd1498Szrj inline
~mem_alloc_description()564*38fd1498Szrj mem_alloc_description<T>::~mem_alloc_description ()
565*38fd1498Szrj {
566*38fd1498Szrj for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
567*38fd1498Szrj ++it)
568*38fd1498Szrj {
569*38fd1498Szrj delete (*it).first;
570*38fd1498Szrj delete (*it).second;
571*38fd1498Szrj }
572*38fd1498Szrj
573*38fd1498Szrj delete m_map;
574*38fd1498Szrj delete m_reverse_map;
575*38fd1498Szrj delete m_reverse_object_map;
576*38fd1498Szrj }
577*38fd1498Szrj
578*38fd1498Szrj /* Get all tracked instances registered by the description. Items are filtered
579*38fd1498Szrj by ORIGIN type, LENGTH is return value where we register the number of
580*38fd1498Szrj elements in the list. If we want to process custom order, CMP comparator
581*38fd1498Szrj can be provided. */
582*38fd1498Szrj
583*38fd1498Szrj template <class T>
584*38fd1498Szrj inline
585*38fd1498Szrj typename mem_alloc_description<T>::mem_list_t *
get_list(mem_alloc_origin origin,unsigned * length,int (* cmp)(const void * first,const void * second))586*38fd1498Szrj mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length,
587*38fd1498Szrj int (*cmp) (const void *first, const void *second))
588*38fd1498Szrj {
589*38fd1498Szrj /* vec data structure is not used because all vectors generate memory
590*38fd1498Szrj allocation info a it would create a cycle. */
591*38fd1498Szrj size_t element_size = sizeof (mem_list_t);
592*38fd1498Szrj mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ());
593*38fd1498Szrj unsigned i = 0;
594*38fd1498Szrj
595*38fd1498Szrj for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end ();
596*38fd1498Szrj ++it)
597*38fd1498Szrj if ((*it).first->m_origin == origin)
598*38fd1498Szrj list[i++] = std::pair<mem_location*, T*> (*it);
599*38fd1498Szrj
600*38fd1498Szrj qsort (list, i, element_size, cmp == NULL ? T::compare : cmp);
601*38fd1498Szrj *length = i;
602*38fd1498Szrj
603*38fd1498Szrj return list;
604*38fd1498Szrj }
605*38fd1498Szrj
606*38fd1498Szrj /* Get sum value for ORIGIN type of allocation for the descriptor. */
607*38fd1498Szrj
608*38fd1498Szrj template <class T>
609*38fd1498Szrj inline T
get_sum(mem_alloc_origin origin)610*38fd1498Szrj mem_alloc_description<T>::get_sum (mem_alloc_origin origin)
611*38fd1498Szrj {
612*38fd1498Szrj unsigned length;
613*38fd1498Szrj mem_list_t *list = get_list (origin, &length);
614*38fd1498Szrj T sum;
615*38fd1498Szrj
616*38fd1498Szrj for (unsigned i = 0; i < length; i++)
617*38fd1498Szrj sum = sum + *list[i].second;
618*38fd1498Szrj
619*38fd1498Szrj XDELETEVEC (list);
620*38fd1498Szrj
621*38fd1498Szrj return sum;
622*38fd1498Szrj }
623*38fd1498Szrj
624*38fd1498Szrj /* Dump all tracked instances of type ORIGIN. If we want to process custom
625*38fd1498Szrj order, CMP comparator can be provided. */
626*38fd1498Szrj
627*38fd1498Szrj template <class T>
628*38fd1498Szrj inline void
dump(mem_alloc_origin origin,int (* cmp)(const void * first,const void * second))629*38fd1498Szrj mem_alloc_description<T>::dump (mem_alloc_origin origin,
630*38fd1498Szrj int (*cmp) (const void *first,
631*38fd1498Szrj const void *second))
632*38fd1498Szrj {
633*38fd1498Szrj unsigned length;
634*38fd1498Szrj
635*38fd1498Szrj fprintf (stderr, "\n");
636*38fd1498Szrj
637*38fd1498Szrj mem_list_t *list = get_list (origin, &length, cmp);
638*38fd1498Szrj T total = get_sum (origin);
639*38fd1498Szrj
640*38fd1498Szrj T::dump_header (mem_location::get_origin_name (origin));
641*38fd1498Szrj for (int i = length - 1; i >= 0; i--)
642*38fd1498Szrj list[i].second->dump (list[i].first, total);
643*38fd1498Szrj
644*38fd1498Szrj total.dump_footer ();
645*38fd1498Szrj
646*38fd1498Szrj XDELETEVEC (list);
647*38fd1498Szrj
648*38fd1498Szrj fprintf (stderr, "\n");
649*38fd1498Szrj }
650*38fd1498Szrj
651*38fd1498Szrj #endif // GCC_MEM_STATS_H
652