<PRIVATE
+: commas ( n -- str )
+ number>string
+ reverse 3 group "," join reverse ;
+
: kilobytes ( n -- str )
- 1024 /i number>string
- dup length 4 > [ 3 cut* "," glue ] when
- " KB" append ;
+ 1024 /i commas " KB" append ;
+
+: micros>string ( n -- str )
+ commas " microseconds" append ;
: fancy-table. ( obj alist -- )
[ [ nip first ] [ second call( obj -- str ) ] 2bi 2array ] with map
enable-gc-events [ ] [ disable-gc-events drop ] cleanup
disable-gc-events byte-array>gc-event-array ; inline
-: generation-sizes-before ( events -- sizes )
- [
- {
- [ start-time>> ]
- [ nursery-size-before>> ]
- [ aging-size-before>> ]
- [ tenured-size-before>> ]
- [ code-size-before>> ]
- } cleave 5 narray
- ] { } map-as ;
-
-: generation-sizes-after ( events -- sizes )
- [
- {
- [ start-time>> ]
- [ nursery-size-after>> ]
- [ aging-size-after>> ]
- [ tenured-size-after>> ]
- [ code-size-after>> ]
- } cleave 5 narray
- ] { } map-as ;
-
-: reclaimed-space ( events -- sizes )
- [
- [ start-time>> ] [
- {
- [ [ nursery-size-before>> ] [ nursery-size-after>> ] bi - ]
- [ [ aging-size-before>> ] [ aging-size-after>> ] bi - ]
- [ [ tenured-size-before>> ] [ tenured-size-after>> ] bi - ]
- [ [ code-size-before>> ] [ code-size-after>> ] bi - ]
- } cleave
- + + +
- ] bi 2array
- ] { } map-as ;
-
-: allocated-space ( events -- sizes )
- 2 <sliced-clumps> [
- [ second start-time>> ] [
- {
- [ [ second nursery-size-before>> ] [ first nursery-size-after>> ] bi - ]
- [ [ second aging-size-before>> ] [ first aging-size-after>> ] bi - ]
- [ [ second tenured-size-before>> ] [ first tenured-size-after>> ] bi - ]
- [ [ second code-size-before>> ] [ first code-size-after>> ] bi - ]
- } cleave
- + + +
- ] bi 2array
- ] { } map-as ;
+: gc-op-string ( op -- string )
+ {
+ { collect-nursery-op [ "copying from nursery" ] }
+ { collect-aging-op [ "copying from aging" ] }
+ { collect-to-tenured-op [ "copying to tenured" ] }
+ { collect-full-op [ "mark and sweep" ] }
+ { collect-compact-op [ "mark and compact" ] }
+ { collect-growing-heap-op [ "grow heap" ] }
+ } case ;
+
+: space-reclaimed ( event -- bytes )
+ [ data-heap-before>> ] [ data-heap-after>> ] bi
+ [ [ nursery>> ] [ aging>> ] [ tenured>> ] tri [ occupied>> ] tri@ + + ] bi@ - ;
+
+: gc-event. ( event -- )
+ {
+ { "Event type:" [ op>> gc-op-string ] }
+ { "Total time:" [ total-time>> micros>string ] }
+ { "Space reclaimed:" [ space-reclaimed kilobytes ] }
+ } fancy-table. ;
collect-compact-op
collect-growing-heap-op ;
-STRUCT: gc-event
-{ op uint }
-{ nursery-size-before cell }
-{ aging-size-before cell }
-{ tenured-size-before cell }
-{ tenured-free-block-count-before cell }
-{ code-size-before cell }
-{ code-free-block-count-before cell }
-{ nursery-size-after cell }
-{ aging-size-after cell }
-{ tenured-size-after cell }
-{ tenured-free-block-count-after cell }
-{ code-size-after cell }
-{ code-free-block-count-after cell }
-{ cards-scanned cell }
-{ decks-scanned cell }
-{ code-blocks-scanned cell }
-{ start-time ulonglong }
-{ total-time cell }
-{ card-scan-time cell }
-{ code-scan-time cell }
-{ data-sweep-time cell }
-{ code-sweep-time cell }
-{ compaction-time cell } ;
-
STRUCT: copying-sizes
{ size cell }
{ occupied cell }
{ cards cell }
{ decks cell }
{ mark-stack cell } ;
+
+STRUCT: gc-event
+{ op uint }
+{ data-heap-before data-heap-room }
+{ code-heap-before mark-sweep-sizes }
+{ data-heap-after data-heap-room }
+{ code-heap-after mark-sweep-sizes }
+{ cards-scanned cell }
+{ decks-scanned cell }
+{ code-blocks-scanned cell }
+{ start-time ulonglong }
+{ total-time cell }
+{ card-scan-time cell }
+{ code-scan-time cell }
+{ data-sweep-time cell }
+{ code-sweep-time cell }
+{ compaction-time cell } ;
void trim();
};
-template<typename T> byte_array *factor_vm::byte_array_from_value(T *value)
+template<typename Type> byte_array *factor_vm::byte_array_from_value(Type *value)
{
return byte_array_from_values(value,1);
}
-template<typename T> byte_array *factor_vm::byte_array_from_values(T *values, cell len)
+template<typename Type> byte_array *factor_vm::byte_array_from_values(Type *values, cell len)
{
- cell size = sizeof(T) * len;
+ cell size = sizeof(Type) * len;
byte_array *data = allot_uninitialized_array<byte_array>(size);
memcpy(data->data<char>(),values,size);
return data;
update_code_heap_words();
}
-void factor_vm::primitive_code_room()
+code_heap_room factor_vm::code_room()
{
code_heap_room room;
room.contiguous_free = code->allocator->free_blocks.largest_free_block();
room.free_block_count = code->allocator->free_blocks.free_block_count;
+ return room;
+}
+
+void factor_vm::primitive_code_room()
+{
+ code_heap_room room = code_room();
dpush(tag<byte_array>(byte_array_from_value(&room)));
}
cell operator()(object *obj)
{
- if(obj->free_p() || obj->h.hi_tag() != TUPLE_TYPE)
- return obj->size();
- else
+ if(!forwarding_map->marked_p(obj))
+ return forwarding_map->unmarked_space_starting_at(obj);
+ else if(obj->h.hi_tag() == TUPLE_TYPE)
return align(tuple_size_with_forwarding(forwarding_map,obj),data_alignment);
+ else
+ return obj->size();
}
};
box_unsigned_cell(object_size(dpop()));
}
-void factor_vm::primitive_data_room()
+data_heap_room factor_vm::data_room()
{
data_heap_room room;
room.decks = data->decks_end - data->decks;
room.mark_stack = data->tenured->mark_stack.capacity();
+ return room;
+}
+
+void factor_vm::primitive_data_room()
+{
+ data_heap_room room = data_room();
dpush(tag<byte_array>(byte_array_from_value(&room)));
}
p->max_pic_size = 3;
p->fep = false;
- p->verbose_gc = false;
p->signals = true;
#ifdef WINDOWS
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->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;
}
if(p->signals)
init_signals();
- verbose_gc = p->verbose_gc;
-
if(p->console)
open_console();
{
if(large_blocks.size())
{
- large_block_set::iterator end = large_blocks.end();
- free_heap_block *block = *end;
- large_blocks.erase(end);
- return block->size();
+ large_block_set::reverse_iterator last = large_blocks.rbegin();
+ return (*last)->size();
}
else
{
Block *first_block();
Block *last_block();
Block *next_block_after(Block *block);
+ Block *next_allocated_block_after(Block *block);
bool can_allot_p(cell size);
Block *allot(cell size);
void free(Block *block);
return (Block *)((cell)block + block->size());
}
+template<typename Block> Block *free_list_allocator<Block>::next_allocated_block_after(Block *block)
+{
+ while(block != this->last_block() && block->free_p())
+ {
+ free_heap_block *free_block = (free_heap_block *)block;
+ block = (object *)((cell)free_block + free_block->size());
+ }
+
+ if(block == this->last_block())
+ return NULL;
+ else
+ return block;
+}
+
template<typename Block> bool free_list_allocator<Block>::can_allot_p(cell size)
{
return free_blocks.can_allot_p(size);
code_sweep_time(0),
compaction_time(0)
{
- nursery_size_before = parent->nursery.occupied_space();
- aging_size_before = parent->data->aging->occupied_space();
- tenured_size_before = parent->data->tenured->occupied_space();
- tenured_free_block_count_before = parent->data->tenured->free_blocks.free_block_count;
- code_size_before = parent->code->allocator->occupied_space();
- code_free_block_count_before = parent->code->allocator->free_blocks.free_block_count;
+ data_heap_before = parent->data_room();
+ code_heap_before = parent->code_room();
start_time = current_micros();
}
void gc_event::ended_gc(factor_vm *parent)
{
- nursery_size_after = parent->nursery.occupied_space();
- aging_size_after = parent->data->aging->occupied_space();
- tenured_size_after = parent->data->tenured->occupied_space();
- tenured_free_block_count_after = parent->data->tenured->free_blocks.free_block_count;
- code_size_after = parent->code->allocator->occupied_space();
- code_free_block_count_after = parent->code->allocator->free_blocks.free_block_count;
+ data_heap_after = parent->data_room();
+ code_heap_after = parent->code_room();
total_time = current_micros() - start_time;
}
-std::ostream &operator<<(std::ostream &out, const gc_event *event)
-{
- out << "<event\n"
- << " op = '" << event->op << "'\n"
- << " nursery_size_before = '" << event->nursery_size_before << "'\n"
- << " aging_size_before = '" << event->aging_size_before << "'\n"
- << " tenured_size_before = '" << event->tenured_size_before << "'\n"
- << " tenured_free_block_count_before = '" << event->tenured_free_block_count_before << "'\n"
- << " code_size_before = '" << event->code_size_before << "'\n"
- << " code_free_block_count_before = '" << event->code_free_block_count_before << "'\n"
- << " nursery_size_after = '" << event->nursery_size_after << "'\n"
- << " aging_size_after = '" << event->aging_size_after << "'\n"
- << " tenured_size_after = '" << event->tenured_size_after << "'\n"
- << " tenured_free_block_count_after = '" << event->tenured_free_block_count_after << "'\n"
- << " code_size_after = '" << event->code_size_after << "'\n"
- << " code_free_block_count_after = '" << event->code_free_block_count_after << "'\n"
- << " cards_scanned = '" << event->cards_scanned << "'\n"
- << " decks_scanned = '" << event->decks_scanned << "'\n"
- << " code_blocks_scanned = '" << event->code_blocks_scanned << "'\n"
- << " start_time = '" << event->start_time << "'\n"
- << " total_time = '" << event->total_time << "'\n"
- << " card_scan_time = '" << event->card_scan_time << "'\n"
- << " code_scan_time = '" << event->code_scan_time << "'\n"
- << " data_sweep_time = '" << event->data_sweep_time << "'\n"
- << " code_sweep_time = '" << event->code_sweep_time << "'\n"
- << " compaction_time = '" << event->compaction_time << "' />";
- return out;
-}
-
gc_state::gc_state(gc_op op_, factor_vm *parent) : op(op_), start_time(current_micros())
{
event = new gc_event(op,parent);
void factor_vm::end_gc()
{
current_gc->event->ended_gc(this);
- if(verbose_gc) std::cout << current_gc->event << std::endl;
if(gc_events) gc_events->push_back(*current_gc->event);
delete current_gc->event;
current_gc->event = NULL;
{
if(gc_events)
{
- byte_array *data = byte_array_from_values(&gc_events->front(),gc_events->size());
+ byte_array *data = byte_array_from_values(&gc_events->first(),gc_events->size());
dpush(tag<byte_array>(data));
delete gc_events;
struct gc_event {
gc_op op;
- cell nursery_size_before;
- cell aging_size_before;
- cell tenured_size_before;
- cell tenured_free_block_count_before;
- cell code_size_before;
- cell code_free_block_count_before;
- cell nursery_size_after;
- cell aging_size_after;
- cell tenured_size_after;
- cell tenured_free_block_count_after;
- cell code_size_after;
- cell code_free_block_count_after;
+ data_heap_room data_heap_before;
+ code_heap_room code_heap_before;
+ data_heap_room data_heap_after;
+ code_heap_room code_heap_after;
cell cards_scanned;
cell decks_scanned;
cell code_blocks_scanned;
cell young_size, aging_size, tenured_size;
cell code_size;
bool fep;
- bool verbose_gc;
bool console;
bool signals;
cell max_pic_size;
#endif
return new_block;
}
+
+ /* Find the next allocated block without calling size() on unmarked
+ objects. */
+ cell unmarked_space_starting_at(Block *original)
+ {
+ char *start = (char *)original;
+ char *scan = start;
+ char *end = (char *)(this->start + this->size);
+
+ while(scan != end && !marked_p((Block *)scan))
+ scan += block_granularity;
+
+ return scan - start;
+ }
};
}
#include "aging_space.hpp"
#include "tenured_space.hpp"
#include "data_heap.hpp"
+#include "code_heap.hpp"
#include "gc.hpp"
#include "debug.hpp"
#include "strings.hpp"
#include "io.hpp"
#include "image.hpp"
#include "alien.hpp"
-#include "code_heap.hpp"
#include "callbacks.hpp"
#include "vm.hpp"
#include "tagged.hpp"
return NULL;
}
- object *first_allocated_block_after(object *block)
- {
- while(block != this->last_block() && block->free_p())
- {
- free_heap_block *free_block = (free_heap_block *)block;
- block = (object *)((cell)free_block + free_block->size());
- }
-
- if(block == this->last_block())
- return NULL;
- else
- return block;
- }
-
cell first_object()
{
- return (cell)first_allocated_block_after(this->first_block());
+ return (cell)next_allocated_block_after(this->first_block());
}
cell next_object_after(cell scan)
{
cell size = ((object *)scan)->size();
object *next = (object *)(scan + size);
- return (cell)first_allocated_block_after(next);
+ return (cell)next_allocated_block_after(next);
}
void clear_mark_bits()
/* GC is off during heap walking */
bool gc_off;
- /* GC logging */
- bool verbose_gc;
-
/* Data heap */
data_heap *data;
void set_data_heap(data_heap *data_);
void init_data_heap(cell young_size, cell aging_size, cell tenured_size);
void primitive_size();
+ data_heap_room data_room();
void primitive_data_room();
void begin_scan();
void end_scan();
void update_code_heap_words_and_literals();
void relocate_code_heap();
void primitive_modify_code_heap();
+ code_heap_room code_room();
void primitive_code_room();
void primitive_strip_stack_traces();