track cumulative allocation
Extend `current-memory-use` to accept a 'cumulative flag.
This commit is contained in:
parent
a0a0e41908
commit
0034c31820
|
@ -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]{
|
||||||
|
|
||||||
|
|
|
@ -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. */
|
||||||
|
|
|
@ -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)))
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 *);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user