#ifndef lint
static char rcsid[] = "$Header: heapprof.c,v 1.2 91/05/06 12:25:42 dcurtis Exp $";
#endif
/* $Log:	heapprof.c,v $
 * Revision 1.2  91/05/06  12:25:42  dcurtis
 * *** empty log message ***
 * 
 * Revision 1.1  91/03/27  17:42:28  mtv
 * Initial revision
 * 
 */

#ifdef HEAP_PROF

#include <stdio.h>
#include "gc.h"

/* the maximum number of object sizes > min( MAXOBJSZ, MAXAOBJSZ ) */
#define MAX_OBJ_SIZES 1024

objcount atomic_cnts[ MAXAOBJSZ+1 ];
objcount composite_cnts[ MAXOBJSZ+1 ];
int do_census_report = 1;
int hblks_freed;

static bigobjcount big_cnts[ MAX_OBJ_SIZES ];

/* zeros the population counts */
void census_init()
{
  register int i;
  for (i = 0; i < MAXAOBJSZ; i++)
    atomic_cnts[i].nobjs = atomic_cnts[i].nhblks = 0;
  for (i = 0; i < MAXOBJSZ; i++)
    composite_cnts[i].nobjs = composite_cnts[i].nhblks = 0;
  for (i = 0; i < MAX_OBJ_SIZES; i++)
    big_cnts[i].size = big_cnts[i].count = 0;
  hblks_freed = 0;
}

/* sz is object size in words */
void census_big_obj(sz)
int sz;
{
  register int i;
  for (i = 0; i < MAX_OBJ_SIZES; i++) {
    if (big_cnts[i].size == 0 || big_cnts[i].size == sz) {
      big_cnts[i].size = sz;
      big_cnts[i].count++;
      return;
    }
  }
  write(fileno(stderr), "MAX_OBJ_SIZE overflow in census_big_obj\n ", 41);
}

static int cmp_boc(boc1, boc2)
bigobjcount *boc1, *boc2;
{
  if (boc1->size < boc2->size) return(-1);
  if (boc1->size == boc2->size) return(0);
  return(1);
}  

void census_report()
{
  register int i;
  int n_obj_sizes;
  int free_hblks = 0;   /* number of words on hblkfreelist */
  struct hblk *p;
  FILE *log;
  static int first = 1;
  static char *header_string =
    "                      overhead     used     free   (words)";

  log = fopen("census.out", first ? "w" : "a");
  first = 0;
  if (log == NULL) {
    fprintf(stderr, "Couldn't open census.log\n");
    exit(1);
  }

  fprintf(log, "\nAtomic objects:    %s\n", header_string);
  fixed_size_report(log, atomic_cnts, MAXAOBJSZ, aobjfreelist);

  fprintf(log, "\nComposite objects: %s\n", header_string);
  fixed_size_report(log, composite_cnts, MAXOBJSZ, objfreelist);

  /* sort big_cnts by object size using quicksort */
  for (i = 0; i < MAX_OBJ_SIZES; i++)
    if (!big_cnts[i].size) break;
  n_obj_sizes = i;

/*
  qsort((char *) &big_cnts[0], n_obj_sizes, sizeof(bigobjcount), cmp_boc);
 */

  fprintf(log, "\nBig objects (atomic and composite)\n\n");
  for (i = 0; i < n_obj_sizes; i++) {
    if (!big_cnts[i].size) {
      fprintf(stderr, "Assertion failed in census_report (big_cnts)\n");
      exit(1);
    }
    fprintf(log, "%5d words: %6d objects\n",
	    big_cnts[i].size, big_cnts[i].count);
  }

  fprintf(log, "\nFreed %d hblks.\n", hblks_freed);
  p = hblkfreelist;
  while (p) {
    free_hblks += (p->hb_sz / sizeof(word));
    p = p->hb_next;
  }
  fprintf(log, "HBLK free list has %d blocks totaling %d words.\n",
	  free_hblks / (HBLKSIZE / sizeof(word)), free_hblks);
  fclose(log);
}

static int length(lst)
struct obj *lst;
{
  register int len;
  register struct obj *l;

  l = lst;
  len = 0;
  while (l) {
    len++;
    l = l->obj_link;
  }
  return(len);
}

static fixed_size_report(log, cnts, n, freelist)
FILE *log;
objcount cnts[];
int n;
struct obj * freelist[];
{
  register int i;
  int overhead, used, free;     /* in words */
  int avail;              /* in objects */
  int objs_per_hblk;
  int tot_objs = 0, tot_hblks = 0;
  int tot_overhead = 0, tot_used = 0, tot_avail = 0;

  for (i = 0; i < n; i++) {
    if (cnts[i].nobjs) {
      objs_per_hblk = BODY_SZ / i;
      overhead = ((HBLKSIZE/sizeof(word)) - objs_per_hblk*i) * cnts[i].nhblks;
      used = cnts[i].nobjs * i;
      avail = (objs_per_hblk * cnts[i].nhblks - cnts[i].nobjs) * i;
      
      tot_objs += cnts[i].nobjs;
      tot_hblks += cnts[i].nhblks;
      tot_overhead += overhead;
      tot_used += used;
      tot_avail += avail;

      fprintf(log, "%5d words: %6d objs in %4d hblks  ( %7d %8d %8d )\n",
	      i, cnts[i].nobjs, cnts[i].nhblks,
	      overhead, used, avail);
#if 0
      free = length(freelist[i]);
      if (free != avail)
	fprintf(log, "***** %d word freelist of wrong length: %d\n", i, free);
    }
    else if (freelist[i]) {
      fprintf(log, "***** freelist for %d words nonempty!\n", i);
#endif
    }
  }
  if (tot_objs)
    fprintf(log, "\n    Totals: %7d objs in %4d hblks  ( %7d %8d %8d )\n",
	    tot_objs, tot_hblks, tot_overhead, tot_used, tot_avail);
}


#endif

