stats.c 8.57 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. 
 *
 */

/****************************************************************
 * stats.c
 * 
 * $Author: blythe $
 * $Date: 2002/05/29 01:09:10 $
 *****************************************************************/
#include <stdio.h>
#include <sys/time.h>
#include <bstring.h>
#include <sys/resource.h>
#include "embra.h"
#include "stats.h"
#include "clock.h"
#include "hw_events.h"
#include "debug.h"

#define GETSTATS
/* print sim speed to log */
#define GET_SPEED 250
/* specify the frequency of speed prints to the log (base=250). */
#define GET_SPEED_FREQU 250

#undef CHECKMMU
#define STAT(_x) (em_stats._x)



/* real time for simulator speed evaluation */
static struct timeval stime, etime, newstime;
static uint64 oldtotalIcount=0,
                totalIcount,
                oldtotalCycles=0,
                totalCycles,
                oldcpu0cycles=0;
static long secondsRun;
static int cpu;

/* Scale factor for hi-res timer */
static double s_per_tick;

/* Assembly callout Stuff */
  int virt_qc_i_misses;
  int virt_qc_d_excl_misses;
  int virt_qc_d_shared_misses;

stats_t em_stats;

SimTime embraInstrCount[SIM_MAXCPUS];
SimTime embraLastCount[SIM_MAXCPUS];

SimTime embraTotalInstructions;

void Dump_QC_Counters( int cpuNum)
{
   if( embra.emode == EMBRA_PAGE ) {
     EMBRA_INSTR_COUNT_EVENT(cpuNum,
                             EmbraCpuCycleCount(cpuNum) - embraLastCount[cpuNum]);
     embraLastCount[cpuNum] = EmbraCpuCycleCount(cpuNum);

   } else {
     embraInstrCount[cpuNum] += EMP[cpuNum].Sihit_count;
     
     EMBRA_INSTR_COUNT_EVENT(cpuNum,EMP[cpuNum].Sihit_count);
     EMBRA_REF_COUNT_EVENT(cpuNum,EMP[cpuNum].Sdhit_count);
     EMP[cpuNum].Sdhit_count = 0;
     EMP[cpuNum].Sihit_count = 0;
   }
}

SimTime EmbraCpuInstrCount(int cpuNum)
{

   return embraInstrCount[cpuNum] + EMP[cpuNum].Sihit_count;

}

void Stat_Init( void )
{
#ifdef notdef
   s_per_tick = Hw_Counter_Cycleval()/(1000.0*1000.0*1000.0*1000.0);
#endif                               
}




/* Floating point function called via backdoor */  
void Print_Recent_Stats( int cpuNum )
{
  struct timeval t;
  gettimeofday(&t);
  CPUPrint("\n");
  if( embra.MPinUP ) {
     int i;
     for(i = 0; i < TOTAL_CPUS; i++) {
        Dump_QC_Counters(i);
        CPUPrint("EM_CPU %d Cycle %lld PC 0x%llx RA 0x%llx Proc %s\n",
                 i, EMP[i].cycleCount, (Reg64)EMP[i].PC, (Reg64)EMP[i].R[31],
                 "foo" );
     }
  } else {
     Dump_QC_Counters(cpuNum);
     CPUPrint("EM_CPU %d Cycle %lld PC 0x%llx RA 0x%llx Proc %s\n",
              cpuNum, EMP[cpuNum].cycleCount, (Reg64)EMP[cpuNum].PC,
              (Reg64)EMP[cpuNum].R[31],
              "foo");
  }
  CPUPrint("EM_B Usec %lld Bdr %lldr/%lldur/%dc\n", 
           (int64)t.tv_sec*1000*1000+t.tv_usec,
           STAT( backdoor_ref ),
           STAT( backdoor_unaltered_ref ),
           STAT( backdoor_calls )
     );
  CPUPrint("EM_T Tran %.3fs/%db/%di  TC %dt/%di/%dk/%df KF %di/%dd/%db\n",
           ( (double)( s_per_tick * STAT( trans_timer.ticks ) ) ),
           STAT( translations ),
           STAT( trans_instrs ),
           STAT( tc_flushes ),
           STAT( icache_coherence),
           STAT( kern_cacheflush_tc_flush ),
           STAT( tc_filled ),
           STAT( kern_I_cacheflush ),
           STAT( kern_D_cacheflush ),
           STAT( kern_ID_cacheflush )
     );
  CPUPrint("EM_C0 EXC %d INT %d MOD %d RS %d/%d WS %d/%d  SYS %d\n",
           STAT( exceptions ),
           STAT( exception_type[0][0] ),
           STAT( exception_type[0][1] ),
           STAT( exception_type[0][2] ),
           STAT( exception_type[1][2] ),
           STAT( exception_type[0][3] ),
           STAT( exception_type[1][3] ),
           STAT( exception_type[0][8] )
     );
  CPUPrint("EM_CH Invk/bncd %u/%u (k/spec) %u/%u (usr/smpg) %u/%u smln %u\n",
           STAT( chain_invocations ),
           STAT( chain_bounced ),
           STAT( chain_known_chains ),
           STAT( chain_spec_chains ),
           STAT( chain_user_chains ),
           STAT( chain_samepg_chains ),
           STAT( chain_sameln_chains )
     );
#ifdef GET_QC
  if( embra.emode == EMBRA_CACHE ) {
     CPUPrint("EM_QC V/P(i/s/x) %lld %lld %lld %lld %lld %lld\n",
              STAT(vqc_i_misses),
              STAT(vqc_d_shared_misses),
              STAT(vqc_d_excl_misses),
              STAT(pqc_i_misses),
              STAT(pqc_d_shared_misses),
              STAT(pqc_d_excl_misses)
        );
  } else {
     CPUPrint("EM_MMU (i/s/x) %lld %lld %lld\n",
              STAT(pqc_i_misses),
              STAT(pqc_d_shared_misses),
              STAT(pqc_d_excl_misses)
        );
  }
#endif
#ifdef GET_REG_USAGE
  CPUPrint("Reg Use  0:%d 1:%d  2:%d  3:%d   4:%d   5:%d   6:%d   7:%d   8>:%d\n",
		 STAT( reg_usage[0] ),
		 STAT( reg_usage[1] ),
		 STAT( reg_usage[2] ),
		 STAT( reg_usage[3] ),
		 STAT( reg_usage[4] ),
		 STAT( reg_usage[5] ),
		 STAT( reg_usage[6] ),
		 STAT( reg_usage[7] ),
		 STAT( reg_usage[8] ) + STAT( reg_usage[9] ) +
		 STAT( reg_usage[10] ) + STAT( reg_usage[11] ) +
		 STAT( reg_usage[12] ) + STAT( reg_usage[13] ) +
		 STAT( reg_usage[14] ) + STAT( reg_usage[15] ) +
		 STAT( reg_usage[16] ) + STAT( reg_usage[17] ) +
		 STAT( reg_usage[18] ) + STAT( reg_usage[19] ) +
		 STAT( reg_usage[20] ) + STAT( reg_usage[21] ) +
		 STAT( reg_usage[22] ) + STAT( reg_usage[23] ) +
		 STAT( reg_usage[24] ) + STAT( reg_usage[25] ) +
		 STAT( reg_usage[26] ) + STAT( reg_usage[27] ) +
		 STAT( reg_usage[28] ) + STAT( reg_usage[29] ) +
		 STAT( reg_usage[30] ) + STAT( reg_usage[31] ) +
		 STAT( reg_usage[32] ) 
	);
#endif
#ifdef BB_HISTOGRAM
  CPUPrint("EM_BB 16   %d   %d   %d   %d   %d   %d   %d   %d   %d   %d\n",
		 STAT( bb_sizes[0] ),
		 STAT( bb_sizes[1] ),
		 STAT( bb_sizes[2] ),
		 STAT( bb_sizes[3] ),
		 STAT( bb_sizes[4] ),
		 STAT( bb_sizes[5] ),
		 STAT( bb_sizes[6] ),
		 STAT( bb_sizes[7] ),
		 STAT( bb_sizes[8] ),
		 STAT( bb_sizes[9] )
	);
  CPUPrint("EM_DEC 4   %d   %d   %d   %d   %d   %d   %d   %d   %d   %d\n",
		 STAT( dec_bb_sizes[0] ),
		 STAT( dec_bb_sizes[1] ),
		 STAT( dec_bb_sizes[2] ),
		 STAT( dec_bb_sizes[3] ),
		 STAT( dec_bb_sizes[4] ),
		 STAT( dec_bb_sizes[5] ),
		 STAT( dec_bb_sizes[6] ),
		 STAT( dec_bb_sizes[7] ),
		 STAT( dec_bb_sizes[8] ),
		 STAT( dec_bb_sizes[9] )
	);
#endif
  CPUPrint("EM_PCTC(in/ct/lk/ms/bms)ne(lk/ms) %d %.3f%% %d %.3f%% %.3f%%  %d %.3f%%\n",
           STAT( pc_tc_insert ),
           100.0*STAT( pc_tc_conflicts )/(float)STAT( pc_tc_insert ),
           STAT( pc_tc_lookup ),
           100.0*STAT( pc_tc_lookup_misses )/(float)STAT( pc_tc_lookup ),
           100.0*STAT( pc_tc_bdoor_misses )/(float)STAT( pc_tc_lookup ),
           STAT(ne_pc_tc_lookup),
           100.0*STAT(ne_pc_tc_lookup_misses)/(float)STAT(ne_pc_tc_lookup)
           );



  /*
   * Print speed stats 
   */
  
  {
     static SimTime prevTotalInstr=0;
     double diff = EmbraTimeDiff();
     int i;
     SimTime totalInstr=0;
     if (embra.emode==EMBRA_PAGE) { 
        totalInstr = TOTAL_CPUS * EmbraCpuCycleCount(0);
     } else { 
        for (i=0;i<TOTAL_CPUS;i++) {
           totalInstr += embraInstrCount[i];
        }
     }
     if (diff >0) { 
        CPUPrint("EM_KIPS %10lld cycles %1.3f seconds %5.0f KIPS \n",
                 EmbraCpuCycleCount(0),
                 diff,
                 (totalInstr-prevTotalInstr) / diff / 1000 );
     } else {
        CPUPrint("EM_KIPS %10lld inf KIPS \n",EmbraCpuCycleCount(0));
     }
     prevTotalInstr = totalInstr;
  }
     
  
  CPUPrint("EM_X\n");
  CPUPrint("\n");

}

/* This should not be needed, but for some reason the indys seg fault */
/* on readin g the timer */

#define NO_HW_COUNTER
/*****Support for the hi-res timer as exported by simhwtimer.h *****/
int hw_counter_start( HW_counter* count )
{
#ifndef NO_HW_COUNTER   
  count->current = Hw_Counter_Read();
#endif
  count->on = 1;
  return 0;
}

int hw_counter_stop( HW_counter* count )
{
  if( count->on )
        {
#ifndef NO_HW_COUNTER   
          count->ticks += ( Hw_Counter_Read() - count->current );
#endif
          count->on = 0;
          return 1;
        }
  return 0;
}

int hw_counter_reset( HW_counter* count )
{
  count->ticks = 0LL;
  return 0;
}


double EmbraTimeDiff(void)
{
   static int init=0;
   static struct timeval old;
   struct timeval new;
   double diff;
   
   gettimeofday(&new,NULL);
   if (init) {
      diff=new.tv_sec - old.tv_sec; 
      diff += 0.000001 * (new.tv_usec - old.tv_usec);
   } else { 
      diff= 0;
   }
   init = 1;
   old = new;
   return diff;
}