Annotation of gforth/engine/profile.c, revision 1.15

1.1       anton       1: /* VM profiling support stuff
                      2: 
1.15    ! anton       3:   Copyright (C) 2001,2002,2003,2007 Free Software Foundation, Inc.
1.1       anton       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
1.14      anton       9:   as published by the Free Software Foundation, either version 3
1.1       anton      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
1.14      anton      18:   along with this program; if not, see http://www.gnu.org/licenses/.
1.1       anton      19: */
                     20: 
                     21: #include "config.h"
1.7       anton      22: #include "forth.h"
1.1       anton      23: #include <stdlib.h>
                     24: #include <stdio.h>
1.2       anton      25: #include <assert.h>
1.1       anton      26: 
1.2       anton      27: 
1.1       anton      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);
1.2       anton      69:   assert(new->insts != NULL);
1.1       anton      70:   new->ninsts = 0;
                     71:   blocks[hash(ip)] = new;
                     72:   return new;
                     73: }
                     74: 
                     75: void add_inst(block_count *b, char *inst)
                     76: {
1.2       anton      77:   b->insts = realloc(b->insts, (b->ninsts+1) * sizeof(char *));
1.1       anton      78:   b->insts[b->ninsts++] = inst;
                     79: }
                     80: 
                     81: void vm_count_block(Xt *ip)
                     82: {
                     83:   block_insert(ip)->count++;
                     84: }
                     85: 
1.2       anton      86: #ifdef DIRECT_THREADED
1.9       anton      87: #define VM_IS_INST(inst, n) ((inst) == vm_prims[n])
1.2       anton      88: #else
1.9       anton      89: #define VM_IS_INST(inst, n) ((inst) == &(vm_prims[n]))
1.2       anton      90: #endif
1.1       anton      91: 
                     92: void postprocess_block(block_count *b)
                     93: {
                     94:   Xt *ip = b->ip;
                     95:   block_count *next_block;
                     96: 
                     97:   do {
1.13      anton      98: #include "profile.i"
1.1       anton      99:     /* else */
                    100:     {
                    101:       add_inst(b,"unknown");
                    102:       ip++;
                    103:     }
1.5       anton     104:   _endif_:
1.1       anton     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: 
1.11      anton     130: #if 1
1.6       anton     131: /* full basic blocks only */
1.1       anton     132: void print_block(FILE *file, block_count *b)
                    133: {
1.2       anton     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);
1.3       anton     140: }
1.6       anton     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;
1.3       anton     146: 
1.6       anton     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 */
1.3       anton     156: void print_block(FILE *file, block_count *b)
                    157: {
                    158:   size_t i,j,k;
                    159: 
1.11      anton     160:   for (i=1; i<2; i++)
1.4       anton     161:     for (j=0; i+j<=b->ninsts; j++) {
1.3       anton     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:     }
1.1       anton     167: }
1.6       anton     168: #endif
1.1       anton     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>