track cumulative allocation

Extend `current-memory-use` to accept a 'cumulative flag.
This commit is contained in:
Matthew Flatt 2016-08-09 12:43:23 -06:00
parent a0a0e41908
commit 0034c31820
7 changed files with 91 additions and 26 deletions

View File

@ -350,24 +350,42 @@ garbage-collection mode, depending on @racket[request]:
#:changed "6.3.0.2" @elem{Added @racket['incremental] mode.}]} #:changed "6.3.0.2" @elem{Added @racket['incremental] mode.}]}
@defproc[(current-memory-use [cust custodian? #f]) exact-nonnegative-integer?]{ @defproc[(current-memory-use [mode (or/c #f 'cumulative custodian?) #f])
exact-nonnegative-integer?]{
Returns an estimate of the number of bytes of memory occupied by Returns information about memory use:
reachable data from @racket[cust]. This estimate is calculated by the
last garbage collection, and can be 0 if none occurred (or if none occurred
since the given custodian was created). The @racket[current-memory-use]
function does @italic{not} perform a collection by itself; doing one
before the call will generally decrease the result (or increase it from
0 if no collections happened yet).
If @racket[cust] is not provided, the estimate is a total reachable from @itemlist[
any custodians.
When Racket is compiled without support for memory accounting, the @item{If @racket[mode] is @racket[#f] (the default), the result is an
estimate is the same (i.e., all memory) for any individual custodian; estimate of the number of bytes reachable from any custodian.}
see also @racket[custodian-memory-accounting-available?].
@item{If @racket[mode] is @racket['cumulative], returns an estimate
of the total number of bytes allocated since start up,
including bytes that have since been reclaimed by garbage
collection.}
@item{If @racket[mode] is a custodian, returns an estimate of the
number of bytes of memory occupied by reachable data from
@racket[mode]. This estimate is calculated by the last garbage
collection, and can be 0 if none occurred (or if none occurred
since the given custodian was created). The
@racket[current-memory-use] function does @italic{not} perform
a collection by itself; doing one before the call will
generally decrease the result (or increase it from 0 if no
collections happened yet).
When Racket is compiled without support for memory accounting,
the estimate is the same as when @racket[mode] is @racket[#f]
(i.e., all memory) for any individual custodian. See also
@racket[custodian-memory-accounting-available?].}
]
See also @racket[vector-set-performance-stats!].
@history[#:changed "6.6.0.3" @elem{Added @racket['cumulative] mode.}]}
See also @racket[vector-set-performance-stats!].}
@defproc[(dump-memory-stats [v any/c] ...) any]{ @defproc[(dump-memory-stats [v any/c] ...) any]{

View File

@ -145,6 +145,11 @@ GC2_EXTERN intptr_t GC_get_memory_use(void *c);
Returns the number of currently-allocated bytes (speficilly for Returns the number of currently-allocated bytes (speficilly for
custodian c, as much as the GC's accounting makes possible). */ custodian c, as much as the GC's accounting makes possible). */
GC2_EXTERN intptr_t GC_get_memory_ever_allocated();
/*
Returns the number of total number of allocated bytes, including
bytes that have since been reclaimed. */
GC2_EXTERN int GC_accouting_enabled(); GC2_EXTERN int GC_accouting_enabled();
/* /*
Reports whether memory accounting is enabled. */ Reports whether memory accounting is enabled. */

View File

@ -41,6 +41,9 @@
/* Avoid incremental GC if the heap seems to be getting too fragmented: */ /* Avoid incremental GC if the heap seems to be getting too fragmented: */
#define HIGH_FRAGMENTATION_RATIO 2 #define HIGH_FRAGMENTATION_RATIO 2
/* Initial and minimum value to treat as previous use after a full GC: */
#define INITIAL_FULL_MEMORY_USE (20 * 1024 * 1024)
/* Whether to use a little aging, moving gen-0 objects to a /* Whether to use a little aging, moving gen-0 objects to a
gen-1/2 space: */ gen-1/2 space: */
#define AGE_GEN_0_TO_GEN_HALF(gc) ((gc)->started_incremental) #define AGE_GEN_0_TO_GEN_HALF(gc) ((gc)->started_incremental)
@ -745,7 +748,7 @@ static void NewGC_initialize(NewGC *newgc, NewGC *inheritgc, NewGC *parentgc) {
newgc->mmu = mmu_create(newgc); newgc->mmu = mmu_create(newgc);
newgc->generations_available = 1; newgc->generations_available = 1;
newgc->last_full_mem_use = (20 * 1024 * 1024); newgc->last_full_mem_use = INITIAL_FULL_MEMORY_USE;
newgc->new_btc_mark = 1; newgc->new_btc_mark = 1;
newgc->place_memory_limit = (uintptr_t)(intptr_t)-1; newgc->place_memory_limit = (uintptr_t)(intptr_t)-1;
@ -973,6 +976,16 @@ intptr_t GC_get_memory_use(void *o)
return (intptr_t)amt; return (intptr_t)amt;
} }
intptr_t GC_get_memory_ever_allocated()
{
NewGC *gc = GC_get_GC();
uintptr_t amt;
amt = add_no_overflow(gen0_size_in_use(gc), gc->total_memory_allocated);
return (intptr_t)amt;
}
/*****************************************************************************/ /*****************************************************************************/
/* Write barrier */ /* Write barrier */
/* */ /* */
@ -5314,6 +5327,8 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full,
old_gen0 = gen0_size_in_use(gc) + gc->gen0_phantom_count; old_gen0 = gen0_size_in_use(gc) + gc->gen0_phantom_count;
old_mem_allocated = mmu_memory_allocated(gc->mmu) + gc->phantom_count + gc->gen0_phantom_count; old_mem_allocated = mmu_memory_allocated(gc->mmu) + gc->phantom_count + gc->gen0_phantom_count;
gc->total_memory_allocated += old_gen0;
TIME_DECLS(); TIME_DECLS();
dump_page_map(gc, "pre"); dump_page_map(gc, "pre");
@ -5334,7 +5349,9 @@ static void garbage_collect(NewGC *gc, int force_full, int no_full,
This approach makes total memory use roughly a constant This approach makes total memory use roughly a constant
fraction of the actual use by live data: */ fraction of the actual use by live data: */
|| (gc->memory_in_use > (FULL_COLLECTION_SIZE_RATIO || (gc->memory_in_use > (FULL_COLLECTION_SIZE_RATIO
* gc->last_full_mem_use * ((gc->last_full_mem_use < INITIAL_FULL_MEMORY_USE)
? INITIAL_FULL_MEMORY_USE
: gc->last_full_mem_use)
* (gc->incremental_requested * (gc->incremental_requested
? INCREMENTAL_EXTRA_SIZE_RATIO ? INCREMENTAL_EXTRA_SIZE_RATIO
: 1))) : 1)))

View File

@ -312,6 +312,8 @@ typedef struct NewGC {
uintptr_t minor_old_skipped; uintptr_t minor_old_skipped;
uintptr_t modified_unprotects; uintptr_t modified_unprotects;
uintptr_t total_memory_allocated; /* doesn't include current gen0 */
/* THREAD_LOCAL variables that need to be saved off */ /* THREAD_LOCAL variables that need to be saved off */
void *saved_GC_variable_stack; void *saved_GC_variable_stack;
uintptr_t saved_GC_gen0_alloc_page_ptr; uintptr_t saved_GC_gen0_alloc_page_ptr;

View File

@ -799,7 +799,7 @@ static intptr_t mem_use, mem_limit = FIRST_GC_LIMIT;
int GC_free_space_divisor = 4; int GC_free_space_divisor = 4;
#endif #endif
static intptr_t mem_real_use, mem_uncollectable_use; static intptr_t mem_real_use, mem_uncollectable_use, mem_cumulative_use;
static intptr_t sector_mem_use, sector_admin_mem_use, sector_free_mem_use; static intptr_t sector_mem_use, sector_admin_mem_use, sector_free_mem_use;
static intptr_t manage_mem_use, manage_real_mem_use; static intptr_t manage_mem_use, manage_real_mem_use;
@ -2230,11 +2230,14 @@ void GC_dump(void)
FPRINTF(STDERR, "End Map\n"); FPRINTF(STDERR, "End Map\n");
} }
long GC_get_memory_use() size_t GC_get_memory_use()
{ {
/* returns a `long' instead of `intptr_t' for compatibility return (size_t)mem_real_use;
with the Boehm GC */ }
return (long)mem_real_use;
size_t GC_get_total_bytes()
{
return (size_t)mem_cumulative_use;
} }
void GC_end_stubborn_change(void *p) void GC_end_stubborn_change(void *p)
@ -2504,6 +2507,7 @@ static void *do_malloc(SET_NO_BACKINFO
else else
mem_use += size; mem_use += size;
mem_real_use += (size + sizeof(MemoryChunk)); mem_real_use += (size + sizeof(MemoryChunk));
mem_cumulative_use += (size + sizeof(MemoryChunk));
num_chunks++; num_chunks++;
if (!low_plausible || (c->start < low_plausible)) if (!low_plausible || (c->start < low_plausible))
@ -2642,6 +2646,7 @@ static void *do_malloc(SET_NO_BACKINFO
high_plausible = block->end; high_plausible = block->end;
mem_real_use += SECTOR_SEGMENT_SIZE; mem_real_use += SECTOR_SEGMENT_SIZE;
mem_cumulative_use += SECTOR_SEGMENT_SIZE;
block_top: block_top:
@ -2950,6 +2955,7 @@ static void register_finalizer(void *p, void (*f)(void *p, void *data),
if (!fn) { if (!fn) {
fn = (Finalizer *)malloc_managed(sizeof(Finalizer)); fn = (Finalizer *)malloc_managed(sizeof(Finalizer));
mem_real_use += sizeof(Finalizer); mem_real_use += sizeof(Finalizer);
mem_cumulative_use += sizeof(Finalizer);
GC_fo_entries++; GC_fo_entries++;
} }

View File

@ -35,7 +35,8 @@ SGC_EXTERN void *GC_base(void *);
SGC_EXTERN void GC_dump(void); SGC_EXTERN void GC_dump(void);
SGC_EXTERN long GC_get_memory_use(); SGC_EXTERN size_t GC_get_memory_use();
SGC_EXTERN size_t GC_get_total_bytes();
SGC_EXTERN void GC_end_stubborn_change(void *); SGC_EXTERN void GC_end_stubborn_change(void *);

View File

@ -244,6 +244,7 @@ THREAD_LOCAL_DECL(struct Scheme_GC_Pre_Post_Callback_Desc *gc_prepost_callback_d
ROSYM static Scheme_Object *read_symbol, *write_symbol, *execute_symbol, *delete_symbol, *exists_symbol; ROSYM static Scheme_Object *read_symbol, *write_symbol, *execute_symbol, *delete_symbol, *exists_symbol;
ROSYM static Scheme_Object *client_symbol, *server_symbol; ROSYM static Scheme_Object *client_symbol, *server_symbol;
ROSYM static Scheme_Object *major_symbol, *minor_symbol, *incremental_symbol; ROSYM static Scheme_Object *major_symbol, *minor_symbol, *incremental_symbol;
ROSYM static Scheme_Object *cumulative_symbol;
ROSYM static Scheme_Object *initial_compiled_file_check_symbol; ROSYM static Scheme_Object *initial_compiled_file_check_symbol;
@ -528,6 +529,9 @@ void scheme_init_thread(Scheme_Env *env)
minor_symbol = scheme_intern_symbol("minor"); minor_symbol = scheme_intern_symbol("minor");
incremental_symbol = scheme_intern_symbol("incremental"); incremental_symbol = scheme_intern_symbol("incremental");
REGISTER_SO(cumulative_symbol);
cumulative_symbol = scheme_intern_symbol("cumulative");
GLOBAL_PRIM_W_ARITY("dump-memory-stats" , scheme_dump_gc_stats, 0, -1, env); GLOBAL_PRIM_W_ARITY("dump-memory-stats" , scheme_dump_gc_stats, 0, -1, env);
GLOBAL_PRIM_W_ARITY("vector-set-performance-stats!", current_stats , 1, 2, env); GLOBAL_PRIM_W_ARITY("vector-set-performance-stats!", current_stats , 1, 2, env);
@ -734,6 +738,7 @@ static Scheme_Object *collect_garbage(int argc, Scheme_Object *argv[])
static Scheme_Object *current_memory_use(int argc, Scheme_Object *args[]) static Scheme_Object *current_memory_use(int argc, Scheme_Object *args[])
{ {
Scheme_Object *arg = NULL; Scheme_Object *arg = NULL;
int cumulative = 0;
uintptr_t retval = 0; uintptr_t retval = 0;
if (argc) { if (argc) {
@ -741,19 +746,30 @@ static Scheme_Object *current_memory_use(int argc, Scheme_Object *args[])
arg = args[0]; arg = args[0];
} else if (SAME_TYPE(SCHEME_TYPE(args[0]), scheme_custodian_type)) { } else if (SAME_TYPE(SCHEME_TYPE(args[0]), scheme_custodian_type)) {
arg = args[0]; arg = args[0];
} else if (SAME_OBJ(args[0], cumulative_symbol)) {
cumulative = 1;
arg = NULL;
} else { } else {
scheme_wrong_contract("current-memory-use", scheme_wrong_contract("current-memory-use",
"(or/c custodian? #f)", "(or/c custodian? 'cumulative #f)",
0, argc, args); 0, argc, args);
} }
} }
if (cumulative) {
#ifdef MZ_PRECISE_GC #ifdef MZ_PRECISE_GC
retval = GC_get_memory_use(arg); retval = GC_get_memory_ever_allocated();
#else #else
scheme_unused_object(arg); retval = GC_get_total_bytes();
retval = GC_get_memory_use();
#endif #endif
} else {
#ifdef MZ_PRECISE_GC
retval = GC_get_memory_use(arg);
#else
scheme_unused_object(arg);
retval = GC_get_memory_use();
#endif
}
return scheme_make_integer_value_from_unsigned(retval); return scheme_make_integer_value_from_unsigned(retval);
} }