File:  [gforth] / gforth / engine / profile.c
Revision 1.15: download - view: text, annotated - select for diffs
Mon Dec 31 19:02:25 2007 UTC (13 years, 3 months ago) by anton
Branches: MAIN
CVS tags: v0-7-0, HEAD
updated copyright year after changing license notice

    1: /* VM profiling support stuff
    2: 
    3:   Copyright (C) 2001,2002,2003,2007 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 3
   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, see http://www.gnu.org/licenses/.
   19: */
   20: 
   21: #include "config.h"
   22: #include "forth.h"
   23: #include <stdlib.h>
   24: #include <stdio.h>
   25: #include <assert.h>
   26: 
   27: 
   28: /* data structure: simple hash table with external chaining */
   29: 
   30: #define HASH_SIZE (1<<20)
   31: 
   32: typedef struct block_count {
   33:   struct block_count *next; /* next in hash table */
   34:   struct block_count *fallthrough; /* the block that this one falls
   35:                                        through to without SUPER_END */
   36:   Xt *ip;
   37:   long long count;
   38:   char **insts;
   39:   size_t ninsts;
   40: } block_count;
   41: 
   42: block_count *blocks[HASH_SIZE];
   43: 
   44: #define hash(p) ((((Cell)(p))/sizeof(Xt))&(HASH_SIZE-1))
   45: 
   46: block_count *block_lookup(Xt *ip)
   47: {
   48:   block_count *b = blocks[hash(ip)];
   49: 
   50:   while (b!=NULL && b->ip!=ip)
   51:     b = b->next;
   52:   return b;
   53: }
   54: 
   55: /* looks up present elements, inserts absent elements */
   56: block_count *block_insert(Xt *ip)
   57: { 
   58:   block_count *b = block_lookup(ip);
   59:   block_count *new;
   60: 
   61:   if (b != NULL)
   62:     return b;
   63:   new = (block_count *)malloc(sizeof(block_count));
   64:   new->next = blocks[hash(ip)];
   65:   new->fallthrough = NULL;
   66:   new->ip = ip;
   67:   new->count = 0LL;
   68:   new->insts = malloc(0);
   69:   assert(new->insts != NULL);
   70:   new->ninsts = 0;
   71:   blocks[hash(ip)] = new;
   72:   return new;
   73: }
   74: 
   75: void add_inst(block_count *b, char *inst)
   76: {
   77:   b->insts = realloc(b->insts, (b->ninsts+1) * sizeof(char *));
   78:   b->insts[b->ninsts++] = inst;
   79: }
   80: 
   81: void vm_count_block(Xt *ip)
   82: {
   83:   block_insert(ip)->count++;
   84: }
   85: 
   86: #ifdef DIRECT_THREADED
   87: #define VM_IS_INST(inst, n) ((inst) == vm_prims[n])
   88: #else
   89: #define VM_IS_INST(inst, n) ((inst) == &(vm_prims[n]))
   90: #endif
   91: 
   92: void postprocess_block(block_count *b)
   93: {
   94:   Xt *ip = b->ip;
   95:   block_count *next_block;
   96: 
   97:   do {
   98: #include "profile.i"
   99:     /* else */
  100:     {
  101:       add_inst(b,"unknown");
  102:       ip++;
  103:     }
  104:   _endif_:
  105:     next_block = block_lookup(ip);
  106:   } while (next_block == NULL);
  107:   /* we fell through, so set fallthrough and update the count */
  108:   b->fallthrough = next_block;
  109:   /* also update the counts of all following fallthrough blocks that
  110:      have already been processed */
  111:   while (next_block != NULL) {
  112:     next_block->count += b->count;
  113:     next_block = next_block->fallthrough;
  114:   }
  115: }
  116: 
  117: /* Deal with block entry by falling through from non-SUPER_END
  118:    instructions.  And fill the insts and ninsts fields. */
  119: void postprocess(void)
  120: {
  121:   size_t i;
  122: 
  123:   for (i=0; i<HASH_SIZE; i++) {
  124:     block_count *b = blocks[i];
  125:     for (; b!=0; b = b->next)
  126:       postprocess_block(b);
  127:    }
  128: }
  129: 
  130: #if 1
  131: /* full basic blocks only */
  132: void print_block(FILE *file, block_count *b)
  133: {
  134:   size_t i;
  135: 
  136:   fprintf(file,"%14lld\t",b->count);
  137:   for (i=0; i<b->ninsts; i++)
  138:     fprintf(file, "%s ", b->insts[i]);
  139:   putc('\n', file);
  140: }
  141: #elif 0
  142: /* full basic blocks and all their prefixes */
  143: void print_block(FILE *file, block_count *b)
  144: {
  145:   size_t i,j;
  146: 
  147:   for (j=1; j<=b->ninsts; j++) {
  148:     fprintf(file,"%14lld\t",b->count);
  149:     for (i=0; i<j; i++)
  150:       fprintf(file, "%s ", b->insts[i]);
  151:     putc('\n', file);
  152:   }
  153: }
  154: #else
  155: /* all subsequences up to length 12 */
  156: void print_block(FILE *file, block_count *b)
  157: {
  158:   size_t i,j,k;
  159: 
  160:   for (i=1; i<2; i++)
  161:     for (j=0; i+j<=b->ninsts; j++) {
  162:       fprintf(file,"%14lld\t",b->count);
  163:       for (k=j; k<i+j; k++)
  164: 	fprintf(file, "%s ", b->insts[k]);
  165:       putc('\n', file);
  166:     }
  167: }
  168: #endif
  169: 
  170: void vm_print_profile(FILE *file)
  171: {
  172:   size_t i;
  173: 
  174:   postprocess();
  175:   for (i=0; i<HASH_SIZE; i++) {
  176:     block_count *b = blocks[i];
  177:     for (; b!=0; b = b->next)
  178:       print_block(file, b);
  179:    }
  180: }

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