1 #ifndef GCC_MEM_STATS_H
2 #define GCC_MEM_STATS_H
4 /* Forward declaration. */
5 template<typename Key
, typename Value
,
6 typename Traits
= default_hashmap_traits
>
9 #define LOCATION_LINE_EXTRA_SPACE 30
10 #define LOCATION_LINE_WIDTH 48
12 /* Memory allocation location. */
15 /* Default constructor. */
21 mem_location (mem_alloc_origin origin
, bool ggc
,
22 const char *filename
= NULL
, int line
= 0,
23 const char *function
= NULL
):
24 m_filename (filename
), m_function (function
), m_line (line
), m_origin
25 (origin
), m_ggc (ggc
) {}
27 /* Copy constructor. */
29 mem_location (mem_location
&other
): m_filename (other
.m_filename
),
30 m_function (other
.m_function
), m_line (other
.m_line
),
31 m_origin (other
.m_origin
), m_ggc (other
.m_ggc
) {}
33 /* Compute hash value based on file name, function name and line in
34 source code. As there is just a single pointer registered for every
35 constant that points to e.g. the same file name, we can use hash
42 hash
.add_ptr (m_filename
);
43 hash
.add_ptr (m_function
);
44 hash
.add_int (m_line
);
49 /* Return true if the memory location is equal to OTHER. */
51 equal (mem_location
&other
)
53 return m_filename
== other
.m_filename
&& m_function
== other
.m_function
54 && m_line
== other
.m_line
;
57 /* Return trimmed filename for the location. */
59 get_trimmed_filename ()
61 const char *s1
= m_filename
;
64 while ((s2
= strstr (s1
, "gcc/")))
73 unsigned l
= strlen (get_trimmed_filename ()) + strlen (m_function
)
74 + LOCATION_LINE_EXTRA_SPACE
;
76 char *s
= XNEWVEC (char, l
);
77 sprintf (s
, "%s:%i (%s)", get_trimmed_filename (),
80 s
[MIN (LOCATION_LINE_WIDTH
, l
- 1)] = '\0';
85 /* Return display name associated to ORIGIN type. */
87 get_origin_name (mem_alloc_origin origin
)
89 return mem_alloc_origin_names
[(unsigned) origin
];
92 /* File name of source code. */
93 const char *m_filename
;
95 const char *m_function
;
96 /* Line number in source code. */
99 mem_alloc_origin m_origin
;
100 /* Flag if used by GGC allocation. */
104 /* Memory usage register to a memory location. */
107 /* Default constructor. */
108 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {}
111 mem_usage (size_t allocated
, size_t times
, size_t peak
, size_t instances
= 0):
112 m_allocated (allocated
), m_times (times
), m_peak (peak
),
113 m_instances (instances
) {}
115 /* Register overhead of SIZE bytes. */
117 register_overhead (size_t size
)
122 if (m_peak
< m_allocated
)
123 m_peak
= m_allocated
;
126 /* Release overhead of SIZE bytes. */
128 release_overhead (size_t size
)
130 gcc_assert (size
<= m_allocated
);
135 /* Sum the usage with SECOND usage. */
137 operator+ (const mem_usage
&second
)
139 return mem_usage (m_allocated
+ second
.m_allocated
,
140 m_times
+ second
.m_times
,
141 m_peak
+ second
.m_peak
,
142 m_instances
+ second
.m_instances
);
145 /* Comparison operator. */
147 operator< (const mem_usage
&second
) const
149 return (m_allocated
== second
.m_allocated
?
150 (m_peak
== second
.m_peak
? m_times
< second
.m_times
151 : m_peak
< second
.m_peak
) : m_allocated
< second
.m_allocated
);
154 /* Compare wrapper used by qsort method. */
156 compare (const void *first
, const void *second
)
158 typedef std::pair
<mem_location
*, mem_usage
*> mem_pair_t
;
160 const mem_pair_t f
= *(const mem_pair_t
*)first
;
161 const mem_pair_t s
= *(const mem_pair_t
*)second
;
163 return (*f
.second
) < (*s
.second
);
166 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */
168 dump (mem_location
*loc
, mem_usage
&total
) const
170 char *location_string
= loc
->to_string ();
172 fprintf (stderr
, "%-48s %10li:%5.1f%%%10li%10li:%5.1f%%%10s\n",
174 (long)m_allocated
, get_percent (m_allocated
, total
.m_allocated
),
175 (long)m_peak
, (long)m_times
,
176 get_percent (m_times
, total
.m_times
), loc
->m_ggc
? "ggc" : "heap");
178 free (location_string
);
186 fprintf (stderr
, "%s%54li%27li\n", "Total", (long)m_allocated
,
191 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */
193 get_percent (size_t nominator
, size_t denominator
)
195 return denominator
== 0 ? 0.0f
: nominator
* 100.0 / denominator
;
198 /* Print line made of dashes. */
200 print_dash_line (size_t count
= 140)
202 fprintf (stderr
, "%s\n", std::string (count
, '-').c_str ());
205 /* Dump header with NAME. */
207 dump_header (const char *name
)
209 fprintf (stderr
, "%-48s %11s%16s%10s%17s\n", name
, "Leak", "Peak",
214 /* Current number of allocated bytes. */
216 /* Number of allocations. */
218 /* Peak allocation in bytes. */
220 /* Number of container instances. */
224 /* Memory usage pair that connectes memory usage and number
225 of allocated bytes. */
227 struct mem_usage_pair
229 mem_usage_pair (T
*usage_
, size_t allocated_
): usage (usage_
),
230 allocated (allocated_
) {}
236 /* Memory allocation description. */
238 class mem_alloc_description
241 struct mem_alloc_hashmap_traits
: default_hashmap_traits
244 hash (const mem_location
*l
)
246 inchash::hash hstate
;
248 hstate
.add_ptr ((const void *)l
->m_filename
);
249 hstate
.add_ptr (l
->m_function
);
250 hstate
.add_int (l
->m_line
);
252 return hstate
.end ();
256 equal_keys (const mem_location
*l1
, const mem_location
*l2
)
258 return l1
->m_filename
== l2
->m_filename
259 && l1
->m_function
== l2
->m_function
260 && l1
->m_line
== l2
->m_line
;
264 /* Internal class type definitions. */
265 typedef hash_map
<mem_location
*, T
*, mem_alloc_hashmap_traits
> mem_map_t
;
266 typedef hash_map
<const void *, mem_usage_pair
<T
>, default_hashmap_traits
>
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