vm: remove crummy old GC stats, split off free list code, clean up various other things

db4
Slava Pestov 2009-10-26 22:08:35 -05:00
parent 85dc9fda26
commit e793a72060
24 changed files with 286 additions and 364 deletions

View File

@ -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 \

View File

@ -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. ( -- )

View File

@ -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# -- ? )) }

View File

@ -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_)) {}

View File

@ -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;
}
}; };
} }

View File

@ -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);
} }
} }

View File

@ -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());

View File

@ -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);
} }
}; };

View File

@ -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()
{ {

View File

@ -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());

View File

@ -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();

138
vm/free_list.cpp Normal file
View File

@ -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;
}
}

42
vm/free_list.hpp Normal file
View File

@ -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();
};
}

View File

@ -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 */

View File

@ -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_)) {}

View File

@ -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()

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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"

View File

@ -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_)) {}

View File

@ -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,

View File

@ -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_)) {}

View File

@ -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)
{ {