Mercurial > hg > CbC > CbC_gcc
comparison gcc/mem-stats.h @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
comparison
equal
deleted
inserted
replaced
131:84e7813d76e9 | 145:1830386684a0 |
---|---|
1 /* A memory statistics tracking infrastructure. | 1 /* A memory statistics tracking infrastructure. |
2 Copyright (C) 2015-2018 Free Software Foundation, Inc. | 2 Copyright (C) 2015-2020 Free Software Foundation, Inc. |
3 Contributed by Martin Liska <mliska@suse.cz> | 3 Contributed by Martin Liska <mliska@suse.cz> |
4 | 4 |
5 This file is part of GCC. | 5 This file is part of GCC. |
6 | 6 |
7 GCC is free software; you can redistribute it and/or modify it under | 7 GCC is free software; you can redistribute it and/or modify it under |
29 | 29 |
30 #define LOCATION_LINE_EXTRA_SPACE 30 | 30 #define LOCATION_LINE_EXTRA_SPACE 30 |
31 #define LOCATION_LINE_WIDTH 48 | 31 #define LOCATION_LINE_WIDTH 48 |
32 | 32 |
33 /* Memory allocation location. */ | 33 /* Memory allocation location. */ |
34 struct mem_location | 34 class mem_location |
35 { | 35 { |
36 public: | |
36 /* Default constructor. */ | 37 /* Default constructor. */ |
37 inline | 38 inline |
38 mem_location () {} | 39 mem_location () {} |
39 | 40 |
40 /* Constructor. */ | 41 /* Constructor. */ |
121 /* Flag if used by GGC allocation. */ | 122 /* Flag if used by GGC allocation. */ |
122 bool m_ggc; | 123 bool m_ggc; |
123 }; | 124 }; |
124 | 125 |
125 /* Memory usage register to a memory location. */ | 126 /* Memory usage register to a memory location. */ |
126 struct mem_usage | 127 class mem_usage |
127 { | 128 { |
129 public: | |
128 /* Default constructor. */ | 130 /* Default constructor. */ |
129 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {} | 131 mem_usage (): m_allocated (0), m_times (0), m_peak (0), m_instances (1) {} |
130 | 132 |
131 /* Constructor. */ | 133 /* Constructor. */ |
132 mem_usage (size_t allocated, size_t times, size_t peak, size_t instances = 0): | 134 mem_usage (size_t allocated, size_t times, size_t peak, size_t instances = 0): |
203 inline void | 205 inline void |
204 dump (mem_location *loc, mem_usage &total) const | 206 dump (mem_location *loc, mem_usage &total) const |
205 { | 207 { |
206 char *location_string = loc->to_string (); | 208 char *location_string = loc->to_string (); |
207 | 209 |
208 fprintf (stderr, "%-48s %10" PRIu64 ":%5.1f%%" | 210 fprintf (stderr, "%-48s " PRsa (9) ":%5.1f%%" |
209 "%10" PRIu64 "%10" PRIu64 ":%5.1f%%%10s\n", | 211 PRsa (9) PRsa (9) ":%5.1f%%%10s\n", |
210 location_string, (uint64_t)m_allocated, | 212 location_string, SIZE_AMOUNT (m_allocated), |
211 get_percent (m_allocated, total.m_allocated), | 213 get_percent (m_allocated, total.m_allocated), |
212 (uint64_t)m_peak, (uint64_t)m_times, | 214 SIZE_AMOUNT (m_peak), SIZE_AMOUNT (m_times), |
213 get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap"); | 215 get_percent (m_times, total.m_times), loc->m_ggc ? "ggc" : "heap"); |
214 | 216 |
215 free (location_string); | 217 free (location_string); |
216 } | 218 } |
217 | 219 |
218 /* Dump footer. */ | 220 /* Dump footer. */ |
219 inline void | 221 inline void |
220 dump_footer () const | 222 dump_footer () const |
221 { | 223 { |
222 print_dash_line (); | 224 fprintf (stderr, "%s" PRsa (53) PRsa (26) "\n", "Total", |
223 fprintf (stderr, "%s%54" PRIu64 "%27" PRIu64 "\n", "Total", | 225 SIZE_AMOUNT (m_allocated), SIZE_AMOUNT (m_times)); |
224 (uint64_t)m_allocated, (uint64_t)m_times); | |
225 print_dash_line (); | |
226 } | 226 } |
227 | 227 |
228 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */ | 228 /* Return fraction of NOMINATOR and DENOMINATOR in percent. */ |
229 static inline float | 229 static inline float |
230 get_percent (size_t nominator, size_t denominator) | 230 get_percent (size_t nominator, size_t denominator) |
245 static inline void | 245 static inline void |
246 dump_header (const char *name) | 246 dump_header (const char *name) |
247 { | 247 { |
248 fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak", | 248 fprintf (stderr, "%-48s %11s%16s%10s%17s\n", name, "Leak", "Peak", |
249 "Times", "Type"); | 249 "Times", "Type"); |
250 print_dash_line (); | |
251 } | 250 } |
252 | 251 |
253 /* Current number of allocated bytes. */ | 252 /* Current number of allocated bytes. */ |
254 size_t m_allocated; | 253 size_t m_allocated; |
255 /* Number of allocations. */ | 254 /* Number of allocations. */ |
261 }; | 260 }; |
262 | 261 |
263 /* Memory usage pair that connectes memory usage and number | 262 /* Memory usage pair that connectes memory usage and number |
264 of allocated bytes. */ | 263 of allocated bytes. */ |
265 template <class T> | 264 template <class T> |
266 struct mem_usage_pair | 265 class mem_usage_pair |
267 { | 266 { |
267 public: | |
268 mem_usage_pair (T *usage_, size_t allocated_): usage (usage_), | 268 mem_usage_pair (T *usage_, size_t allocated_): usage (usage_), |
269 allocated (allocated_) {} | 269 allocated (allocated_) {} |
270 | 270 |
271 T *usage; | 271 T *usage; |
272 size_t allocated; | 272 size_t allocated; |
280 struct mem_location_hash : nofree_ptr_hash <mem_location> | 280 struct mem_location_hash : nofree_ptr_hash <mem_location> |
281 { | 281 { |
282 static hashval_t | 282 static hashval_t |
283 hash (value_type l) | 283 hash (value_type l) |
284 { | 284 { |
285 inchash::hash hstate; | 285 inchash::hash hstate; |
286 | 286 |
287 hstate.add_ptr ((const void *)l->m_filename); | 287 hstate.add_ptr ((const void *)l->m_filename); |
288 hstate.add_ptr (l->m_function); | 288 hstate.add_ptr (l->m_function); |
289 hstate.add_int (l->m_line); | 289 hstate.add_int (l->m_line); |
290 | 290 |
291 return hstate.end (); | 291 return hstate.end (); |
292 } | 292 } |
293 | 293 |
294 static bool | 294 static bool |
295 equal (value_type l1, value_type l2) | 295 equal (value_type l1, value_type l2) |
296 { | 296 { |
297 return l1->m_filename == l2->m_filename | 297 return (l1->m_filename == l2->m_filename |
298 && l1->m_function == l2->m_function | 298 && l1->m_function == l2->m_function |
299 && l1->m_line == l2->m_line; | 299 && l1->m_line == l2->m_line); |
300 } | 300 } |
301 }; | 301 }; |
302 | 302 |
303 /* Internal class type definitions. */ | 303 /* Internal class type definitions. */ |
304 typedef hash_map <mem_location_hash, T *> mem_map_t; | 304 typedef hash_map <mem_location_hash, T *> mem_map_t; |
311 | 311 |
312 /* Default destructor. */ | 312 /* Default destructor. */ |
313 ~mem_alloc_description (); | 313 ~mem_alloc_description (); |
314 | 314 |
315 /* Returns true if instance PTR is registered by the memory description. */ | 315 /* Returns true if instance PTR is registered by the memory description. */ |
316 bool | 316 bool contains_descriptor_for_instance (const void *ptr); |
317 contains_descriptor_for_instance (const void *ptr); | |
318 | 317 |
319 /* Return descriptor for instance PTR. */ | 318 /* Return descriptor for instance PTR. */ |
320 T * | 319 T *get_descriptor_for_instance (const void *ptr); |
321 get_descriptor_for_instance (const void *ptr); | |
322 | 320 |
323 /* Register memory allocation descriptor for container PTR which is | 321 /* Register memory allocation descriptor for container PTR which is |
324 described by a memory LOCATION. */ | 322 described by a memory LOCATION. */ |
325 T * | 323 T *register_descriptor (const void *ptr, mem_location *location); |
326 register_descriptor (const void *ptr, mem_location *location); | |
327 | 324 |
328 /* Register memory allocation descriptor for container PTR. ORIGIN identifies | 325 /* Register memory allocation descriptor for container PTR. ORIGIN identifies |
329 type of container and GGC identifes if the allocation is handled in GGC | 326 type of container and GGC identifes if the allocation is handled in GGC |
330 memory. Each location is identified by file NAME, LINE in source code and | 327 memory. Each location is identified by file NAME, LINE in source code and |
331 FUNCTION name. */ | 328 FUNCTION name. */ |
332 T * | 329 T *register_descriptor (const void *ptr, mem_alloc_origin origin, |
333 register_descriptor (const void *ptr, mem_alloc_origin origin, | |
334 bool ggc, const char *name, int line, | 330 bool ggc, const char *name, int line, |
335 const char *function); | 331 const char *function); |
336 | 332 |
337 /* Register instance overhead identified by PTR pointer. Allocation takes | 333 /* Register instance overhead identified by PTR pointer. Allocation takes |
338 SIZE bytes. */ | 334 SIZE bytes. */ |
339 T * | 335 T *register_instance_overhead (size_t size, const void *ptr); |
340 register_instance_overhead (size_t size, const void *ptr); | |
341 | 336 |
342 /* For containers (and GGC) where we want to track every instance object, | 337 /* For containers (and GGC) where we want to track every instance object, |
343 we register allocation of SIZE bytes, identified by PTR pointer, belonging | 338 we register allocation of SIZE bytes, identified by PTR pointer, belonging |
344 to USAGE descriptor. */ | 339 to USAGE descriptor. */ |
345 void | 340 void register_object_overhead (T *usage, size_t size, const void *ptr); |
346 register_object_overhead (T *usage, size_t size, const void *ptr); | |
347 | 341 |
348 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true, | 342 /* Release PTR pointer of SIZE bytes. If REMOVE_FROM_MAP is set to true, |
349 remove the instance from reverse map. */ | 343 remove the instance from reverse map. Return memory usage that belongs |
350 void | 344 to this memory description. */ |
351 release_instance_overhead (void *ptr, size_t size, | 345 T *release_instance_overhead (void *ptr, size_t size, |
352 bool remove_from_map = false); | 346 bool remove_from_map = false); |
353 | 347 |
354 /* Release intance object identified by PTR pointer. */ | 348 /* Release instance object identified by PTR pointer. */ |
355 void | 349 void release_object_overhead (void *ptr); |
356 release_object_overhead (void *ptr); | 350 |
351 /* Unregister a memory allocation descriptor registered with | |
352 register_descriptor (remove from reverse map), unless it is | |
353 unregistered through release_instance_overhead with | |
354 REMOVE_FROM_MAP = true. */ | |
355 void unregister_descriptor (void *ptr); | |
357 | 356 |
358 /* Get sum value for ORIGIN type of allocation for the descriptor. */ | 357 /* Get sum value for ORIGIN type of allocation for the descriptor. */ |
359 T | 358 T get_sum (mem_alloc_origin origin); |
360 get_sum (mem_alloc_origin origin); | |
361 | 359 |
362 /* Get all tracked instances registered by the description. Items | 360 /* Get all tracked instances registered by the description. Items |
363 are filtered by ORIGIN type, LENGTH is return value where we register | 361 are filtered by ORIGIN type, LENGTH is return value where we register |
364 the number of elements in the list. If we want to process custom order, | 362 the number of elements in the list. If we want to process custom order, |
365 CMP comparator can be provided. */ | 363 CMP comparator can be provided. */ |
366 mem_list_t * | 364 mem_list_t *get_list (mem_alloc_origin origin, unsigned *length); |
367 get_list (mem_alloc_origin origin, unsigned *length, | |
368 int (*cmp) (const void *first, const void *second) = NULL); | |
369 | 365 |
370 /* Dump all tracked instances of type ORIGIN. If we want to process custom | 366 /* Dump all tracked instances of type ORIGIN. If we want to process custom |
371 order, CMP comparator can be provided. */ | 367 order, CMP comparator can be provided. */ |
372 void dump (mem_alloc_origin origin, | 368 void dump (mem_alloc_origin origin); |
373 int (*cmp) (const void *first, const void *second) = NULL); | |
374 | 369 |
375 /* Reverse object map used for every object allocation mapping. */ | 370 /* Reverse object map used for every object allocation mapping. */ |
376 reverse_object_map_t *m_reverse_object_map; | 371 reverse_object_map_t *m_reverse_object_map; |
377 | 372 |
378 private: | 373 private: |
389 | 384 |
390 /* Reverse pointer to usage mapping. */ | 385 /* Reverse pointer to usage mapping. */ |
391 reverse_mem_map_t *m_reverse_map; | 386 reverse_mem_map_t *m_reverse_map; |
392 }; | 387 }; |
393 | 388 |
394 | |
395 /* Returns true if instance PTR is registered by the memory description. */ | 389 /* Returns true if instance PTR is registered by the memory description. */ |
396 | 390 |
397 template <class T> | 391 template <class T> |
398 inline bool | 392 inline bool |
399 mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr) | 393 mem_alloc_description<T>::contains_descriptor_for_instance (const void *ptr) |
408 mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr) | 402 mem_alloc_description<T>::get_descriptor_for_instance (const void *ptr) |
409 { | 403 { |
410 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL; | 404 return m_reverse_map->get (ptr) ? (*m_reverse_map->get (ptr)).usage : NULL; |
411 } | 405 } |
412 | 406 |
413 | 407 /* Register memory allocation descriptor for container PTR which is |
414 /* Register memory allocation descriptor for container PTR which is | 408 described by a memory LOCATION. */ |
415 described by a memory LOCATION. */ | 409 |
416 template <class T> | 410 template <class T> |
417 inline T* | 411 inline T* |
418 mem_alloc_description<T>::register_descriptor (const void *ptr, | 412 mem_alloc_description<T>::register_descriptor (const void *ptr, |
419 mem_location *location) | 413 mem_location *location) |
420 { | 414 { |
511 } | 505 } |
512 | 506 |
513 /* Release PTR pointer of SIZE bytes. */ | 507 /* Release PTR pointer of SIZE bytes. */ |
514 | 508 |
515 template <class T> | 509 template <class T> |
516 inline void | 510 inline T * |
517 mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size, | 511 mem_alloc_description<T>::release_instance_overhead (void *ptr, size_t size, |
518 bool remove_from_map) | 512 bool remove_from_map) |
519 { | 513 { |
520 mem_usage_pair<T> *slot = m_reverse_map->get (ptr); | 514 mem_usage_pair<T> *slot = m_reverse_map->get (ptr); |
521 | 515 |
522 if (!slot) | 516 if (!slot) |
523 { | 517 { |
524 /* Due to PCH, it can really happen. */ | 518 /* Due to PCH, it can really happen. */ |
525 return; | 519 return NULL; |
526 } | 520 } |
527 | 521 |
528 mem_usage_pair<T> usage_pair = *slot; | 522 T *usage = (*slot).usage; |
529 usage_pair.usage->release_overhead (size); | 523 usage->release_overhead (size); |
530 | 524 |
531 if (remove_from_map) | 525 if (remove_from_map) |
532 m_reverse_map->remove (ptr); | 526 m_reverse_map->remove (ptr); |
533 } | 527 |
534 | 528 return usage; |
535 /* Release intance object identified by PTR pointer. */ | 529 } |
530 | |
531 /* Release instance object identified by PTR pointer. */ | |
536 | 532 |
537 template <class T> | 533 template <class T> |
538 inline void | 534 inline void |
539 mem_alloc_description<T>::release_object_overhead (void *ptr) | 535 mem_alloc_description<T>::release_object_overhead (void *ptr) |
540 { | 536 { |
541 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr); | 537 std::pair <T *, size_t> *entry = m_reverse_object_map->get (ptr); |
542 if (entry) | 538 entry->first->release_overhead (entry->second); |
543 { | 539 m_reverse_object_map->remove (ptr); |
544 entry->first->release_overhead (entry->second); | 540 } |
545 m_reverse_object_map->remove (ptr); | 541 |
546 } | 542 /* Unregister a memory allocation descriptor registered with |
543 register_descriptor (remove from reverse map), unless it is | |
544 unregistered through release_instance_overhead with | |
545 REMOVE_FROM_MAP = true. */ | |
546 template <class T> | |
547 inline void | |
548 mem_alloc_description<T>::unregister_descriptor (void *ptr) | |
549 { | |
550 m_reverse_map->remove (ptr); | |
547 } | 551 } |
548 | 552 |
549 /* Default contructor. */ | 553 /* Default contructor. */ |
550 | 554 |
551 template <class T> | 555 template <class T> |
552 inline | 556 inline |
553 mem_alloc_description<T>::mem_alloc_description () | 557 mem_alloc_description<T>::mem_alloc_description () |
554 { | 558 { |
555 m_map = new mem_map_t (13, false, false); | 559 m_map = new mem_map_t (13, false, false, false); |
556 m_reverse_map = new reverse_mem_map_t (13, false, false); | 560 m_reverse_map = new reverse_mem_map_t (13, false, false, false); |
557 m_reverse_object_map = new reverse_object_map_t (13, false, false); | 561 m_reverse_object_map = new reverse_object_map_t (13, false, false, false); |
558 } | 562 } |
559 | 563 |
560 /* Default destructor. */ | 564 /* Default destructor. */ |
561 | 565 |
562 template <class T> | 566 template <class T> |
581 can be provided. */ | 585 can be provided. */ |
582 | 586 |
583 template <class T> | 587 template <class T> |
584 inline | 588 inline |
585 typename mem_alloc_description<T>::mem_list_t * | 589 typename mem_alloc_description<T>::mem_list_t * |
586 mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length, | 590 mem_alloc_description<T>::get_list (mem_alloc_origin origin, unsigned *length) |
587 int (*cmp) (const void *first, const void *second)) | |
588 { | 591 { |
589 /* vec data structure is not used because all vectors generate memory | 592 /* vec data structure is not used because all vectors generate memory |
590 allocation info a it would create a cycle. */ | 593 allocation info a it would create a cycle. */ |
591 size_t element_size = sizeof (mem_list_t); | 594 size_t element_size = sizeof (mem_list_t); |
592 mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ()); | 595 mem_list_t *list = XCNEWVEC (mem_list_t, m_map->elements ()); |
595 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end (); | 598 for (typename mem_map_t::iterator it = m_map->begin (); it != m_map->end (); |
596 ++it) | 599 ++it) |
597 if ((*it).first->m_origin == origin) | 600 if ((*it).first->m_origin == origin) |
598 list[i++] = std::pair<mem_location*, T*> (*it); | 601 list[i++] = std::pair<mem_location*, T*> (*it); |
599 | 602 |
600 qsort (list, i, element_size, cmp == NULL ? T::compare : cmp); | 603 qsort (list, i, element_size, T::compare); |
601 *length = i; | 604 *length = i; |
602 | 605 |
603 return list; | 606 return list; |
604 } | 607 } |
605 | 608 |
624 /* Dump all tracked instances of type ORIGIN. If we want to process custom | 627 /* Dump all tracked instances of type ORIGIN. If we want to process custom |
625 order, CMP comparator can be provided. */ | 628 order, CMP comparator can be provided. */ |
626 | 629 |
627 template <class T> | 630 template <class T> |
628 inline void | 631 inline void |
629 mem_alloc_description<T>::dump (mem_alloc_origin origin, | 632 mem_alloc_description<T>::dump (mem_alloc_origin origin) |
630 int (*cmp) (const void *first, | |
631 const void *second)) | |
632 { | 633 { |
633 unsigned length; | 634 unsigned length; |
634 | 635 |
635 fprintf (stderr, "\n"); | 636 fprintf (stderr, "\n"); |
636 | 637 |
637 mem_list_t *list = get_list (origin, &length, cmp); | 638 mem_list_t *list = get_list (origin, &length); |
638 T total = get_sum (origin); | 639 T total = get_sum (origin); |
639 | 640 |
641 T::print_dash_line (); | |
640 T::dump_header (mem_location::get_origin_name (origin)); | 642 T::dump_header (mem_location::get_origin_name (origin)); |
643 T::print_dash_line (); | |
641 for (int i = length - 1; i >= 0; i--) | 644 for (int i = length - 1; i >= 0; i--) |
642 list[i].second->dump (list[i].first, total); | 645 list[i].second->dump (list[i].first, total); |
643 | 646 T::print_dash_line (); |
647 | |
648 T::dump_header (mem_location::get_origin_name (origin)); | |
649 T::print_dash_line (); | |
644 total.dump_footer (); | 650 total.dump_footer (); |
651 T::print_dash_line (); | |
645 | 652 |
646 XDELETEVEC (list); | 653 XDELETEVEC (list); |
647 | 654 |
648 fprintf (stderr, "\n"); | 655 fprintf (stderr, "\n"); |
649 } | 656 } |