static void assert2_pair_addresses_mapped( msgc_context_t *context, word w ) { { #ifndef NDEBUG2 if (isptr(pair_cdr(w)) && ! gc_is_address_mapped( context->gc, ptrof(pair_cdr(w)), FALSE )) { gc_is_address_mapped( context->gc, ptrof(pair_cdr(w)), TRUE ); consolemsg("unmapped address, pair 0x%08x in gen %d, cdr = 0x%08x", w, gen_of(w), pair_cdr(w)); consolemsg("(gno count: %d)", context->gc->gno_count); assert2(0); } if (isptr(pair_car(w)) && ! gc_is_address_mapped( context->gc, ptrof(pair_car(w)), FALSE )) { gc_is_address_mapped( context->gc, ptrof(pair_car(w)), TRUE ); consolemsg("unmapped address, pair 0x%08x in gen %d, car = 0x%08x", w, gen_of(w), pair_car(w)); consolemsg("(gno count: %d)", context->gc->gno_count); assert2(0); } #endif } }
/* Returns TRUE implies entire leaf post-enumeration is clear[ed] (ie all zero bits). * * Note that a low limit_addr may lead to partial inspection of the * leaf, which could yield false negative (FALSE when leaf is clear). */ static bool tnode_enum_leaf( extbmp_t *ebmp, int gno, bool ignore_gno, bool gno_is_static_area, bool need_tagged_ptr, leaf_t *leaf, word first_addr_for_leaf, word first_enum_addr, word limit_enum_addr, bool (*scanner)(word loc, void *data), void *data ) { word *bitmap; int leaf_words, leaf_word_limit; int word_idx, j, bit_in_word; word curr_bmp_word, obj; bool scan_retval; bool found_nonzero_word; word limit_addr_for_leaf; leaf_words = ebmp->leaf_words; limit_addr_for_leaf = (first_addr_for_leaf + (2*sizeof(word)*8*sizeof(word))*leaf_words); assert( limit_addr_for_leaf == leaf_wordaddr_lim( ebmp, first_addr_for_leaf )); #if 0 if (ignore_gno) consolemsg( "tnode_enum_leaf( ebmp, gno ignored, need_tagged_ptr=%s, leaf, ..) " " leaf_addrs:[0x%08x,0x%08x) enum:[0x%08x,0x%08x)", need_tagged_ptr?"TRUE":"FALSE", first_addr_for_leaf, limit_addr_for_leaf, first_enum_addr, limit_enum_addr ); else consolemsg( "tnode_enum_leaf( ebmp, gno=%d refd, need_tagged_ptr=%s, leaf, ..) " " leaf_addrs:[0x%08x,0x%08x) enum:[0x%08x,0x%08x)", gno, need_tagged_ptr?"TRUE":"FALSE", first_addr_for_leaf, limit_addr_for_leaf, first_enum_addr, limit_enum_addr ); #endif bitmap = leaf->bitmap; found_nonzero_word = FALSE; if (first_enum_addr >= limit_addr_for_leaf) { return FALSE; } else if (first_enum_addr > first_addr_for_leaf) { /* skipping words before enum start addr */ int delta = (first_enum_addr - first_addr_for_leaf); int newidx = (delta >> BIT_IDX_SHIFT) / BITS_IN_WORD; #if 0 consolemsg("leaf_words:%d enum:[0x%08x,0x%08x) leaf:[0x%08x,0x%08x) delta:%d newidx:%d", leaf_words, first_enum_addr, limit_enum_addr, first_addr_for_leaf, limit_addr_for_leaf, delta, newidx ); #endif if (newidx > 0) found_nonzero_word = TRUE; /* be conservative since we're skipping words. */ word_idx = newidx; } else {
bool extbmp_is_member( extbmp_t *ebmp, word untagged_w ) { /* untagged_w in ebmp ? */ leaf_t *leaf; word first; bool found; unsigned int bit_idx, word_idx, bit_in_word; found = find_leaf_or_fail( ebmp, untagged_w, &leaf, &first ); #if 0 if (found) { word lim = leaf_wordaddr_lim( ebmp, first ); assert2( first <= untagged_w ); assert2( untagged_w < lim ); consolemsg( "extbmp_is_member( ebmp, w=0x%08x )" " found, leaf=0x%08x first=0x%08x lim=0x%08x", untagged_w, leaf, first, lim); } else { consolemsg( "extbmp_is_member( ebmp, w=0x%08x ) unfound", untagged_w ); } #endif if (! found) return FALSE; assert2( first <= untagged_w ); assert2( untagged_w < leaf_wordaddr_lim( ebmp, first )); bit_idx = (untagged_w - first) >> BIT_IDX_SHIFT; word_idx = bit_idx >> BIT_IDX_TO_WORDADDR; bit_in_word = 1 << (bit_idx & BIT_IN_WORD_MASK); return (leaf->bitmap[ word_idx ] & bit_in_word); }
/* Assert that the bitmap in context is a conservative approximation of actual liveness info. */ void msgc_assert_conservative_approximation( msgc_context_t *context ) { msgc_context_t *ncontext; int marked=0, traced=0, words_marked=0, diffs=0; word *b1, *b2; int i; ncontext = msgc_begin( context->gc ); assert( ncontext->words_in_bitmap == context->words_in_bitmap ); assert( ncontext->lowest_heap_address == context->lowest_heap_address ); msgc_mark_objects_from_roots( ncontext, &marked, &traced, &words_marked ); b1 = context->bitmap; b2 = ncontext->bitmap; for ( i=0 ; i < ncontext->words_in_bitmap ; i++ ) { word w1 = b1[i], w2 = b2[i]; if (w1 != w2) { /* Want w1 superset of w2 */ if ((w1 & w2) != w2) { consolemsg( " gen mark failed@%p: conservative=0x%08x accurate=0x%08x", (void*)(ncontext->lowest_heap_address + (i*8*BITS_IN_WORD)/sizeof(word)), w1, w2 ); diffs++; } } } assert( diffs == 0 ); msgc_end( ncontext ); }
static void move_leaf_to_mixed_list( extbmp_t *ebmp, leaf_t *leaf, int gno ) { int old_gno; leaf_t *prev, *next; assert( leaf->gno != 0 ); #if 0 consolemsg("leaf [0x%08x,0x%08x] of %d became mixed with %d", leaf->start, leaf->limit, leaf->gno, gno ); #endif old_gno = leaf->gno; prev = leaf->prev_for_gno; next = leaf->next_for_gno; if (prev != NULL) prev->next_for_gno = next; if (next != NULL) next->prev_for_gno = prev; leaf->prev_for_gno = NULL; leaf->next_for_gno = NULL; if (ebmp->gno_to_leaf[old_gno] == leaf) { assert( prev == NULL ); ebmp->gno_to_leaf[old_gno] = next; } insert_leaf_in_list_core( ebmp, leaf, 0 ); }
static void assert2_object_contents_mapped( msgc_context_t *context, word w, int n ) { #ifndef NDEBUG2 int i; for ( i=0 ; i < n ; i++ ) { if (isptr(vector_ref( w, i )) && ! gc_is_address_mapped( context->gc, ptrof(vector_ref( w, i )), FALSE )) { consolemsg("unmapped address, vector 0x%08x in gen %d, elem [%d] = 0x%08x", w, gen_of( w ), i, vector_ref( w, i )); consolemsg("(gno count: %d)", context->gc->gno_count); assert2(0); } } #endif }
static void assert2_los_addresses_mapped( msgc_context_t *context, word obj, int k, int next ) { #ifndef NDEBUG2 int i; for ( i=0 ; i < k ; i++ ) { if (isptr(vector_ref(obj, i+next)) && ! gc_is_address_mapped( context->gc, ptrof(vector_ref(obj, i+next)), FALSE )) { assert( gc_is_address_mapped( context->gc, ptrof(obj), TRUE )); consolemsg("unmapped address, los vector 0x%08x in gen %d, elem [%d] = 0x%08x", obj, gen_of(obj), i+next, vector_ref(obj, i+next )); consolemsg("(gno count: %d)", context->gc->gno_count); assert2(0); } } #endif }
static void assert2_tag_hdr_consistency( msgc_context_t *context, word w ) { #ifndef NDEBUG2 switch (tagof(w)) { case VEC_TAG: if (!(ishdr(*ptrof(w)) && header(*ptrof(w)) == header(VEC_HDR) )) { consolemsg("VEC w: 0x%08x *ptrof(w): 0x%08x ishdr: %s header(*ptrof(w)): %x", w, *ptrof(w), ishdr(*ptrof(w))?"TRUE":"FALSE", header(*ptrof(w))); } assert( ishdr(*ptrof(w)) && header(*ptrof(w)) == header(VEC_HDR) ); break; case PROC_TAG: if (!( ishdr(*ptrof(w)) && header(*ptrof(w)) == header(PROC_HDR) )) { consolemsg("PROC w: 0x%08x *ptrof(w): 0x%08x ishdr: %s header(*ptrof(w)): %x", w, *ptrof(w), ishdr(*ptrof(w))?"TRUE":"FALSE", header(*ptrof(w))); } assert( ishdr(*ptrof(w)) && header(*ptrof(w)) == header(PROC_HDR) ); break; } #endif }
void msgc_end( msgc_context_t *context ) { int n; n = free_stack( context->los_stack.seg ); n += free_stack( context->stack.seg ); if (n > 2) consolemsg( " Warning: deep mark stack: %d elements.", n*STACKSIZE ); gclib_free( context->bitmap, context->words_in_bitmap*sizeof(word) ); context->bitmap = 0; free( context ); }
/* Returns TRUE iff untagged_w was already in ebmp */ bool extbmp_add_elem( extbmp_t *ebmp, word untagged_w ) { /* ebmp := ebmp U { untagged_w } */ leaf_t *leaf; word first, lim; word entry_word; bool retval; unsigned int bit_idx, word_idx, bit_in_word; assert( tagof(untagged_w) == 0 ); first = 0xFFFFFFF; lim = 0x0; find_or_alloc_leaf( ebmp, untagged_w, &leaf, &first ); lim = leaf_wordaddr_lim( ebmp, first ); assert( first <= untagged_w ); assert( untagged_w < lim ); bit_idx = (untagged_w - first) >> BIT_IDX_SHIFT; word_idx = bit_idx >> BIT_IDX_TO_WORDADDR; bit_in_word = 1 << (bit_idx & BIT_IN_WORD_MASK); #if 0 if ( ! (bit_in_word & leaf->bitmap[ word_idx ] )) consolemsg(" extbmp_add_elem new elem: 0x%08x (%d) mhdr:0x%08x", untagged_w, gen_of(untagged_w), *(ptrof(untagged_w)) ); #endif entry_word = leaf->bitmap[ word_idx ]; retval = entry_word & bit_in_word; entry_word |= bit_in_word; leaf->bitmap[ word_idx ] = entry_word; assert2( extbmp_is_member(ebmp, untagged_w )); { int gno; gno = gen_of( untagged_w ); assert( gno != 0 ); if (leaf->gno == 0) { /* mixed leaf; do nothing */ } else if (leaf->gno < 0) { insert_leaf_in_list( ebmp, leaf, gno ); } else if (leaf->gno != gno) { move_leaf_to_mixed_list( ebmp, leaf, gno ); } } return retval; }
void print_float_stats( char *caller_name, gc_t *gc ) { /* every collection cycle, lets use the mark/sweep system to * measure how much float has accumulated. */ { msgc_context_t *context; msgc_context_t *context_incl_remsets; int i, rgn; int marked=0, traced=0, words_marked=0; int marked_incl=0, traced_incl=0, words_marked_incl=0; int total_float_words = 0, total_float_objects = 0; int estimated_live = 0; struct visit_measuring_float_data data; context = msgc_begin( gc ); msfloat_mark_objects_from_roots( context, &marked, &traced, &words_marked ); context_incl_remsets = msgc_begin( gc ); msfloat_mark_objects_from_roots_and_remsets( context_incl_remsets ); for( i=0; i < DATA(gc)->ephemeral_area_count; i++) { data.context = context; data.context_incl_remsets = context_incl_remsets; zero_measuring_float_data( &data ); DATA(gc)->ephemeral_area[ i ]->enumerate ( DATA(gc)->ephemeral_area[ i ], visit_measuring_float, &data ); print_float_stats_for_rgn( caller_name, gc, i, data ); total_float_objects += data.objs.zzflt+data.objs.rsflt; total_float_words += data.words.zzflt+data.objs.rsflt; if (INCLUDE_POP_RGNS_IN_LOADCALC || ! DATA(gc)->ephemeral_area[i]->has_popular_objects) estimated_live += DATA(gc)->ephemeral_area[ i ]->bytes_live_last_major_gc/sizeof(word); } consolemsg( "cycle % 3d total float { objs: %dk words: %dK (%3d%%,%3d%%) } nextrefine: %d " "promoted % 10d/% 10d " "live{ est: %dK act: %dK max: %dK } estdelta: %0.2f ", DATA(gc)->rrof_cycle_count, total_float_objects/1000, total_float_words/1024, (int)(100.0*(double)total_float_words/(double)words_marked), DATA(gc)->max_live_words?(int)(100.0*(double)total_float_words/(double)DATA(gc)->max_live_words):0, DATA(gc)->rrof_refine_mark_countdown, DATA(gc)->since_finished_snapshot_began.words_promoted, DATA(gc)->since_developing_snapshot_began.words_promoted, estimated_live/1024, words_marked/1024, DATA(gc)->max_live_words/1024, estimated_live?(((double)estimated_live)/(double)words_marked):0.0 ); msgc_end( context_incl_remsets ); msgc_end( context ); } }
/* Dump the list during a forward walk, and compute sizes forwards and backwards. Useful during debugging. WARNING: don't run this on a mark list during GC because the prev() pointers are not right during GC. */ static void dump_list( los_list_t *l, char *tag, int nbytes ) { word *p; int fwd_n, fwd_size, backwd_n, backwd_size; consolemsg( "{LOS} list dump %s for %d bytes", tag, nbytes ); consolemsg( "{LOS} header at 0x%p", l->header - HEADER_WORDS ); fwd_n = fwd_size = 0; for ( p = next( l->header ) ; p != l->header ; p = next( p ) ) { consolemsg( "{LOS} > %d bytes at 0x%p", size( p ), p - HEADER_WORDS ); fwd_n++; fwd_size += size( p ); } backwd_size = 0; backwd_n = 0; for ( p = prev( l->header ) ; p != l->header ; p = prev( p ) ) { backwd_n++; backwd_size += size( p ); } consolemsg( "{LOS} l->bytes=%d, fwd=%d/%d, backwd=%d/%d", l->bytes, fwd_n, fwd_size, backwd_n, backwd_size ); if (fwd_size != l->bytes || backwd_size != l->bytes || fwd_n != backwd_n) consolemsg( "{LOS} WARNING: sizes computed differently!" ); }
static void update_windows_drop_outdated( gc_mmu_log_t *log, gc_log_phase_t incoming, unsigned elapsed_real, unsigned elapsed_cpu ) { struct event_window *w; int i; int choose_new_first = -2; int new_idx; for ( i = 0; i < log->windows.len; i++ ) { w = &log->windows.array[i]; if (w->window_start_real.buf_idx < 0) { assert( log->buffer.first == 0 ); choose_new_first = -1; } if (w->window_start_cpu.buf_idx < 0) { assert( log->buffer.first == 0 ); choose_new_first = -1; } new_idx = update_window_drop_outdated( log, w, incoming, elapsed_real, elapsed_cpu ); if (choose_new_first < -1) choose_new_first = new_idx; else if (choose_new_first == -1) /* no-op */; else choose_new_first = buf_min( log, choose_new_first, new_idx ); } #if 0 consolemsg("pre(first): %d post(first): %d", log->buffer.first, choose_new_first); #endif if (choose_new_first == -1) { assert( log->buffer.first == 0 ); /* means leave it unchanged */ } else { log->buffer.first = choose_new_first; } }
int advFileCopy(int destfd, int srcfd, unsigned long size, const char *name, int semid, int logfd, int sigfd, int confd){ unsigned long size_so_far = 0; struct signalfd_siginfo fdsi; struct pollfd pollfds[2]; int readret, writeret, shellReturn; struct buffer buf; struct buffer * fbuf = &buf; if (createBuf(fbuf, 3000) < 0) return -1; /* Setting up stuff for Polling */ pollfds[0].fd = srcfd; /* data incoming from peer */ pollfds[0].events = POLLIN; pollfds[0].revents = 0; pollfds[1].fd = sigfd; /* communication with signalfd */ pollfds[1].events = POLLIN; pollfds[1].revents = 0; while (1) { if ( poll(pollfds, 2, -1) <= 0) { if (errno == EINTR || errno == EAGAIN ) continue; /* Signals */ logmsg(semid, logfd, LOGLEVEL_FATAL, "POLLING Error:%d - %s.\n", errno, strerror(errno)); return -1; } if ( pollfds[0].revents & POLLIN ) { /* peer calls */ switch((readret = readToBuf(srcfd, fbuf))){ case -1: logmsg(semid, logfd, LOGLEVEL_FATAL, "FATAL (advFileCopy): read()-error from fd.\n"); shellReturn = EXIT_FAILURE; break; case -2: logmsg(semid, logfd, LOGLEVEL_WARN, "WARNING (advFileCopy): couldn't read (EINTR or EAGAIN). This " "shouldn't happen if signalfd() is used.\n"); shellReturn = EXIT_FAILURE; break; case 0: /* end of transfer */ /* might also throw a POLLHUP */ if (size != size_so_far){ logmsg(semid, logfd, LOGLEVEL_WARN, "Error(advFileCopy) File transfer was quit from other side.\n"); shellReturn = EXIT_FAILURE; } else { logmsg(semid, logfd, LOGLEVEL_WARN, "Error(advFileCopy) File transfer completed successfully.\n"); shellReturn = EXIT_SUCCESS; } break; default: size_so_far += readret; } while (-2 == ( writeret = writeBuf(destfd, fbuf))); if (writeret < 0) { logmsg(semid, logfd, LOGLEVEL_WARN, "Error(advFileCopy) Failure on write operation.\n"); shellReturn = EXIT_FAILURE; break; } } else if(pollfds[1].revents & POLLIN) { /* incoming signal */ readret = read(sigfd, &fdsi, sizeof(struct signalfd_siginfo)); if (readret != sizeof(struct signalfd_siginfo)){ fprintf(stderr, "signalfd returned something broken"); shellReturn = EXIT_FAILURE; } switch(fdsi.ssi_signo){ case SIGINT: case SIGQUIT: logmsg(semid, logfd, LOGLEVEL_VERBOSE, "Child %d quit with status %d\n", fdsi.ssi_pid, fdsi.ssi_status); shellReturn = EXIT_SUCCESS; break; case SIGUSR1: consolemsg(semid, confd, "%s is %.1F percent done\n", name, (double)size_so_far/size); break; default: logmsg(semid, logfd, LOGLEVEL_WARN, "Encountered unknown signal on sigfd %d", fdsi.ssi_signo); } } else { /* Somethings broken with poll */ fprintf(stderr, "Dunno what to do with this poll"); shellReturn = EXIT_FAILURE; } if (shellReturn !=EXIT_NO) break; } freeBuf(fbuf); return shellReturn; }
static void print_float_stats_for_rgn( char *caller_name, gc_t *gc, int i, struct visit_measuring_float_data data ) { int rgn; int newmax; int data_count, easy_float, hard_float; { char bars[BAR_LENGTH+2]; bars[BAR_LENGTH] = '\0'; bars[BAR_LENGTH+1] = '\0'; { int allocated; data_count = data.words.total*4; easy_float = data.words.zzflt*4+data.words.rsflt*4; hard_float = data.words.rsflt*4; newmax = DATA(gc)->ephemeral_area[i]->maximum; allocated = DATA(gc)->ephemeral_area[i]->allocated; if ( allocated > newmax ) { if ( allocated > 2*newmax ) { consolemsg( " rgn %d allocated: %d significantly exceeds %d", i, allocated, newmax ); } newmax = allocated; } newmax = fill_up_to( bars, ' ', '@', newmax, newmax ); newmax = fill_up_to( bars, '.', '!', data_count, newmax ); newmax = fill_up_to( bars, 'Z', 'z', easy_float, newmax ); newmax = fill_up_to( bars, 'R', 'r', hard_float, newmax ); } { bool rgn_summarized; int rgn_summarized_live; old_heap_t *heap = DATA(gc)->ephemeral_area[ i ]; char *rgn_grp_str; rgn = i+1; rgn_summarized_live = ((DATA(gc)->summaries != NULL) ? sm_summarized_live( DATA(gc)->summaries, rgn ) : 0); rgn_grp_str = region_group_name( region_group_of(heap )); oh_synchronize( heap ); consolemsg( "%scycle % 3d region% 4d " "rgn sumz live: %8d lastmajor: %7d " "float{ objs: %7d/%7d words: %7d/%7d %7d }%s%s %s %s", caller_name, DATA(gc)->rrof_cycle_count, rgn, rgn_summarized_live, heap->bytes_live_last_major_gc/sizeof(word), data.objs.zzflt+data.objs.rsflt, data.objs.total, data.words.zzflt+data.words.rsflt, data.words.total, heap->allocated/4, rgn_grp_str, (( rgn == DATA(gc)->rrof_to_region && rgn == DATA(gc)->rrof_next_region ) ? "*" : ( rgn == DATA(gc)->rrof_to_region && (DATA(gc)->summaries != NULL) && (sm_is_rgn_summarized( DATA(gc)->summaries, rgn ) || sm_will_rgn_be_summarized_next( DATA(gc)->summaries, rgn )) ) ? "T" : ( rgn == DATA(gc)->rrof_to_region ) ? "t" : ( rgn == DATA(gc)->rrof_next_region ) ? "n" : ( (DATA(gc)->summaries != NULL) && sm_is_rgn_summarized( DATA(gc)->summaries, rgn ) && sm_is_rgn_summary_avail( DATA(gc)->summaries, rgn )) ? "s" : ( (DATA(gc)->summaries != NULL) && sm_is_rgn_summarized( DATA(gc)->summaries, rgn ) && sm_is_rgn_summary_over_pop( DATA(gc)->summaries, rgn )) ? "p" : ( (DATA(gc)->summaries != NULL) && sm_will_rgn_be_summarized_next( DATA(gc)->summaries, rgn ) && sm_is_rgn_summary_over_pop( DATA(gc)->summaries, rgn )) ? "P" : ( (DATA(gc)->summaries != NULL) && sm_will_rgn_be_summarized_next( DATA(gc)->summaries, rgn ) && (! sm_is_rgn_summarized_next( DATA(gc)->summaries, rgn ) || sm_is_rgn_summary_avail_next( DATA(gc)->summaries, rgn ))) ? "S" : ( rgn > DATA(gc)->region_count ) ? "e" : /* else */ " "), bars, (DATA(gc)->ephemeral_area[ i ]-> has_popular_objects ? "(popular)" : "") ); } } }