1 #ifndef GCC_MEM_STATS_H
2 #define GCC_MEM_STATS_H
4 /* Forward declaration. */
5 template<typename Key
, typename Value
,
6 typename Traits
= simple_hashmap_traits
<default_hash_traits
<Key
>,
10 #define LOCATION_LINE_EXTRA_SPACE 30
11 #define LOCATION_LINE_WIDTH 48
13 /* Memory allocation location. */
16 /* Default constructor. */
22 mem_location (mem_alloc_origin origin
, bool ggc
,
23 const char *filename
= NULL
, int line
= 0,
24 const char *function
= NULL
):
25 m_filename (filename
), m_function (function
), m_line (line
), m_origin
26 (origin
), m_ggc (ggc
) {}
28 /* Copy constructor. */
30 mem_location (mem_location
&other
): m_filename (other
.m_filename
),
31 m_function (other
.m_function
), m_line (other
.m_line
),
32 m_origin (other
.m_origin
), m_ggc (other
.m_ggc
) {}
34 /* Compute hash value based on file name, function name and line in
35 source code. As there is just a single pointer registered for every
36 constant that points to e.g. the same file name, we can use hash
43 hash
.add_ptr (m_filename
);
44 hash
.add_ptr (m_function
);
45 hash
.add_int (m_line
);
50 /* Return true if the memory location is equal to OTHER. */
52 equal (mem_location
&other
)
54 return m_filename
== other
.m_filename
&& m_function
== other
.m_function
55 && m_line
== other
.m_line
;
58 /* Return trimmed filename for the location. */
60 get_trimmed_filename ()
62 const char *s1
= m_filename
;
65 while ((s2
= strstr (s1
, "gcc/")))
74 unsigned l
= strlen (get_trimmed_filename ()) + strlen (m_function
)
75 + LOCATION_LINE_EXTRA_SPACE
;
77 char *s
= XNEWVEC (char, l
);
78 sprintf (s
, "%s:%i (%s)", get_trimmed_filename (),
81 s
[MIN (LOCATION_LINE_WIDTH
, l
- 1)] = '\0';
86 /* Return display name associated to ORIGIN type. */
88 get_origin_name (mem_alloc_origin origin
)
90 return mem_alloc_origin_names
[(unsigned) origin
];
93 /* File name of source code. */
94 const char *m_filename
;
96 const char *m_function
;
97 /* Line number in source code. */
100 mem_alloc_origin m_origin
;
101 /* Flag if used by GGC allocation. */
105 /* Memory usage register to a memory location. */
108 /* Default constructor. */
109 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
112 mem_usage (size_t allocated
, size_t times
, size_t peak
, size_t instances
= 0):
113 m_allocated (allocated
), m_times (times
), m_peak (peak
),
114 m_instances (instances
) {}
116 /* Register overhead of SIZE bytes. */
118 register_overhead (size_t size
)
123 if (m_peak
< m_allocated
)
124 m_peak
= m_allocated
;
127 /* Release overhead of SIZE bytes. */
129 release_overhead (size_t size
)
131 gcc_assert (size
<= m_allocated
);
136 /* Sum the usage with SECOND usage. */
138 operator+ (const mem_usage
&second
)
140 return mem_usage (m_allocated
+ second
.m_allocated
,
141 m_times
+ second
.m_times
,
142 m_peak
+ second
.m_peak
,
143 m_instances
+ second
.m_instances
);
146 /* Comparison operator. */
148 operator< (const mem_usage
&second
) const
150 return (m_allocated
== second
.m_allocated
?
151 (m_peak
== second
.m_peak
? m_times
< second
.m_times
152 : m_peak
< second
.m_peak
) : m_allocated
< second
.m_allocated
);
155 /* Compare wrapper used by qsort method. */
157 compare (const void *first
, const void *second
)
159 typedef std::pair
<mem_location
*, mem_usage
*> mem_pair_t
;
161 const mem_pair_t f
= *(const mem_pair_t
*)first
;
162 const mem_pair_t s
= *(const mem_pair_t
*)second
;
164 return (*f
.second
) < (*s
.second
);
167 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
169 dump (mem_location
*loc
, mem_usage
&total
) const
171 char *location_string
= loc
->to_string ();
173 fprintf (stderr
, "%-48s %10li:%5.1f%%%10li%10li:%5.1f%%%10s\n",
175 (long)m_allocated
, get_percent (m_allocated
, total
.m_allocated
),
176 (long)m_peak
, (long)m_times
,
177 get_percent (m_times
, total
.m_times
), loc
->m_ggc
? "ggc" : "heap");
179 free (location_string
);
187 fprintf (stderr
, "%s%54li%27li\n", "Total", (long)m_allocated
,
192 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */
194 get_percent (size_t nominator
, size_t denominator
)
196 return denominator
== 0 ? 0.0f
: nominator
* 100.0 / denominator
;
199 /* Print line made of dashes. */
201 print_dash_line (size_t count
= 140)
205 fputc ('\n', stderr
);
208 /* Dump header with NAME. */
210 dump_header (const char *name
)
212 fprintf (stderr
, "%-48s %11s%16s%10s%17s\n", name
, "Leak", "Peak",
217 /* Current number of allocated bytes. */
219 /* Number of allocations. */
221 /* Peak allocation in bytes. */
223 /* Number of container instances. */
227 /* Memory usage pair that connectes memory usage and number
228 of allocated bytes. */
230 struct mem_usage_pair
232 mem_usage_pair (T
*usage_
, size_t allocated_
): usage (usage_
),
233 allocated (allocated_
) {}
239 /* Memory allocation description. */
241 class mem_alloc_description
244 struct mem_location_hash
: nofree_ptr_hash
<mem_location
>
249 inchash::hash hstate
;
251 hstate
.add_ptr ((const void *)l
->m_filename
);
252 hstate
.add_ptr (l
->m_function
);
253 hstate
.add_int (l
->m_line
);
255 return hstate
.end ();
259 equal (value_type l1
, value_type l2
)
261 return l1
->m_filename
== l2
->m_filename
262 && l1
->m_function
== l2
->m_function
263 && l1
->m_line
== l2
->m_line
;
267 /* Internal class type definitions. */
268 typedef hash_map
<mem_location_hash
, T
*> mem_map_t
;
269 typedef hash_map
<const void *, mem_usage_pair
<T
> > reverse_mem_map_t
;
270 typedef hash_map
<const void *, std::pair
<T
*, size_t> > reverse_object_map_t
;
271 typedef std::pair
<mem_location
*, T
*> mem_list_t
;
273 /* Default contructor. */
274 mem_alloc_description ();
276 /* Default destructor. */
277 ~mem_alloc_description ();
279 /* Returns true if instance PTR is registered by the memory description. */
281 contains_descriptor_for_instance (const void *ptr
);
283 /* Return descriptor for instance PTR. */
285 get_descriptor_for_instance (const void *ptr
);
287 /* Register memory allocation descriptor for container PTR which is
288 described by a memory LOCATION. */
290 register_descriptor (const void *ptr
, mem_location
*location
);
292 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
293 type of container and GGC identifes if the allocation is handled in GGC
294 memory. Each location is identified by file NAME, LINE in source code and
297 register_descriptor (const void *ptr
, mem_alloc_origin origin
,
298 bool ggc
, const char *name
, int line
,
299 const char *function
);
301 /* Register instance overhead identified by PTR pointer. Allocation takes
304 register_instance_overhead (size_t size
, const void *ptr
);
306 /* For containers (and GGC) where we want to track every instance object,
307 we register allocation of SIZE bytes, identified by PTR pointer, belonging
308 to USAGE descriptor. */
310 register_object_overhead (T
*usage
, size_t size
, const void *ptr
);
312 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
313 remove the instance from reverse map. */
315 release_instance_overhead (void *ptr
, size_t size
,
316 bool remove_from_map
= false);
318 /* Release intance object identified by PTR pointer. */
320 release_object_overhead (void *ptr
);
322 /* Get sum value for ORIGIN type of allocation for the descriptor. */
324 get_sum (mem_alloc_origin origin
);
326 /* Get all tracked instances registered by the description. Items
327 are filtered by ORIGIN type, LENGTH is return value where we register
328 the number of elements in the list. If we want to process custom order,
329 CMP comparator can be provided. */
331 get_list (mem_alloc_origin origin
, unsigned *length
,
332 int (*cmp
) (const void *first
, const void *second
) = NULL
);
334 /* Dump all tracked instances of type ORIGIN. If we want to process custom
335 order, CMP comparator can be provided. */
336 void dump (mem_alloc_origin origin
,
337 int (*cmp
) (const void *first
, const void *second
) = NULL
);
339 /* Reverse object map used for every object allocation mapping. */
340 reverse_object_map_t
*m_reverse_object_map
;
343 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
344 in NAME source file, at LINE in source code, in FUNCTION. */
345 T
*register_overhead (size_t size
, mem_alloc_origin origin
, const char *name
,
346 int line
, const char *function
, const void *ptr
);
348 /* Allocation location coupled to the description. */
349 mem_location m_location
;
351 /* Location to usage mapping. */
354 /* Reverse pointer to usage mapping. */
355 reverse_mem_map_t
*m_reverse_map
;
359 /* Returns true if instance PTR is registered by the memory description. */
363 mem_alloc_description
<T
>::contains_descriptor_for_instance (const void *ptr
)
365 return m_reverse_map
->get (ptr
);
368 /* Return descriptor for instance PTR. */
372 mem_alloc_description
<T
>::get_descriptor_for_instance (const void *ptr
)
374 return m_reverse_map
->get (ptr
) ? (*m_reverse_map
->get (ptr
)).usage
: NULL
;
378 /* Register memory allocation descriptor for container PTR which is
379 described by a memory LOCATION. */
382 mem_alloc_description
<T
>::register_descriptor (const void *ptr
,
383 mem_location
*location
)
387 T
**slot
= m_map
->get (location
);
392 usage
->m_instances
++;
397 m_map
->put (location
, usage
);
400 if (!m_reverse_map
->get (ptr
))
401 m_reverse_map
->put (ptr
, mem_usage_pair
<T
> (usage
, 0));
406 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
407 type of container and GGC identifes if the allocation is handled in GGC
408 memory. Each location is identified by file NAME, LINE in source code and
413 mem_alloc_description
<T
>::register_descriptor (const void *ptr
,
414 mem_alloc_origin origin
,
416 const char *filename
,
418 const char *function
)
420 mem_location
*l
= new mem_location (origin
, ggc
, filename
, line
, function
);
421 return register_descriptor (ptr
, l
);
424 /* Register instance overhead identified by PTR pointer. Allocation takes
429 mem_alloc_description
<T
>::register_instance_overhead (size_t size
,
432 mem_usage_pair
<T
> *slot
= m_reverse_map
->get (ptr
);
435 /* Due to PCH, it can really happen. */
439 T
*usage
= (*slot
).usage
;
440 usage
->register_overhead (size
);
445 /* For containers (and GGC) where we want to track every instance object,
446 we register allocation of SIZE bytes, identified by PTR pointer, belonging
447 to USAGE descriptor. */
451 mem_alloc_description
<T
>::register_object_overhead (T
*usage
, size_t size
,
454 /* In case of GGC, it is possible to have already occupied the memory
456 m_reverse_object_map
->put (ptr
, std::pair
<T
*, size_t> (usage
, size
));
459 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
460 in NAME source file, at LINE in source code, in FUNCTION. */
464 mem_alloc_description
<T
>::register_overhead (size_t size
,
465 mem_alloc_origin origin
,
466 const char *filename
,
468 const char *function
,
471 T
*usage
= register_descriptor (ptr
, origin
, filename
, line
, function
);
472 usage
->register_overhead (size
);
477 /* Release PTR pointer of SIZE bytes. */
481 mem_alloc_description
<T
>::release_instance_overhead (void *ptr
, size_t size
,
482 bool remove_from_map
)
484 mem_usage_pair
<T
> *slot
= m_reverse_map
->get (ptr
);
488 /* Due to PCH, it can really happen. */
492 mem_usage_pair
<T
> usage_pair
= *slot
;
493 usage_pair
.usage
->release_overhead (size
);
496 m_reverse_map
->remove (ptr
);
499 /* Release intance object identified by PTR pointer. */
503 mem_alloc_description
<T
>::release_object_overhead (void *ptr
)
505 std::pair
<T
*, size_t> *entry
= m_reverse_object_map
->get (ptr
);
508 entry
->first
->release_overhead (entry
->second
);
509 m_reverse_object_map
->remove (ptr
);
513 /* Default contructor. */
517 mem_alloc_description
<T
>::mem_alloc_description ()
519 m_map
= new mem_map_t (13, false, false);
520 m_reverse_map
= new reverse_mem_map_t (13, false, false);
521 m_reverse_object_map
= new reverse_object_map_t (13, false, false);
524 /* Default destructor. */
528 mem_alloc_description
<T
>::~mem_alloc_description ()
530 for (typename
mem_map_t::iterator it
= m_map
->begin (); it
!= m_map
->end ();
538 delete m_reverse_map
;
539 delete m_reverse_object_map
;
542 /* Get all tracked instances registered by the description. Items are filtered
543 by ORIGIN type, LENGTH is return value where we register the number of
544 elements in the list. If we want to process custom order, CMP comparator
549 typename mem_alloc_description
<T
>::mem_list_t
*
550 mem_alloc_description
<T
>::get_list (mem_alloc_origin origin
, unsigned *length
,
551 int (*cmp
) (const void *first
, const void *second
))
553 /* vec data structure is not used because all vectors generate memory
554 allocation info a it would create a cycle. */
555 size_t element_size
= sizeof (mem_list_t
);
556 mem_list_t
*list
= XCNEWVEC (mem_list_t
, m_map
->elements ());
559 for (typename
mem_map_t::iterator it
= m_map
->begin (); it
!= m_map
->end ();
561 if ((*it
).first
->m_origin
== origin
)
562 list
[i
++] = std::pair
<mem_location
*, T
*> (*it
);
564 qsort (list
, i
, element_size
, cmp
== NULL
? T::compare
: cmp
);
570 /* Get sum value for ORIGIN type of allocation for the descriptor. */
574 mem_alloc_description
<T
>::get_sum (mem_alloc_origin origin
)
577 mem_list_t
*list
= get_list (origin
, &length
);
580 for (unsigned i
= 0; i
< length
; i
++)
581 sum
= sum
+ *list
[i
].second
;
588 /* Dump all tracked instances of type ORIGIN. If we want to process custom
589 order, CMP comparator can be provided. */
593 mem_alloc_description
<T
>::dump (mem_alloc_origin origin
,
594 int (*cmp
) (const void *first
,
599 fprintf (stderr
, "\n");
601 mem_list_t
*list
= get_list (origin
, &length
, cmp
);
602 T total
= get_sum (origin
);
604 T::dump_header (mem_location::get_origin_name (origin
));
605 for (int i
= length
- 1; i
>= 0; i
--)
606 list
[i
].second
->dump (list
[i
].first
, total
);
608 total
.dump_footer ();
612 fprintf (stderr
, "\n");
615 #endif // GCC_MEM_STATS_H