Exemplo n.º 1
0
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
    }
}
Exemplo n.º 2
0
/* 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 {
Exemplo n.º 3
0
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);
}
Exemplo n.º 4
0
/* 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 );
}
Exemplo n.º 5
0
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 );
}
Exemplo n.º 6
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
}
Exemplo n.º 7
0
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
}
Exemplo n.º 8
0
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

}
Exemplo n.º 9
0
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 );
}
Exemplo n.º 10
0
/* 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;
}
Exemplo n.º 11
0
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 );
  }
}
Exemplo n.º 12
0
/* 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!" );
}
Exemplo n.º 13
0
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;
  }
}
Exemplo n.º 14
0
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;
}
Exemplo n.º 15
0
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)" : "")
                  );
    }
  }
}