Mercurial > hg > xemacs-beta
comparison src/alloc.c @ 5160:ab9ee10a53e4
fix various problems with allocation statistics, track overhead properly
-------------------- ChangeLog entries follow: --------------------
lisp/ChangeLog addition:
2010-03-20 Ben Wing <ben@xemacs.org>
* diagnose.el (show-memory-usage):
* diagnose.el (show-object-memory-usage-stats):
Further changes to correspond with changes in the C code;
add an additional column showing the overhead used with each type,
and add it into the grand total memory usage.
src/ChangeLog addition:
2010-03-20 Ben Wing <ben@xemacs.org>
* alloc.c:
* alloc.c (init_lrecord_stats):
* alloc.c (free_normal_lisp_object):
* alloc.c (struct):
* alloc.c (clear_lrecord_stats):
* alloc.c (tick_lrecord_stats):
* alloc.c (COUNT_FROB_BLOCK_USAGE):
* alloc.c (COPY_INTO_LRECORD_STATS):
* alloc.c (sweep_strings):
* alloc.c (UNMARK_string):
* alloc.c (gc_sweep_1):
* alloc.c (finish_object_memory_usage_stats):
* alloc.c (object_memory_usage_stats):
* alloc.c (object_dead_p):
* alloc.c (fixed_type_block_overhead):
* alloc.c (lisp_object_storage_size):
* emacs.c (main_1):
* lisp.h:
* lrecord.h:
Export lisp_object_storage_size() and malloced_storage_size() even
when not MEMORY_USAGE_STATS, to get the non-MEMORY_USAGE_STATS
build to compile.
Don't export fixed_type_block_overhead() any more.
Some code cleanup, rearrangement, add some section headers.
Clean up various bugs especially involving computation of overhead
and double-counting certain usage in total_gc_usage. Add
statistics computing the overhead used by all types. Don't add a
special entry for string headers in the object-memory-usage-stats
because it's already present as just "string". But do count the
overhead used by long strings. Don't try to call the
memory_usage() methods when NEW_GC because there's nowhere obvious
in the sweep stage to make the calls.
* marker.c (compute_buffer_marker_usage):
Just use lisp_object_storage_size() rather than trying to
reimplement it.
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Sat, 20 Mar 2010 20:20:30 -0500 |
parents | cb303ff63e76 |
children | 57f4dcb14ad5 e374ea766cc1 |
comparison
equal
deleted
inserted
replaced
5159:cb303ff63e76 | 5160:ab9ee10a53e4 |
---|---|
110 | 110 |
111 /* This is just for use by the printer, to allow things to print uniquely. | 111 /* This is just for use by the printer, to allow things to print uniquely. |
112 We have a separate UID space for each object. (Important because the | 112 We have a separate UID space for each object. (Important because the |
113 UID is only 20 bits in old-GC, and 22 in NEW_GC.) */ | 113 UID is only 20 bits in old-GC, and 22 in NEW_GC.) */ |
114 int lrecord_uid_counter[countof (lrecord_implementations_table)]; | 114 int lrecord_uid_counter[countof (lrecord_implementations_table)]; |
115 | |
116 #ifndef USE_KKCC | |
117 /* Object marker functions are in the lrecord_implementation structure. | |
118 But copying them to a parallel array is much more cache-friendly. | |
119 This hack speeds up (garbage-collect) by about 5%. */ | |
120 Lisp_Object (*lrecord_markers[countof (lrecord_implementations_table)]) (Lisp_Object); | |
121 #endif /* not USE_KKCC */ | |
122 | |
123 struct gcpro *gcprolist; | |
115 | 124 |
116 /* Non-zero means we're in the process of doing the dump */ | 125 /* Non-zero means we're in the process of doing the dump */ |
117 int purify_flag; | 126 int purify_flag; |
118 | 127 |
119 /* Non-zero means we're pdumping out or in */ | 128 /* Non-zero means we're pdumping out or in */ |
515 int bytes_in_use; | 524 int bytes_in_use; |
516 int bytes_in_use_including_overhead; | 525 int bytes_in_use_including_overhead; |
517 } lrecord_stats [countof (lrecord_implementations_table)]; | 526 } lrecord_stats [countof (lrecord_implementations_table)]; |
518 | 527 |
519 void | 528 void |
520 init_lrecord_stats () | 529 init_lrecord_stats (void) |
521 { | 530 { |
522 xzero (lrecord_stats); | 531 xzero (lrecord_stats); |
523 } | 532 } |
524 | 533 |
525 void | 534 void |
842 XRECORD_LHEADER_IMPLEMENTATION (obj); | 851 XRECORD_LHEADER_IMPLEMENTATION (obj); |
843 assert (!imp->size_in_bytes_method); | 852 assert (!imp->size_in_bytes_method); |
844 | 853 |
845 zero_sized_lisp_object (obj, lisp_object_size (obj)); | 854 zero_sized_lisp_object (obj, lisp_object_size (obj)); |
846 } | 855 } |
847 | |
848 #ifdef MEMORY_USAGE_STATS | |
849 | |
850 Bytecount | |
851 lisp_object_storage_size (Lisp_Object obj, struct usage_stats *ustats) | |
852 { | |
853 #ifndef NEW_GC | |
854 const struct lrecord_implementation *imp = | |
855 XRECORD_LHEADER_IMPLEMENTATION (obj); | |
856 #endif /* not NEW_GC */ | |
857 Bytecount size = lisp_object_size (obj); | |
858 | |
859 #ifdef NEW_GC | |
860 return mc_alloced_storage_size (size, ustats); | |
861 #else | |
862 if (imp->frob_block_p) | |
863 { | |
864 Bytecount overhead = fixed_type_block_overhead (size); | |
865 if (ustats) | |
866 { | |
867 ustats->was_requested += size; | |
868 ustats->malloc_overhead += overhead; | |
869 } | |
870 return size + overhead; | |
871 } | |
872 else | |
873 return malloced_storage_size (XPNTR (obj), size, ustats); | |
874 #endif | |
875 } | |
876 | |
877 #endif /* MEMORY_USAGE_STATS */ | |
878 | 856 |
879 void | 857 void |
880 free_normal_lisp_object (Lisp_Object obj) | 858 free_normal_lisp_object (Lisp_Object obj) |
881 { | 859 { |
882 #ifndef NEW_GC | 860 #ifndef NEW_GC |
3388 return object; | 3366 return object; |
3389 } | 3367 } |
3390 | 3368 |
3391 | 3369 |
3392 /************************************************************************/ | 3370 /************************************************************************/ |
3393 /* Garbage Collection */ | 3371 /* Staticpro, MCpro */ |
3394 /************************************************************************/ | 3372 /************************************************************************/ |
3395 | |
3396 #ifndef USE_KKCC | |
3397 /* Object marker functions are in the lrecord_implementation structure. | |
3398 But copying them to a parallel array is much more cache-friendly. | |
3399 This hack speeds up (garbage-collect) by about 5%. */ | |
3400 Lisp_Object (*lrecord_markers[countof (lrecord_implementations_table)]) (Lisp_Object); | |
3401 #endif /* not USE_KKCC */ | |
3402 | |
3403 struct gcpro *gcprolist; | |
3404 | 3373 |
3405 /* We want the staticpro list relocated, but not the pointers found | 3374 /* We want the staticpro list relocated, but not the pointers found |
3406 therein, because they refer to locations in the global data segment, not | 3375 therein, because they refer to locations in the global data segment, not |
3407 in the heap; we only dump heap objects. Hence we use a trivial | 3376 in the heap; we only dump heap objects. Hence we use a trivial |
3408 description, as for pointerless objects. (Note that the data segment | 3377 description, as for pointerless objects. (Note that the data segment |
3537 } | 3506 } |
3538 #endif | 3507 #endif |
3539 | 3508 |
3540 #endif /* not DEBUG_XEMACS */ | 3509 #endif /* not DEBUG_XEMACS */ |
3541 | 3510 |
3542 | |
3543 | |
3544 | |
3545 | |
3546 #ifdef NEW_GC | 3511 #ifdef NEW_GC |
3547 static const struct memory_description mcpro_description_1[] = { | 3512 static const struct memory_description mcpro_description_1[] = { |
3548 { XD_END } | 3513 { XD_END } |
3549 }; | 3514 }; |
3550 | 3515 |
3602 } | 3567 } |
3603 | 3568 |
3604 #endif /* not DEBUG_XEMACS */ | 3569 #endif /* not DEBUG_XEMACS */ |
3605 #endif /* NEW_GC */ | 3570 #endif /* NEW_GC */ |
3606 | 3571 |
3572 | |
3573 /************************************************************************/ | |
3574 /* Allocation Statistics */ | |
3575 /************************************************************************/ | |
3607 | 3576 |
3608 #ifndef NEW_GC | 3577 #ifndef NEW_GC |
3609 static int gc_count_num_short_string_in_use; | 3578 static int gc_count_num_short_string_in_use; |
3610 static Bytecount gc_count_string_total_size; | 3579 static Bytecount gc_count_string_total_size; |
3611 static Bytecount gc_count_short_string_total_size; | 3580 static Bytecount gc_count_short_string_total_size; |
3581 static Bytecount gc_count_long_string_storage_including_overhead; | |
3612 | 3582 |
3613 /* static int gc_count_total_records_used, gc_count_records_total_size; */ | 3583 /* static int gc_count_total_records_used, gc_count_records_total_size; */ |
3614 | 3584 |
3615 | 3585 |
3616 /* stats on lcrecords in use - kinda kludgy */ | 3586 /* stats on objects in use */ |
3617 | 3587 |
3618 static struct | 3588 static struct |
3619 { | 3589 { |
3620 int instances_in_use; | 3590 Elemcount instances_in_use; |
3621 int bytes_in_use; | 3591 Bytecount bytes_in_use; |
3622 int instances_freed; | 3592 Bytecount bytes_in_use_overhead; |
3623 int bytes_freed; | 3593 Elemcount instances_freed; |
3624 int instances_on_free_list; | 3594 Bytecount bytes_freed; |
3625 int bytes_on_free_list; | 3595 Bytecount bytes_freed_overhead; |
3596 Elemcount instances_on_free_list; | |
3597 Bytecount bytes_on_free_list; | |
3598 Bytecount bytes_on_free_list_overhead; | |
3626 #ifdef MEMORY_USAGE_STATS | 3599 #ifdef MEMORY_USAGE_STATS |
3627 Bytecount nonlisp_bytes_in_use; | 3600 Bytecount nonlisp_bytes_in_use; |
3628 struct generic_usage_stats stats; | 3601 struct generic_usage_stats stats; |
3629 #endif | 3602 #endif |
3630 } lrecord_stats [countof (lrecord_implementations_table)]; | 3603 } lrecord_stats [countof (lrecord_implementations_table)]; |
3631 | 3604 |
3605 static void | |
3606 clear_lrecord_stats (void) | |
3607 { | |
3608 xzero (lrecord_stats); | |
3609 gc_count_num_short_string_in_use = 0; | |
3610 gc_count_string_total_size = 0; | |
3611 gc_count_short_string_total_size = 0; | |
3612 gc_count_long_string_storage_including_overhead = 0; | |
3613 } | |
3614 | |
3615 /* Keep track of extra statistics for strings -- length of the string | |
3616 characters for short and long strings, number of short and long strings. */ | |
3617 static void | |
3618 tick_string_stats (Lisp_String *p, int from_sweep) | |
3619 { | |
3620 Bytecount size = p->size_; | |
3621 gc_count_string_total_size += size; | |
3622 if (!BIG_STRING_SIZE_P (size)) | |
3623 { | |
3624 gc_count_short_string_total_size += size; | |
3625 gc_count_num_short_string_in_use++; | |
3626 } | |
3627 else | |
3628 gc_count_long_string_storage_including_overhead += | |
3629 malloced_storage_size (p->data_, p->size_, NULL); | |
3630 /* During the sweep stage, we count the total number of strings in use. | |
3631 This gets those not stored in pdump storage. For pdump storage, we | |
3632 need to bump the number of strings in use so as to get an accurate | |
3633 count of all strings in use (pdump or not). But don't do this when | |
3634 called from the sweep stage, or we will double-count. */ | |
3635 if (!from_sweep) | |
3636 gc_count_num_string_in_use++; | |
3637 } | |
3638 | |
3639 /* As objects are sweeped, we record statistics about their memory usage. | |
3640 Currently, all lcrecords are processed this way as well as any frob-block | |
3641 objects that were saved and restored as a result of the pdump process. | |
3642 (See pdump_objects_unmark().) Other frob-block objects do NOT get their | |
3643 statistics noted this way -- instead, as the frob blocks are swept, | |
3644 COPY_INTO_LRECORD_STATS() is called, and notes statistics about the | |
3645 frob blocks. */ | |
3646 | |
3632 void | 3647 void |
3633 tick_lrecord_stats (const struct lrecord_header *h, | 3648 tick_lrecord_stats (const struct lrecord_header *h, |
3634 enum lrecord_alloc_status status) | 3649 enum lrecord_alloc_status status) |
3635 { | 3650 { |
3636 int type_index = h->type; | 3651 int type_index = h->type; |
3637 Bytecount sz = detagged_lisp_object_size (h); | 3652 Bytecount obj = wrap_pointer_1 (h); |
3653 Bytecount sz = lisp_object_size (obj); | |
3654 Bytecount sz_with_overhead = lisp_object_storage_size (obj, NULL); | |
3655 Bytecount overhead = sz_with_overhead - sz; | |
3638 | 3656 |
3639 switch (status) | 3657 switch (status) |
3640 { | 3658 { |
3641 case ALLOC_IN_USE: | 3659 case ALLOC_IN_USE: |
3642 lrecord_stats[type_index].instances_in_use++; | 3660 lrecord_stats[type_index].instances_in_use++; |
3643 lrecord_stats[type_index].bytes_in_use += sz; | 3661 lrecord_stats[type_index].bytes_in_use += sz; |
3662 lrecord_stats[type_index].bytes_in_use_overhead += overhead; | |
3663 if (STRINGP (obj)) | |
3664 tick_string_stats (XSTRING (obj), 0); | |
3644 #ifdef MEMORY_USAGE_STATS | 3665 #ifdef MEMORY_USAGE_STATS |
3645 { | 3666 { |
3646 struct generic_usage_stats stats; | 3667 struct generic_usage_stats stats; |
3647 Lisp_Object obj = wrap_pointer_1 (h); | |
3648 if (HAS_OBJECT_METH_P (obj, memory_usage)) | 3668 if (HAS_OBJECT_METH_P (obj, memory_usage)) |
3649 { | 3669 { |
3650 int i; | 3670 int i; |
3651 int total_stats = OBJECT_PROPERTY (obj, num_extra_memusage_stats); | 3671 int total_stats = OBJECT_PROPERTY (obj, num_extra_memusage_stats); |
3652 xzero (stats); | 3672 xzero (stats); |
3659 #endif | 3679 #endif |
3660 break; | 3680 break; |
3661 case ALLOC_FREE: | 3681 case ALLOC_FREE: |
3662 lrecord_stats[type_index].instances_freed++; | 3682 lrecord_stats[type_index].instances_freed++; |
3663 lrecord_stats[type_index].bytes_freed += sz; | 3683 lrecord_stats[type_index].bytes_freed += sz; |
3684 lrecord_stats[type_index].bytes_freed_overhead += overhead; | |
3664 break; | 3685 break; |
3665 case ALLOC_ON_FREE_LIST: | 3686 case ALLOC_ON_FREE_LIST: |
3666 lrecord_stats[type_index].instances_on_free_list++; | 3687 lrecord_stats[type_index].instances_on_free_list++; |
3667 lrecord_stats[type_index].bytes_on_free_list += sz; | 3688 lrecord_stats[type_index].bytes_on_free_list += sz; |
3689 lrecord_stats[type_index].bytes_on_free_list_overhead += overhead; | |
3668 break; | 3690 break; |
3669 default: | 3691 default: |
3670 ABORT (); | 3692 ABORT (); |
3671 } | 3693 } |
3672 } | 3694 } |
3680 tick_lrecord_stats (h, ALLOC_ON_FREE_LIST); | 3702 tick_lrecord_stats (h, ALLOC_ON_FREE_LIST); |
3681 } | 3703 } |
3682 else | 3704 else |
3683 tick_lrecord_stats (h, free_p ? ALLOC_FREE : ALLOC_IN_USE); | 3705 tick_lrecord_stats (h, free_p ? ALLOC_FREE : ALLOC_IN_USE); |
3684 } | 3706 } |
3707 | |
3685 #endif /* not NEW_GC */ | 3708 #endif /* not NEW_GC */ |
3686 | 3709 |
3687 | 3710 |
3711 /************************************************************************/ | |
3712 /* Garbage Collection -- Sweep/Compact */ | |
3713 /************************************************************************/ | |
3714 | |
3688 #ifndef NEW_GC | 3715 #ifndef NEW_GC |
3689 /* Free all unmarked records */ | 3716 /* Free all unmarked records */ |
3690 static void | 3717 static void |
3691 sweep_lcrecords_1 (struct old_lcrecord_header **prev, int *used) | 3718 sweep_lcrecords_1 (struct old_lcrecord_header **prev, int *used) |
3692 { | 3719 { |
3743 } | 3770 } |
3744 *used = num_used; | 3771 *used = num_used; |
3745 /* *total = total_size; */ | 3772 /* *total = total_size; */ |
3746 } | 3773 } |
3747 | 3774 |
3775 static Bytecount fixed_type_block_overhead (Bytecount size, | |
3776 Bytecount per_block); | |
3777 | |
3748 /* And the Lord said: Thou shalt use the `c-backslash-region' command | 3778 /* And the Lord said: Thou shalt use the `c-backslash-region' command |
3749 to make macros prettier. */ | 3779 to make macros prettier. */ |
3750 | 3780 |
3751 #define COUNT_FROB_BLOCK_USAGE(type) \ | 3781 #define COUNT_FROB_BLOCK_USAGE(type) \ |
3752 EMACS_INT s = 0; \ | 3782 EMACS_INT s = 0; \ |
3783 EMACS_INT s_overhead = 0; \ | |
3753 struct type##_block *x = current_##type##_block; \ | 3784 struct type##_block *x = current_##type##_block; \ |
3754 while (x) { s += sizeof (*x) + MALLOC_OVERHEAD; x = x->prev; } \ | 3785 while (x) { s += sizeof (*x) + MALLOC_OVERHEAD; x = x->prev; } \ |
3786 s_overhead = fixed_type_block_overhead (s, sizeof (struct type##_block)); \ | |
3755 DO_NOTHING | 3787 DO_NOTHING |
3756 | 3788 |
3757 #define COPY_INTO_LRECORD_STATS(type) \ | 3789 #define COPY_INTO_LRECORD_STATS(type) \ |
3758 do { \ | 3790 do { \ |
3759 COUNT_FROB_BLOCK_USAGE (type); \ | 3791 COUNT_FROB_BLOCK_USAGE (type); \ |
3760 lrecord_stats[lrecord_type_##type].bytes_in_use += s; \ | 3792 lrecord_stats[lrecord_type_##type].bytes_in_use += s; \ |
3793 lrecord_stats[lrecord_type_##type].bytes_in_use_overhead += \ | |
3794 s_overhead; \ | |
3761 lrecord_stats[lrecord_type_##type].instances_on_free_list += \ | 3795 lrecord_stats[lrecord_type_##type].instances_on_free_list += \ |
3762 gc_count_num_##type##_freelist; \ | 3796 gc_count_num_##type##_freelist; \ |
3763 lrecord_stats[lrecord_type_##type].instances_in_use += \ | 3797 lrecord_stats[lrecord_type_##type].instances_in_use += \ |
3764 gc_count_num_##type##_in_use; \ | 3798 gc_count_num_##type##_in_use; \ |
3765 } while (0) | 3799 } while (0) |
4421 | 4455 |
4422 #ifndef NEW_GC | 4456 #ifndef NEW_GC |
4423 static void | 4457 static void |
4424 sweep_strings (void) | 4458 sweep_strings (void) |
4425 { | 4459 { |
4426 int num_small_used = 0; | |
4427 Bytecount num_small_bytes = 0, num_bytes = 0; | |
4428 int debug = debug_string_purity; | 4460 int debug = debug_string_purity; |
4429 | 4461 |
4430 #define UNMARK_string(ptr) do { \ | 4462 #define UNMARK_string(ptr) do { \ |
4431 Lisp_String *p = (ptr); \ | 4463 Lisp_String *p = (ptr); \ |
4432 Bytecount size = p->size_; \ | |
4433 UNMARK_RECORD_HEADER (&(p->u.lheader)); \ | 4464 UNMARK_RECORD_HEADER (&(p->u.lheader)); \ |
4434 num_bytes += size; \ | 4465 tick_string_stats (p, 1); \ |
4435 if (!BIG_STRING_SIZE_P (size)) \ | |
4436 { \ | |
4437 num_small_bytes += size; \ | |
4438 num_small_used++; \ | |
4439 } \ | |
4440 if (debug) \ | 4466 if (debug) \ |
4441 debug_string_purity_print (wrap_string (p)); \ | 4467 debug_string_purity_print (wrap_string (p)); \ |
4442 } while (0) | 4468 } while (0) |
4443 #define ADDITIONAL_FREE_string(ptr) do { \ | 4469 #define ADDITIONAL_FREE_string(ptr) do { \ |
4444 Bytecount size = ptr->size_; \ | 4470 Bytecount size = ptr->size_; \ |
4445 if (BIG_STRING_SIZE_P (size)) \ | 4471 if (BIG_STRING_SIZE_P (size)) \ |
4446 xfree (ptr->data_); \ | 4472 xfree (ptr->data_); \ |
4447 } while (0) | 4473 } while (0) |
4448 | 4474 |
4449 SWEEP_FIXED_TYPE_BLOCK_1 (string, Lisp_String, u.lheader); | 4475 SWEEP_FIXED_TYPE_BLOCK_1 (string, Lisp_String, u.lheader); |
4450 | |
4451 gc_count_num_short_string_in_use = num_small_used; | |
4452 gc_count_string_total_size = num_bytes; | |
4453 gc_count_short_string_total_size = num_small_bytes; | |
4454 } | 4476 } |
4455 #endif /* not NEW_GC */ | 4477 #endif /* not NEW_GC */ |
4456 | 4478 |
4457 #ifndef NEW_GC | 4479 #ifndef NEW_GC |
4458 void | 4480 void |
4459 gc_sweep_1 (void) | 4481 gc_sweep_1 (void) |
4460 { | 4482 { |
4461 /* Reset all statistics to 0. They will be incremented when | 4483 /* Reset all statistics to 0. They will be incremented when |
4462 sweeping lcrecords, frob-block lrecords and dumped objects. */ | 4484 sweeping lcrecords, frob-block lrecords and dumped objects. */ |
4463 xzero (lrecord_stats); | 4485 clear_lrecord_stats (); |
4464 | 4486 |
4465 /* Free all unmarked records. Do this at the very beginning, | 4487 /* Free all unmarked records. Do this at the very beginning, |
4466 before anything else, so that the finalize methods can safely | 4488 before anything else, so that the finalize methods can safely |
4467 examine items in the objects. sweep_lcrecords_1() makes | 4489 examine items in the objects. sweep_lcrecords_1() makes |
4468 sure to call all the finalize methods *before* freeing anything, | 4490 sure to call all the finalize methods *before* freeing anything, |
4540 #ifdef PDUMP | 4562 #ifdef PDUMP |
4541 pdump_objects_unmark (); | 4563 pdump_objects_unmark (); |
4542 #endif | 4564 #endif |
4543 } | 4565 } |
4544 #endif /* not NEW_GC */ | 4566 #endif /* not NEW_GC */ |
4567 | |
4545 | 4568 |
4546 /* Clearing for disksave. */ | 4569 /************************************************************************/ |
4570 /* "Disksave Finalization" -- Preparing for Dumping */ | |
4571 /************************************************************************/ | |
4547 | 4572 |
4548 void | 4573 void |
4549 disksave_object_finalization (void) | 4574 disksave_object_finalization (void) |
4550 { | 4575 { |
4551 /* It's important that certain information from the environment not get | 4576 /* It's important that certain information from the environment not get |
4677 } | 4702 } |
4678 | 4703 |
4679 void | 4704 void |
4680 finish_object_memory_usage_stats (void) | 4705 finish_object_memory_usage_stats (void) |
4681 { | 4706 { |
4682 #ifdef MEMORY_USAGE_STATS | 4707 /* Here we add up the aggregate values for each statistic, previously |
4708 computed during tick_lrecord_stats(), to get a single combined value | |
4709 of non-Lisp memory usage for all objects of each type. We can't | |
4710 do this if NEW_GC because nothing like tick_lrecord_stats() gets | |
4711 called -- instead, statistics are computed when objects are allocated, | |
4712 which is too early to be calling the memory_usage() method. */ | |
4713 #if defined (MEMORY_USAGE_STATS) && !defined (NEW_GC) | |
4683 int i; | 4714 int i; |
4684 for (i = 0; i < countof (lrecord_implementations_table); i++) | 4715 for (i = 0; i < countof (lrecord_implementations_table); i++) |
4685 { | 4716 { |
4686 struct lrecord_implementation *imp = lrecord_implementations_table[i]; | 4717 struct lrecord_implementation *imp = lrecord_implementations_table[i]; |
4687 if (imp && imp->num_extra_nonlisp_memusage_stats) | 4718 if (imp && imp->num_extra_nonlisp_memusage_stats) |
4690 for (j = 0; j < imp->num_extra_nonlisp_memusage_stats; j++) | 4721 for (j = 0; j < imp->num_extra_nonlisp_memusage_stats; j++) |
4691 lrecord_stats[i].nonlisp_bytes_in_use += | 4722 lrecord_stats[i].nonlisp_bytes_in_use += |
4692 lrecord_stats[i].stats.othervals[j]; | 4723 lrecord_stats[i].stats.othervals[j]; |
4693 } | 4724 } |
4694 } | 4725 } |
4695 #endif /* MEMORY_USAGE_STATS */ | 4726 #endif /* defined (MEMORY_USAGE_STATS) && !defined (NEW_GC) */ |
4696 } | 4727 } |
4697 | 4728 |
4698 static Lisp_Object | 4729 static Lisp_Object |
4699 object_memory_usage_stats (int set_total_gc_usage) | 4730 object_memory_usage_stats (int set_total_gc_usage) |
4700 { | 4731 { |
4731 } | 4762 } |
4732 } | 4763 } |
4733 | 4764 |
4734 #else /* not NEW_GC */ | 4765 #else /* not NEW_GC */ |
4735 | 4766 |
4736 #define HACK_O_MATIC(type, name, pl) \ | |
4737 do { \ | |
4738 COUNT_FROB_BLOCK_USAGE (type); \ | |
4739 tgu_val += s; \ | |
4740 (pl) = gc_plist_hack ((name), s, (pl)); \ | |
4741 } while (0) | |
4742 | |
4743 #define FROB(type) \ | |
4744 do { \ | |
4745 COUNT_FROB_BLOCK_USAGE (type); \ | |
4746 tgu_val += s; \ | |
4747 } while (0) | |
4748 | |
4749 FROB (extent); | |
4750 FROB (event); | |
4751 FROB (marker); | |
4752 FROB (float); | |
4753 #ifdef HAVE_BIGNUM | |
4754 FROB (bignum); | |
4755 #endif /* HAVE_BIGNUM */ | |
4756 #ifdef HAVE_RATIO | |
4757 FROB (ratio); | |
4758 #endif /* HAVE_RATIO */ | |
4759 #ifdef HAVE_BIGFLOAT | |
4760 FROB (bigfloat); | |
4761 #endif /* HAVE_BIGFLOAT */ | |
4762 FROB (compiled_function); | |
4763 FROB (symbol); | |
4764 FROB (cons); | |
4765 | |
4766 #undef FROB | |
4767 | |
4768 for (i = 0; i < lrecord_type_count; i++) | 4767 for (i = 0; i < lrecord_type_count; i++) |
4769 { | 4768 { |
4770 if (lrecord_stats[i].bytes_in_use != 0 | 4769 if (lrecord_stats[i].bytes_in_use != 0 |
4771 || lrecord_stats[i].bytes_freed != 0 | 4770 || lrecord_stats[i].bytes_freed != 0 |
4772 || lrecord_stats[i].instances_on_free_list != 0) | 4771 || lrecord_stats[i].instances_on_free_list != 0) |
4773 { | 4772 { |
4774 Ascbyte buf[255]; | 4773 Ascbyte buf[255]; |
4775 const Ascbyte *name = lrecord_implementations_table[i]->name; | 4774 const Ascbyte *name = lrecord_implementations_table[i]->name; |
4776 | 4775 |
4776 sprintf (buf, "%s-storage-overhead", name); | |
4777 pl = gc_plist_hack (buf, lrecord_stats[i].bytes_in_use_overhead, pl); | |
4778 tgu_val += lrecord_stats[i].bytes_in_use_overhead; | |
4777 sprintf (buf, "%s-storage", name); | 4779 sprintf (buf, "%s-storage", name); |
4778 pl = gc_plist_hack (buf, lrecord_stats[i].bytes_in_use, pl); | 4780 pl = gc_plist_hack (buf, lrecord_stats[i].bytes_in_use, pl); |
4779 tgu_val += lrecord_stats[i].bytes_in_use; | 4781 tgu_val += lrecord_stats[i].bytes_in_use; |
4782 #ifdef MEMORY_USAGE_STATS | |
4780 if (lrecord_stats[i].nonlisp_bytes_in_use) | 4783 if (lrecord_stats[i].nonlisp_bytes_in_use) |
4781 { | 4784 { |
4782 sprintf (buf, "%s-non-lisp-storage", name); | 4785 sprintf (buf, "%s-non-lisp-storage", name); |
4783 pl = gc_plist_hack (buf, lrecord_stats[i].nonlisp_bytes_in_use, | 4786 pl = gc_plist_hack (buf, lrecord_stats[i].nonlisp_bytes_in_use, |
4784 pl); | 4787 pl); |
4785 tgu_val += lrecord_stats[i].nonlisp_bytes_in_use; | 4788 tgu_val += lrecord_stats[i].nonlisp_bytes_in_use; |
4786 } | 4789 } |
4790 #endif /* MEMORY_USAGE_STATS */ | |
4787 pluralize_and_append (buf, name, "-freed"); | 4791 pluralize_and_append (buf, name, "-freed"); |
4788 if (lrecord_stats[i].instances_freed != 0) | 4792 if (lrecord_stats[i].instances_freed != 0) |
4789 pl = gc_plist_hack (buf, lrecord_stats[i].instances_freed, pl); | 4793 pl = gc_plist_hack (buf, lrecord_stats[i].instances_freed, pl); |
4790 pluralize_and_append (buf, name, "-on-free-list"); | 4794 pluralize_and_append (buf, name, "-on-free-list"); |
4791 if (lrecord_stats[i].instances_on_free_list != 0) | 4795 if (lrecord_stats[i].instances_on_free_list != 0) |
4794 pluralize_and_append (buf, name, "-used"); | 4798 pluralize_and_append (buf, name, "-used"); |
4795 pl = gc_plist_hack (buf, lrecord_stats[i].instances_in_use, pl); | 4799 pl = gc_plist_hack (buf, lrecord_stats[i].instances_in_use, pl); |
4796 } | 4800 } |
4797 } | 4801 } |
4798 | 4802 |
4799 HACK_O_MATIC (string, "string-header-storage", pl); | 4803 pl = gc_plist_hack ("long-string-chars-storage-overhead", |
4804 gc_count_long_string_storage_including_overhead - | |
4805 (gc_count_string_total_size | |
4806 - gc_count_short_string_total_size), pl); | |
4807 pl = gc_plist_hack ("long-string-chars-storage", | |
4808 gc_count_string_total_size | |
4809 - gc_count_short_string_total_size, pl); | |
4810 do | |
4811 { | |
4812 COUNT_FROB_BLOCK_USAGE (string_chars); | |
4813 tgu_val += s + s_overhead; | |
4814 pl = gc_plist_hack ("short-string-chars-storage-overhead", s_overhead, pl); | |
4815 pl = gc_plist_hack ("short-string-chars-storage", s, pl); | |
4816 } | |
4817 while (0); | |
4818 | |
4800 pl = gc_plist_hack ("long-strings-total-length", | 4819 pl = gc_plist_hack ("long-strings-total-length", |
4801 gc_count_string_total_size | 4820 gc_count_string_total_size |
4802 - gc_count_short_string_total_size, pl); | 4821 - gc_count_short_string_total_size, pl); |
4803 HACK_O_MATIC (string_chars, "short-string-storage", pl); | |
4804 pl = gc_plist_hack ("short-strings-total-length", | 4822 pl = gc_plist_hack ("short-strings-total-length", |
4805 gc_count_short_string_total_size, pl); | 4823 gc_count_short_string_total_size, pl); |
4806 pl = gc_plist_hack ("strings-free", gc_count_num_string_freelist, pl); | |
4807 pl = gc_plist_hack ("long-strings-used", | 4824 pl = gc_plist_hack ("long-strings-used", |
4808 gc_count_num_string_in_use | 4825 gc_count_num_string_in_use |
4809 - gc_count_num_short_string_in_use, pl); | 4826 - gc_count_num_short_string_in_use, pl); |
4810 pl = gc_plist_hack ("short-strings-used", | 4827 pl = gc_plist_hack ("short-strings-used", |
4811 gc_count_num_short_string_in_use, pl); | 4828 gc_count_num_short_string_in_use, pl); |
4812 | |
4813 #undef HACK_O_MATIC | |
4814 | 4829 |
4815 #endif /* NEW_GC */ | 4830 #endif /* NEW_GC */ |
4816 | 4831 |
4817 if (set_total_gc_usage) | 4832 if (set_total_gc_usage) |
4818 { | 4833 { |
5105 need_to_garbage_collect || | 5120 need_to_garbage_collect || |
5106 need_to_check_c_alloca || | 5121 need_to_check_c_alloca || |
5107 need_to_signal_post_gc; | 5122 need_to_signal_post_gc; |
5108 } | 5123 } |
5109 | 5124 |
5110 | |
5111 int | 5125 int |
5112 object_dead_p (Lisp_Object obj) | 5126 object_dead_p (Lisp_Object obj) |
5113 { | 5127 { |
5114 return ((BUFFERP (obj) && !BUFFER_LIVE_P (XBUFFER (obj))) || | 5128 return ((BUFFERP (obj) && !BUFFER_LIVE_P (XBUFFER (obj))) || |
5115 (FRAMEP (obj) && !FRAME_LIVE_P (XFRAME (obj))) || | 5129 (FRAMEP (obj) && !FRAME_LIVE_P (XFRAME (obj))) || |
5118 (CONSOLEP (obj) && !CONSOLE_LIVE_P (XCONSOLE (obj))) || | 5132 (CONSOLEP (obj) && !CONSOLE_LIVE_P (XCONSOLE (obj))) || |
5119 (EVENTP (obj) && !EVENT_LIVE_P (XEVENT (obj))) || | 5133 (EVENTP (obj) && !EVENT_LIVE_P (XEVENT (obj))) || |
5120 (EXTENTP (obj) && !EXTENT_LIVE_P (XEXTENT (obj)))); | 5134 (EXTENTP (obj) && !EXTENT_LIVE_P (XEXTENT (obj)))); |
5121 } | 5135 } |
5122 | 5136 |
5123 #ifdef MEMORY_USAGE_STATS | 5137 #ifdef ALLOC_TYPE_STATS |
5124 | 5138 |
5125 /* Attempt to determine the actual amount of space that is used for | 5139 /* Attempt to determine the actual amount of space that is used for |
5126 the block allocated starting at PTR, supposedly of size "CLAIMED_SIZE". | 5140 the block allocated starting at PTR, supposedly of size "CLAIMED_SIZE". |
5127 | 5141 |
5128 It seems that the following holds: | 5142 It seems that the following holds: |
5212 } | 5226 } |
5213 return claimed_size; | 5227 return claimed_size; |
5214 } | 5228 } |
5215 | 5229 |
5216 #ifndef NEW_GC | 5230 #ifndef NEW_GC |
5217 Bytecount | 5231 static Bytecount |
5218 fixed_type_block_overhead (Bytecount size) | 5232 fixed_type_block_overhead (Bytecount size, Bytecount per_block) |
5219 { | 5233 { |
5220 Bytecount per_block = TYPE_ALLOC_SIZE (cons, unsigned char); | |
5221 Bytecount overhead = 0; | 5234 Bytecount overhead = 0; |
5222 Bytecount storage_size = malloced_storage_size (0, per_block, 0); | 5235 Bytecount storage_size = malloced_storage_size (0, per_block, 0); |
5223 while (size >= per_block) | 5236 while (size >= per_block) |
5224 { | 5237 { |
5225 size -= per_block; | 5238 size -= per_block; |
5226 overhead += sizeof (void *) + per_block - storage_size; | 5239 overhead += storage_size - per_block; |
5227 } | 5240 } |
5228 if (rand () % per_block < size) | 5241 if (rand () % per_block < size) |
5229 overhead += sizeof (void *) + per_block - storage_size; | 5242 overhead += storage_size - per_block; |
5230 return overhead; | 5243 return overhead; |
5231 } | 5244 } |
5232 #endif /* not NEW_GC */ | 5245 #endif /* not NEW_GC */ |
5233 #endif /* MEMORY_USAGE_STATS */ | 5246 |
5247 Bytecount | |
5248 lisp_object_storage_size (Lisp_Object obj, struct usage_stats *ustats) | |
5249 { | |
5250 #ifndef NEW_GC | |
5251 const struct lrecord_implementation *imp = | |
5252 XRECORD_LHEADER_IMPLEMENTATION (obj); | |
5253 #endif /* not NEW_GC */ | |
5254 Bytecount size = lisp_object_size (obj); | |
5255 | |
5256 #ifdef NEW_GC | |
5257 return mc_alloced_storage_size (size, ustats); | |
5258 #else | |
5259 if (imp->frob_block_p) | |
5260 { | |
5261 Bytecount overhead = | |
5262 /* #### Always using cons_block is incorrect but close; only | |
5263 string_chars_block is significantly different in size, and | |
5264 it won't ever be seen in this function */ | |
5265 fixed_type_block_overhead (size, sizeof (struct cons_block)); | |
5266 if (ustats) | |
5267 { | |
5268 ustats->was_requested += size; | |
5269 ustats->malloc_overhead += overhead; | |
5270 } | |
5271 return size + overhead; | |
5272 } | |
5273 else | |
5274 return malloced_storage_size (XPNTR (obj), size, ustats); | |
5275 #endif | |
5276 } | |
5277 | |
5278 #endif /* ALLOC_TYPE_STATS */ | |
5234 | 5279 |
5235 | 5280 |
5281 /************************************************************************/ | |
5282 /* Initialization */ | |
5283 /************************************************************************/ | |
5284 | |
5236 /* Initialization */ | 5285 /* Initialization */ |
5237 static void | 5286 static void |
5238 common_init_alloc_early (void) | 5287 common_init_alloc_early (void) |
5239 { | 5288 { |
5240 #ifndef Qzero | 5289 #ifndef Qzero |