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/errors.o \
|
||||
vm/factor.o \
|
||||
vm/free_list.o \
|
||||
vm/full_collector.o \
|
||||
vm/gc.o \
|
||||
vm/image.o \
|
||||
|
|
|
@ -9,35 +9,50 @@ IN: tools.memory
|
|||
<PRIVATE
|
||||
|
||||
: kilobytes ( n -- str )
|
||||
number>string
|
||||
1024 /i number>string
|
||||
dup length 4 > [ 3 cut* "," glue ] when
|
||||
" KB" append ;
|
||||
|
||||
: memory-table. ( sizes seq -- )
|
||||
swap [ kilobytes ] map zip simple-table. ;
|
||||
: fancy-table. ( seq alist -- )
|
||||
[ [ nip first ] [ second call( obj -- str ) ] 2bi 2array ] 2map
|
||||
simple-table. ;
|
||||
|
||||
: young-room. ( seq -- )
|
||||
{ "Total:" "Allocated:" "Free:" } memory-table. ;
|
||||
{
|
||||
{ "Total:" [ kilobytes ] }
|
||||
{ "Allocated:" [ kilobytes ] }
|
||||
{ "Free:" [ kilobytes ] }
|
||||
} fancy-table. ;
|
||||
|
||||
: nursery-room. ( seq -- ) "- Nursery space" print young-room. ;
|
||||
|
||||
: aging-room. ( seq -- ) "- Aging space" print young-room. ;
|
||||
|
||||
: 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. ;
|
||||
|
||||
: misc-room. ( seq -- )
|
||||
"- 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 HEAP" print nl
|
||||
data-room
|
||||
3 cut [ nursery-room. nl ] dip
|
||||
3 cut [ aging-room. nl ] dip
|
||||
4 cut [ tenured-room. nl ] dip
|
||||
5 cut [ tenured-room. nl ] dip
|
||||
misc-room. ;
|
||||
|
||||
: code-room. ( -- )
|
||||
|
|
|
@ -423,7 +423,6 @@ tuple
|
|||
{ "minor-gc" "memory" (( -- )) }
|
||||
{ "gc" "memory" (( -- )) }
|
||||
{ "compact-gc" "memory" (( -- )) }
|
||||
{ "gc-stats" "memory" f }
|
||||
{ "(save-image)" "memory.private" (( path -- )) }
|
||||
{ "(save-image-and-exit)" "memory.private" (( path -- )) }
|
||||
{ "datastack" "kernel" (( -- ds )) }
|
||||
|
@ -509,7 +508,6 @@ tuple
|
|||
{ "resize-byte-array" "byte-arrays" (( n byte-array -- newbyte-array )) }
|
||||
{ "dll-valid?" "alien.libraries" (( dll -- ? )) }
|
||||
{ "unimplemented" "kernel.private" (( -- * )) }
|
||||
{ "gc-reset" "memory" (( -- )) }
|
||||
{ "jit-compile" "quotations" (( quot -- )) }
|
||||
{ "load-locals" "locals.backend" (( ... n -- )) }
|
||||
{ "check-datastack" "kernel.private" (( array in# out# -- ? )) }
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace factor
|
|||
aging_collector::aging_collector(factor_vm *parent_) :
|
||||
copying_collector<aging_space,aging_policy>(
|
||||
parent_,
|
||||
&parent_->gc_stats.aging_stats,
|
||||
parent_->data->aging,
|
||||
aging_policy(parent_)) {}
|
||||
|
||||
|
|
|
@ -11,17 +11,27 @@ template<typename Block> struct bump_allocator {
|
|||
explicit bump_allocator(cell size_, cell start_) :
|
||||
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;
|
||||
}
|
||||
|
||||
inline Block *allot(cell size)
|
||||
Block *allot(cell size)
|
||||
{
|
||||
cell h = here;
|
||||
here = h + align(size,data_alignment);
|
||||
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 */
|
||||
if(block == NULL)
|
||||
{
|
||||
cell used, total_free, max_free;
|
||||
code->allocator->usage(&used,&total_free,&max_free);
|
||||
|
||||
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";
|
||||
std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
|
||||
std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
|
||||
fatal_error("Out of memory in add-compiled-block",0);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -199,13 +199,11 @@ void factor_vm::primitive_code_room()
|
|||
{
|
||||
growable_array a(this);
|
||||
|
||||
cell used, total_free, max_free;
|
||||
code->allocator->usage(&used,&total_free,&max_free);
|
||||
|
||||
a.add(tag_fixnum(code->seg->size >> 10));
|
||||
a.add(tag_fixnum(used >> 10));
|
||||
a.add(tag_fixnum(total_free >> 10));
|
||||
a.add(tag_fixnum(max_free >> 10));
|
||||
a.add(tag_fixnum(code->allocator->size));
|
||||
a.add(tag_fixnum(code->allocator->occupied_space()));
|
||||
a.add(tag_fixnum(code->allocator->free_space()));
|
||||
a.add(tag_fixnum(code->allocator->free_blocks.largest_free_block()));
|
||||
a.add(tag_fixnum(code->allocator->free_blocks.free_block_count));
|
||||
|
||||
a.trim();
|
||||
dpush(a.elements.value());
|
||||
|
|
|
@ -3,13 +3,11 @@ namespace factor
|
|||
|
||||
template<typename TargetGeneration, typename Policy> struct collector_workhorse {
|
||||
factor_vm *parent;
|
||||
generation_statistics *stats;
|
||||
TargetGeneration *target;
|
||||
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_),
|
||||
stats(stats_),
|
||||
target(target_),
|
||||
policy(policy_) {}
|
||||
|
||||
|
@ -36,9 +34,6 @@ template<typename TargetGeneration, typename Policy> struct collector_workhorse
|
|||
memcpy(newpointer,untagged,size);
|
||||
untagged->h.forward_to(newpointer);
|
||||
|
||||
stats->object_count++;
|
||||
stats->bytes_copied += size;
|
||||
|
||||
policy.promoted_object(newpointer);
|
||||
|
||||
return newpointer;
|
||||
|
@ -69,29 +64,34 @@ template<typename TargetGeneration, typename Policy> struct collector_workhorse
|
|||
template<typename TargetGeneration, typename Policy>
|
||||
inline static slot_visitor<collector_workhorse<TargetGeneration,Policy> > make_collector_workhorse(
|
||||
factor_vm *parent,
|
||||
generation_statistics *stats,
|
||||
TargetGeneration *target,
|
||||
Policy policy)
|
||||
{
|
||||
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 {
|
||||
factor_vm *parent;
|
||||
data_heap *data;
|
||||
code_heap *code;
|
||||
generation_statistics *stats;
|
||||
TargetGeneration *target;
|
||||
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_),
|
||||
data(parent_->data),
|
||||
code(parent_->code),
|
||||
stats(stats_),
|
||||
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)
|
||||
{
|
||||
|
@ -127,7 +127,7 @@ template<typename TargetGeneration, typename Policy> struct collector {
|
|||
for(; iter != end; 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)
|
||||
{
|
||||
parent->gc_stats.decks_scanned++;
|
||||
decks_scanned++;
|
||||
|
||||
cell first_card = first_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)
|
||||
{
|
||||
parent->gc_stats.cards_scanned++;
|
||||
cards_scanned++;
|
||||
|
||||
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> {
|
||||
cell scan;
|
||||
|
||||
explicit copying_collector(factor_vm *parent_, generation_statistics *stats_, TargetGeneration *target_, Policy policy_) :
|
||||
collector<TargetGeneration,Policy>(parent_,stats_,target_,policy_), scan(target_->here) {}
|
||||
explicit copying_collector(factor_vm *parent_, TargetGeneration *target_, Policy policy_) :
|
||||
collector<TargetGeneration,Policy>(parent_,target_,policy_), scan(target_->here) {}
|
||||
|
||||
void cheneys_algorithm()
|
||||
{
|
||||
|
|
|
@ -206,24 +206,23 @@ void factor_vm::primitive_data_room()
|
|||
{
|
||||
growable_array a(this);
|
||||
|
||||
a.add(tag_fixnum((nursery.size) >> 10));
|
||||
a.add(tag_fixnum((nursery.here - nursery.start) >> 10));
|
||||
a.add(tag_fixnum((nursery.end - nursery.here) >> 10));
|
||||
a.add(tag_fixnum(nursery.size));
|
||||
a.add(tag_fixnum(nursery.occupied_space()));
|
||||
a.add(tag_fixnum(nursery.free_space()));
|
||||
|
||||
a.add(tag_fixnum((data->aging->size) >> 10));
|
||||
a.add(tag_fixnum((data->aging->here - data->aging->start) >> 10));
|
||||
a.add(tag_fixnum((data->aging->end - data->aging->here) >> 10));
|
||||
a.add(tag_fixnum(data->aging->size));
|
||||
a.add(tag_fixnum(data->aging->occupied_space()));
|
||||
a.add(tag_fixnum(data->aging->free_space()));
|
||||
|
||||
cell used, total_free, max_free;
|
||||
data->tenured->usage(&used,&total_free,&max_free);
|
||||
a.add(tag_fixnum(data->tenured->size >> 10));
|
||||
a.add(tag_fixnum(used >> 10));
|
||||
a.add(tag_fixnum(total_free >> 10));
|
||||
a.add(tag_fixnum(max_free >> 10));
|
||||
a.add(tag_fixnum(data->tenured->size));
|
||||
a.add(tag_fixnum(data->tenured->occupied_space()));
|
||||
a.add(tag_fixnum(data->tenured->free_space()));
|
||||
a.add(tag_fixnum(data->tenured->free_blocks.largest_free_block()));
|
||||
a.add(tag_fixnum(data->tenured->free_blocks.free_block_count));
|
||||
|
||||
a.add(tag_fixnum((data->cards_end - data->cards) >> 10));
|
||||
a.add(tag_fixnum((data->decks_end - data->decks) >> 10));
|
||||
a.add(tag_fixnum((data->tenured->mark_stack.capacity()) >> 10));
|
||||
a.add(tag_fixnum(data->cards_end - data->cards));
|
||||
a.add(tag_fixnum(data->decks_end - data->decks));
|
||||
a.add(tag_fixnum(data->tenured->mark_stack.capacity()));
|
||||
|
||||
a.trim();
|
||||
dpush(a.elements.value());
|
||||
|
|
|
@ -38,7 +38,7 @@ void factor_vm::default_parameters(vm_parameters *p)
|
|||
p->max_pic_size = 3;
|
||||
|
||||
p->fep = false;
|
||||
p->verbosegc = false;
|
||||
p->verbose_gc = false;
|
||||
p->signals = true;
|
||||
|
||||
#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(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("-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(STRCMP(arg,STRING_LITERAL("-console")) == 0) p->console = true;
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ void factor_vm::init_factor(vm_parameters *p)
|
|||
if(p->signals)
|
||||
init_signals();
|
||||
|
||||
verbosegc = p->verbosegc;
|
||||
verbose_gc = p->verbose_gc;
|
||||
|
||||
if(p->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
|
||||
{
|
||||
|
||||
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 {
|
||||
cell size;
|
||||
cell start;
|
||||
|
@ -37,21 +9,16 @@ template<typename Block> struct free_list_allocator {
|
|||
mark_bits<Block> state;
|
||||
|
||||
explicit free_list_allocator(cell size, cell start);
|
||||
void initial_free_list(cell occupied);
|
||||
bool contains_p(Block *block);
|
||||
Block *first_block();
|
||||
Block *last_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);
|
||||
Block *allot(cell size);
|
||||
void free(Block *block);
|
||||
void usage(cell *used, cell *total_free, cell *max_free);
|
||||
cell occupied();
|
||||
cell occupied_space();
|
||||
cell free_space();
|
||||
void sweep();
|
||||
template<typename Iterator> void sweep(Iterator &iter);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -91,125 +58,19 @@ template<typename Block> Block *free_list_allocator<Block>::next_block_after(Blo
|
|||
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)
|
||||
{
|
||||
cell attempt = 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;
|
||||
return free_blocks.can_allot_p(size);
|
||||
}
|
||||
|
||||
template<typename Block> Block *free_list_allocator<Block>::allot(cell size)
|
||||
{
|
||||
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)
|
||||
{
|
||||
block = split_free_block(block,size);
|
||||
block = free_blocks.split_free_block(block,size);
|
||||
return (Block *)block;
|
||||
}
|
||||
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_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> void free_list_allocator<Block>::usage(cell *used, cell *total_free, cell *max_free)
|
||||
template<typename Block> cell free_list_allocator<Block>::free_space()
|
||||
{
|
||||
*used = 0;
|
||||
*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);
|
||||
}
|
||||
return free_blocks.free_space;
|
||||
}
|
||||
|
||||
/* The size of the heap after compaction */
|
||||
template<typename Block> cell free_list_allocator<Block>::occupied()
|
||||
template<typename Block> cell free_list_allocator<Block>::occupied_space()
|
||||
{
|
||||
Block *scan = first_block();
|
||||
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;
|
||||
return size - free_blocks.free_space;
|
||||
}
|
||||
|
||||
template<typename Block>
|
||||
void free_list_allocator<Block>::sweep()
|
||||
{
|
||||
this->clear_free_list();
|
||||
free_blocks.clear_free_list();
|
||||
|
||||
Block *prev = NULL;
|
||||
Block *scan = this->first_block();
|
||||
|
@ -300,7 +120,7 @@ void free_list_allocator<Block>::sweep()
|
|||
else if(this->state.marked_p(scan))
|
||||
{
|
||||
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;
|
||||
}
|
||||
else
|
||||
|
@ -322,14 +142,14 @@ void free_list_allocator<Block>::sweep()
|
|||
}
|
||||
|
||||
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 Iterator>
|
||||
void free_list_allocator<Block>::sweep(Iterator &iter)
|
||||
{
|
||||
this->clear_free_list();
|
||||
free_blocks.clear_free_list();
|
||||
|
||||
Block *prev = NULL;
|
||||
Block *scan = this->first_block();
|
||||
|
@ -352,7 +172,7 @@ void free_list_allocator<Block>::sweep(Iterator &iter)
|
|||
else if(this->state.marked_p(scan))
|
||||
{
|
||||
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;
|
||||
iter(scan,size);
|
||||
}
|
||||
|
@ -375,7 +195,7 @@ void free_list_allocator<Block>::sweep(Iterator &iter)
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -403,11 +223,11 @@ template<typename Iterator, typename Sizer>
|
|||
void free_list_allocator<Block>::compact(Iterator &iter, Sizer &sizer)
|
||||
{
|
||||
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
|
||||
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 */
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace factor
|
|||
full_collector::full_collector(factor_vm *parent_) :
|
||||
collector<tenured_space,full_policy>(
|
||||
parent_,
|
||||
&parent_->gc_stats.full_stats,
|
||||
parent_->data->tenured,
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if(verbosegc)
|
||||
if(verbose_gc)
|
||||
std::cout << "GC requested, op=" << op << std::endl;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
if(verbosegc)
|
||||
if(verbose_gc)
|
||||
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:
|
||||
collect_nursery();
|
||||
record_gc_stats(&gc_stats.nursery_stats);
|
||||
break;
|
||||
case collect_aging_op:
|
||||
collect_aging();
|
||||
record_gc_stats(&gc_stats.aging_stats);
|
||||
break;
|
||||
case collect_to_tenured_op:
|
||||
collect_to_tenured();
|
||||
record_gc_stats(&gc_stats.aging_stats);
|
||||
break;
|
||||
case collect_full_op:
|
||||
collect_mark_impl(trace_contexts_p);
|
||||
collect_sweep_impl();
|
||||
update_code_heap_words_and_literals();
|
||||
record_gc_stats(&gc_stats.full_stats);
|
||||
break;
|
||||
case collect_compact_op:
|
||||
collect_mark_impl(trace_contexts_p);
|
||||
collect_compact_impl(trace_contexts_p);
|
||||
record_gc_stats(&gc_stats.full_stats);
|
||||
break;
|
||||
case collect_growing_heap_op:
|
||||
collect_growing_heap(requested_bytes,trace_contexts_p);
|
||||
record_gc_stats(&gc_stats.full_stats);
|
||||
break;
|
||||
default:
|
||||
critical_error("Bad GC op\n",current_gc->op);
|
||||
break;
|
||||
}
|
||||
|
||||
if(verbosegc)
|
||||
if(verbose_gc)
|
||||
std::cout << "GC done, op=" << current_gc->op << std::endl;
|
||||
|
||||
delete current_gc;
|
||||
|
@ -128,49 +113,6 @@ void factor_vm::primitive_compact_gc()
|
|||
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
|
||||
to coalesce equal but distinct quotations and wrappers. */
|
||||
void factor_vm::primitive_become()
|
||||
|
|
19
vm/gc.hpp
19
vm/gc.hpp
|
@ -10,25 +10,6 @@ enum gc_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 {
|
||||
gc_op op;
|
||||
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->tenured_size);
|
||||
|
||||
clear_gc_stats();
|
||||
|
||||
fixnum bytes_read = fread((void*)data->tenured->start,1,h->data_size,file);
|
||||
|
||||
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.version = image_version;
|
||||
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_size = code->allocator->occupied();
|
||||
h.code_size = code->allocator->occupied_space();
|
||||
|
||||
h.true_object = true_object;
|
||||
h.bignum_zero = bignum_zero;
|
||||
|
|
|
@ -35,7 +35,7 @@ struct vm_parameters {
|
|||
cell young_size, aging_size, tenured_size;
|
||||
cell code_size;
|
||||
bool fep;
|
||||
bool verbosegc;
|
||||
bool verbose_gc;
|
||||
bool console;
|
||||
bool signals;
|
||||
cell max_pic_size;
|
||||
|
|
|
@ -51,6 +51,7 @@ namespace factor
|
|||
#include "code_block.hpp"
|
||||
#include "bump_allocator.hpp"
|
||||
#include "mark_bits.hpp"
|
||||
#include "free_list.hpp"
|
||||
#include "free_list_allocator.hpp"
|
||||
#include "write_barrier.hpp"
|
||||
#include "object_start_map.hpp"
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace factor
|
|||
nursery_collector::nursery_collector(factor_vm *parent_) :
|
||||
copying_collector<aging_space,nursery_policy>(
|
||||
parent_,
|
||||
&parent_->gc_stats.nursery_stats,
|
||||
parent_->data->aging,
|
||||
nursery_policy(parent_)) {}
|
||||
|
||||
|
|
|
@ -55,7 +55,6 @@ PRIMITIVE_FORWARD(existsp)
|
|||
PRIMITIVE_FORWARD(minor_gc)
|
||||
PRIMITIVE_FORWARD(full_gc)
|
||||
PRIMITIVE_FORWARD(compact_gc)
|
||||
PRIMITIVE_FORWARD(gc_stats)
|
||||
PRIMITIVE_FORWARD(save_image)
|
||||
PRIMITIVE_FORWARD(save_image_and_exit)
|
||||
PRIMITIVE_FORWARD(datastack)
|
||||
|
@ -115,7 +114,6 @@ PRIMITIVE_FORWARD(call_clear)
|
|||
PRIMITIVE_FORWARD(resize_byte_array)
|
||||
PRIMITIVE_FORWARD(dll_validp)
|
||||
PRIMITIVE_FORWARD(unimplemented)
|
||||
PRIMITIVE_FORWARD(clear_gc_stats)
|
||||
PRIMITIVE_FORWARD(jit_compile)
|
||||
PRIMITIVE_FORWARD(load_locals)
|
||||
PRIMITIVE_FORWARD(check_datastack)
|
||||
|
@ -193,7 +191,6 @@ const primitive_type primitives[] = {
|
|||
primitive_minor_gc,
|
||||
primitive_full_gc,
|
||||
primitive_compact_gc,
|
||||
primitive_gc_stats,
|
||||
primitive_save_image,
|
||||
primitive_save_image_and_exit,
|
||||
primitive_datastack,
|
||||
|
@ -279,7 +276,6 @@ const primitive_type primitives[] = {
|
|||
primitive_resize_byte_array,
|
||||
primitive_dll_validp,
|
||||
primitive_unimplemented,
|
||||
primitive_clear_gc_stats,
|
||||
primitive_jit_compile,
|
||||
primitive_load_locals,
|
||||
primitive_check_datastack,
|
||||
|
|
|
@ -6,7 +6,6 @@ namespace factor
|
|||
to_tenured_collector::to_tenured_collector(factor_vm *myvm_) :
|
||||
collector<tenured_space,to_tenured_policy>(
|
||||
myvm_,
|
||||
&myvm_->gc_stats.aging_stats,
|
||||
myvm_->data->tenured,
|
||||
to_tenured_policy(myvm_)) {}
|
||||
|
||||
|
|
10
vm/vm.hpp
10
vm/vm.hpp
|
@ -47,7 +47,7 @@ struct factor_vm
|
|||
bool gc_off;
|
||||
|
||||
/* GC logging */
|
||||
bool verbosegc;
|
||||
bool verbose_gc;
|
||||
|
||||
/* Data heap */
|
||||
data_heap *data;
|
||||
|
@ -61,9 +61,6 @@ struct factor_vm
|
|||
/* Only set if we're performing a GC */
|
||||
gc_state *current_gc;
|
||||
|
||||
/* Statistics */
|
||||
gc_statistics gc_stats;
|
||||
|
||||
/* If a runtime function needs to call another function which potentially
|
||||
allocates memory, it must wrap any local variable references to Factor
|
||||
objects in gc_root instances */
|
||||
|
@ -251,18 +248,13 @@ struct factor_vm
|
|||
void collect_sweep_impl();
|
||||
void collect_compact_impl(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 primitive_minor_gc();
|
||||
void primitive_full_gc();
|
||||
void primitive_compact_gc();
|
||||
void primitive_gc_stats();
|
||||
void clear_gc_stats();
|
||||
void primitive_become();
|
||||
void inline_gc(cell *gc_roots_base, cell gc_roots_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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue