
#include <stdio.h>

#include "libguile/_scm.h"
#include "libguile/eval.h"
#include "libguile/stime.h"
#include "libguile/stackchk.h"
#include "libguile/struct.h"
#include "libguile/smob.h"
#include "libguile/unif.h"
#include "libguile/async.h"
#include "libguile/ports.h"
#include "libguile/root.h"
#include "libguile/strings.h"
#include "libguile/vectors.h"
#include "libguile/weaks.h"
#include "libguile/hashtab.h"
#include "libguile/tags.h"
#include "libguile/private-gc.h"
#include "libguile/validate.h"
#include "libguile/deprecation.h"
#include "libguile/gc.h"

#include "private-gc.h"



/*
  stats
 */


void scm_i_print_card_analysis (scm_t_cell * card);
void scm_i_print_segment_analysis (scm_t_heap_segment*seg);
void scm_i_print_analysis (void);
void scm_i_analyse_card (scm_t_cell * card, int*,int*,int*,int*);
void scm_i_segment_analysis  (scm_t_heap_segment* );


void
scm_i_print_segment_analysis (scm_t_heap_segment * seg)
{
  scm_t_cell * p = seg->bounds[0];
  scm_t_cell * end = seg->bounds[1];
  int k = 0;
  for (; p <end ; p += SCM_GC_CARD_N_CELLS)
    {
      scm_i_print_card_analysis (p);
      k+=8;
      if (k > 70)
	{
	  printf("\n");
	  k = 0;
	}
    }
}

void
scm_i_print_analysis (void)
{
  int i =0;  
  for (; i <  scm_i_heap_segment_table_size; i++)
    {
      scm_i_segment_analysis (scm_i_heap_segment_table[i]);
    }
  
}


/*
  try to get a grip on how the cells are laid out.
*/
#define CHECK_LOCAL_REFERENCE(x)			\
{							\
  (*total_ptr) ++;						\
  if (SCM_GC_CELL_CARD(scmptr) == SCM_GC_CELL_CARD(x))	\
   ( *local) ++;						\
}


void
scm_i_analyse_card (scm_t_cell * card,
		    int * local,
		    int * total_ptr,
		    int *marked,
		    int * total_cell
		    )
{
  int span = SCM_GC_CARD_DOUBLECELLP(card) ? 2 : 1;  
  scm_t_cell *end = card + SCM_GC_CARD_N_CELLS;
  scm_t_cell *p = end - span;

  /*
     ASSUMPTION: n_header_cells <= 2. 
   */
  for (; p > card;  p -= span)
    {
      (*total_cell)++;
      if (SCM_GC_MARK_P (p))
	{
	  SCM scmptr   =(SCM) p;

	  (*marked) ++;
	  

	  switch (SCM_TYP7 (scmptr)) {
	  case scm_tcs_cons_nimcar:
	    CHECK_LOCAL_REFERENCE(SCM_CAR (scmptr));
	    CHECK_LOCAL_REFERENCE(SCM_CDR (scmptr));
	    break ; 
	  case scm_tcs_cons_imcar:
	    CHECK_LOCAL_REFERENCE( SCM_CDR (scmptr));
	    break;
	  case scm_tc7_pws:
	    CHECK_LOCAL_REFERENCE(SCM_SETTER (scmptr));
	    CHECK_LOCAL_REFERENCE(SCM_PROCEDURE(scmptr));
	    break;
	  case scm_tcs_closures:
	    if (SCM_IMP (SCM_ENV (scmptr)))
	      {
		CHECK_LOCAL_REFERENCE(SCM_CLOSCAR (scmptr));
	      }
	    else
	      {
		CHECK_LOCAL_REFERENCE(SCM_CLOSCAR (scmptr));
		CHECK_LOCAL_REFERENCE(SCM_ENV (scmptr));
	      }
	    break;
	  case scm_tc7_vector:
	    {
	      int i = SCM_VECTOR_LENGTH (scmptr);
	      while (i-- > 0)
		{
		  CHECK_LOCAL_REFERENCE( (SCM_VELTS (scmptr)[i]));
		}
	    }
	    break;

	  case scm_tc7_symbol:
	    CHECK_LOCAL_REFERENCE(SCM_PROP_SLOTS (scmptr));

	    break;

	  case scm_tc7_variable:
	    CHECK_LOCAL_REFERENCE (SCM_CELL_OBJECT_1 (scmptr));
	    break;

	  }
	}
    }
}

void
scm_i_segment_analysis  (scm_t_heap_segment* seg)
{
  int local =0;
  int total=0;
  int cells=0;
  int marked =0;

  scm_t_cell * p = seg->bounds[0];
  scm_t_cell * end = seg->bounds[1];

  for (; p <end ; p += SCM_GC_CARD_N_CELLS)
    {

      scm_i_analyse_card (p, &local, &total,
			  &marked, &cells);
    }

  printf ("%6d cells %4.2f %% local, %4.2f %% marked\n",
	  cells,
	  total ? (local *100.0) / total : 0.0,
	  (marked*100.0)/ cells);
}

static int
scm_i_get_msb (int k)
{
  int l = 0;
  while (k)
    {
      l++;
      k >>= 1;
    }
  return l;
}


void 
scm_i_print_card_analysis (scm_t_cell * card)
{
  int local = 0;
  int total =  0;
  int marked = 0;
  int ndata =0;
  scm_i_analyse_card (card, &local, &total, &marked,&ndata);

  printf ("L%2dM%2.1f ", local * 100 / (total + 1),
	  (marked * 100.0) / (ndata + 1));
}




