16 #include <unordered_set>
18 #include <unordered_map>
21 #include <sys/resource.h>
29 PIN_ERROR(
"Pin tool to gather calling context on each load and store.\n" + KNOB_BASE::StringKnobSummary() +
"\n");
37 #define CACHE_LINE_BITS (6)
38 #define CACHE_INDEX_BITS (20)
39 #define CACHE_SZ (1L << (CACHE_LINE_BITS + CACHE_INDEX_BITS))
40 #define CACHE_LINE_SZ (1L << CACHE_LINE_BITS)
41 #define CACHE_LINE_MASK (CACHE_LINE_SZ - 1)
42 #define CACHE_LINE_BASE(addr) ((size_t)(addr) & (~CACHE_LINE_MASK))
44 #define CACHE_NUM_LINES (CACHE_SZ / CACHE_LINE_SZ)
45 #define CACHE_TAG_MASK (~CACHE_LINE_MASK)
46 #define CACHE_TAG(address) (((size_t)address) & CACHE_TAG_MASK)
47 #define CACHE_LINE_INDEX(address) (((size_t)(address) & (CACHE_SZ - 1)) >> CACHE_LINE_BITS)
48 #define IS_VALID(address) (cache[CACHE_LINE_INDEX(((size_t)address))].isInUse && (cache[CACHE_LINE_INDEX(((size_t)address))].tag == CACHE_TAG(((size_t)address))))
49 #define SET_TAG(address) (cache[CACHE_LINE_INDEX(((size_t)address))].tag = CACHE_TAG(address))
50 #define SET_INUSE(address) (cache[CACHE_LINE_INDEX(((size_t)address))].isInUse = true)
51 #define GET_TAG(address) (cache[CACHE_LINE_INDEX(((size_t)address))].tag)
52 #define WAS_DIFFERENT(address) (cache[CACHE_LINE_INDEX(((size_t)address))].wasDifferent)
55 #define MAX_WRITE_OP_LENGTH (512)
56 #define MAX_WRITE_OPS_IN_INS (8)
66 : tag(0), isDirty(false), isInUse(false), wasDifferent(false) {}
75 : sameData(0), evicts(0), unchanged(0), dirtyEvicts(0) {}
127 uint64_t
address = (uint64_t)addr;
135 bool isRedundant =
true;
137 if (originalVal[i] != curValue[i]) {
156 originalVal[i] = newValue[i];
191 #define MAX_FILE_PATH (1000)
197 char* envPath = getenv(
"CACHE_CLIENT_OUTPUT_FILE");
201 snprintf(name,
sizeof(name),
"%s", envPath);
204 gethostname(name + strlen(name),
MAX_FILE_PATH - strlen(name));
205 pid_t pid = getpid();
206 sprintf(name + strlen(name),
"%d", pid);
207 cerr <<
"\n Creating log file at:" << name <<
"\n";
215 for (
int i = 0; i < argc; i++) {
224 template <u
int16_t AccessLen, u
int32_t bufferOffset>
226 static __attribute__((always_inline))
bool IsPartialWriteRedundant(
size_t startOffset,
size_t length, THREADID threadId) {
232 static __attribute__((always_inline))
bool IsWriteRedundant(
void*& addr, THREADID threadId) {
238 return *((uint8_t*)(&avPair->
value)) == *(
static_cast<uint8_t*
>(avPair->
address));
240 return *((uint16_t*)(&avPair->
value)) == *(
static_cast<uint16_t*
>(avPair->
address));
242 return *((uint32_t*)(&avPair->
value)) == *(
static_cast<uint32_t*
>(avPair->
address));
244 return *((uint64_t*)(&avPair->
value)) == *(
static_cast<uint64_t*
>(avPair->
address));
246 return memcmp(&avPair->
value, avPair->
address, AccessLen) == 0;
249 static __attribute__((always_inline)) VOID RecordNByteValueBeforeWrite(
void* addr, THREADID threadId) {
255 *((uint8_t*)(&avPair->
value)) = *(
static_cast<uint8_t*
>(addr));
258 *((uint16_t*)(&avPair->
value)) = *(
static_cast<uint16_t*
>(addr));
261 *((uint32_t*)(&avPair->
value)) = *(
static_cast<uint32_t*
>(addr));
264 *((uint64_t*)(&avPair->
value)) = *(
static_cast<uint64_t*
>(addr));
267 memcpy(&avPair->
value, addr, AccessLen);
270 static __attribute__((always_inline)) VOID CheckNByteValueAfterWrite(THREADID threadId) {
273 bool isRedundantWrite = IsWriteRedundant(addr, threadId);
274 if (isRedundantWrite) {
279 if (isSameCacheLine) {
284 size_t firstCacheLineStart = 0;
285 size_t lastCacheLineAccessLength = (
size_t)addr + AccessLen -
CACHE_LINE_BASE((
size_t)addr + AccessLen - 1);
288 if ((!
WAS_DIFFERENT(addr)) && IsPartialWriteRedundant(firstCacheLineStart, firstCacheLineAccessLength, threadId)) {
291 if ((!
WAS_DIFFERENT(addr + AccessLen - 1)) && IsPartialWriteRedundant(lastCacheLineStart, lastCacheLineAccessLength, threadId)) {
294 for (
size_t startOffset = firstCacheLineAccessLength; startOffset < lastCacheLineStart; startOffset +=
CACHE_LINE_SZ) {
314 memcpy(&(tData->
buffer[bufferOffset].
value), addr, accessLen);
321 if (memcmp(tData->
buffer[bufferOffset].
value, (
void*)addr, accessLen) == 0) {
325 size_t firstCacheLineStart = 0;
326 size_t lastCacheLineAccessLength = addr + accessLen -
CACHE_LINE_BASE((
size_t)(addr) + accessLen - 1);
327 size_t lastCacheLineStart =
CACHE_LINE_BASE((
size_t)(addr) + accessLen - 1) - addr;
329 if ((!
WAS_DIFFERENT(addr)) && (0 == memcmp((
void*)(tData->
buffer[bufferOffset].
value + firstCacheLineStart), (
void*)(addr + firstCacheLineStart), firstCacheLineAccessLength))) {
332 if ((!
WAS_DIFFERENT(addr + accessLen - 1)) && (0 == memcmp((
void*)(tData->
buffer[bufferOffset].
value + lastCacheLineStart), (
void*)(addr + lastCacheLineStart), lastCacheLineAccessLength))) {
335 for (
size_t startOffset = firstCacheLineAccessLength; startOffset < lastCacheLineStart; startOffset +=
CACHE_LINE_SZ) {
341 #define HANDLE_CASE(NUM, BUFFER_INDEX, HAS_FALLTHRU) \
343 INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)RedSpyAnalysis<(NUM), (BUFFER_INDEX)>::RecordNByteValueBeforeWrite, IARG_MEMORYOP_EA, memOp, IARG_THREAD_ID, IARG_END); \
344 INS_InsertPredicatedCall(ins, HAS_FALLTHRU ? IPOINT_AFTER : IPOINT_TAKEN_BRANCH, (AFUNPTR)RedSpyAnalysis<(NUM), (BUFFER_INDEX)>::CheckNByteValueAfterWrite, IARG_THREAD_ID, IARG_INST_PTR, IARG_END); \
347 #define HANDLE_LARGE(HAS_FALLTHRU) \
348 INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)RecordValueBeforeLargeWrite, IARG_MEMORYOP_EA, memOp, IARG_MEMORYWRITE_SIZE, IARG_UINT32, readBufferSlotIndex, IARG_THREAD_ID, IARG_END); \
349 INS_InsertPredicatedCall(ins, HAS_FALLTHRU ? IPOINT_AFTER : IPOINT_TAKEN_BRANCH, (AFUNPTR)CheckAfterLargeWrite, IARG_MEMORYREAD_SIZE, IARG_UINT32, readBufferSlotIndex, IARG_THREAD_ID, IARG_END)
353 UINT32 memOperands = INS_MemoryOperandCount(ins);
354 for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
355 if (INS_MemoryOperandIsWritten(ins, memOp)) {
364 template <u
int32_t readBufferSlotIndex>
366 static __attribute__((always_inline))
void InstrumentReadValueBeforeAndAfterWriting(INS ins, UINT32 memOp,
bool hasFallThru) {
367 UINT32 refSize = INS_MemoryOperandSize(ins, memOp);
384 UINT32 memOperands = INS_MemoryOperandCount(ins);
385 if (memOperands == 0)
388 for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
389 if (INS_MemoryOperandIsWritten(ins, memOp)) {
390 INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)
OnAccess, IARG_MEMORYOP_EA, memOp, IARG_MEMORYWRITE_SIZE, IARG_BOOL, 1, IARG_END);
392 INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)
OnAccess, IARG_MEMORYOP_EA, memOp, IARG_MEMORYREAD_SIZE, IARG_BOOL, 0, IARG_END);
398 bool hasFallThu = INS_HasFallThrough(ins);
408 UINT32 memOperands = INS_MemoryOperandCount(ins);
410 int readBufferSlotIndex = 0;
412 for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
413 if (!INS_MemoryOperandIsWritten(ins, memOp))
415 switch (readBufferSlotIndex) {
441 readBufferSlotIndex++;
448 getrusage(RUSAGE_SELF, &u);
449 return (
size_t)(u.ru_maxrss);
454 fprintf(
gTraceFile,
"\n Total evict=%lu, dirtyEvicts=%lu, redundant=%lu, unchanged=%lu, waste=%f, cacheFixable=%f, Peak RSS=%zu\n",
stats.
evicts,
stats.
dirtyEvicts,
stats.
sameData,
stats.
unchanged, 100.0 *
stats.
sameData /
stats.
dirtyEvicts, 100.0 *
stats.
unchanged /
stats.
dirtyEvicts,
getPeakRSS());
462 static void HandleSysCall(THREADID threadIndex, CONTEXT* ctxt, SYSCALL_STANDARD std, VOID* v) {
467 inline VOID
Update(uint32_t bytes, THREADID threadId) {
474 for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
475 uint32_t totBytes = 0;
476 for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) {
477 if (INS_IsMemoryWrite(ins)) {
481 BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)
Update, IARG_UINT32, totBytes, IARG_THREAD_ID, IARG_END);
486 static VOID
ThreadFiniFunc(THREADID threadId,
const CONTEXT* ctxt, INT32 code, VOID* v) {
499 #ifdef MULTI_THREADED
506 int main(
int argc,
char* argv[]) {
508 if (PIN_Init(argc, argv))
532 PIN_AddFiniFunction(
FiniFunc,
nullptr);
#define MAX_WRITE_OP_LENGTH
static void HandleOneCacheLine(void **address, bool isWrite)
static void ClientInit(int argc, char *argv[])
int main(int argc, char *argv[])
static VOID ImageUnload(IMG img, VOID *v)
thread_local Stats_t stats
static RedSpyThreadData * gSingleThreadedTData
#define CACHE_LINE_INDEX(address)
thread_local Cache_t cache[CACHE_NUM_LINES]
#define MAX_WRITE_OPS_IN_INS
static VOID InstrumentInsCallback(INS ins, VOID *v)
static void OnEvict(void **addr)
#define HANDLE_CASE(NUM, BUFFER_INDEX, HAS_FALLTHRU)
static void HandleSysCall(THREADID threadIndex, CONTEXT *ctxt, SYSCALL_STANDARD std, VOID *v)
#define WAS_DIFFERENT(address)
VOID Update(uint32_t bytes, THREADID threadId)
static VOID RecordValueBeforeLargeWrite(void *addr, UINT32 accessLen, uint32_t bufferOffset, THREADID threadId)
static void OnAccess(void **address, uint64_t accessLen, bool isWrite)
static VOID ThreadFiniFunc(THREADID threadId, const CONTEXT *ctxt, INT32 code, VOID *v)
static void InstrumentTrace(TRACE trace, void *f)
static void InitThreadData(RedSpyThreadData *tdata)
RedSpyThreadData * ClientGetTLS(const THREADID threadId)
static VOID FiniFunc(INT32 code, VOID *v)
#define IS_VALID(address)
static int GetNumWriteOperandsInIns(INS ins, UINT32 &whichOp)
#define SET_INUSE(address)
#define HANDLE_LARGE(HAS_FALLTHRU)
static TLS_KEY client_tls_key
static VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
static VOID CheckAfterLargeWrite(UINT32 accessLen, uint32_t bufferOffset, THREADID threadId)
#define CACHE_LINE_BASE(addr)
hpcrun_metricFlags_t flags
static USIZE INS_MemoryWriteSize(INS ins)
uint8_t value[MAX_WRITE_OP_LENGTH]
uint8_t value[MAX_WRITE_OP_LENGTH]
uint8_t value[CACHE_LINE_SZ]
return memcmp(avPair->value+startOffset,(void **)(avPair->address)+startOffset, length)
static __attribute__((always_inline)) bool IsWriteRedundant(void *&addr
static __attribute__((always_inline)) bool IsPartialWriteRedundant(size_t startOffset
static __attribute__((always_inline)) VOID CheckNByteValueAfterWrite(THREADID threadId)
static __attribute__((always_inline)) VOID RecordNByteValueBeforeWrite(void *addr
static __attribute__((always_inline)) void InstrumentReadValueBeforeAndAfterWriting(INS ins
AddrValPair buffer[MAX_WRITE_OPS_IN_INS]