Skip to content

Commit

Permalink
fixed big performance bug in weak hash tables
Browse files Browse the repository at this point in the history
git-svn-id: http://caml.inria.fr/svn/ocaml/trunk@8766 f963ae5c-01c2-4b8c-9fe0-0dff7051ff02
  • Loading branch information
Damien Doligez committed Jan 11, 2008
1 parent cdd5542 commit db20929
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 94 deletions.
51 changes: 34 additions & 17 deletions byterun/major_gc.c
Expand Up @@ -48,12 +48,13 @@ extern char *caml_fl_merge; /* Defined in freelist.c. */

static char *markhp, *chunk, *limit;

static int gc_subphase; /* Subphase_main, Subphase_weak, Subphase_final */
#define Subphase_main 10
#define Subphase_weak 11
#define Subphase_final 12
int caml_gc_subphase; /* Subphase_{main,weak1,weak2,final} */
static value *weak_prev;

#ifdef DEBUG
static unsigned long major_gc_counter = 0;
#endif

static void realloc_gray_vals (void)
{
value *new;
Expand Down Expand Up @@ -111,9 +112,10 @@ static void start_cycle (void)
caml_gc_message (0x01, "Starting new major GC cycle\n", 0);
caml_darken_all_roots();
caml_gc_phase = Phase_mark;
gc_subphase = Subphase_main;
caml_gc_subphase = Subphase_main;
markhp = NULL;
#ifdef DEBUG
++ major_gc_counter;
caml_heap_check ();
#endif
}
Expand All @@ -126,6 +128,7 @@ static void mark_slice (intnat work)
mlsize_t size, i;

caml_gc_message (0x40, "Marking %ld words\n", work);
caml_gc_message (0x40, "Subphase = %ld\n", caml_gc_subphase);
gray_vals_ptr = gray_vals_cur;
while (work > 0){
if (gray_vals_ptr > gray_vals){
Expand Down Expand Up @@ -187,23 +190,19 @@ static void mark_slice (intnat work)
chunk = caml_heap_start;
markhp = chunk;
limit = chunk + Chunk_size (chunk);
}else if (gc_subphase == Subphase_main){
}else if (caml_gc_subphase == Subphase_main){
/* The main marking phase is over. Start removing weak pointers to
dead values. */
gc_subphase = Subphase_weak;
caml_gc_subphase = Subphase_weak1;
weak_prev = &caml_weak_list_head;
}else if (gc_subphase == Subphase_weak){
}else if (caml_gc_subphase == Subphase_weak1){
value cur, curfield;
mlsize_t sz, i;
header_t hd;

cur = *weak_prev;
if (cur != (value) NULL){
hd = Hd_val (cur);
if (Color_hd (hd) == Caml_white){
/* The whole array is dead, remove it from the list. */
*weak_prev = Field (cur, 0);
}else{
sz = Wosize_hd (hd);
for (i = 1; i < sz; i++){
curfield = Field (cur, i);
Expand All @@ -227,18 +226,36 @@ static void mark_slice (intnat work)
}
}
}
weak_prev = &Field (cur, 0);
work -= Whsize_hd (hd);
}else{
/* Subphase_weak1 is done. Start removing dead weak arrays. */
caml_gc_subphase = Subphase_weak2;
weak_prev = &caml_weak_list_head;
}
}else if (caml_gc_subphase == Subphase_weak2){
value cur;
header_t hd;

cur = *weak_prev;
if (cur != (value) NULL){
hd = Hd_val (cur);
if (Color_hd (hd) == Caml_white){
/* The whole array is dead, remove it from the list. */
*weak_prev = Field (cur, 0);
}else{
weak_prev = &Field (cur, 0);
}
work -= Whsize_hd (hd);
work -= 1;
}else{
/* Subphase_weak is done. Handle finalised values. */
/* Subphase_weak2 is done. Handle finalised values. */
gray_vals_cur = gray_vals_ptr;
caml_final_update ();
gray_vals_ptr = gray_vals_cur;
gc_subphase = Subphase_final;
caml_gc_subphase = Subphase_final;
}
}else{
Assert (gc_subphase == Subphase_final);
Assert (caml_gc_subphase == Subphase_final);
/* Initialise the sweep phase. */
gray_vals_cur = gray_vals_ptr;
caml_gc_sweep_hp = caml_heap_start;
Expand Down Expand Up @@ -352,7 +369,7 @@ intnat caml_major_collection_slice (intnat howmuch)
if (p < dp) p = dp;
if (p < caml_extra_heap_resources) p = caml_extra_heap_resources;

caml_gc_message (0x40, "allocated_words = %"
caml_gc_message (0x40, "allocated_words = %"
ARCH_INTNAT_PRINTF_FORMAT "u\n",
caml_allocated_words);
caml_gc_message (0x40, "extra_heap_resources = %"
Expand Down
5 changes: 5 additions & 0 deletions byterun/major_gc.h
Expand Up @@ -33,6 +33,7 @@ typedef struct {
#define Chunk_block(c) (((heap_chunk_head *) (c)) [-1]).block

extern int caml_gc_phase;
extern int caml_gc_subphase;
extern uintnat caml_allocated_words;
extern double caml_extra_heap_resources;
extern uintnat caml_dependent_size, caml_dependent_allocated;
Expand All @@ -41,6 +42,10 @@ extern uintnat caml_fl_size_at_phase_change;
#define Phase_mark 0
#define Phase_sweep 1
#define Phase_idle 2
#define Subphase_main 10
#define Subphase_weak1 11
#define Subphase_weak2 12
#define Subphase_final 13

CAMLextern char *caml_heap_start;
extern uintnat total_heap_size;
Expand Down
74 changes: 58 additions & 16 deletions byterun/weak.c
Expand Up @@ -45,6 +45,24 @@ CAMLprim value caml_weak_create (value len)
#define None_val (Val_int(0))
#define Some_tag 0

static void do_set (value ar, mlsize_t offset, value v)
{
if (Is_block (v) && Is_young (v)){
/* modified version of Modify */
value old = Field (ar, offset);
Field (ar, offset) = v;
if (!(Is_block (old) && Is_young (old))){
if (caml_weak_ref_table.ptr >= caml_weak_ref_table.limit){
CAMLassert (caml_weak_ref_table.ptr == caml_weak_ref_table.limit);
caml_realloc_ref_table (&caml_weak_ref_table);
}
*caml_weak_ref_table.ptr++ = &Field (ar, offset);
}
}else{
Field (ar, offset) = v;
}
}

CAMLprim value caml_weak_set (value ar, value n, value el)
{
mlsize_t offset = Long_val (n) + 1;
Expand All @@ -53,22 +71,10 @@ CAMLprim value caml_weak_set (value ar, value n, value el)
caml_invalid_argument ("Weak.set");
}
if (el != None_val){
value v; Assert (Wosize_val (el) == 1);
v = Field (el, 0);
if (Is_block (v) && Is_young (v)){
/* modified version of Modify */
value old = Field (ar, offset);
Field (ar, offset) = v;
if (!(Is_block (old) && Is_young (old))){
if (caml_weak_ref_table.ptr >= caml_weak_ref_table.limit){
CAMLassert (caml_weak_ref_table.ptr == caml_weak_ref_table.limit);
caml_realloc_ref_table (&caml_weak_ref_table);
}
*caml_weak_ref_table.ptr++ = &Field (ar, offset);
}
}else{
Field (ar, offset) = v;
}
Assert (Wosize_val (el) == 1);
do_set (ar, offset, Field (el, 0));
}else{
Field (ar, offset) = caml_weak_none;
}
return Val_unit;
}
Expand Down Expand Up @@ -149,3 +155,39 @@ CAMLprim value caml_weak_check (value ar, value n)
}
return Val_bool (Field (ar, offset) != caml_weak_none);
}

CAMLprim value caml_weak_blit (value ars, value ofs,
value ard, value ofd, value len)
{
mlsize_t offset_s = Long_val (ofs) + 1;
mlsize_t offset_d = Long_val (ofd) + 1;
mlsize_t length = Long_val (len);
long i;
Assert (Is_in_heap (ars));
Assert (Is_in_heap (ard));
if (offset_s < 1 || offset_s + length > Wosize_val (ars)){
caml_invalid_argument ("Weak.blit");
}
if (offset_d < 1 || offset_d + length > Wosize_val (ard)){
caml_invalid_argument ("Weak.blit");
}
if (caml_gc_phase == Phase_mark && caml_gc_subphase == Subphase_weak1){
for (i = 0; i < length; i++){
value v = Field (ars, offset_s + i);
if (v != caml_weak_none && Is_block (v) && Is_in_heap (v)
&& Is_white_val (v)){
Field (ars, offset_s + i) = caml_weak_none;
}
}
}
if (offset_d < offset_s){
for (i = 0; i < length; i++){
do_set (ard, offset_d + i, Field (ars, offset_s + i));
}
}else{
for (i = length - 1; i >= 0; i--){
do_set (ard, offset_d + i, Field (ars, offset_s + i));
}
}
return Val_unit;
}

0 comments on commit db20929

Please sign in to comment.