cpu_stats.c 10.3 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. 
 *
 */

/****************************************************************
 * cpu_stats.c
 *
 * Author: $author$
 * Date: $date$
 ****************************************************************/
#include <sys/time.h>
#include "simutil.h"
#include "simstats.h"
#include "sim_error.h"
#include "cpu_stats.h"
#include "cpu_interface.h"
#include "machine_params.h"
#include "syslimits.h"

CPUStats *cpuStats;

static struct timeval startTime, endTime, newStartTime;

/* Exported functions */
void InitCPUStats(void)
{
   cpuStats = (CPUStats *)calloc(TOTAL_CPUS, sizeof(CPUStats)); 
   gettimeofday(&startTime, NULL);
}

void ResetCPUStats(void) 
{
   bzero((char*)cpuStats, (TOTAL_CPUS * sizeof(CPUStats))); 
}

/*****************************************************************
 * Print out a subset of the statistics for temporal knowledge of 
 * behavior.
 *****************************************************************/

static struct HoldCPUStats {
   SimCounter Icnt;
   SimTime cycleCount;
   SimTime syncTime;
   unsigned int syscalls, interrupts, faults;
} oldstats[SIM_MAXCPUS];

static SimCounter oldTotalIcnt;
static SimTime oldCycleCnt;
static long secondsRun;

void
PrintPeriodicCPUStats(void)
{
   int cpuNum;
   SimCounter newIcnt;
   SimCounter totalIcnt;
   SimTime newSyncTime; 
   SimTime totalSyncTime;
   uint newSyscalls, newInterrupts, newFaults;
   double cpi;
   SimTime cycleCount = CPUVec.CycleCount(0);
   totalIcnt = 0; 
   totalSyncTime = 0;

   for (cpuNum = 0; cpuNum < TOTAL_CPUS; cpuNum++) {
      struct HoldCPUStats *s = &(oldstats[cpuNum]);

      totalIcnt += newIcnt = STATS_VALUE(cpuNum, numInstructions);
      
      totalSyncTime += newSyncTime =
         SPIN_LOOP_INST 
         * (STATS_VALUE(cpuNum, syncStats.llNonZero) 
            + STATS_VALUE(cpuNum, syncStats.scFailed));   
      
      newSyscalls   = STATS_VALUE(cpuNum, numSyscalls) - s->syscalls;
      newInterrupts = STATS_VALUE(cpuNum, numInterrupts) - s->interrupts;
      newFaults     = STATS_VALUE(cpuNum, numFaults) - s->faults;

      s->syscalls   = STATS_VALUE(cpuNum, numSyscalls);
      s->interrupts = STATS_VALUE(cpuNum, numInterrupts);
      s->faults     = STATS_VALUE(cpuNum, numFaults);

      if ((newIcnt - s->Icnt) > 0)
	cpi = (double)(cycleCount - s->cycleCount) /
	  ((double)(newIcnt - s->Icnt));
      
      CPUPrint("C%d 0x%08llx CPI %4.2f Sys %lld Int %lld TLB %lld\n",  
                 cpuNum, (Reg64)CPUVec.CurrentPC(cpuNum), cpi, (uint64)newSyscalls,
                 (uint64)newInterrupts, (uint64)newFaults);

      /* Update current statistics for next time */
      s->Icnt = newIcnt; 
      s->cycleCount = cycleCount;
      s->syncTime = newSyncTime;
   }
   
   /* Now for some simulator statistics */
   gettimeofday(&endTime, NULL);
   newStartTime = endTime;
   if (startTime.tv_usec < endTime.tv_usec) {
      endTime.tv_usec -= startTime.tv_usec ;
      endTime.tv_sec -= startTime.tv_sec;
   } else {
      endTime.tv_usec -= startTime.tv_usec;
      endTime.tv_usec += 1000000;
      endTime.tv_sec -= (startTime.tv_sec-1);
   }
   
   secondsRun = (endTime.tv_sec + endTime.tv_usec/1000000);
   
   CPUPrint("CPU Util: %5.3f%% SPEED: %5.3f Kcycles/sec %5.2f KIPS\n",
              ((100.0 * (totalIcnt - oldTotalIcnt))/TOTAL_CPUS) / 
              (cycleCount - oldCycleCnt),
              ((cycleCount - oldCycleCnt)) /
              (1000.0*secondsRun),
              ((totalIcnt - oldTotalIcnt)) /
              (1000.0*secondsRun));
   
   startTime    = newStartTime;
   oldTotalIcnt = totalIcnt;
   oldCycleCnt  = cycleCount;
}

/*****************************************************************
 * PrintCPUStats
 *****************************************************************/
static void 
PrintCPUStats(void)
{
   int cpuNum;

   CPUPrint("*********\n");
   CPUPrint("CPU stats\n");
   CPUPrint("*********\n");
   CPUPrint("M_EVENT Total Cycles %lld\n", CPUVec.CycleCount(0));
   for (cpuNum=0; cpuNum<TOTAL_CPUS; cpuNum++) {
      CPUPrint("M_EVENT_C%d Insts %lld\n", cpuNum, 
                 (uint64)STATS_VALUE(cpuNum, numInstructions)); 
      CPUPrint("M_EVENT_C%d FP-Insts %lld\n", cpuNum, 
                 (uint64)STATS_VALUE(cpuNum, numFPOps));
      CPUPrint("M_EVENT_C%d Bdoor Insts %lld\n", cpuNum, 
                 (uint64)STATS_VALUE(cpuNum, numBdoorInsts));
      CPUPrint("M_EVENT_C%d Halted Time %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, haltedTime));
      CPUPrint("M_EVENT_C%d CPI %5.3f\n", cpuNum, 
                 (double)((double)CPUVec.CycleCount(cpuNum)
                          / (double)STATS_VALUE(cpuNum, numInstructions)));
      
      CPUPrint("M_EVENT_C%d LLs %lld\n", cpuNum, 
                 (uint64)STATS_VALUE(cpuNum, syncStats.lls)); 
      CPUPrint("M_EVENT_C%d LLNonZero %lld\n", cpuNum, 
                 (uint64)STATS_VALUE(cpuNum, syncStats.llNonZero));
      CPUPrint("M_EVENT_C%d LLStallTime %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, syncStats.llStallTime));
      CPUPrint("M_EVENT_C%d SCs %lld\n", cpuNum, 
                 (uint64)STATS_VALUE(cpuNum, syncStats.scs));
      CPUPrint("M_EVENT_C%d SCFailed %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, syncStats.scFailed));
      CPUPrint("M_EVENT_C%d SCStallTime %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, syncStats.scStallTime));
      CPUPrint("M_EVENT_C%d SyncStallTime %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, syncStallTime));

      /* Sync Op Statistics */
      CPUPrint("M_EVENT_C%d SyncOps %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, syncOps));
      CPUPrint("M_EVENT_C%d SyncOpStallTime %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, syncOpStallTime));
      
      /* Prefetching Statistics */
      CPUPrint("M_EVENT_C%d Prefetches %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefs));
      CPUPrint("M_EVENT_C%d PrefetchL1Hits %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefL1Hits));
      CPUPrint("M_EVENT_C%d PrefetchL2Hits %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefL2Hits));
      CPUPrint("M_EVENT_C%d PrefetchMerges %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefMerges));
      CPUPrint("M_EVENT_C%d PrefetchUpgrades %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefUpgrades));
      CPUPrint("M_EVENT_C%d PrefetchStalls %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefStalls));
      CPUPrint("M_EVENT_C%d PrefetchMHTStall %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefMHTStall));
      CPUPrint("M_EVENT_C%d PrefetchMHTStallTime %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefMHTStallTime));
      CPUPrint("M_EVENT_C%d PrefetchUpgrades %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefUpgrades));
      CPUPrint("M_EVENT_C%d PrefetchTLBMisses %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefTLBMisses));

      CPUPrint("M_EVENT_C%d PrefetchExclusives %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefXs));
      CPUPrint("M_EVENT_C%d PrefetchXL1Hits %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefXL1Hits));
      CPUPrint("M_EVENT_C%d PrefetchXL2Hits %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefXL2Hits));
      CPUPrint("M_EVENT_C%d PrefetchXMerges %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefXMerges));
      CPUPrint("M_EVENT_C%d PrefetchXUpgrades %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefXUpgrades));
      CPUPrint("M_EVENT_C%d PrefetchXStall %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefXStalls));
      CPUPrint("M_EVENT_C%d PrefetchXMHTStall %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefXMHTStall));
      CPUPrint("M_EVENT_C%d PrefetchXMHTStallTime %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefXMHTStallTime));
      CPUPrint("M_EVENT_C%d PrefetchXUpgrades %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefXUpgrades));
      CPUPrint("M_EVENT_C%d PrefetchXTLBMisses %lld\n", cpuNum,
                 (uint64)STATS_VALUE(cpuNum, prefStats.prefXTLBMisses));

      /* Write buffer statistics */
      CPUPrint("M_EVENT_C%d WriteMHTStall %lld\n", cpuNum,
               (uint64)STATS_VALUE(cpuNum, writeBufferStats.writeMHTStall));
      CPUPrint("M_EVENT_C%d WriteMHTStallTime %lld\n", cpuNum,
               (uint64)STATS_VALUE(cpuNum, writeBufferStats.writeMHTStallTime));
   }
}


/*****************************************************************
 * PrintSyscallStats
 *****************************************************************/
static void 
PrintSyscallStats(void)
{
   int i;
   int cpuNum;
   SimCounter syscallCount[MAX_SYSCALL];

   CPUPrint("************************\n");
   CPUPrint("SYSCALL statistics\n");
   CPUPrint("************************\n");

   for (i=0; i<MAX_SYSCALL; i++) {
      syscallCount[i] = 0;
      for (cpuNum=0; cpuNum < TOTAL_CPUS; cpuNum++) {
         syscallCount[i] += STATS_VALUE(cpuNum, syscallCount[i]);
      }
      if (syscallCount[i]) {
         CPUPrint("M-SYSCALL %d %lld %s\n", i, 
                    (uint64)syscallCount[i], syscallName[i]);
      }
   }
}

/*****************************************************************
 * PrintCP0Stats
 * 
 *****************************************************************/
static void
PrintCP0Stats(void)
{
#ifndef SOLO
   int cpuNum, j;

   CPUPrint("********************\n");
   CPUPrint("CP0 statistics\n");
   CPUPrint("********************\n");

   CPUPrint("SOLO doesn't keep CP0 stats\n");
   for (cpuNum=0; cpuNum<TOTAL_CPUS; cpuNum++) {
      for (j=0; j<MAX_CAUSE; j++) {
         CPUPrint("M-EXC %d %lld %s\n", cpuNum, 
                  (uint64)STATS_VALUE(cpuNum, causeCount[j]), causeName[j]);
      }
      CPUPrint("M-EXC UTLB_RMISS %lld\n", (uint64)STATS_VALUE(cpuNum, utlbCount[2]));
      CPUPrint("M-EXC UTLB_WMISS %lld\n", (uint64)STATS_VALUE(cpuNum, utlbCount[3]));
   }
#endif
}



void PrintAllCPUStats(void)
{
   PrintCPUStats();
   PrintSyscallStats();
   PrintCP0Stats();

}