false_sharing.c 10.5 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. 
 *
 */

/***********************************************************************
 * false_sharing.c
 * Cache interface that determines true and false sharing.
 * 
 * $Author: blythe $
 * $Date: 2002/05/29 01:09:09 $
 *
 * XXX bug: scales with TOTAL_CPUS, which is bad
 * XXX      for multiple machines (although theoretically correct)
 * XXX bug: sparse address space not really supported
 ***********************************************************************/

#include <stdlib.h>
#include "string.h"
#include "sim_error.h"
#include "cpu_interface.h"
#include "simutil.h"
#include "machine_params.h"
#include "false_sharing.h"
#include "memstat.h"
#include "statrecord.h"
#include "tcl_init.h"
#include "arch_specifics.h"


FalseSharingBV *falseSharingMaskEntries[MAX_MACHINES];
uint falseSharingMask;
bool falseSharing;

static FalseSharingEntry *falseSharingAccessed[MAX_MACHINES][SIM_MAXCPUS];
static FalseSharingBV *falseSharingModifyWords;
static MA startMA;
static MA endMA;

static struct {
   StatRecordFieldDesc falseSharing[NUM_CATEGS];
   StatRecordFieldDesc trueSharing[NUM_CATEGS];
   StatRecordFieldDesc falseSharingStall[NUM_CATEGS];
   StatRecordFieldDesc trueSharingStall[NUM_CATEGS];
} falseSharingBucket;

#define PADDR_TO_INDEX(_pa,_way) \
 (((_pa>>log2SCACHE_LINE_SIZE) & (SCACHE_INDEX-1))*SCACHE_ASSOC + _way)


#ifdef TRACK_FALSE_SHARING
int FalseSharing = 1;
#else
int FalseSharing = 0;
#endif

extern int memstatOption;

/*****************************************************************
 * FalseSharingInit
 *****************************************************************/

void FalseSharingEarlyInit(void)
{
   if (FalseSharing) { 
      if (memstatOption == 0) {
         CPUWarning("\n\nFALSE SHARING: requires MemStat enabled (Level != None)\n\n");
         return;
      }
      MemStatInitCategoryFields(falseSharingBucket.trueSharing, "trueSharing", 
                                STATRECORD_DATA|STATRECORD_INSTRUCTION);
      MemStatInitCategoryFields(falseSharingBucket.falseSharing, "falseSharing", 
                                STATRECORD_DATA|STATRECORD_INSTRUCTION);
      MemStatInitCategoryFields(falseSharingBucket.trueSharingStall, "trueShStall", 
                                STATRECORD_DATA|STATRECORD_INSTRUCTION);
      MemStatInitCategoryFields(falseSharingBucket.falseSharingStall, "falseShStall", 
                                STATRECORD_DATA|STATRECORD_INSTRUCTION);
      falseSharing = 1;
   }
}
    
void 
FalseSharingLateInit(void)
{
   int machine;
   int i;
   int scacheLine   = SCACHE_LINE_SIZE;
   int scacheSize   = SCACHE_SIZE;
   int shift;
   long totalMemSize = 0;

   if (!falseSharing) { 
      return;  
   }
   CPUWarning("FALSE SHARING: initialized\n");
   falseSharingMask = scacheLine -1;
   
   if (scacheLine > 4* 8 * sizeof(FalseSharingBV)) {
      shift = GetLog2(scacheLine / (8 * sizeof(FalseSharingBV)));
   } else {
      shift = 2; /* word granularity */
   }
   ASSERT(TOTAL_CPUS && NUM_MACHINES);

   for (machine = 0; machine < NUM_MACHINES; machine++) {
      ASSERT(MEM_SIZE(machine));
      totalMemSize += MEM_SIZE(machine);
      
      falseSharingMaskEntries[machine] = 
         (FalseSharingBV *) ZALLOC_PERM(scacheLine* sizeof(FalseSharingBV),
                                        "FalseSharing");

      for (i=0; i<scacheLine; i++) {
         uint j = (i>>shift);
         ASSERT( j < 8 * sizeof(FalseSharingBV) );
         falseSharingMaskEntries[machine][i] = 1<<j;
      }
       
      for (i=0; i<NUM_CPUS(machine); i++) { 
         int j;
         falseSharingAccessed[machine][i] = 
            (FalseSharingEntry *) ZALLOC_PERM(sizeof(FalseSharingEntry) 
                                              * scacheSize / scacheLine ,"FalseSharing");
         for(j=0;j< scacheSize / scacheLine; j++) {
            falseSharingAccessed[machine][i][j].categ = -1;
         }
      }
   }
   falseSharingModifyWords = (FalseSharingBV *)
      ZALLOC_PERM(sizeof(FalseSharingBV)*
                  (totalMemSize/scacheLine) *
                  TOTAL_CPUS,
                  "FalseSharing");

   ASSERT(falseSharingModifyWords);

   startMA = PHYS_TO_MEMADDR(0,0);
   endMA   = startMA + totalMemSize;
   ASSERT(startMA);

}

/*****************************************************************
 * SCacheLineToFalseSharing
 *****************************************************************/
FalseSharingEntry *
SCacheLineToFalseSharing(int cpuNum, PA pAddr, int way) 
{
   uint index = PADDR_TO_INDEX(pAddr,way);
   if (!falseSharing) { 
      return 0;
   } else { 
      return (falseSharingAccessed[M_FROM_CPU(cpuNum)]
              [MCPU_FROM_CPU(cpuNum)]) + index ;
   }
}

/*****************************************************************
 * FalseSharingDefine
 *****************************************************************/
void 
FalseSharingDefine(int cpuNum, PA pAddr, int way, VA PC, VA vAddr, int stall)
{
   uint index;
   FalseSharingEntry *e;
   if( !falseSharing ) { return; }
   index = PADDR_TO_INDEX(pAddr,way);
   if( interest(pAddr)) {
      LogEntry("def", cpuNum,"pA=0x%08x index=0x%06x way=%i \n",pAddr,index,way);
   }
   e = (falseSharingAccessed[M_FROM_CPU(cpuNum)]
        [MCPU_FROM_CPU(cpuNum)])+index;

   ASSERT (!e->valid);
#ifndef SIM_ALPHA
   ASSERT (vAddr);
#endif
   e->valid = 1;
   e->PC = PC;
   e->vAddr = vAddr;
   e->pAddr = pAddr;
   e->stall = stall;
   e->snap = StatRecordAllocSnapshot(cpuNum);
   e->accessedWords = 0;  /* clear bit vector */
   e->categ = -1;
}

/*****************************************************************
 * FalseSharingDefineOffset
 *****************************************************************/
void 
FalseSharingDefineOffset(int cpuNum, PA pAddr,int way, int categ)
{
   uint index;
   FalseSharingEntry *e;
   if( !falseSharing ) { return; }
   index = PADDR_TO_INDEX(pAddr,way);
   e = (falseSharingAccessed[M_FROM_CPU(cpuNum)]
        [MCPU_FROM_CPU(cpuNum)])+index;

   ASSERT (e->valid);
   ASSERT( e->categ < 0 );
   ASSERT( categ >= 0 && categ < NUM_CATEGS);
   ASSERT (pAddr>>log2SCACHE_LINE_SIZE == e->pAddr>>log2SCACHE_LINE_SIZE);
   e->categ = categ;
}

/*****************************************************************
 * FalseSharingEvict
 *****************************************************************/
void 
FalseSharingEvict(int cpuNum, PA pAddr, int way, int type)
{
   int machine = M_FROM_CPU(cpuNum);
   MA mAddr    = PHYS_TO_MEMADDR(machine,pAddr);
   PA mAddrOff = (PA)(mAddr-startMA);

   uint index;
   FalseSharingEntry *e;
   FalseSharingBV *modifiedBV;

   if (!falseSharing) { 
      return; 
   }
   ASSERT( startMA <= mAddr && mAddr < endMA);
   ASSERT(mAddrOff >= 0);

   index = PADDR_TO_INDEX(pAddr,way);
   e = (falseSharingAccessed[machine][MCPU_FROM_CPU(cpuNum)])+index;
   if( interest(pAddr)) {
      LogEntry("evict", cpuNum,"pA=0x%08x index=0x%06x way=%i \n",pAddr,index,way);
   }
   /* now we know if it is true or false sharing */
   if( !e->valid ) {
      ASSERT (e->categ < 0);
      /* 
       *miss was not recorded. 
       *Most likely an instruction miss on that line.
       */
      return;
   }
   if (pAddr>>log2SCACHE_LINE_SIZE != e->pAddr>>log2SCACHE_LINE_SIZE) {
      LogEntry("FALSESH",cpuNum,"pAddr missmatched %x != %x type=%x \n",
               pAddr,e->pAddr,type);
      return;
   }
   ASSERT(e->categ >= 0);
   modifiedBV = &falseSharingModifyWords[((mAddrOff>>log2SCACHE_LINE_SIZE)*TOTAL_CPUS) + cpuNum];

   if (e->accessedWords & *modifiedBV) { 
      /* true sharing */
      StatRecordIncrement(e->snap, e->PC, e->vAddr, 
                          falseSharingBucket.trueSharing[e->categ],1);
      StatRecordIncrement(e->snap, e->PC, e->vAddr, 
                          falseSharingBucket.trueSharingStall[e->categ],
                          e->stall);
      
      *modifiedBV = 0;
   } else { 
      StatRecordIncrement(e->snap, e->PC, e->vAddr, 
                          falseSharingBucket.falseSharing[e->categ],1);
        StatRecordIncrement(e->snap, e->PC, e->vAddr,
                          falseSharingBucket.falseSharingStall[e->categ],
                          e->stall);
   }  
   StatRecordFreeSnapshot(e->snap);
   e->vAddr = 0;
   e->valid = 0;
   e->categ = -1;
}

/*****************************************************************
 * FalseSharingModify
 *****************************************************************/
void 
FalseSharingModify(int cpuNum, PA pAddr)
{
   int machine = M_FROM_CPU(cpuNum);
   MA mAddr = PHYS_TO_MEMADDR(cpuNum,pAddr);
   PA mAddrOff = (PA)(mAddr-startMA);

   FalseSharingBV *modifiedBV;
   FalseSharingBV mask;
   int i;
   
   if (!falseSharing) { 
      return; 
   }
   ASSERT(startMA <= mAddr && mAddr < endMA);

   modifiedBV = &falseSharingModifyWords[(mAddrOff>>log2SCACHE_LINE_SIZE) * TOTAL_CPUS];
   mask = falseSharingMaskEntries[machine][pAddr&falseSharingMask];
   
   for(i=0;i<TOTAL_CPUS;i++){
      if (i != cpuNum) {
         *modifiedBV |= mask;
         
      }
      modifiedBV++;
   }
}
   
/*****************************************************************
 * FalseSharingModify
 * Called when the simulation ends. All true sharing misses
 * are classified as such. 
 *****************************************************************/

void FalseSharingCleanup(void)
{
   int lines;
   int cpuNum;
   int index;
   int count=0;

   if (!falseSharing) return;
   ASSERT (SCACHE_SIZE && SCACHE_LINE_SIZE);
   lines = SCACHE_SIZE / SCACHE_LINE_SIZE;
   for(cpuNum=0; cpuNum < TOTAL_CPUS;cpuNum++) {
      int machine = M_FROM_CPU(cpuNum);
      for(index=0;index < lines; index++){ 
         FalseSharingEntry *e =
             (falseSharingAccessed[machine][MCPU_FROM_CPU(cpuNum)])+index;
         FalseSharingBV *modifiedBV = 
            &falseSharingModifyWords[index*TOTAL_CPUS + cpuNum];
         
         if( !e->valid ) continue;
         ASSERT(e->categ >= 0);
         if (e->accessedWords & *modifiedBV) { 
            /* true sharing */
            count++;
            StatRecordIncrement(e->snap, e->PC, e->vAddr, 
                                falseSharingBucket.trueSharing[e->categ],1);
            StatRecordIncrement(e->snap, e->PC, e->vAddr, 
                                falseSharingBucket.trueSharingStall[e->categ],
                                e->stall);
             *modifiedBV = 0;
            StatRecordFreeSnapshot(e->snap);
            e->vAddr = 0;
            e->valid = 0;
            e->categ = -1;
         }
      }
   }
   CPUWarning("FALSE SHARING CLEANUP : %d true sharings  detected \n",count);
}