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
> > >
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_location_hash
: nofree_ptr_hash
<mem_location
>
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 (value_type l1
, value_type 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_hash
, T
*> mem_map_t
;
266 typedef hash_map
<const void *, mem_usage_pair
<T
> > reverse_mem_map_t
;
267 typedef hash_map
<const void *, std::pair
<T
*, size_t> > reverse_object_map_t
;
268 typedef std::pair
<mem_location
*, T
*> mem_list_t
;
270 /* Default contructor. */
271 mem_alloc_description ();
273 /* Default destructor. */
274 ~mem_alloc_description ();
276 /* Returns true if instance PTR is registered by the memory description. */
278 contains_descriptor_for_instance (const void *ptr
);
280 /* Return descriptor for instance PTR. */
282 get_descriptor_for_instance (const void *ptr
);
284 /* Register memory allocation descriptor for container PTR which is
285 described by a memory LOCATION. */
287 register_descriptor (const void *ptr
, mem_location
*location
);
289 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
290 type of container and GGC identifes if the allocation is handled in GGC
291 memory. Each location is identified by file NAME, LINE in source code and
294 register_descriptor (const void *ptr
, mem_alloc_origin origin
,
295 bool ggc
, const char *name
, int line
,
296 const char *function
);
298 /* Register instance overhead identified by PTR pointer. Allocation takes
301 register_instance_overhead (size_t size
, const void *ptr
);
303 /* For containers (and GGC) where we want to track every instance object,
304 we register allocation of SIZE bytes, identified by PTR pointer, belonging
305 to USAGE descriptor. */
307 register_object_overhead (T
*usage
, size_t size
, const void *ptr
);
309 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true,
310 remove the instance from reverse map. */
312 release_instance_overhead (void *ptr
, size_t size
,
313 bool remove_from_map
= false);
315 /* Release intance object identified by PTR pointer. */
317 release_object_overhead (void *ptr
);
319 /* Get sum value for ORIGIN type of allocation for the descriptor. */
321 get_sum (mem_alloc_origin origin
);
323 /* Get all tracked instances registered by the description. Items
324 are filtered by ORIGIN type, LENGTH is return value where we register
325 the number of elements in the list. If we want to process custom order,
326 CMP comparator can be provided. */
328 get_list (mem_alloc_origin origin
, unsigned *length
,
329 int (*cmp
) (const void *first
, const void *second
) = NULL
);
331 /* Dump all tracked instances of type ORIGIN. If we want to process custom
332 order, CMP comparator can be provided. */
333 void dump (mem_alloc_origin origin
,
334 int (*cmp
) (const void *first
, const void *second
) = NULL
);
336 /* Reverse object map used for every object allocation mapping. */
337 reverse_object_map_t
*m_reverse_object_map
;
340 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
341 in NAME source file, at LINE in source code, in FUNCTION. */
342 T
*register_overhead (size_t size
, mem_alloc_origin origin
, const char *name
,
343 int line
, const char *function
, const void *ptr
);
345 /* Allocation location coupled to the description. */
346 mem_location m_location
;
348 /* Location to usage mapping. */
351 /* Reverse pointer to usage mapping. */
352 reverse_mem_map_t
*m_reverse_map
;
356 /* Returns true if instance PTR is registered by the memory description. */
360 mem_alloc_description
<T
>::contains_descriptor_for_instance (const void *ptr
)
362 return m_reverse_map
->get (ptr
);
365 /* Return descriptor for instance PTR. */
369 mem_alloc_description
<T
>::get_descriptor_for_instance (const void *ptr
)
371 return m_reverse_map
->get (ptr
) ? (*m_reverse_map
->get (ptr
)).usage
: NULL
;
375 /* Register memory allocation descriptor for container PTR which is
376 described by a memory LOCATION. */
379 mem_alloc_description
<T
>::register_descriptor (const void *ptr
,
380 mem_location
*location
)
384 T
**slot
= m_map
->get (location
);
389 usage
->m_instances
++;
394 m_map
->put (location
, usage
);
397 if (!m_reverse_map
->get (ptr
))
398 m_reverse_map
->put (ptr
, mem_usage_pair
<T
> (usage
, 0));
403 /* Register memory allocation descriptor for container PTR. ORIGIN identifies
404 type of container and GGC identifes if the allocation is handled in GGC
405 memory. Each location is identified by file NAME, LINE in source code and
410 mem_alloc_description
<T
>::register_descriptor (const void *ptr
,
411 mem_alloc_origin origin
,
413 const char *filename
,
415 const char *function
)
417 mem_location
*l
= new mem_location (origin
, ggc
, filename
, line
, function
);
418 return register_descriptor (ptr
, l
);
421 /* Register instance overhead identified by PTR pointer. Allocation takes
426 mem_alloc_description
<T
>::register_instance_overhead (size_t size
,
429 mem_usage_pair
<T
> *slot
= m_reverse_map
->get (ptr
);
432 /* Due to PCH, it can really happen. */
436 T
*usage
= (*slot
).usage
;
437 usage
->register_overhead (size
);
442 /* For containers (and GGC) where we want to track every instance object,
443 we register allocation of SIZE bytes, identified by PTR pointer, belonging
444 to USAGE descriptor. */
448 mem_alloc_description
<T
>::register_object_overhead (T
*usage
, size_t size
,
451 /* In case of GGC, it is possible to have already occupied the memory
453 m_reverse_object_map
->put (ptr
, std::pair
<T
*, size_t> (usage
, size
));
456 /* Register overhead of SIZE bytes of ORIGIN type. PTR pointer is allocated
457 in NAME source file, at LINE in source code, in FUNCTION. */
461 mem_alloc_description
<T
>::register_overhead (size_t size
,
462 mem_alloc_origin origin
,
463 const char *filename
,
465 const char *function
,
468 T
*usage
= register_descriptor (ptr
, origin
, filename
, line
, function
);
469 usage
->register_overhead (size
);
474 /* Release PTR pointer of SIZE bytes. */
478 mem_alloc_description
<T
>::release_instance_overhead (void *ptr
, size_t size
,
479 bool remove_from_map
)
481 mem_usage_pair
<T
> *slot
= m_reverse_map
->get (ptr
);
485 /* Due to PCH, it can really happen. */
489 mem_usage_pair
<T
> usage_pair
= *slot
;
490 usage_pair
.usage
->release_overhead (size
);
493 m_reverse_map
->remove (ptr
);
496 /* Release intance object identified by PTR pointer. */
500 mem_alloc_description
<T
>::release_object_overhead (void *ptr
)
502 std::pair
<T
*, size_t> *entry
= m_reverse_object_map
->get (ptr
);
505 entry
->first
->release_overhead (entry
->second
);
506 m_reverse_object_map
->remove (ptr
);
510 /* Default contructor. */
514 mem_alloc_description
<T
>::mem_alloc_description ()
516 m_map
= new mem_map_t (13, false, false);
517 m_reverse_map
= new reverse_mem_map_t (13, false, false);
518 m_reverse_object_map
= new reverse_object_map_t (13, false, false);
521 /* Default destructor. */
525 mem_alloc_description
<T
>::~mem_alloc_description ()
527 for (typename
mem_map_t::iterator it
= m_map
->begin (); it
!= m_map
->end ();
535 delete m_reverse_map
;
536 delete m_reverse_object_map
;
539 /* Get all tracked instances registered by the description. Items are filtered
540 by ORIGIN type, LENGTH is return value where we register the number of
541 elements in the list. If we want to process custom order, CMP comparator
546 typename mem_alloc_description
<T
>::mem_list_t
*
547 mem_alloc_description
<T
>::get_list (mem_alloc_origin origin
, unsigned *length
,
548 int (*cmp
) (const void *first
, const void *second
))
550 /* vec data structure is not used because all vectors generate memory
551 allocation info a it would create a cycle. */
552 size_t element_size
= sizeof (mem_list_t
);
553 mem_list_t
*list
= XCNEWVEC (mem_list_t
, m_map
->elements ());
556 for (typename
mem_map_t::iterator it
= m_map
->begin (); it
!= m_map
->end ();
558 if ((*it
).first
->m_origin
== origin
)
559 list
[i
++] = std::pair
<mem_location
*, T
*> (*it
);
561 qsort (list
, i
, element_size
, cmp
== NULL
? T::compare
: cmp
);
567 /* Get sum value for ORIGIN type of allocation for the descriptor. */
571 mem_alloc_description
<T
>::get_sum (mem_alloc_origin origin
)
574 mem_list_t
*list
= get_list (origin
, &length
);
577 for (unsigned i
= 0; i
< length
; i
++)
578 sum
= sum
+ *list
[i
].second
;
585 /* Dump all tracked instances of type ORIGIN. If we want to process custom
586 order, CMP comparator can be provided. */
590 mem_alloc_description
<T
>::dump (mem_alloc_origin origin
,
591 int (*cmp
) (const void *first
,
596 fprintf (stderr
, "\n");
598 mem_list_t
*list
= get_list (origin
, &length
, cmp
);
599 T total
= get_sum (origin
);
601 T::dump_header (mem_location::get_origin_name (origin
));
602 for (int i
= length
- 1; i
>= 0; i
--)
603 list
[i
].second
->dump (list
[i
].first
, total
);
605 total
.dump_footer ();
609 fprintf (stderr
, "\n");
612 #endif // GCC_MEM_STATS_H