File:  [gforth] / gforth / engine / profile.c
Revision 1.7: download - view: text, annotated - select for diffs
Tue Dec 24 23:40:30 2002 UTC (16 years, 10 months ago) by anton
Branches: MAIN
CVS tags: HEAD
Gforth now supports large files (>2GB) on small machines (32-bits/cell).
forth.h now asks for all kinds of POSIX, X/Open, and GNU support.
rearranged include files such that forth.h precedes the system files.

    1: /* VM profiling support stuff
    2: 
    3:   Copyright (C) 2001 Free Software Foundation, Inc.
    4: 
    5:   This file is part of Gforth.
    6: 
    7:   Gforth is free software; you can redistribute it and/or
    8:   modify it under the terms of the GNU General Public License
    9:   as published by the Free Software Foundation; either version 2
   10:   of the License, or (at your option) any later version.
   11: 
   12:   This program is distributed in the hope that it will be useful,
   13:   but WITHOUT ANY WARRANTY; without even the implied warranty of
   14:   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   15:   GNU General Public License for more details.
   16: 
   17:   You should have received a copy of the GNU General Public License
   18:   along with this program; if not, write to the Free Software
   19:   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
   20: */
   21: 
   22: #include "config.h"
   23: #include "forth.h"
   24: #include <stdlib.h>
   25: #include <stdio.h>
   26: #include <assert.h>
   27: 
   28: 
   29: /* data structure: simple hash table with external chaining */
   30: 
   31: #define HASH_SIZE (1<<20)
   32: 
   33: typedef struct block_count {
   34:   struct block_count *next; /* next in hash table */
   35:   struct block_count *fallthrough; /* the block that this one falls
   36:                                        through to without SUPER_END */
   37:   Xt *ip;
   38:   long long count;
   39:   char **insts;
   40:   size_t ninsts;
   41: } block_count;
   42: 
   43: block_count *blocks[HASH_SIZE];
   44: 
   45: #define hash(p) ((((Cell)(p))/sizeof(Xt))&(HASH_SIZE-1))
   46: 
   47: block_count *block_lookup(Xt *ip)
   48: {
   49:   block_count *b = blocks[hash(ip)];
   50: 
   51:   while (b!=NULL && b->ip!=ip)
   52:     b = b->next;
   53:   return b;
   54: }
   55: 
   56: /* looks up present elements, inserts absent elements */
   57: block_count *block_insert(Xt *ip)
   58: { 
   59:   block_count *b = block_lookup(ip);
   60:   block_count *new;
   61: 
   62:   if (b != NULL)
   63:     return b;
   64:   new = (block_count *)malloc(sizeof(block_count));
   65:   new->next = blocks[hash(ip)];
   66:   new->fallthrough = NULL;
   67:   new->ip = ip;
   68:   new->count = 0LL;
   69:   new->insts = malloc(0);
   70:   assert(new->insts != NULL);
   71:   new->ninsts = 0;
   72:   blocks[hash(ip)] = new;
   73:   return new;
   74: }
   75: 
   76: void add_inst(block_count *b, char *inst)
   77: {
   78:   b->insts = realloc(b->insts, (b->ninsts+1) * sizeof(char *));
   79:   b->insts[b->ninsts++] = inst;
   80: }
   81: 
   82: void vm_count_block(Xt *ip)
   83: {
   84:   block_insert(ip)->count++;
   85: }
   86: 
   87: #ifdef DIRECT_THREADED
   88: #define VM_IS_INST(inst, n) ((inst) == vm_prims[(n)+DOESJUMP+1])
   89: #else
   90: #define VM_IS_INST(inst, n) ((inst) == &(vm_prims[(n)+DOESJUMP+1]))
   91: #endif
   92: 
   93: void postprocess_block(block_count *b)
   94: {
   95:   Xt *ip = b->ip;
   96:   block_count *next_block;
   97: 
   98:   do {
   99: #include "profile.i"
  100:     /* else */
  101:     {
  102:       add_inst(b,"unknown");
  103:       ip++;
  104:     }
  105:   _endif_:
  106:     next_block = block_lookup(ip);
  107:   } while (next_block == NULL);
  108:   /* we fell through, so set fallthrough and update the count */
  109:   b->fallthrough = next_block;
  110:   /* also update the counts of all following fallthrough blocks that
  111:      have already been processed */
  112:   while (next_block != NULL) {
  113:     next_block->count += b->count;
  114:     next_block = next_block->fallthrough;
  115:   }
  116: }
  117: 
  118: /* Deal with block entry by falling through from non-SUPER_END
  119:    instructions.  And fill the insts and ninsts fields. */
  120: void postprocess(void)
  121: {
  122:   size_t i;
  123: 
  124:   for (i=0; i<HASH_SIZE; i++) {
  125:     block_count *b = blocks[i];
  126:     for (; b!=0; b = b->next)
  127:       postprocess_block(b);
  128:    }
  129: }
  130: 
  131: #if 0
  132: /* full basic blocks only */
  133: void print_block(FILE *file, block_count *b)
  134: {
  135:   size_t i;
  136: 
  137:   fprintf(file,"%14lld\t",b->count);
  138:   for (i=0; i<b->ninsts; i++)
  139:     fprintf(file, "%s ", b->insts[i]);
  140:   putc('\n', file);
  141: }
  142: #elif 0
  143: /* full basic blocks and all their prefixes */
  144: void print_block(FILE *file, block_count *b)
  145: {
  146:   size_t i,j;
  147: 
  148:   for (j=1; j<=b->ninsts; j++) {
  149:     fprintf(file,"%14lld\t",b->count);
  150:     for (i=0; i<j; i++)
  151:       fprintf(file, "%s ", b->insts[i]);
  152:     putc('\n', file);
  153:   }
  154: }
  155: #else
  156: /* all subsequences up to length 12 */
  157: void print_block(FILE *file, block_count *b)
  158: {
  159:   size_t i,j,k;
  160: 
  161:   for (i=2; i<12; i++)
  162:     for (j=0; i+j<=b->ninsts; j++) {
  163:       fprintf(file,"%14lld\t",b->count);
  164:       for (k=j; k<i+j; k++)
  165: 	fprintf(file, "%s ", b->insts[k]);
  166:       putc('\n', file);
  167:     }
  168: }
  169: #endif
  170: 
  171: void vm_print_profile(FILE *file)
  172: {
  173:   size_t i;
  174: 
  175:   postprocess();
  176:   for (i=0; i<HASH_SIZE; i++) {
  177:     block_count *b = blocks[i];
  178:     for (; b!=0; b = b->next)
  179:       print_block(file, b);
  180:    }
  181: }

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