ms_stats.c 12.9 KB
/*
 * Copyright (C) 1996-1998 by the Board of Trustees
 *    of Leland Stanford Junior University.
 * 
 * This file is part of the SimOS distribution. 
 * See LICENSE file for terms of the license. 
 *
 */


	/*
	 *  ms_stats  -  Collect statistics on a per procedure basis during
	 *		the running of the simulator.
	 *
	 *  Contains the functions push_stats and pop_stats, and the
	 *  routine print_stats, called on program exit.
	 *
	 *  The PROCSTATS flag, if set, forces per procedure statistics to
	 *  be kept and output at end.
	 *
	 *	Jim Bennett
	 *	1994
	 */

#include <stdlib.h>
#include "ms.h"
#include "./ms_stats.h"
#include "sim_error.h"
#include "cpu_state.h"
#include "mipsy.h"
#include "hw_events.h"
#include "statrecord.h"

static	double	convert_stat (struct s_cpu_state *st, int st_index, int mode);
static	double	convert_stat_sum (struct s_cpu_state *st, int st_index);

static void PRINT(char *format, ...)
{
   va_list ap;
   CPUPrint("%MXS:");
   va_start(ap,format);
   vCPUPrint(format,ap);
   va_end(ap);
}

/*****************************************************************
 * STAT RECORD ROUTINES
 *
 * All hardware events that should be tracked by statrecord go here.
 *****************************************************************/
struct MSEventsBucket {
   StatRecordFieldDesc dMXSL1Stall;
   StatRecordFieldDesc dMXSL2Stall;
   StatRecordFieldDesc dMXSUpgradeStall;
   StatRecordFieldDesc iMXSL1Stall;
   StatRecordFieldDesc iMXSL2Stall;
   StatRecordFieldDesc pipelineMXSStall;
} msEventBucket;

#define DEF_FIELD(_field,_fl) (msEventBucket._field = StatRecordDefineField(# _field,_fl))

#define STAT_RECORD(_f, _inc) \
  StatRecordEntry(cpuNum, pc, vAddr, msEventBucket._f, _inc);
#define STAT_RECORD_I(_f, _inc) \
  StatRecordEntry(cpuNum, pc, 0, msEventBucket._f, _inc);
#define STAT_RECORD_D(_f, _inc) \
  StatRecordEntry(cpuNum, 0, vAddr, msEventBucket._f, _inc);

void 
ms_events_init(void)
{
   /* MXS-related counters */
   DEF_FIELD(dMXSL1Stall, STATRECORD_INSTRUCTION|STATRECORD_DATA);
   DEF_FIELD(dMXSL2Stall, STATRECORD_INSTRUCTION|STATRECORD_DATA);
   DEF_FIELD(iMXSL1Stall, STATRECORD_INSTRUCTION);
   DEF_FIELD(iMXSL2Stall, STATRECORD_INSTRUCTION);
   DEF_FIELD(dMXSUpgradeStall, STATRECORD_INSTRUCTION|STATRECORD_DATA);
   DEF_FIELD(pipelineMXSStall, STATRECORD_INSTRUCTION);
}

void 
ms_attribute_stall(int cpuNum, int vAddr, int pc, int stall, int stallType)
{
   if (stallType & E_PIPELINE) {
      STAT_RECORD_I(pipelineMXSStall,stall);
      return;
   }
   if (stallType & E_D) {
      if (stallType & E_L1) { 
         STAT_RECORD(dMXSL1Stall,stall);
         return;
      }
      if (((stallType & E_L1) && (stallType & E_UPGRADE)) 
          || ((stallType & E_L2) && (stallType & E_UPGRADE))) {
         STAT_RECORD(dMXSUpgradeStall,stall);
         return;
      }
      ASSERT(stallType & E_L2);
      STAT_RECORD(dMXSL2Stall,stall);
   } else { 
      ASSERT(vAddr==pc);
      ASSERT(stallType & E_I);
      if (stallType & E_L1) {
         STAT_RECORD(iMXSL1Stall,stall);
      } else { 
         ASSERT(stallType & E_L2);
         STAT_RECORD(iMXSL2Stall,stall);
      }
   }
}


/*----------------------------------------------------------------------*/
/*									*/
/*	ms_exec never returns, but exits when the app calls exit.	*/
/*	But just before exiting, the following routine gets called	*/
/*	to print out the collected statistics.				*/
/*									*/
/*----------------------------------------------------------------------*/

void print_stats (struct s_cpu_state *st)
	{
	}


	/*
	 *  convert_stat  -  Convert statistic to double precision
	 *		     floating point number.
	 */

static double convert_stat (struct s_cpu_state *st, int st_index, int mode)
	{
	double	t;

	t = (double) (st->stats[mode][st_index]);
	return (t);
	}

	/*
	 *  convert_stat_sum  -  Convert statistic to double precision
	 *		         floating point number.
	 */

static double convert_stat_sum (struct s_cpu_state *st, int st_index)
	{
         return (convert_stat(st,st_index,0) + 
		 convert_stat(st,st_index,1) +
		 convert_stat(st,st_index,2) + 
		 convert_stat(st,st_index,3));
        
	}

void dump_stats (struct s_cpu_state *st)
{
	int	i, mode;

    if ((st->work_ticks == 0) && (st->work_cycle == 0)) {
	    /* Must not of run yet. */
            return;
    }

        for (mode = 0; mode < NUM_MODES; mode++) {
             {
		CPUState *P = (CPUState *) (st->mipsyPtr);
 	        PRINT( "DUMPSTATS: CPU %d MODE %d @ %lld %9d%0.5d\n", P->myNum,mode,
		         (uint64)MipsyReadTime(P->myNum), st->work_ticks, st->work_cycle);
	     }

/* Then output gathered statistics		*/


	     for (i = 0; i < ST_NTYPES; i++) {
		 if (sh_stat_names[i][0] == 0) continue;
#define PRINT_IF_NOT_ZERO(_format, _name, _value) \
             if ((_value) != 0) PRINT(_format, _name, (double)(_value))
		 PRINT_IF_NOT_ZERO( "%s: %.0f\n", sh_stat_names[i],
                                    convert_stat(st,i, mode));
	     }
#undef PRINT_IF_NOT_ZERO
#define PRINT_IF_NOT_ZERO(_format, _index, _value) \
             if ((_value) != 0) PRINT(_format, _index, (double)(_value))

             PRINT_IF_NOT_ZERO("SAMPLE: %d %.0f\n",mode,st->sample_stats[mode].samples);
             for (i = 0; i < (sizeof(st->sample_stats[mode].nthreads_hist) / 
                              sizeof(st->sample_stats[mode].nthreads_hist[0])); i++) {                
                PRINT_IF_NOT_ZERO("NTHREADS_HIST: %d %.0f\n",i,st->sample_stats[mode].nthreads_hist[i]);
             }
             for (i = 0; i < (sizeof(st->sample_stats[mode].reg_hist) / 
                              sizeof(st->sample_stats[mode].reg_hist[0])); i++) {                
                PRINT_IF_NOT_ZERO("REGS_HIST: %d %.0f\n",i,st->sample_stats[mode].reg_hist[i]);
             }
             for (i = 0; i < (sizeof(st->sample_stats[mode].iwin_hist) / 
                              sizeof(st->sample_stats[mode].iwin_hist[0])); i++) {                
                PRINT_IF_NOT_ZERO("IWIN_INST_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].iwin_hist[i].inst);
                PRINT_IF_NOT_ZERO("IWIN_SPECINST_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].iwin_hist[i].specInst);
                PRINT_IF_NOT_ZERO("IWIN_LDST_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].iwin_hist[i].ldstInst);
                PRINT_IF_NOT_ZERO("IWIN_LDSTDEP_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].iwin_hist[i].ldstdepInst);
                PRINT_IF_NOT_ZERO("IWIN_REGDEP_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].iwin_hist[i].regdepInst);
                PRINT_IF_NOT_ZERO("IWIN_SQUASH_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].iwin_hist[i].squashInst);
             }
             for (i = 0; i < (sizeof(st->sample_stats[mode].ldst_hist) / 
                              sizeof(st->sample_stats[mode].ldst_hist[0])); i++) {                
                PRINT_IF_NOT_ZERO("LDST_INST_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].ldst_hist[i].inst);
                PRINT_IF_NOT_ZERO("LDST_DONE_INST_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].ldst_hist[i].doneInst);
                PRINT_IF_NOT_ZERO("LDST_PEND_INST_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].ldst_hist[i].pendInst);
                PRINT_IF_NOT_ZERO("LDST_CONFLICT_INST_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].ldst_hist[i].conflictInst);
                PRINT_IF_NOT_ZERO("LDST_FAILED_INST_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].ldst_hist[i].failedInst);
                PRINT_IF_NOT_ZERO("LDST_STALL_INST_HIST: %d %.0f\n",i,
                                  st->sample_stats[mode].ldst_hist[i].stallInst);

             }
                                  

	}
}

void MxsPrintStatus(struct s_cpu_state *st) 
{
  return;
#ifdef BANREMOVE
  double grad_insts, grad_squashed, cond_br_correct, cond_br_incorrect, 
           ind_br_correct, ind_br_incorrect;
    double igrad_insts, igrad_squashed, icond_br_correct, icond_br_incorrect, 
           iind_br_correct, iind_br_incorrect;

    CPUState *P = (CPUState *) (st->mipsyPtr);
    static struct { 
	double grad_insts, grad_squashed, cond_br_correct, cond_br_incorrect, 
           ind_br_correct, ind_br_incorrect;
       
    } old[MIPSY_MAX_CPUS];
 
    if ((st->work_ticks == 0) && (st->work_cycle == 0)) {
	    /* Must not of run yet. */
            return;
    }


    cond_br_correct = convert_stat_sum (st, ST_CORRECT_FALLTHRU) + 
		      convert_stat_sum (st, ST_CORRECT_W_FALLTHRU) + 
		      convert_stat_sum (st, ST_CORRECT_W_TAKEN) +
		      convert_stat_sum (st, ST_CORRECT_TAKEN);

    cond_br_incorrect = convert_stat_sum (st, ST_INCORRECT_FALLTHRU) + 
		      convert_stat_sum (st, ST_INCORRECT_W_FALLTHRU) + 
		      convert_stat_sum (st, ST_INCORRECT_W_TAKEN) +
		      convert_stat_sum (st, ST_INCORRECT_TAKEN);

    ind_br_correct = convert_stat_sum (st, ST_CORRECT_IND_BR);
    ind_br_incorrect = convert_stat_sum (st, ST_INCORRECT_IND_BR);

    grad_insts = (double) P->numInstructions;
    grad_squashed = convert_stat_sum (st, ST_GRAD_SQUASHED);
    icond_br_correct = cond_br_correct - old[P->myNum].cond_br_correct;
    icond_br_incorrect = cond_br_incorrect - old[P->myNum].cond_br_incorrect;
    iind_br_correct = ind_br_correct - old[P->myNum].ind_br_correct;
    iind_br_incorrect = ind_br_incorrect - old[P->myNum].ind_br_incorrect;
    igrad_insts = grad_insts - old[P->myNum].grad_insts;
    igrad_squashed = grad_squashed - old[P->myNum].grad_squashed;

    PRINT ("CPU%d BR (%3.1f%%) JR (%3.1f%%) Squash (%3.1f%%)\n",P->myNum,
	   100.0*icond_br_correct/(icond_br_correct + icond_br_incorrect + .0000001),
	   100.0*iind_br_correct/(iind_br_correct + iind_br_incorrect + .0000001),
	   100.0*igrad_squashed/(igrad_squashed + igrad_insts + .0000001));

   old[P->myNum].grad_insts = grad_insts;
   old[P->myNum].grad_squashed = grad_squashed;
   old[P->myNum].cond_br_correct = cond_br_correct;
   old[P->myNum].cond_br_incorrect = cond_br_incorrect;
   old[P->myNum].ind_br_correct = ind_br_correct;
   old[P->myNum].ind_br_incorrect = ind_br_incorrect;
#endif
}


void 
MxsSampleStats(struct s_cpu_state *st, int mode) 
{
    int inum, r;
    struct s_ldst_buffer *entry;
    int  instInWindow , specInstInWindow , ldstInstInWindow ,
        ldstdepInstInWindow , regdepInstInWindow , squashInstInWindow;
    int  ldstBufferInst, ldstDoneInst , ldstConflictInst , ldstFailedInst, 
        ldstStallInst,  ldstPendInst;
    int regBusyCount;


    st->sample_stats[mode].samples++;

    st->sample_stats[mode].nthreads_hist[st->nthreads]++;

    regBusyCount = 0;
     for (r = 0; r < MAX_PREG/2; r++) {
        if (st->reg_rstat[r].reg_status & REG_BUSY)
           regBusyCount++;
     }
     st->sample_stats[mode].reg_hist[regBusyCount]++;

 
    instInWindow = specInstInWindow =  ldstInstInWindow =
        ldstdepInstInWindow = regdepInstInWindow = squashInstInWindow = 0;


     inum = st->iwin_headgrad; 
     while (inum >= 0) {
         int flags = st->iwin_flags[inum];
         instInWindow++;
         if (flags & IWIN_SPEC) 
            specInstInWindow++;
         if (flags & IWIN_LDST) 
            ldstInstInWindow++;
         if (flags & IWIN_LDST_DEP) 
            ldstdepInstInWindow++;
         if (flags & (IWIN_DEP2|IWIN_DEP3)) 
            regdepInstInWindow++;
         if (flags & IWIN_SQUASH) 
            squashInstInWindow++;

         inum = st->iwin_grad[inum];
     }

     st->sample_stats[mode].iwin_hist[instInWindow].inst++;
     st->sample_stats[mode].iwin_hist[specInstInWindow].specInst++;
     st->sample_stats[mode].iwin_hist[ldstInstInWindow].ldstInst++;
     st->sample_stats[mode].iwin_hist[ldstdepInstInWindow].ldstdepInst++;
     st->sample_stats[mode].iwin_hist[regdepInstInWindow].regdepInst++;
     st->sample_stats[mode].iwin_hist[squashInstInWindow].squashInst++;


     ldstBufferInst = ldstDoneInst = ldstConflictInst = ldstFailedInst = 
        ldstStallInst = ldstPendInst = 0;
     for (entry = st->ldst_head; entry; entry = entry->next) {
        int status = entry->ls->status;
        ldstBufferInst++;
        if (status & LS_ST_DONE) {
           ldstDoneInst++;
           continue;
        }
        if (status & LS_ST_PEND) 
           ldstPendInst++;
        if (status & LS_ST_CONFLICT) 
           ldstConflictInst++;
        if (status & LS_ST_FAILED) 
           ldstFailedInst++;
        if (status & LS_ST_STALL) 
           ldstStallInst++;
     }

     st->sample_stats[mode].ldst_hist[ldstBufferInst].inst++;
     st->sample_stats[mode].ldst_hist[ldstDoneInst].doneInst++;
     st->sample_stats[mode].ldst_hist[ldstPendInst].pendInst++;
     st->sample_stats[mode].ldst_hist[ldstConflictInst].conflictInst++;
     st->sample_stats[mode].ldst_hist[ldstFailedInst].failedInst++;
     st->sample_stats[mode].ldst_hist[ldstStallInst].stallInst++;

}