xref: /dflybsd-src/contrib/gcc-8.0/gcc/mem-stats.h (revision 38fd149817dfbff97799f62fcb70be98c4e32523)
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