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)
203 fprintf (stderr
, "%s\n", std::string (count
, '-').c_str ());
206 /* Dump header with NAME. */
208 dump_header (const char *name
)
210 fprintf (stderr
, "%-48s %11s%16s%10s%17s\n", name
, "Leak", "Peak",
215 /* Current number of allocated bytes. */
217 /* Number of allocations. */
219 /* Peak allocation in bytes. */
221 /* Number of container instances. */
225 /* Memory usage pair that connectes memory usage and number
226 of allocated bytes. */
228 struct mem_usage_pair
230 mem_usage_pair (T
*usage_
, size_t allocated_
): usage (usage_
),
231 allocated (allocated_
) {}
237 /* Memory allocation description. */
239 class mem_alloc_description
242 struct mem_location_hash
: nofree_ptr_hash
<mem_location
>
247 inchash::hash hstate
;
249 hstate
.add_ptr ((const void *)l
->m_filename
);
250 hstate
.add_ptr (l
->m_function
);
251 hstate
.add_int (l
->m_line
);
253 return hstate
.end ();
257 equal (value_type l1
, value_type l2
)
259 return l1
->m_filename
== l2
->m_filename
260 && l1
->m_function
== l2
->m_function
261 && l1
->m_line
== l2
->m_line
;
265 /* Internal class type definitions. */
266 typedef hash_map
<mem_location_hash
, T
*> mem_map_t
;
267 typedef hash_map
<const void *, mem_usage_pair
<T
> > reverse_mem_map_t
;
268 typedef hash_map
<const void *, std::pair
<T
*, size_t> > reverse_object_map_t
;
269 typedef std::pair
<mem_location
*, T
*> mem_list_t
;
271 /* Default contructor. */
272 mem_alloc_description ();
274 /* Default destructor. */
275 ~mem_alloc_description ();
277 /* Returns true if instance PTR is registered by the memory description. */
279 contains_descriptor_for_instance (const void *ptr
);
281 /* Return descriptor for instance PTR. */
283 get_descriptor_for_instance (const void *ptr
);
285 /* Register memory allocation descriptor for container PTR which is
286 described by a memory LOCATION. */
288 register_descriptor (const void *ptr
, mem_location
*location
);
290 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
291 type of container and GGC identifes if the allocation is handled in GGC
292 memory. Each location is identified by file NAME, LINE in source code and
295 register_descriptor (const void *ptr
, mem_alloc_origin origin
,
296 bool ggc
, const char *name
, int line
,
297 const char *function
);
299 /* Register instance overhead identified by PTR pointer. Allocation takes
302 register_instance_overhead (size_t size
, const void *ptr
);
304 /* For containers (and GGC) where we want to track every instance object,
305 we register allocation of SIZE bytes, identified by PTR pointer, belonging
306 to USAGE descriptor. */
308 register_object_overhead (T
*usage
, size_t size
, const void *ptr
);
310 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
311 remove the instance from reverse map. */
313 release_instance_overhead (void *ptr
, size_t size
,
314 bool remove_from_map
= false);
316 /* Release intance object identified by PTR pointer. */
318 release_object_overhead (void *ptr
);
320 /* Get sum value for ORIGIN type of allocation for the descriptor. */
322 get_sum (mem_alloc_origin origin
);
324 /* Get all tracked instances registered by the description. Items
325 are filtered by ORIGIN type, LENGTH is return value where we register
326 the number of elements in the list. If we want to process custom order,
327 CMP comparator can be provided. */
329 get_list (mem_alloc_origin origin
, unsigned *length
,
330 int (*cmp
) (const void *first
, const void *second
) = NULL
);
332 /* Dump all tracked instances of type ORIGIN. If we want to process custom
333 order, CMP comparator can be provided. */
334 void dump (mem_alloc_origin origin
,
335 int (*cmp
) (const void *first
, const void *second
) = NULL
);
337 /* Reverse object map used for every object allocation mapping. */
338 reverse_object_map_t
*m_reverse_object_map
;
341 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
342 in NAME source file, at LINE in source code, in FUNCTION. */
343 T
*register_overhead (size_t size
, mem_alloc_origin origin
, const char *name
,
344 int line
, const char *function
, const void *ptr
);
346 /* Allocation location coupled to the description. */
347 mem_location m_location
;
349 /* Location to usage mapping. */
352 /* Reverse pointer to usage mapping. */
353 reverse_mem_map_t
*m_reverse_map
;
357 /* Returns true if instance PTR is registered by the memory description. */
361 mem_alloc_description
<T
>::contains_descriptor_for_instance (const void *ptr
)
363 return m_reverse_map
->get (ptr
);
366 /* Return descriptor for instance PTR. */
370 mem_alloc_description
<T
>::get_descriptor_for_instance (const void *ptr
)
372 return m_reverse_map
->get (ptr
) ? (*m_reverse_map
->get (ptr
)).usage
: NULL
;
376 /* Register memory allocation descriptor for container PTR which is
377 described by a memory LOCATION. */
380 mem_alloc_description
<T
>::register_descriptor (const void *ptr
,
381 mem_location
*location
)
385 T
**slot
= m_map
->get (location
);
390 usage
->m_instances
++;
395 m_map
->put (location
, usage
);
398 if (!m_reverse_map
->get (ptr
))
399 m_reverse_map
->put (ptr
, mem_usage_pair
<T
> (usage
, 0));
404 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
405 type of container and GGC identifes if the allocation is handled in GGC
406 memory. Each location is identified by file NAME, LINE in source code and
411 mem_alloc_description
<T
>::register_descriptor (const void *ptr
,
412 mem_alloc_origin origin
,
414 const char *filename
,
416 const char *function
)
418 mem_location
*l
= new mem_location (origin
, ggc
, filename
, line
, function
);
419 return register_descriptor (ptr
, l
);
422 /* Register instance overhead identified by PTR pointer. Allocation takes
427 mem_alloc_description
<T
>::register_instance_overhead (size_t size
,
430 mem_usage_pair
<T
> *slot
= m_reverse_map
->get (ptr
);
433 /* Due to PCH, it can really happen. */
437 T
*usage
= (*slot
).usage
;
438 usage
->register_overhead (size
);
443 /* For containers (and GGC) where we want to track every instance object,
444 we register allocation of SIZE bytes, identified by PTR pointer, belonging
445 to USAGE descriptor. */
449 mem_alloc_description
<T
>::register_object_overhead (T
*usage
, size_t size
,
452 /* In case of GGC, it is possible to have already occupied the memory
454 m_reverse_object_map
->put (ptr
, std::pair
<T
*, size_t> (usage
, size
));
457 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
458 in NAME source file, at LINE in source code, in FUNCTION. */
462 mem_alloc_description
<T
>::register_overhead (size_t size
,
463 mem_alloc_origin origin
,
464 const char *filename
,
466 const char *function
,
469 T
*usage
= register_descriptor (ptr
, origin
, filename
, line
, function
);
470 usage
->register_overhead (size
);
475 /* Release PTR pointer of SIZE bytes. */
479 mem_alloc_description
<T
>::release_instance_overhead (void *ptr
, size_t size
,
480 bool remove_from_map
)
482 mem_usage_pair
<T
> *slot
= m_reverse_map
->get (ptr
);
486 /* Due to PCH, it can really happen. */
490 mem_usage_pair
<T
> usage_pair
= *slot
;
491 usage_pair
.usage
->release_overhead (size
);
494 m_reverse_map
->remove (ptr
);
497 /* Release intance object identified by PTR pointer. */
501 mem_alloc_description
<T
>::release_object_overhead (void *ptr
)
503 std::pair
<T
*, size_t> *entry
= m_reverse_object_map
->get (ptr
);
506 entry
->first
->release_overhead (entry
->second
);
507 m_reverse_object_map
->remove (ptr
);
511 /* Default contructor. */
515 mem_alloc_description
<T
>::mem_alloc_description ()
517 m_map
= new mem_map_t (13, false, false);
518 m_reverse_map
= new reverse_mem_map_t (13, false, false);
519 m_reverse_object_map
= new reverse_object_map_t (13, false, false);
522 /* Default destructor. */
526 mem_alloc_description
<T
>::~mem_alloc_description ()
528 for (typename
mem_map_t::iterator it
= m_map
->begin (); it
!= m_map
->end ();
536 delete m_reverse_map
;
537 delete m_reverse_object_map
;
540 /* Get all tracked instances registered by the description. Items are filtered
541 by ORIGIN type, LENGTH is return value where we register the number of
542 elements in the list. If we want to process custom order, CMP comparator
547 typename mem_alloc_description
<T
>::mem_list_t
*
548 mem_alloc_description
<T
>::get_list (mem_alloc_origin origin
, unsigned *length
,
549 int (*cmp
) (const void *first
, const void *second
))
551 /* vec data structure is not used because all vectors generate memory
552 allocation info a it would create a cycle. */
553 size_t element_size
= sizeof (mem_list_t
);
554 mem_list_t
*list
= XCNEWVEC (mem_list_t
, m_map
->elements ());
557 for (typename
mem_map_t::iterator it
= m_map
->begin (); it
!= m_map
->end ();
559 if ((*it
).first
->m_origin
== origin
)
560 list
[i
++] = std::pair
<mem_location
*, T
*> (*it
);
562 qsort (list
, i
, element_size
, cmp
== NULL
? T::compare
: cmp
);
568 /* Get sum value for ORIGIN type of allocation for the descriptor. */
572 mem_alloc_description
<T
>::get_sum (mem_alloc_origin origin
)
575 mem_list_t
*list
= get_list (origin
, &length
);
578 for (unsigned i
= 0; i
< length
; i
++)
579 sum
= sum
+ *list
[i
].second
;
586 /* Dump all tracked instances of type ORIGIN. If we want to process custom
587 order, CMP comparator can be provided. */
591 mem_alloc_description
<T
>::dump (mem_alloc_origin origin
,
592 int (*cmp
) (const void *first
,
597 fprintf (stderr
, "\n");
599 mem_list_t
*list
= get_list (origin
, &length
, cmp
);
600 T total
= get_sum (origin
);
602 T::dump_header (mem_location::get_origin_name (origin
));
603 for (int i
= length
- 1; i
>= 0; i
--)
604 list
[i
].second
->dump (list
[i
].first
, total
);
606 total
.dump_footer ();
610 fprintf (stderr
, "\n");
613 #endif // GCC_MEM_STATS_H