simrecord.c 6.99 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. 
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#ifdef SGI
#include <bstrings.h>
#endif
#include <strings.h>

#include "simrecord.h"
#include "sim_error.h"
#include "simutil.h"
#include "cpu_interface.h"


#define LOW_RES_INDEX(_a)  (_a >>recPtr->log2LowRes)
#define HIGH_RES_INDEX(_a) ((_a&(recPtr->lowRes-1))>>recPtr->log2HighRes)

typedef char Bucket;

typedef struct SimRecord {
   int bucketSize;
   long highRes;
   long lowRes;
   int log2HighRes;
   int log2LowRes;
   
   Bucket ***firstLevelArray; 
   char *isHighRes;
   Bucket *lowResBuckets;
   long lowResEntries, highResEntries;
   VA lastAddr;
   Bucket * lastBucket;
   Bucket *outOfRange;
   char tableName[32];
} SimRecord;

#ifdef SIM_ALPHA
int VASizeLog2 = 44;
#else
int VASizeLog2 = 32;
#endif


SimRec 
SimRecTableInit(char *tableName, int bucketSize, 
		long lowRes, 
		long highRes) 
{
   SimRecord *recPtr;


#ifndef __alpha
   if (sizeof(VA)!=4) {
      CPUError("ByPC/ByDdata tables only implemented for 32-bit address spaces\n");
      return 0;
   }
#endif

   recPtr = (struct SimRecord *) ZMALLOC(sizeof(struct SimRecord),"SimRecTable" );
   recPtr->bucketSize = bucketSize;
   strncpy(recPtr->tableName,tableName,sizeof(recPtr->tableName)-1);
   recPtr->lowRes = lowRes;
   recPtr->highRes = highRes;
   recPtr->log2LowRes = GetLog2(lowRes);
   recPtr->log2HighRes = GetLog2(highRes);


   /*
    * data structure sizes 
    */
   recPtr->lowResEntries = 1<<(VASizeLog2-recPtr->log2LowRes);
   recPtr->highResEntries = recPtr->lowRes /  recPtr->highRes;
   
   /*
    * allocation
    */
   recPtr->firstLevelArray = (char ***)
      ZMALLOC(recPtr->lowResEntries*sizeof(void *),"SimRecord");
   recPtr->outOfRange = ZMALLOC( bucketSize,"SimRecord");
   recPtr->isHighRes = 
      ZMALLOC(recPtr->lowResEntries ,"SimRecord" );
   recPtr->lowResBuckets =  
      ZMALLOC( bucketSize*recPtr->lowResEntries,"SimRecord::LowRes");
   return recPtr; 
}  


void
SimRecAddHighResRange(SimRec recPtr, VA  addr, unsigned long size) 
{
   int a;
   VA endAddr = addr + size - 1;
   
   for(a=LOW_RES_INDEX(addr);a<=LOW_RES_INDEX(endAddr);++a) {
      CPUWarning("SimRec: detail 0x%08lx 0x%08lx at %d\n", (Reg64)addr,size,a);
      recPtr->isHighRes[a] = 1;
   }
}



void *
SimRecBucketAddr(SimRec recPtr, VA addr)
{
   Bucket **firstLevelPtr;
   Bucket *bucketPtr;
   unsigned long long lowInd,highInd;
   
   /* 
    * align
    */
   addr = addr & ~(recPtr->highRes-1);
   
   /* 
    * cache last translation 
    */
   if( addr == recPtr->lastAddr ) { 
      return recPtr->lastBucket;
   }
   recPtr->lastAddr = addr;
   
   /* 
    * low res
    */
   lowInd = LOW_RES_INDEX(addr);
   ASSERT( lowInd < recPtr->lowResEntries);
   if (!recPtr->isHighRes[lowInd]) {
      recPtr->lastBucket = recPtr->lowResBuckets + 
         (lowInd * recPtr->bucketSize);
      return recPtr->lastBucket;
   } 

   /*
    * high Res
    */
   firstLevelPtr = recPtr->firstLevelArray[lowInd];
   if( !firstLevelPtr ) { 
      recPtr->firstLevelArray[lowInd] = (Bucket **)
          ZMALLOC(recPtr->highResEntries * sizeof(void*),"SimRecord");
      firstLevelPtr = recPtr->firstLevelArray[lowInd];
   }
   highInd = HIGH_RES_INDEX(addr);
   ASSERT( highInd < recPtr->highResEntries );
   
   bucketPtr = firstLevelPtr[highInd];
   if( !bucketPtr ) { 
      firstLevelPtr[highInd] = 
         ZMALLOC(recPtr->bucketSize,"SimRecord");
      bucketPtr = firstLevelPtr[highInd];
   }
   recPtr->lastBucket = bucketPtr;
   return  bucketPtr;
}
   

int
SimRecDump(SimRec recPtr, int fd, int entrySize, char *fieldNames, int reset)
{
   int len;
   uint a,b,start;
   SimRecHeader hdr;
   uint startEnd[2];
   unsigned long long lowInd, highInd;
   Bucket **firstLevelPtr;

   bzero((char *) &hdr, sizeof(hdr));
   hdr.magic = SIMREC_MAGIC;
   hdr.version = 6;
   strncpy(hdr.tableName, recPtr->tableName, sizeof(hdr.tableName)-1);
   hdr.addrStart = 0;
   hdr.lowRes = recPtr->lowRes;
   hdr.highRes = recPtr->highRes;
   hdr.bucketSize = recPtr->bucketSize;
   hdr.entrySize = entrySize;
   hdr.fieldNamesLen = strlen(fieldNames)+1;

   if (write(fd, (char *) &hdr, sizeof(hdr)) != sizeof(hdr)) {
      goto err;
   }
   if (write(fd,fieldNames,hdr.fieldNamesLen) != hdr.fieldNamesLen ) {
      goto err;
   }

   /*
    *  lowRes 
    */
   
   len = recPtr->lowResEntries * recPtr->bucketSize;
   if (write(fd, recPtr->lowResBuckets, len) != len) {
      goto err;
   }
   if (reset) {
      bzero(recPtr->lowResBuckets, len);
   }
  
   /* out of bounds */
   len = recPtr->bucketSize;
   if (write(fd, recPtr->outOfRange, len) != len) {
      goto err;
   }
   if (reset) {
      bzero(recPtr->outOfRange, len);
   }

   /* 
    *  high Res
    */

   for (lowInd=0;lowInd<recPtr->lowResEntries;lowInd++) {
      a = lowInd * recPtr->lowRes;
      if( !recPtr->isHighRes[lowInd] ) 
         continue;
      firstLevelPtr = recPtr->firstLevelArray[lowInd];
      if( !firstLevelPtr ) 
         continue;
      
      /*
       * iterate over 1 low res range
       */
      b = a;
      while( b < a + recPtr->lowRes ) {
         int count;
         /*
          * skip over empty entries
          */
         while( b < a + recPtr->lowRes ) {
            highInd = HIGH_RES_INDEX(b);
            if( firstLevelPtr[highInd] ) 
               break;
            b+= recPtr->highRes;
         }
         start = b;
         while( b < a + recPtr->lowRes ) { 
            highInd = HIGH_RES_INDEX(b);
            if( !firstLevelPtr[highInd] ) 
               break; 
            b += recPtr->highRes;
         }
         /*
          * now write buckets from start to b
          */
         startEnd[0] = start;
         startEnd[1] = (b - start) >>recPtr->log2HighRes;
         if( write(fd,startEnd,2*sizeof(int)) != 2*sizeof(int) ) 
            goto err;
         count = 0;
         while( start < b ) {
            highInd = HIGH_RES_INDEX(start);
            ASSERT( firstLevelPtr[highInd]);
            if( write(fd,firstLevelPtr[highInd],recPtr->bucketSize) !=
                recPtr->bucketSize) {
               goto err;
            }
            if (reset) {
               free(firstLevelPtr[highInd]);
               firstLevelPtr[highInd] = NULL;
            }
            count++;
            start  += recPtr->highRes;
         }
         ASSERT( count == startEnd[1]);
      }
   }
   /*
    * write trailer information
    */
   startEnd[0] = 0;
   startEnd[1] = 0;
   if( write(fd,startEnd,2*sizeof(int) )!=2*sizeof(int) )
      goto err;
   return 0;	
 
  err:
   CPUWarning("SimRecord: memstat write failed at cycleCount = %lld\n",
              (uint64)CPUVec.CycleCount(0));
   close(fd);
   return 1;
   
} 


void SimRecReset(SimRec recPtr)
{
   CPUWarning("SimRecReset is not implemented. Counters are not set to 0\n");
		   
}