1 #ifndef GCC_MEM_STATS_H
2 #define GCC_MEM_STATS_H
4 #include "hash-map-traits.h"
6 #include "mem-stats-traits.h"
9 /* Forward declaration. */
10 template<typename Key
, typename Value
,
11 typename Traits
= default_hashmap_traits
>
14 /* Memory allocation location. */
17 /* Default constructor. */
18 inline mem_location () {}
21 inline mem_location (const char *filename
, const char *function
, int line
,
22 mem_alloc_origin origin
, bool ggc
):
23 m_filename (filename
), m_function (function
), m_line (line
), m_origin
24 (origin
), m_ggc (ggc
) {}
26 /* Compute hash value based on file name, function name and line in
27 source code. As there is just a single pointer registered for every
28 constant that points to e.g. the same file name, we can use hash
34 hash
.add_ptr (m_filename
);
35 hash
.add_ptr (m_function
);
36 hash
.add_int (m_line
);
41 /* Return true if the memory location is equal to OTHER. */
42 int equal (mem_location
&other
)
44 return m_filename
== other
.m_filename
&& m_function
== other
.m_function
45 && m_line
== other
.m_line
;
48 /* Return trimmed filename for the location. */
49 inline const char *get_trimmed_filename ()
51 const char *s1
= m_filename
;
54 while ((s2
= strstr (s1
, "gcc/")))
60 /* Return display name associated to ORIGIN type. */
61 static const char *get_origin_name (mem_alloc_origin origin
)
63 return mem_alloc_origin_names
[(unsigned) origin
];
66 /* File name of source code. */
67 const char *m_filename
;
69 const char *m_function
;
70 /* Line number in source code. */
73 mem_alloc_origin m_origin
;
74 /* Flag if used by GGC allocation. */
78 /* Memory usage register to a memory location. */
81 /* Default constructor. */
82 mem_usage (): m_allocated (0), m_times (0), m_peak (0) {}
85 mem_usage (size_t allocated
, size_t times
, size_t peak
):
86 m_allocated (allocated
), m_times (times
), m_peak (peak
) {}
88 /* Register overhead of SIZE bytes. */
89 inline void register_overhead (size_t size
)
94 if (m_peak
< m_allocated
)
98 /* Release overhead of SIZE bytes. */
99 inline void release_overhead (size_t size
)
101 gcc_assert (size
<= m_allocated
);
106 /* Sum the usage with SECOND usage. */
107 mem_usage
operator+ (const mem_usage
&second
)
109 return mem_usage (m_allocated
+ second
.m_allocated
,
110 m_times
+ second
.m_times
,
111 m_peak
+ second
.m_peak
);
114 /* Comparison operator. */
115 inline bool operator< (const mem_usage
&second
) const
117 return (m_allocated
== second
.m_allocated
?
118 (m_peak
== second
.m_peak
? m_times
< second
.m_times
119 : m_peak
< second
.m_peak
) : m_allocated
< second
.m_allocated
);
122 /* Compare wrapper used by qsort method. */
123 static int compare (const void *first
, const void *second
)
125 typedef std::pair
<mem_location
*, mem_usage
*> mem_pair_t
;
127 const mem_pair_t f
= *(const mem_pair_t
*)first
;
128 const mem_pair_t s
= *(const mem_pair_t
*)second
;
130 return (*f
.second
) < (*s
.second
);
133 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
134 inline void dump (mem_location
*loc
, mem_usage
&total
) const
137 sprintf (s
, "%s:%i (%s)", loc
->get_trimmed_filename (),
138 loc
->m_line
, loc
->m_function
);
142 fprintf (stderr
, "%-48s %10li:%5.1f%%%10li%10li:%5.1f%%%10s\n", s
,
143 (long)m_allocated
, get_percent (m_allocated
, total
.m_allocated
),
144 (long)m_peak
, (long)m_times
,
145 get_percent (m_times
, total
.m_times
), loc
->m_ggc
? "ggc" : "heap");
149 inline void dump_footer ()
152 fprintf (stderr
, "%s%54li%27li\n", "Total", (long)m_allocated
,
157 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */
158 static inline float get_percent (size_t nominator
, size_t denominator
)
160 return denominator
== 0 ? 0.0f
: nominator
* 100.0 / denominator
;
163 /* Print line made of dashes. */
164 static inline void print_dash_line ()
166 fprintf (stderr
, "%s\n", std::string (128, '-').c_str ());
169 /* Dump header with NAME. */
170 static inline void dump_header (const char *name
)
172 fprintf (stderr
, "%-48s %11s%16s%10s%17s\n", name
, "Leak", "Peak",
177 /* Current number of allocated bytes. */
179 /* Number of allocations. */
181 /* Peak allocation in bytes. */
185 /* Memory usage pair that connectes memory usage and number
186 of allocated bytes. */
188 struct mem_usage_pair
190 mem_usage_pair (T
*usage_
, size_t allocated_
): usage (usage_
),
191 allocated (allocated_
) {}
197 /* Memory allocation description. */
199 class mem_alloc_description
202 struct mem_alloc_hashmap_traits
: default_hashmap_traits
205 hash (const mem_location
*l
)
207 inchash::hash hstate
;
209 hstate
.add_ptr ((const void *)l
->m_filename
);
210 hstate
.add_ptr (l
->m_function
);
211 hstate
.add_int (l
->m_line
);
213 return hstate
.end ();
217 equal_keys (const mem_location
*l1
, const mem_location
*l2
)
219 return l1
->m_filename
== l2
->m_filename
220 && l1
->m_function
== l2
->m_function
221 && l1
->m_line
== l2
->m_line
;
225 /* Internal class type definitions. */
226 typedef hash_map
<mem_location
*, T
*, mem_alloc_hashmap_traits
> mem_map_t
;
227 typedef hash_map
<const void *, mem_usage_pair
<T
>, default_hashmap_traits
>
229 typedef hash_map
<const void *, std::pair
<T
*, size_t> > reverse_object_map_t
;
230 typedef std::pair
<mem_location
*, T
*> mem_list_t
;
232 /* Default contructor. */
233 mem_alloc_description ();
235 /* Default destructor. */
236 ~mem_alloc_description ();
238 /* Returns true if instance PTR is registered by the memory description. */
239 bool contains_descriptor_for_instance (const void *ptr
);
241 /* Return descriptor for instance PTR. */
242 T
*get_descriptor_for_instance (const void *ptr
);
244 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
245 type of container and GGC identifes if the allocation is handled in GGC
246 memory. Each location is identified by file NAME, LINE in source code and
248 T
*register_descriptor (const void *ptr
, mem_alloc_origin origin
,
249 bool ggc
, const char *name
, int line
,
250 const char *function
);
252 /* Register instance overhead identified by PTR pointer. Allocation takes
254 T
*register_instance_overhead (size_t size
, const void *ptr
);
256 /* For containers (and GGC) where we want to track every instance object,
257 we register allocation of SIZE bytes, identified by PTR pointer, belonging
258 to USAGE descriptor. */
259 void register_object_overhead (T
*usage
, size_t size
, const void *ptr
);
261 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
262 remove the instance from reverse map. */
263 void release_instance_overhead (void *ptr
, size_t size
,
264 bool remove_from_map
= false);
266 /* Release intance object identified by PTR pointer. */
267 void release_object_overhead (void *ptr
);
269 /* Get sum value for ORIGIN type of allocation for the descriptor. */
270 T
get_sum (mem_alloc_origin origin
);
272 /* Get all tracked instances registered by the description. Items
273 are filtered by ORIGIN type, LENGTH is return value where we register
274 the number of elements in the list. If we want to process custom order,
275 CMP comparator can be provided. */
276 mem_list_t
*get_list (mem_alloc_origin origin
, unsigned *length
,
277 int (*cmp
) (const void *first
, const void *second
)
280 /* Dump all tracked instances of type ORIGIN. If we want to process custom
281 order, CMP comparator can be provided. */
282 void dump (mem_alloc_origin origin
,
283 int (*cmp
) (const void *first
, const void *second
) = NULL
);
285 /* Reverse object map used for every object allocation mapping. */
286 reverse_object_map_t
*m_reverse_object_map
;
289 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
290 in NAME source file, at LINE in source code, in FUNCTION. */
291 T
*register_overhead (size_t size
, mem_alloc_origin origin
, const char *name
,
292 int line
, const char *function
, const void *ptr
);
294 /* Allocation location coupled to the description. */
295 mem_location m_location
;
297 /* Location to usage mapping. */
300 /* Reverse pointer to usage mapping. */
301 reverse_mem_map_t
*m_reverse_map
;
304 #include "hash-map.h"
306 /* Returns true if instance PTR is registered by the memory description. */
310 mem_alloc_description
<T
>::contains_descriptor_for_instance (const void *ptr
)
312 return m_reverse_map
->get (ptr
);
315 /* Return descriptor for instance PTR. */
319 mem_alloc_description
<T
>::get_descriptor_for_instance (const void *ptr
)
321 return m_reverse_map
->get (ptr
) ? (*m_reverse_map
->get (ptr
)).usage
: NULL
;
324 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
325 type of container and GGC identifes if the allocation is handled in GGC
326 memory. Each location is identified by file NAME, LINE in source code and
331 mem_alloc_description
<T
>::register_descriptor (const void *ptr
,
332 mem_alloc_origin origin
,
334 const char *filename
,
336 const char *function
)
338 mem_location
*l
= new mem_location (filename
, function
, line
, origin
, ggc
);
341 T
**slot
= m_map
->get (l
);
350 m_map
->put (l
, usage
);
353 if (!m_reverse_map
->get (ptr
))
354 m_reverse_map
->put (ptr
, mem_usage_pair
<T
> (usage
, 0));
359 /* Register instance overhead identified by PTR pointer. Allocation takes
364 mem_alloc_description
<T
>::register_instance_overhead (size_t size
,
367 mem_usage_pair
<T
> *slot
= m_reverse_map
->get (ptr
);
370 /* Due to PCH, it can really happen. */
374 T
*usage
= (*slot
).usage
;
375 usage
->register_overhead (size
);
380 /* For containers (and GGC) where we want to track every instance object,
381 we register allocation of SIZE bytes, identified by PTR pointer, belonging
382 to USAGE descriptor. */
386 mem_alloc_description
<T
>::register_object_overhead (T
*usage
, size_t size
,
389 /* In case of GGC, it is possible to have already occupied the memory
391 m_reverse_object_map
->put (ptr
, std::pair
<T
*, size_t> (usage
, size
));
394 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
395 in NAME source file, at LINE in source code, in FUNCTION. */
399 mem_alloc_description
<T
>::register_overhead (size_t size
,
400 mem_alloc_origin origin
,
401 const char *filename
,
403 const char *function
,
406 T
*usage
= register_descriptor (ptr
, origin
, filename
, line
, function
);
407 usage
->register_overhead (size
);
412 /* Release PTR pointer of SIZE bytes. */
416 mem_alloc_description
<T
>::release_instance_overhead (void *ptr
, size_t size
,
417 bool remove_from_map
)
419 mem_usage_pair
<T
> *slot
= m_reverse_map
->get (ptr
);
423 /* Due to PCH, it can really happen. */
427 mem_usage_pair
<T
> usage_pair
= *slot
;
428 usage_pair
.usage
->release_overhead (size
);
431 m_reverse_map
->remove (ptr
);
434 /* Release intance object identified by PTR pointer. */
438 mem_alloc_description
<T
>::release_object_overhead (void *ptr
)
440 std::pair
<T
*, size_t> *entry
= m_reverse_object_map
->get (ptr
);
443 entry
->first
->release_overhead (entry
->second
);
444 m_reverse_object_map
->remove (ptr
);
448 /* Default contructor. */
452 mem_alloc_description
<T
>::mem_alloc_description ()
454 m_map
= new mem_map_t (13, false, false);
455 m_reverse_map
= new reverse_mem_map_t (13, false, false);
456 m_reverse_object_map
= new reverse_object_map_t (13, false, false);
459 /* Default destructor. */
463 mem_alloc_description
<T
>::~mem_alloc_description ()
465 for (typename
mem_map_t::iterator it
= m_map
->begin (); it
!= m_map
->end ();
473 delete m_reverse_map
;
474 delete m_reverse_object_map
;
477 /* Get all tracked instances registered by the description. Items are filtered
478 by ORIGIN type, LENGTH is return value where we register the number of
479 elements in the list. If we want to process custom order, CMP comparator
484 typename mem_alloc_description
<T
>::mem_list_t
*
485 mem_alloc_description
<T
>::get_list (mem_alloc_origin origin
, unsigned *length
,
486 int (*cmp
) (const void *first
, const void *second
))
488 /* vec data structure is not used because all vectors generate memory
489 allocation info a it would create a cycle. */
490 size_t element_size
= sizeof (mem_list_t
);
491 mem_list_t
*list
= XCNEWVEC (mem_list_t
, m_map
->elements ());
494 for (typename
mem_map_t::iterator it
= m_map
->begin (); it
!= m_map
->end ();
496 if ((*it
).first
->m_origin
== origin
)
497 list
[i
++] = std::pair
<mem_location
*, T
*> (*it
);
499 qsort (list
, i
, element_size
, cmp
== NULL
? T::compare
: cmp
);
505 /* Get sum value for ORIGIN type of allocation for the descriptor. */
509 mem_alloc_description
<T
>::get_sum (mem_alloc_origin origin
)
512 mem_list_t
*list
= get_list (origin
, &length
);
515 for (unsigned i
= 0; i
< length
; i
++)
516 sum
= sum
+ *list
[i
].second
;
523 /* Dump all tracked instances of type ORIGIN. If we want to process custom
524 order, CMP comparator can be provided. */
528 mem_alloc_description
<T
>::dump (mem_alloc_origin origin
,
529 int (*cmp
) (const void *first
,
534 fprintf (stderr
, "\n");
536 mem_list_t
*list
= get_list (origin
, &length
, cmp
);
537 T total
= get_sum (origin
);
539 T::dump_header (mem_location::get_origin_name (origin
));
540 for (int i
= length
- 1; i
>= 0; i
--)
541 list
[i
].second
->dump (list
[i
].first
, total
);
543 total
.dump_footer ();
547 fprintf (stderr
, "\n");
550 #endif // GCC_MEM_STATS_H