File:  [gforth] / gforth / engine / profile.c
Revision 1.1: download - view: text, annotated - select for diffs
Tue Feb 27 21:17:11 2001 UTC (18 years, 4 months ago) by anton
Branches: MAIN
CVS tags: HEAD
good start at profiling for peephole optimization
backtrace now also works for calls done with CALL

/* VM profiling support stuff

  Copyright (C) 2001 Free Software Foundation, Inc.

  This file is part of Gforth.

  Gforth is free software; you can redistribute it and/or
  modify it under the terms of the GNU General Public License
  as published by the Free Software Foundation; either version 2
  of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
*/

#include "config.h"
#include <stdlib.h>
#include <stdio.h>
#include "forth.h"

/* data structure: simple hash table with external chaining */

#define HASH_SIZE (1<<20)

typedef struct block_count {
  struct block_count *next; /* next in hash table */
  struct block_count *fallthrough; /* the block that this one falls
                                       through to without SUPER_END */
  Xt *ip;
  long long count;
  char **insts;
  size_t ninsts;
} block_count;

block_count *blocks[HASH_SIZE];

#define hash(p) ((((Cell)(p))/sizeof(Xt))&(HASH_SIZE-1))

block_count *block_lookup(Xt *ip)
{
  block_count *b = blocks[hash(ip)];

  while (b!=NULL && b->ip!=ip)
    b = b->next;
  return b;
}

/* looks up present elements, inserts absent elements */
block_count *block_insert(Xt *ip)
{ 
  block_count *b = block_lookup(ip);
  block_count *new;

  if (b != NULL)
    return b;
  new = (block_count *)malloc(sizeof(block_count));
  new->next = blocks[hash(ip)];
  new->fallthrough = NULL;
  new->ip = ip;
  new->count = 0LL;
  new->insts = malloc(0);
  new->ninsts = 0;
  blocks[hash(ip)] = new;
  return new;
}

void add_inst(block_count *b, char *inst)
{
  b->insts = realloc(b->insts, b->ninsts * sizeof(char *));
  b->insts[b->ninsts++] = inst;
}

void vm_count_block(Xt *ip)
{
  block_insert(ip)->count++;
}

/* !! fix this */
#define VM_INST(n) NULL

void postprocess_block(block_count *b)
{
  Xt *ip = b->ip;
  block_count *next_block;

  do {
#include "profile.i"
    /* else */
    {
      add_inst(b,"unknown");
      ip++;
    }
    next_block = block_lookup(ip);
  } while (next_block == NULL);
  /* we fell through, so set fallthrough and update the count */
  b->fallthrough = next_block;
  /* also update the counts of all following fallthrough blocks that
     have already been processed */
  while (next_block != NULL) {
    next_block->count += b->count;
    next_block = next_block->fallthrough;
  }
}

/* Deal with block entry by falling through from non-SUPER_END
   instructions.  And fill the insts and ninsts fields. */
void postprocess(void)
{
  size_t i;

  for (i=0; i<HASH_SIZE; i++) {
    block_count *b = blocks[i];
    for (; b!=0; b = b->next)
      postprocess_block(b);
   }
}

void print_block(FILE *file, block_count *b)
{
  fprintf(file,"%12lld ip=%p\n",b->count,b->ip);
}

void vm_print_profile(FILE *file)
{
  size_t i;

  postprocess();
  for (i=0; i<HASH_SIZE; i++) {
    block_count *b = blocks[i];
    for (; b!=0; b = b->next)
      print_block(file, b);
   }
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>