vm: remove crummy old GC stats, split off free list code, clean up various other things
parent
85dc9fda26
commit
e793a72060
1
Makefile
1
Makefile
|
@ -48,6 +48,7 @@ DLL_OBJS = $(PLAF_DLL_OBJS) \
|
||||||
vm/dispatch.o \
|
vm/dispatch.o \
|
||||||
vm/errors.o \
|
vm/errors.o \
|
||||||
vm/factor.o \
|
vm/factor.o \
|
||||||
|
vm/free_list.o \
|
||||||
vm/full_collector.o \
|
vm/full_collector.o \
|
||||||
vm/gc.o \
|
vm/gc.o \
|
||||||
vm/image.o \
|
vm/image.o \
|
||||||
|
|
|
@ -9,35 +9,50 @@ IN: tools.memory
|
||||||
<PRIVATE
|
<PRIVATE
|
||||||
|
|
||||||
: kilobytes ( n -- str )
|
: kilobytes ( n -- str )
|
||||||
number>string
|
1024 /i number>string
|
||||||
dup length 4 > [ 3 cut* "," glue ] when
|
dup length 4 > [ 3 cut* "," glue ] when
|
||||||
" KB" append ;
|
" KB" append ;
|
||||||
|
|
||||||
: memory-table. ( sizes seq -- )
|
: fancy-table. ( seq alist -- )
|
||||||
swap [ kilobytes ] map zip simple-table. ;
|
[ [ nip first ] [ second call( obj -- str ) ] 2bi 2array ] 2map
|
||||||
|
simple-table. ;
|
||||||
|
|
||||||
: young-room. ( seq -- )
|
: young-room. ( seq -- )
|
||||||
{ "Total:" "Allocated:" "Free:" } memory-table. ;
|
{
|
||||||
|
{ "Total:" [ kilobytes ] }
|
||||||
|
{ "Allocated:" [ kilobytes ] }
|
||||||
|
{ "Free:" [ kilobytes ] }
|
||||||
|
} fancy-table. ;
|
||||||
|
|
||||||
: nursery-room. ( seq -- ) "- Nursery space" print young-room. ;
|
: nursery-room. ( seq -- ) "- Nursery space" print young-room. ;
|
||||||
|
|
||||||
: aging-room. ( seq -- ) "- Aging space" print young-room. ;
|
: aging-room. ( seq -- ) "- Aging space" print young-room. ;
|
||||||
|
|
||||||
: mark-sweep-table. ( sizes -- )
|
: mark-sweep-table. ( sizes -- )
|
||||||
{ "Total:" "Allocated:" "Contiguous free:" "Total free:" } memory-table. ;
|
{
|
||||||
|
{ "Total:" [ kilobytes ] }
|
||||||
|
{ "Allocated:" [ kilobytes ] }
|
||||||
|
{ "Total free:" [ kilobytes ] }
|
||||||
|
{ "Contiguous free:" [ kilobytes ] }
|
||||||
|
{ "Free list entries:" [ number>string ] }
|
||||||
|
} fancy-table. ;
|
||||||
|
|
||||||
: tenured-room. ( seq -- ) "- Tenured space" print mark-sweep-table. ;
|
: tenured-room. ( seq -- ) "- Tenured space" print mark-sweep-table. ;
|
||||||
|
|
||||||
: misc-room. ( seq -- )
|
: misc-room. ( seq -- )
|
||||||
"- Miscellaneous buffers" print
|
"- Miscellaneous buffers" print
|
||||||
{ "Card array:" "Deck array:" "Mark stack:" } memory-table. ;
|
{
|
||||||
|
{ "Card array:" [ kilobytes ] }
|
||||||
|
{ "Deck array:" [ kilobytes ] }
|
||||||
|
{ "Mark stack:" [ kilobytes ] }
|
||||||
|
} fancy-table. ;
|
||||||
|
|
||||||
: data-room. ( -- )
|
: data-room. ( -- )
|
||||||
"==== DATA HEAP" print nl
|
"==== DATA HEAP" print nl
|
||||||
data-room
|
data-room
|
||||||
3 cut [ nursery-room. nl ] dip
|
3 cut [ nursery-room. nl ] dip
|
||||||
3 cut [ aging-room. nl ] dip
|
3 cut [ aging-room. nl ] dip
|
||||||
4 cut [ tenured-room. nl ] dip
|
5 cut [ tenured-room. nl ] dip
|
||||||
misc-room. ;
|
misc-room. ;
|
||||||
|
|
||||||
: code-room. ( -- )
|
: code-room. ( -- )
|
||||||
|
|
|
@ -423,7 +423,6 @@ tuple
|
||||||
{ "minor-gc" "memory" (( -- )) }
|
{ "minor-gc" "memory" (( -- )) }
|
||||||
{ "gc" "memory" (( -- )) }
|
{ "gc" "memory" (( -- )) }
|
||||||
{ "compact-gc" "memory" (( -- )) }
|
{ "compact-gc" "memory" (( -- )) }
|
||||||
{ "gc-stats" "memory" f }
|
|
||||||
{ "(save-image)" "memory.private" (( path -- )) }
|
{ "(save-image)" "memory.private" (( path -- )) }
|
||||||
{ "(save-image-and-exit)" "memory.private" (( path -- )) }
|
{ "(save-image-and-exit)" "memory.private" (( path -- )) }
|
||||||
{ "datastack" "kernel" (( -- ds )) }
|
{ "datastack" "kernel" (( -- ds )) }
|
||||||
|
@ -509,7 +508,6 @@ tuple
|
||||||
{ "resize-byte-array" "byte-arrays" (( n byte-array -- newbyte-array )) }
|
{ "resize-byte-array" "byte-arrays" (( n byte-array -- newbyte-array )) }
|
||||||
{ "dll-valid?" "alien.libraries" (( dll -- ? )) }
|
{ "dll-valid?" "alien.libraries" (( dll -- ? )) }
|
||||||
{ "unimplemented" "kernel.private" (( -- * )) }
|
{ "unimplemented" "kernel.private" (( -- * )) }
|
||||||
{ "gc-reset" "memory" (( -- )) }
|
|
||||||
{ "jit-compile" "quotations" (( quot -- )) }
|
{ "jit-compile" "quotations" (( quot -- )) }
|
||||||
{ "load-locals" "locals.backend" (( ... n -- )) }
|
{ "load-locals" "locals.backend" (( ... n -- )) }
|
||||||
{ "check-datastack" "kernel.private" (( array in# out# -- ? )) }
|
{ "check-datastack" "kernel.private" (( array in# out# -- ? )) }
|
||||||
|
|
|
@ -6,7 +6,6 @@ namespace factor
|
||||||
aging_collector::aging_collector(factor_vm *parent_) :
|
aging_collector::aging_collector(factor_vm *parent_) :
|
||||||
copying_collector<aging_space,aging_policy>(
|
copying_collector<aging_space,aging_policy>(
|
||||||
parent_,
|
parent_,
|
||||||
&parent_->gc_stats.aging_stats,
|
|
||||||
parent_->data->aging,
|
parent_->data->aging,
|
||||||
aging_policy(parent_)) {}
|
aging_policy(parent_)) {}
|
||||||
|
|
||||||
|
|
|
@ -11,17 +11,27 @@ template<typename Block> struct bump_allocator {
|
||||||
explicit bump_allocator(cell size_, cell start_) :
|
explicit bump_allocator(cell size_, cell start_) :
|
||||||
here(start_), start(start_), end(start_ + size_), size(size_) {}
|
here(start_), start(start_), end(start_ + size_), size(size_) {}
|
||||||
|
|
||||||
inline bool contains_p(Block *block)
|
bool contains_p(Block *block)
|
||||||
{
|
{
|
||||||
return ((cell)block - start) < size;
|
return ((cell)block - start) < size;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Block *allot(cell size)
|
Block *allot(cell size)
|
||||||
{
|
{
|
||||||
cell h = here;
|
cell h = here;
|
||||||
here = h + align(size,data_alignment);
|
here = h + align(size,data_alignment);
|
||||||
return (Block *)h;
|
return (Block *)h;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cell occupied_space()
|
||||||
|
{
|
||||||
|
return here - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell free_space()
|
||||||
|
{
|
||||||
|
return end - here;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -454,13 +454,8 @@ code_block *factor_vm::allot_code_block(cell size, code_block_type type)
|
||||||
/* Insufficient room even after code GC, give up */
|
/* Insufficient room even after code GC, give up */
|
||||||
if(block == NULL)
|
if(block == NULL)
|
||||||
{
|
{
|
||||||
cell used, total_free, max_free;
|
std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
|
||||||
code->allocator->usage(&used,&total_free,&max_free);
|
std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
|
||||||
|
|
||||||
std::cout << "Code heap stats:\n";
|
|
||||||
std::cout << "Used: " << used << "\n";
|
|
||||||
std::cout << "Total free space: " << total_free << "\n";
|
|
||||||
std::cout << "Largest free block: " << max_free << "\n";
|
|
||||||
fatal_error("Out of memory in add-compiled-block",0);
|
fatal_error("Out of memory in add-compiled-block",0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -199,13 +199,11 @@ void factor_vm::primitive_code_room()
|
||||||
{
|
{
|
||||||
growable_array a(this);
|
growable_array a(this);
|
||||||
|
|
||||||
cell used, total_free, max_free;
|
a.add(tag_fixnum(code->allocator->size));
|
||||||
code->allocator->usage(&used,&total_free,&max_free);
|
a.add(tag_fixnum(code->allocator->occupied_space()));
|
||||||
|
a.add(tag_fixnum(code->allocator->free_space()));
|
||||||
a.add(tag_fixnum(code->seg->size >> 10));
|
a.add(tag_fixnum(code->allocator->free_blocks.largest_free_block()));
|
||||||
a.add(tag_fixnum(used >> 10));
|
a.add(tag_fixnum(code->allocator->free_blocks.free_block_count));
|
||||||
a.add(tag_fixnum(total_free >> 10));
|
|
||||||
a.add(tag_fixnum(max_free >> 10));
|
|
||||||
|
|
||||||
a.trim();
|
a.trim();
|
||||||
dpush(a.elements.value());
|
dpush(a.elements.value());
|
||||||
|
|
|
@ -3,13 +3,11 @@ namespace factor
|
||||||
|
|
||||||
template<typename TargetGeneration, typename Policy> struct collector_workhorse {
|
template<typename TargetGeneration, typename Policy> struct collector_workhorse {
|
||||||
factor_vm *parent;
|
factor_vm *parent;
|
||||||
generation_statistics *stats;
|
|
||||||
TargetGeneration *target;
|
TargetGeneration *target;
|
||||||
Policy policy;
|
Policy policy;
|
||||||
|
|
||||||
explicit collector_workhorse(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
|
explicit collector_workhorse(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
|
||||||
parent(parent_),
|
parent(parent_),
|
||||||
stats(stats_),
|
|
||||||
target(target_),
|
target(target_),
|
||||||
policy(policy_) {}
|
policy(policy_) {}
|
||||||
|
|
||||||
|
@ -36,9 +34,6 @@ template<typename TargetGeneration, typename Policy> struct collector_workhorse
|
||||||
memcpy(newpointer,untagged,size);
|
memcpy(newpointer,untagged,size);
|
||||||
untagged->h.forward_to(newpointer);
|
untagged->h.forward_to(newpointer);
|
||||||
|
|
||||||
stats->object_count++;
|
|
||||||
stats->bytes_copied += size;
|
|
||||||
|
|
||||||
policy.promoted_object(newpointer);
|
policy.promoted_object(newpointer);
|
||||||
|
|
||||||
return newpointer;
|
return newpointer;
|
||||||
|
@ -69,29 +64,34 @@ template<typename TargetGeneration, typename Policy> struct collector_workhorse
|
||||||
template<typename TargetGeneration, typename Policy>
|
template<typename TargetGeneration, typename Policy>
|
||||||
inline static slot_visitor<collector_workhorse<TargetGeneration,Policy> > make_collector_workhorse(
|
inline static slot_visitor<collector_workhorse<TargetGeneration,Policy> > make_collector_workhorse(
|
||||||
factor_vm *parent,
|
factor_vm *parent,
|
||||||
generation_statistics *stats,
|
|
||||||
TargetGeneration *target,
|
TargetGeneration *target,
|
||||||
Policy policy)
|
Policy policy)
|
||||||
{
|
{
|
||||||
return slot_visitor<collector_workhorse<TargetGeneration,Policy> >(parent,
|
return slot_visitor<collector_workhorse<TargetGeneration,Policy> >(parent,
|
||||||
collector_workhorse<TargetGeneration,Policy>(parent,stats,target,policy));
|
collector_workhorse<TargetGeneration,Policy>(parent,target,policy));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TargetGeneration, typename Policy> struct collector {
|
template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
factor_vm *parent;
|
factor_vm *parent;
|
||||||
data_heap *data;
|
data_heap *data;
|
||||||
code_heap *code;
|
code_heap *code;
|
||||||
generation_statistics *stats;
|
|
||||||
TargetGeneration *target;
|
TargetGeneration *target;
|
||||||
slot_visitor<collector_workhorse<TargetGeneration,Policy> > workhorse;
|
slot_visitor<collector_workhorse<TargetGeneration,Policy> > workhorse;
|
||||||
|
cell cards_scanned;
|
||||||
|
cell decks_scanned;
|
||||||
|
cell card_scan_time;
|
||||||
|
cell code_blocks_scanned;
|
||||||
|
|
||||||
explicit collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
|
explicit collector(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
|
||||||
parent(parent_),
|
parent(parent_),
|
||||||
data(parent_->data),
|
data(parent_->data),
|
||||||
code(parent_->code),
|
code(parent_->code),
|
||||||
stats(stats_),
|
|
||||||
target(target_),
|
target(target_),
|
||||||
workhorse(make_collector_workhorse(parent_,stats_,target_,policy_)) {}
|
workhorse(make_collector_workhorse(parent_,target_,policy_)),
|
||||||
|
cards_scanned(0),
|
||||||
|
decks_scanned(0),
|
||||||
|
card_scan_time(0),
|
||||||
|
code_blocks_scanned(0) {}
|
||||||
|
|
||||||
void trace_handle(cell *handle)
|
void trace_handle(cell *handle)
|
||||||
{
|
{
|
||||||
|
@ -127,7 +127,7 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
for(; iter != end; iter++)
|
for(; iter != end; iter++)
|
||||||
{
|
{
|
||||||
trace_literal_references(*iter);
|
trace_literal_references(*iter);
|
||||||
parent->gc_stats.code_blocks_scanned++;
|
code_blocks_scanned++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +195,7 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
{
|
{
|
||||||
if(decks[deck_index] & mask)
|
if(decks[deck_index] & mask)
|
||||||
{
|
{
|
||||||
parent->gc_stats.decks_scanned++;
|
decks_scanned++;
|
||||||
|
|
||||||
cell first_card = first_card_in_deck(deck_index);
|
cell first_card = first_card_in_deck(deck_index);
|
||||||
cell last_card = last_card_in_deck(deck_index);
|
cell last_card = last_card_in_deck(deck_index);
|
||||||
|
@ -204,7 +204,7 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
||||||
{
|
{
|
||||||
if(cards[card_index] & mask)
|
if(cards[card_index] & mask)
|
||||||
{
|
{
|
||||||
parent->gc_stats.cards_scanned++;
|
cards_scanned++;
|
||||||
|
|
||||||
if(end < card_start_address(card_index))
|
if(end < card_start_address(card_index))
|
||||||
{
|
{
|
||||||
|
@ -246,7 +246,7 @@ scan_next_object: {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
end: parent->gc_stats.card_scan_time += (current_micros() - start_time);
|
end: card_scan_time += (current_micros() - start_time);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,8 +15,8 @@ template<typename TargetGeneration, typename Policy>
|
||||||
struct copying_collector : collector<TargetGeneration,Policy> {
|
struct copying_collector : collector<TargetGeneration,Policy> {
|
||||||
cell scan;
|
cell scan;
|
||||||
|
|
||||||
explicit copying_collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
|
explicit copying_collector(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
|
||||||
collector<TargetGeneration,Policy>(parent_,stats_,target_,policy_), scan(target_->here) {}
|
collector<TargetGeneration,Policy>(parent_,target_,policy_), scan(target_->here) {}
|
||||||
|
|
||||||
void cheneys_algorithm()
|
void cheneys_algorithm()
|
||||||
{
|
{
|
||||||
|
|
|
@ -206,24 +206,23 @@ void factor_vm::primitive_data_room()
|
||||||
{
|
{
|
||||||
growable_array a(this);
|
growable_array a(this);
|
||||||
|
|
||||||
a.add(tag_fixnum((nursery.size) >> 10));
|
a.add(tag_fixnum(nursery.size));
|
||||||
a.add(tag_fixnum((nursery.here - nursery.start) >> 10));
|
a.add(tag_fixnum(nursery.occupied_space()));
|
||||||
a.add(tag_fixnum((nursery.end - nursery.here) >> 10));
|
a.add(tag_fixnum(nursery.free_space()));
|
||||||
|
|
||||||
a.add(tag_fixnum((data->aging->size) >> 10));
|
a.add(tag_fixnum(data->aging->size));
|
||||||
a.add(tag_fixnum((data->aging->here - data->aging->start) >> 10));
|
a.add(tag_fixnum(data->aging->occupied_space()));
|
||||||
a.add(tag_fixnum((data->aging->end - data->aging->here) >> 10));
|
a.add(tag_fixnum(data->aging->free_space()));
|
||||||
|
|
||||||
cell used, total_free, max_free;
|
a.add(tag_fixnum(data->tenured->size));
|
||||||
data->tenured->usage(&used,&total_free,&max_free);
|
a.add(tag_fixnum(data->tenured->occupied_space()));
|
||||||
a.add(tag_fixnum(data->tenured->size >> 10));
|
a.add(tag_fixnum(data->tenured->free_space()));
|
||||||
a.add(tag_fixnum(used >> 10));
|
a.add(tag_fixnum(data->tenured->free_blocks.largest_free_block()));
|
||||||
a.add(tag_fixnum(total_free >> 10));
|
a.add(tag_fixnum(data->tenured->free_blocks.free_block_count));
|
||||||
a.add(tag_fixnum(max_free >> 10));
|
|
||||||
|
|
||||||
a.add(tag_fixnum((data->cards_end - data->cards) >> 10));
|
a.add(tag_fixnum(data->cards_end - data->cards));
|
||||||
a.add(tag_fixnum((data->decks_end - data->decks) >> 10));
|
a.add(tag_fixnum(data->decks_end - data->decks));
|
||||||
a.add(tag_fixnum((data->tenured->mark_stack.capacity()) >> 10));
|
a.add(tag_fixnum(data->tenured->mark_stack.capacity()));
|
||||||
|
|
||||||
a.trim();
|
a.trim();
|
||||||
dpush(a.elements.value());
|
dpush(a.elements.value());
|
||||||
|
|
|
@ -38,7 +38,7 @@ void factor_vm::default_parameters(vm_parameters *p)
|
||||||
p->max_pic_size = 3;
|
p->max_pic_size = 3;
|
||||||
|
|
||||||
p->fep = false;
|
p->fep = false;
|
||||||
p->verbosegc = false;
|
p->verbose_gc = false;
|
||||||
p->signals = true;
|
p->signals = true;
|
||||||
|
|
||||||
#ifdef WINDOWS
|
#ifdef WINDOWS
|
||||||
|
@ -87,7 +87,7 @@ void factor_vm::init_parameters_from_args(vm_parameters *p, int argc, vm_char **
|
||||||
else if(factor_arg(arg,STRING_LITERAL("-callbacks=%d"),&p->callback_size));
|
else if(factor_arg(arg,STRING_LITERAL("-callbacks=%d"),&p->callback_size));
|
||||||
else if(STRCMP(arg,STRING_LITERAL("-fep")) == 0) p->fep = true;
|
else if(STRCMP(arg,STRING_LITERAL("-fep")) == 0) p->fep = true;
|
||||||
else if(STRCMP(arg,STRING_LITERAL("-nosignals")) == 0) p->signals = false;
|
else if(STRCMP(arg,STRING_LITERAL("-nosignals")) == 0) p->signals = false;
|
||||||
else if(STRCMP(arg,STRING_LITERAL("-verbosegc")) == 0) p->verbosegc = true;
|
else if(STRCMP(arg,STRING_LITERAL("-verbosegc")) == 0) p->verbose_gc = true;
|
||||||
else if(STRNCMP(arg,STRING_LITERAL("-i="),3) == 0) p->image_path = arg + 3;
|
else if(STRNCMP(arg,STRING_LITERAL("-i="),3) == 0) p->image_path = arg + 3;
|
||||||
else if(STRCMP(arg,STRING_LITERAL("-console")) == 0) p->console = true;
|
else if(STRCMP(arg,STRING_LITERAL("-console")) == 0) p->console = true;
|
||||||
}
|
}
|
||||||
|
@ -142,7 +142,7 @@ void factor_vm::init_factor(vm_parameters *p)
|
||||||
if(p->signals)
|
if(p->signals)
|
||||||
init_signals();
|
init_signals();
|
||||||
|
|
||||||
verbosegc = p->verbosegc;
|
verbose_gc = p->verbose_gc;
|
||||||
|
|
||||||
if(p->console)
|
if(p->console)
|
||||||
open_console();
|
open_console();
|
||||||
|
|
|
@ -0,0 +1,138 @@
|
||||||
|
#include "master.hpp"
|
||||||
|
|
||||||
|
namespace factor
|
||||||
|
{
|
||||||
|
|
||||||
|
void free_list::clear_free_list()
|
||||||
|
{
|
||||||
|
memset(this,0,sizeof(free_list));
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_list::initial_free_list(cell start, cell end, cell occupied)
|
||||||
|
{
|
||||||
|
clear_free_list();
|
||||||
|
if(occupied != end - start)
|
||||||
|
{
|
||||||
|
free_heap_block *last_block = (free_heap_block *)(start + occupied);
|
||||||
|
last_block->make_free(end - (cell)last_block);
|
||||||
|
add_to_free_list(last_block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_list::add_to_free_list(free_heap_block *block)
|
||||||
|
{
|
||||||
|
cell size = block->size();
|
||||||
|
|
||||||
|
free_block_count++;
|
||||||
|
free_space += size;
|
||||||
|
|
||||||
|
if(size < free_list_count * block_granularity)
|
||||||
|
{
|
||||||
|
int index = size / block_granularity;
|
||||||
|
block->next_free = small_blocks[index];
|
||||||
|
small_blocks[index] = block;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
block->next_free = large_blocks;
|
||||||
|
large_blocks = block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
free_heap_block *free_list::find_free_block(cell size)
|
||||||
|
{
|
||||||
|
cell attempt = size;
|
||||||
|
|
||||||
|
while(attempt < free_list_count * block_granularity)
|
||||||
|
{
|
||||||
|
int index = attempt / block_granularity;
|
||||||
|
free_heap_block *block = small_blocks[index];
|
||||||
|
if(block)
|
||||||
|
{
|
||||||
|
small_blocks[index] = block->next_free;
|
||||||
|
|
||||||
|
free_block_count--;
|
||||||
|
free_space -= block->size();
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
attempt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_heap_block *prev = NULL;
|
||||||
|
free_heap_block *block = large_blocks;
|
||||||
|
|
||||||
|
while(block)
|
||||||
|
{
|
||||||
|
if(block->size() >= size)
|
||||||
|
{
|
||||||
|
if(prev)
|
||||||
|
prev->next_free = block->next_free;
|
||||||
|
else
|
||||||
|
large_blocks = block->next_free;
|
||||||
|
|
||||||
|
free_block_count--;
|
||||||
|
free_space -= block->size();
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = block;
|
||||||
|
block = block->next_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_heap_block *free_list::split_free_block(free_heap_block *block, cell size)
|
||||||
|
{
|
||||||
|
if(block->size() != size)
|
||||||
|
{
|
||||||
|
/* split the block in two */
|
||||||
|
free_heap_block *split = (free_heap_block *)((cell)block + size);
|
||||||
|
split->make_free(block->size() - size);
|
||||||
|
split->next_free = block->next_free;
|
||||||
|
block->make_free(size);
|
||||||
|
add_to_free_list(split);
|
||||||
|
}
|
||||||
|
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool free_list::can_allot_p(cell size)
|
||||||
|
{
|
||||||
|
cell attempt = size;
|
||||||
|
|
||||||
|
while(attempt < free_list_count * block_granularity)
|
||||||
|
{
|
||||||
|
int index = attempt / block_granularity;
|
||||||
|
if(small_blocks[index]) return true;
|
||||||
|
attempt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
free_heap_block *block = large_blocks;
|
||||||
|
while(block)
|
||||||
|
{
|
||||||
|
if(block->size() >= size) return true;
|
||||||
|
block = block->next_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell free_list::largest_free_block()
|
||||||
|
{
|
||||||
|
cell largest = 0;
|
||||||
|
free_heap_block *scan = large_blocks;
|
||||||
|
|
||||||
|
while(scan)
|
||||||
|
{
|
||||||
|
largest = std::max(largest,scan->size());
|
||||||
|
scan = scan->next_free;
|
||||||
|
}
|
||||||
|
|
||||||
|
return largest;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
namespace factor
|
||||||
|
{
|
||||||
|
|
||||||
|
static const cell free_list_count = 32;
|
||||||
|
|
||||||
|
struct free_heap_block
|
||||||
|
{
|
||||||
|
cell header;
|
||||||
|
free_heap_block *next_free;
|
||||||
|
|
||||||
|
bool free_p() const
|
||||||
|
{
|
||||||
|
return header & 1 == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
cell size() const
|
||||||
|
{
|
||||||
|
return header >> 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
void make_free(cell size)
|
||||||
|
{
|
||||||
|
header = (size << 3) | 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct free_list {
|
||||||
|
free_heap_block *small_blocks[free_list_count];
|
||||||
|
free_heap_block *large_blocks;
|
||||||
|
cell free_block_count;
|
||||||
|
cell free_space;
|
||||||
|
|
||||||
|
void clear_free_list();
|
||||||
|
void initial_free_list(cell start, cell end, cell occupied);
|
||||||
|
void add_to_free_list(free_heap_block *block);
|
||||||
|
free_heap_block *find_free_block(cell size);
|
||||||
|
free_heap_block *split_free_block(free_heap_block *block, cell size);
|
||||||
|
bool can_allot_p(cell size);
|
||||||
|
cell largest_free_block();
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,34 +1,6 @@
|
||||||
namespace factor
|
namespace factor
|
||||||
{
|
{
|
||||||
|
|
||||||
static const cell free_list_count = 32;
|
|
||||||
|
|
||||||
struct free_heap_block
|
|
||||||
{
|
|
||||||
cell header;
|
|
||||||
free_heap_block *next_free;
|
|
||||||
|
|
||||||
bool free_p() const
|
|
||||||
{
|
|
||||||
return header & 1 == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
cell size() const
|
|
||||||
{
|
|
||||||
return header >> 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
void make_free(cell size)
|
|
||||||
{
|
|
||||||
header = (size << 3) | 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct free_list {
|
|
||||||
free_heap_block *small_blocks[free_list_count];
|
|
||||||
free_heap_block *large_blocks;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Block> struct free_list_allocator {
|
template<typename Block> struct free_list_allocator {
|
||||||
cell size;
|
cell size;
|
||||||
cell start;
|
cell start;
|
||||||
|
@ -37,21 +9,16 @@ template<typename Block> struct free_list_allocator {
|
||||||
mark_bits<Block> state;
|
mark_bits<Block> state;
|
||||||
|
|
||||||
explicit free_list_allocator(cell size, cell start);
|
explicit free_list_allocator(cell size, cell start);
|
||||||
|
void initial_free_list(cell occupied);
|
||||||
bool contains_p(Block *block);
|
bool contains_p(Block *block);
|
||||||
Block *first_block();
|
Block *first_block();
|
||||||
Block *last_block();
|
Block *last_block();
|
||||||
Block *next_block_after(Block *block);
|
Block *next_block_after(Block *block);
|
||||||
void clear_free_list();
|
|
||||||
void add_to_free_list(free_heap_block *block);
|
|
||||||
void initial_free_list(cell size);
|
|
||||||
void assert_free_block(free_heap_block *block);
|
|
||||||
free_heap_block *find_free_block(cell size);
|
|
||||||
free_heap_block *split_free_block(free_heap_block *block, cell size);
|
|
||||||
bool can_allot_p(cell size);
|
bool can_allot_p(cell size);
|
||||||
Block *allot(cell size);
|
Block *allot(cell size);
|
||||||
void free(Block *block);
|
void free(Block *block);
|
||||||
void usage(cell *used, cell *total_free, cell *max_free);
|
cell occupied_space();
|
||||||
cell occupied();
|
cell free_space();
|
||||||
void sweep();
|
void sweep();
|
||||||
template<typename Iterator> void sweep(Iterator &iter);
|
template<typename Iterator> void sweep(Iterator &iter);
|
||||||
template<typename Iterator, typename Sizer> void compact(Iterator &iter, Sizer &sizer);
|
template<typename Iterator, typename Sizer> void compact(Iterator &iter, Sizer &sizer);
|
||||||
|
@ -66,9 +33,9 @@ free_list_allocator<Block>::free_list_allocator(cell size_, cell start_) :
|
||||||
initial_free_list(0);
|
initial_free_list(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Block> void free_list_allocator<Block>::clear_free_list()
|
template<typename Block> void free_list_allocator<Block>::initial_free_list(cell occupied)
|
||||||
{
|
{
|
||||||
memset(&free_blocks,0,sizeof(free_list));
|
free_blocks.initial_free_list(start,end,occupied);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Block> bool free_list_allocator<Block>::contains_p(Block *block)
|
template<typename Block> bool free_list_allocator<Block>::contains_p(Block *block)
|
||||||
|
@ -91,125 +58,19 @@ template<typename Block> Block *free_list_allocator<Block>::next_block_after(Blo
|
||||||
return (Block *)((cell)block + block->size());
|
return (Block *)((cell)block + block->size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Block> void free_list_allocator<Block>::add_to_free_list(free_heap_block *block)
|
|
||||||
{
|
|
||||||
if(block->size() < free_list_count * block_granularity)
|
|
||||||
{
|
|
||||||
int index = block->size() / block_granularity;
|
|
||||||
block->next_free = free_blocks.small_blocks[index];
|
|
||||||
free_blocks.small_blocks[index] = block;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
block->next_free = free_blocks.large_blocks;
|
|
||||||
free_blocks.large_blocks = block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Called after reading the heap from the image file, and after heap compaction.
|
|
||||||
Makes a free list consisting of one free block, at the very end. */
|
|
||||||
template<typename Block> void free_list_allocator<Block>::initial_free_list(cell size)
|
|
||||||
{
|
|
||||||
clear_free_list();
|
|
||||||
if(size != this->size)
|
|
||||||
{
|
|
||||||
free_heap_block *last_block = (free_heap_block *)(start + size);
|
|
||||||
last_block->make_free(end - (cell)last_block);
|
|
||||||
add_to_free_list(last_block);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Block> void free_list_allocator<Block>::assert_free_block(free_heap_block *block)
|
|
||||||
{
|
|
||||||
#ifdef FACTOR_DEBUG
|
|
||||||
assert(block->free_p());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Block> free_heap_block *free_list_allocator<Block>::find_free_block(cell size)
|
|
||||||
{
|
|
||||||
cell attempt = size;
|
|
||||||
|
|
||||||
while(attempt < free_list_count * block_granularity)
|
|
||||||
{
|
|
||||||
int index = attempt / block_granularity;
|
|
||||||
free_heap_block *block = free_blocks.small_blocks[index];
|
|
||||||
if(block)
|
|
||||||
{
|
|
||||||
assert_free_block(block);
|
|
||||||
free_blocks.small_blocks[index] = block->next_free;
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
attempt *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
free_heap_block *prev = NULL;
|
|
||||||
free_heap_block *block = free_blocks.large_blocks;
|
|
||||||
|
|
||||||
while(block)
|
|
||||||
{
|
|
||||||
assert_free_block(block);
|
|
||||||
if(block->size() >= size)
|
|
||||||
{
|
|
||||||
if(prev)
|
|
||||||
prev->next_free = block->next_free;
|
|
||||||
else
|
|
||||||
free_blocks.large_blocks = block->next_free;
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
prev = block;
|
|
||||||
block = block->next_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Block> free_heap_block *free_list_allocator<Block>::split_free_block(free_heap_block *block, cell size)
|
|
||||||
{
|
|
||||||
if(block->size() != size)
|
|
||||||
{
|
|
||||||
/* split the block in two */
|
|
||||||
free_heap_block *split = (free_heap_block *)((cell)block + size);
|
|
||||||
split->make_free(block->size() - size);
|
|
||||||
split->next_free = block->next_free;
|
|
||||||
block->make_free(size);
|
|
||||||
add_to_free_list(split);
|
|
||||||
}
|
|
||||||
|
|
||||||
return block;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Block> bool free_list_allocator<Block>::can_allot_p(cell size)
|
template<typename Block> bool free_list_allocator<Block>::can_allot_p(cell size)
|
||||||
{
|
{
|
||||||
cell attempt = size;
|
return free_blocks.can_allot_p(size);
|
||||||
|
|
||||||
while(attempt < free_list_count * block_granularity)
|
|
||||||
{
|
|
||||||
int index = attempt / block_granularity;
|
|
||||||
if(free_blocks.small_blocks[index]) return true;
|
|
||||||
attempt *= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
free_heap_block *block = free_blocks.large_blocks;
|
|
||||||
while(block)
|
|
||||||
{
|
|
||||||
if(block->size() >= size) return true;
|
|
||||||
block = block->next_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Block> Block *free_list_allocator<Block>::allot(cell size)
|
template<typename Block> Block *free_list_allocator<Block>::allot(cell size)
|
||||||
{
|
{
|
||||||
size = align(size,block_granularity);
|
size = align(size,block_granularity);
|
||||||
|
|
||||||
free_heap_block *block = find_free_block(size);
|
free_heap_block *block = free_blocks.find_free_block(size);
|
||||||
if(block)
|
if(block)
|
||||||
{
|
{
|
||||||
block = split_free_block(block,size);
|
block = free_blocks.split_free_block(block,size);
|
||||||
return (Block *)block;
|
return (Block *)block;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -220,64 +81,23 @@ template<typename Block> void free_list_allocator<Block>::free(Block *block)
|
||||||
{
|
{
|
||||||
free_heap_block *free_block = (free_heap_block *)block;
|
free_heap_block *free_block = (free_heap_block *)block;
|
||||||
free_block->make_free(block->size());
|
free_block->make_free(block->size());
|
||||||
add_to_free_list(free_block);
|
free_blocks.add_to_free_list(free_block);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Compute total sum of sizes of free blocks, and size of largest free block */
|
template<typename Block> cell free_list_allocator<Block>::free_space()
|
||||||
template<typename Block> void free_list_allocator<Block>::usage(cell *used, cell *total_free, cell *max_free)
|
|
||||||
{
|
{
|
||||||
*used = 0;
|
return free_blocks.free_space;
|
||||||
*total_free = 0;
|
|
||||||
*max_free = 0;
|
|
||||||
|
|
||||||
Block *scan = first_block();
|
|
||||||
Block *end = last_block();
|
|
||||||
|
|
||||||
while(scan != end)
|
|
||||||
{
|
|
||||||
cell size = scan->size();
|
|
||||||
|
|
||||||
if(scan->free_p())
|
|
||||||
{
|
|
||||||
*total_free += size;
|
|
||||||
if(size > *max_free)
|
|
||||||
*max_free = size;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
*used += size;
|
|
||||||
|
|
||||||
scan = next_block_after(scan);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The size of the heap after compaction */
|
template<typename Block> cell free_list_allocator<Block>::occupied_space()
|
||||||
template<typename Block> cell free_list_allocator<Block>::occupied()
|
|
||||||
{
|
{
|
||||||
Block *scan = first_block();
|
return size - free_blocks.free_space;
|
||||||
Block *last = last_block();
|
|
||||||
|
|
||||||
while(scan != last)
|
|
||||||
{
|
|
||||||
if(scan->free_p()) break;
|
|
||||||
else scan = next_block_after(scan);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(scan != last)
|
|
||||||
{
|
|
||||||
free_heap_block *free_block = (free_heap_block *)scan;
|
|
||||||
assert(free_block->free_p());
|
|
||||||
assert((cell)scan + free_block->size() == end);
|
|
||||||
|
|
||||||
return (cell)scan - (cell)first_block();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Block>
|
template<typename Block>
|
||||||
void free_list_allocator<Block>::sweep()
|
void free_list_allocator<Block>::sweep()
|
||||||
{
|
{
|
||||||
this->clear_free_list();
|
free_blocks.clear_free_list();
|
||||||
|
|
||||||
Block *prev = NULL;
|
Block *prev = NULL;
|
||||||
Block *scan = this->first_block();
|
Block *scan = this->first_block();
|
||||||
|
@ -300,7 +120,7 @@ void free_list_allocator<Block>::sweep()
|
||||||
else if(this->state.marked_p(scan))
|
else if(this->state.marked_p(scan))
|
||||||
{
|
{
|
||||||
if(prev && prev->free_p())
|
if(prev && prev->free_p())
|
||||||
this->add_to_free_list((free_heap_block *)prev);
|
free_blocks.add_to_free_list((free_heap_block *)prev);
|
||||||
prev = scan;
|
prev = scan;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -322,14 +142,14 @@ void free_list_allocator<Block>::sweep()
|
||||||
}
|
}
|
||||||
|
|
||||||
if(prev && prev->free_p())
|
if(prev && prev->free_p())
|
||||||
this->add_to_free_list((free_heap_block *)prev);
|
free_blocks.add_to_free_list((free_heap_block *)prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Block>
|
template<typename Block>
|
||||||
template<typename Iterator>
|
template<typename Iterator>
|
||||||
void free_list_allocator<Block>::sweep(Iterator &iter)
|
void free_list_allocator<Block>::sweep(Iterator &iter)
|
||||||
{
|
{
|
||||||
this->clear_free_list();
|
free_blocks.clear_free_list();
|
||||||
|
|
||||||
Block *prev = NULL;
|
Block *prev = NULL;
|
||||||
Block *scan = this->first_block();
|
Block *scan = this->first_block();
|
||||||
|
@ -352,7 +172,7 @@ void free_list_allocator<Block>::sweep(Iterator &iter)
|
||||||
else if(this->state.marked_p(scan))
|
else if(this->state.marked_p(scan))
|
||||||
{
|
{
|
||||||
if(prev && prev->free_p())
|
if(prev && prev->free_p())
|
||||||
this->add_to_free_list((free_heap_block *)prev);
|
free_blocks.add_to_free_list((free_heap_block *)prev);
|
||||||
prev = scan;
|
prev = scan;
|
||||||
iter(scan,size);
|
iter(scan,size);
|
||||||
}
|
}
|
||||||
|
@ -375,7 +195,7 @@ void free_list_allocator<Block>::sweep(Iterator &iter)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(prev && prev->free_p())
|
if(prev && prev->free_p())
|
||||||
this->add_to_free_list((free_heap_block *)prev);
|
free_blocks.add_to_free_list((free_heap_block *)prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Block, typename Iterator> struct heap_compactor {
|
template<typename Block, typename Iterator> struct heap_compactor {
|
||||||
|
@ -403,11 +223,11 @@ template<typename Iterator, typename Sizer>
|
||||||
void free_list_allocator<Block>::compact(Iterator &iter, Sizer &sizer)
|
void free_list_allocator<Block>::compact(Iterator &iter, Sizer &sizer)
|
||||||
{
|
{
|
||||||
heap_compactor<Block,Iterator> compactor(&state,first_block(),iter);
|
heap_compactor<Block,Iterator> compactor(&state,first_block(),iter);
|
||||||
this->iterate(compactor,sizer);
|
iterate(compactor,sizer);
|
||||||
|
|
||||||
/* Now update the free list; there will be a single free block at
|
/* Now update the free list; there will be a single free block at
|
||||||
the end */
|
the end */
|
||||||
this->initial_free_list((cell)compactor.address - this->start);
|
free_blocks.initial_free_list(start,end,(cell)compactor.address - start);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* During compaction we have to be careful and measure object sizes differently */
|
/* During compaction we have to be careful and measure object sizes differently */
|
||||||
|
|
|
@ -6,7 +6,6 @@ namespace factor
|
||||||
full_collector::full_collector(factor_vm *parent_) :
|
full_collector::full_collector(factor_vm *parent_) :
|
||||||
collector<tenured_space,full_policy>(
|
collector<tenured_space,full_policy>(
|
||||||
parent_,
|
parent_,
|
||||||
&parent_->gc_stats.full_stats,
|
|
||||||
parent_->data->tenured,
|
parent_->data->tenured,
|
||||||
full_policy(parent_)) {}
|
full_policy(parent_)) {}
|
||||||
|
|
||||||
|
|
64
vm/gc.cpp
64
vm/gc.cpp
|
@ -16,15 +16,6 @@ void factor_vm::update_code_heap_for_minor_gc(std::set<code_block *> *remembered
|
||||||
for(; iter != end; iter++) update_literal_references(*iter);
|
for(; iter != end; iter++) update_literal_references(*iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::record_gc_stats(generation_statistics *stats)
|
|
||||||
{
|
|
||||||
cell gc_elapsed = (current_micros() - current_gc->start_time);
|
|
||||||
stats->collections++;
|
|
||||||
stats->gc_time += gc_elapsed;
|
|
||||||
if(stats->max_gc_time < gc_elapsed)
|
|
||||||
stats->max_gc_time = gc_elapsed;
|
|
||||||
}
|
|
||||||
|
|
||||||
void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
|
void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
|
||||||
{
|
{
|
||||||
assert(!gc_off);
|
assert(!gc_off);
|
||||||
|
@ -34,7 +25,7 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
|
||||||
|
|
||||||
current_gc = new gc_state(op);
|
current_gc = new gc_state(op);
|
||||||
|
|
||||||
if(verbosegc)
|
if(verbose_gc)
|
||||||
std::cout << "GC requested, op=" << op << std::endl;
|
std::cout << "GC requested, op=" << op << std::endl;
|
||||||
|
|
||||||
/* Keep trying to GC higher and higher generations until we don't run out
|
/* Keep trying to GC higher and higher generations until we don't run out
|
||||||
|
@ -62,7 +53,7 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(verbosegc)
|
if(verbose_gc)
|
||||||
std::cout << "GC rewind, op=" << current_gc->op << std::endl;
|
std::cout << "GC rewind, op=" << current_gc->op << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,37 +61,31 @@ void factor_vm::gc(gc_op op, cell requested_bytes, bool trace_contexts_p)
|
||||||
{
|
{
|
||||||
case collect_nursery_op:
|
case collect_nursery_op:
|
||||||
collect_nursery();
|
collect_nursery();
|
||||||
record_gc_stats(&gc_stats.nursery_stats);
|
|
||||||
break;
|
break;
|
||||||
case collect_aging_op:
|
case collect_aging_op:
|
||||||
collect_aging();
|
collect_aging();
|
||||||
record_gc_stats(&gc_stats.aging_stats);
|
|
||||||
break;
|
break;
|
||||||
case collect_to_tenured_op:
|
case collect_to_tenured_op:
|
||||||
collect_to_tenured();
|
collect_to_tenured();
|
||||||
record_gc_stats(&gc_stats.aging_stats);
|
|
||||||
break;
|
break;
|
||||||
case collect_full_op:
|
case collect_full_op:
|
||||||
collect_mark_impl(trace_contexts_p);
|
collect_mark_impl(trace_contexts_p);
|
||||||
collect_sweep_impl();
|
collect_sweep_impl();
|
||||||
update_code_heap_words_and_literals();
|
update_code_heap_words_and_literals();
|
||||||
record_gc_stats(&gc_stats.full_stats);
|
|
||||||
break;
|
break;
|
||||||
case collect_compact_op:
|
case collect_compact_op:
|
||||||
collect_mark_impl(trace_contexts_p);
|
collect_mark_impl(trace_contexts_p);
|
||||||
collect_compact_impl(trace_contexts_p);
|
collect_compact_impl(trace_contexts_p);
|
||||||
record_gc_stats(&gc_stats.full_stats);
|
|
||||||
break;
|
break;
|
||||||
case collect_growing_heap_op:
|
case collect_growing_heap_op:
|
||||||
collect_growing_heap(requested_bytes,trace_contexts_p);
|
collect_growing_heap(requested_bytes,trace_contexts_p);
|
||||||
record_gc_stats(&gc_stats.full_stats);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
critical_error("Bad GC op\n",current_gc->op);
|
critical_error("Bad GC op\n",current_gc->op);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(verbosegc)
|
if(verbose_gc)
|
||||||
std::cout << "GC done, op=" << current_gc->op << std::endl;
|
std::cout << "GC done, op=" << current_gc->op << std::endl;
|
||||||
|
|
||||||
delete current_gc;
|
delete current_gc;
|
||||||
|
@ -128,49 +113,6 @@ void factor_vm::primitive_compact_gc()
|
||||||
true /* trace contexts? */);
|
true /* trace contexts? */);
|
||||||
}
|
}
|
||||||
|
|
||||||
void factor_vm::add_gc_stats(generation_statistics *stats, growable_array *result)
|
|
||||||
{
|
|
||||||
result->add(allot_cell(stats->collections));
|
|
||||||
result->add(tag<bignum>(long_long_to_bignum(stats->gc_time)));
|
|
||||||
result->add(tag<bignum>(long_long_to_bignum(stats->max_gc_time)));
|
|
||||||
result->add(allot_cell(stats->collections == 0 ? 0 : stats->gc_time / stats->collections));
|
|
||||||
result->add(allot_cell(stats->object_count));
|
|
||||||
result->add(tag<bignum>(long_long_to_bignum(stats->bytes_copied)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void factor_vm::primitive_gc_stats()
|
|
||||||
{
|
|
||||||
growable_array result(this);
|
|
||||||
|
|
||||||
add_gc_stats(&gc_stats.nursery_stats,&result);
|
|
||||||
add_gc_stats(&gc_stats.aging_stats,&result);
|
|
||||||
add_gc_stats(&gc_stats.full_stats,&result);
|
|
||||||
|
|
||||||
u64 total_gc_time =
|
|
||||||
gc_stats.nursery_stats.gc_time +
|
|
||||||
gc_stats.aging_stats.gc_time +
|
|
||||||
gc_stats.full_stats.gc_time;
|
|
||||||
|
|
||||||
result.add(tag<bignum>(ulong_long_to_bignum(total_gc_time)));
|
|
||||||
result.add(tag<bignum>(ulong_long_to_bignum(gc_stats.cards_scanned)));
|
|
||||||
result.add(tag<bignum>(ulong_long_to_bignum(gc_stats.decks_scanned)));
|
|
||||||
result.add(tag<bignum>(ulong_long_to_bignum(gc_stats.card_scan_time)));
|
|
||||||
result.add(allot_cell(gc_stats.code_blocks_scanned));
|
|
||||||
|
|
||||||
result.trim();
|
|
||||||
dpush(result.elements.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
void factor_vm::clear_gc_stats()
|
|
||||||
{
|
|
||||||
memset(&gc_stats,0,sizeof(gc_statistics));
|
|
||||||
}
|
|
||||||
|
|
||||||
void factor_vm::primitive_clear_gc_stats()
|
|
||||||
{
|
|
||||||
clear_gc_stats();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* classes.tuple uses this to reshape tuples; tools.deploy.shaker uses this
|
/* classes.tuple uses this to reshape tuples; tools.deploy.shaker uses this
|
||||||
to coalesce equal but distinct quotations and wrappers. */
|
to coalesce equal but distinct quotations and wrappers. */
|
||||||
void factor_vm::primitive_become()
|
void factor_vm::primitive_become()
|
||||||
|
|
19
vm/gc.hpp
19
vm/gc.hpp
|
@ -10,25 +10,6 @@ enum gc_op {
|
||||||
collect_growing_heap_op
|
collect_growing_heap_op
|
||||||
};
|
};
|
||||||
|
|
||||||
/* statistics */
|
|
||||||
struct generation_statistics {
|
|
||||||
cell collections;
|
|
||||||
u64 gc_time;
|
|
||||||
u64 max_gc_time;
|
|
||||||
cell object_count;
|
|
||||||
u64 bytes_copied;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gc_statistics {
|
|
||||||
generation_statistics nursery_stats;
|
|
||||||
generation_statistics aging_stats;
|
|
||||||
generation_statistics full_stats;
|
|
||||||
u64 cards_scanned;
|
|
||||||
u64 decks_scanned;
|
|
||||||
u64 card_scan_time;
|
|
||||||
u64 code_blocks_scanned;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct gc_state {
|
struct gc_state {
|
||||||
gc_op op;
|
gc_op op;
|
||||||
u64 start_time;
|
u64 start_time;
|
||||||
|
|
|
@ -22,8 +22,6 @@ void factor_vm::load_data_heap(FILE *file, image_header *h, vm_parameters *p)
|
||||||
p->aging_size,
|
p->aging_size,
|
||||||
p->tenured_size);
|
p->tenured_size);
|
||||||
|
|
||||||
clear_gc_stats();
|
|
||||||
|
|
||||||
fixnum bytes_read = fread((void*)data->tenured->start,1,h->data_size,file);
|
fixnum bytes_read = fread((void*)data->tenured->start,1,h->data_size,file);
|
||||||
|
|
||||||
if((cell)bytes_read != h->data_size)
|
if((cell)bytes_read != h->data_size)
|
||||||
|
@ -280,9 +278,9 @@ bool factor_vm::save_image(const vm_char *filename)
|
||||||
h.magic = image_magic;
|
h.magic = image_magic;
|
||||||
h.version = image_version;
|
h.version = image_version;
|
||||||
h.data_relocation_base = data->tenured->start;
|
h.data_relocation_base = data->tenured->start;
|
||||||
h.data_size = data->tenured->occupied();
|
h.data_size = data->tenured->occupied_space();
|
||||||
h.code_relocation_base = code->seg->start;
|
h.code_relocation_base = code->seg->start;
|
||||||
h.code_size = code->allocator->occupied();
|
h.code_size = code->allocator->occupied_space();
|
||||||
|
|
||||||
h.true_object = true_object;
|
h.true_object = true_object;
|
||||||
h.bignum_zero = bignum_zero;
|
h.bignum_zero = bignum_zero;
|
||||||
|
|
|
@ -35,7 +35,7 @@ struct vm_parameters {
|
||||||
cell young_size, aging_size, tenured_size;
|
cell young_size, aging_size, tenured_size;
|
||||||
cell code_size;
|
cell code_size;
|
||||||
bool fep;
|
bool fep;
|
||||||
bool verbosegc;
|
bool verbose_gc;
|
||||||
bool console;
|
bool console;
|
||||||
bool signals;
|
bool signals;
|
||||||
cell max_pic_size;
|
cell max_pic_size;
|
||||||
|
|
|
@ -51,6 +51,7 @@ namespace factor
|
||||||
#include "code_block.hpp"
|
#include "code_block.hpp"
|
||||||
#include "bump_allocator.hpp"
|
#include "bump_allocator.hpp"
|
||||||
#include "mark_bits.hpp"
|
#include "mark_bits.hpp"
|
||||||
|
#include "free_list.hpp"
|
||||||
#include "free_list_allocator.hpp"
|
#include "free_list_allocator.hpp"
|
||||||
#include "write_barrier.hpp"
|
#include "write_barrier.hpp"
|
||||||
#include "object_start_map.hpp"
|
#include "object_start_map.hpp"
|
||||||
|
|
|
@ -6,7 +6,6 @@ namespace factor
|
||||||
nursery_collector::nursery_collector(factor_vm *parent_) :
|
nursery_collector::nursery_collector(factor_vm *parent_) :
|
||||||
copying_collector<aging_space,nursery_policy>(
|
copying_collector<aging_space,nursery_policy>(
|
||||||
parent_,
|
parent_,
|
||||||
&parent_->gc_stats.nursery_stats,
|
|
||||||
parent_->data->aging,
|
parent_->data->aging,
|
||||||
nursery_policy(parent_)) {}
|
nursery_policy(parent_)) {}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,6 @@ PRIMITIVE_FORWARD(existsp)
|
||||||
PRIMITIVE_FORWARD(minor_gc)
|
PRIMITIVE_FORWARD(minor_gc)
|
||||||
PRIMITIVE_FORWARD(full_gc)
|
PRIMITIVE_FORWARD(full_gc)
|
||||||
PRIMITIVE_FORWARD(compact_gc)
|
PRIMITIVE_FORWARD(compact_gc)
|
||||||
PRIMITIVE_FORWARD(gc_stats)
|
|
||||||
PRIMITIVE_FORWARD(save_image)
|
PRIMITIVE_FORWARD(save_image)
|
||||||
PRIMITIVE_FORWARD(save_image_and_exit)
|
PRIMITIVE_FORWARD(save_image_and_exit)
|
||||||
PRIMITIVE_FORWARD(datastack)
|
PRIMITIVE_FORWARD(datastack)
|
||||||
|
@ -115,7 +114,6 @@ PRIMITIVE_FORWARD(call_clear)
|
||||||
PRIMITIVE_FORWARD(resize_byte_array)
|
PRIMITIVE_FORWARD(resize_byte_array)
|
||||||
PRIMITIVE_FORWARD(dll_validp)
|
PRIMITIVE_FORWARD(dll_validp)
|
||||||
PRIMITIVE_FORWARD(unimplemented)
|
PRIMITIVE_FORWARD(unimplemented)
|
||||||
PRIMITIVE_FORWARD(clear_gc_stats)
|
|
||||||
PRIMITIVE_FORWARD(jit_compile)
|
PRIMITIVE_FORWARD(jit_compile)
|
||||||
PRIMITIVE_FORWARD(load_locals)
|
PRIMITIVE_FORWARD(load_locals)
|
||||||
PRIMITIVE_FORWARD(check_datastack)
|
PRIMITIVE_FORWARD(check_datastack)
|
||||||
|
@ -193,7 +191,6 @@ const primitive_type primitives[] = {
|
||||||
primitive_minor_gc,
|
primitive_minor_gc,
|
||||||
primitive_full_gc,
|
primitive_full_gc,
|
||||||
primitive_compact_gc,
|
primitive_compact_gc,
|
||||||
primitive_gc_stats,
|
|
||||||
primitive_save_image,
|
primitive_save_image,
|
||||||
primitive_save_image_and_exit,
|
primitive_save_image_and_exit,
|
||||||
primitive_datastack,
|
primitive_datastack,
|
||||||
|
@ -279,7 +276,6 @@ const primitive_type primitives[] = {
|
||||||
primitive_resize_byte_array,
|
primitive_resize_byte_array,
|
||||||
primitive_dll_validp,
|
primitive_dll_validp,
|
||||||
primitive_unimplemented,
|
primitive_unimplemented,
|
||||||
primitive_clear_gc_stats,
|
|
||||||
primitive_jit_compile,
|
primitive_jit_compile,
|
||||||
primitive_load_locals,
|
primitive_load_locals,
|
||||||
primitive_check_datastack,
|
primitive_check_datastack,
|
||||||
|
|
|
@ -6,7 +6,6 @@ namespace factor
|
||||||
to_tenured_collector::to_tenured_collector(factor_vm *myvm_) :
|
to_tenured_collector::to_tenured_collector(factor_vm *myvm_) :
|
||||||
collector<tenured_space,to_tenured_policy>(
|
collector<tenured_space,to_tenured_policy>(
|
||||||
myvm_,
|
myvm_,
|
||||||
&myvm_->gc_stats.aging_stats,
|
|
||||||
myvm_->data->tenured,
|
myvm_->data->tenured,
|
||||||
to_tenured_policy(myvm_)) {}
|
to_tenured_policy(myvm_)) {}
|
||||||
|
|
||||||
|
|
10
vm/vm.hpp
10
vm/vm.hpp
|
@ -47,7 +47,7 @@ struct factor_vm
|
||||||
bool gc_off;
|
bool gc_off;
|
||||||
|
|
||||||
/* GC logging */
|
/* GC logging */
|
||||||
bool verbosegc;
|
bool verbose_gc;
|
||||||
|
|
||||||
/* Data heap */
|
/* Data heap */
|
||||||
data_heap *data;
|
data_heap *data;
|
||||||
|
@ -61,9 +61,6 @@ struct factor_vm
|
||||||
/* Only set if we're performing a GC */
|
/* Only set if we're performing a GC */
|
||||||
gc_state *current_gc;
|
gc_state *current_gc;
|
||||||
|
|
||||||
/* Statistics */
|
|
||||||
gc_statistics gc_stats;
|
|
||||||
|
|
||||||
/* If a runtime function needs to call another function which potentially
|
/* If a runtime function needs to call another function which potentially
|
||||||
allocates memory, it must wrap any local variable references to Factor
|
allocates memory, it must wrap any local variable references to Factor
|
||||||
objects in gc_root instances */
|
objects in gc_root instances */
|
||||||
|
@ -251,18 +248,13 @@ struct factor_vm
|
||||||
void collect_sweep_impl();
|
void collect_sweep_impl();
|
||||||
void collect_compact_impl(bool trace_contexts_p);
|
void collect_compact_impl(bool trace_contexts_p);
|
||||||
void collect_growing_heap(cell requested_bytes, bool trace_contexts_p);
|
void collect_growing_heap(cell requested_bytes, bool trace_contexts_p);
|
||||||
void record_gc_stats(generation_statistics *stats);
|
|
||||||
void gc(gc_op op, cell requested_bytes, bool trace_contexts_p);
|
void gc(gc_op op, cell requested_bytes, bool trace_contexts_p);
|
||||||
void primitive_minor_gc();
|
void primitive_minor_gc();
|
||||||
void primitive_full_gc();
|
void primitive_full_gc();
|
||||||
void primitive_compact_gc();
|
void primitive_compact_gc();
|
||||||
void primitive_gc_stats();
|
|
||||||
void clear_gc_stats();
|
|
||||||
void primitive_become();
|
void primitive_become();
|
||||||
void inline_gc(cell *gc_roots_base, cell gc_roots_size);
|
void inline_gc(cell *gc_roots_base, cell gc_roots_size);
|
||||||
object *allot_object(header header, cell size);
|
object *allot_object(header header, cell size);
|
||||||
void add_gc_stats(generation_statistics *stats, growable_array *result);
|
|
||||||
void primitive_clear_gc_stats();
|
|
||||||
|
|
||||||
template<typename Type> Type *allot(cell size)
|
template<typename Type> Type *allot(cell size)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue