CCTLib
Calling-context and data-object attribution library for Intel Pin
cache_client.cpp
Go to the documentation of this file.
1 // @COPYRIGHT@
2 // Licensed under MIT license.
3 // See LICENSE.TXT file in the project root for more information.
4 // ==============================================================
5 
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <iostream>
10 #include <unistd.h>
11 #include <assert.h>
12 #include <string.h>
13 #include <sys/mman.h>
14 #include <sstream>
15 #include <functional>
16 #include <unordered_set>
17 #include <vector>
18 #include <unordered_map>
19 #include <algorithm>
20 #include <sys/time.h>
21 #include <sys/resource.h>
22 #include "pin.H"
23 // Compat shims for Pin 4.x APIs (INS_MemoryWriteSize is a Pin 3.x name that
24 // was removed; the shim reimplements it via INS_MemoryOperandSize loops).
25 #include "pin_isa_compat.H"
26 using namespace std;
27 
28 static INT32 Usage() {
29  PIN_ERROR("Pin tool to gather calling context on each load and store.\n" + KNOB_BASE::StringKnobSummary() + "\n");
30  return -1;
31 }
32 
33 // Main for RedSpy, initialize the tool, register instrumentation functions and call the target program.
34 static FILE* gTraceFile;
35 
36 
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))
43 
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)
53 
54 
55 #define MAX_WRITE_OP_LENGTH (512)
56 #define MAX_WRITE_OPS_IN_INS (8)
57 
58 
59 struct Cache_t {
60  size_t tag;
61  bool isDirty;
62  bool isInUse;
64  uint8_t value[CACHE_LINE_SZ];
66  : tag(0), isDirty(false), isInUse(false), wasDifferent(false) {}
67 };
68 
69 struct Stats_t {
70  uint64_t sameData;
71  uint64_t evicts;
72  uint64_t unchanged;
73  uint64_t dirtyEvicts;
75  : sameData(0), evicts(0), unchanged(0), dirtyEvicts(0) {}
76 };
77 
78 struct AddrValPair {
79  void* address;
81 };
82 
85  uint64_t bytesWritten;
86  uint64_t bytesRedundant;
87 };
88 
89 static TLS_KEY client_tls_key;
91 
92 // function to access thread-specific data
93 inline RedSpyThreadData* ClientGetTLS(const THREADID threadId) {
94 #ifdef MULTI_THREADED
95  RedSpyThreadData* tdata =
96  static_cast<RedSpyThreadData*>(PIN_GetThreadData(client_tls_key, threadId));
97  return tdata;
98 #else
99  return gSingleThreadedTData;
100 #endif
101 }
102 
103 
104 // TODO(preexisting-bug): these two arrays are ~80 MB per thread at
105 // CACHE_INDEX_BITS=20. Pin 4.x's libc++ TLS descriptor cannot hold objects
106 // this large; the tool CRASHES at ThreadStart under Pin 4.x when the TLS
107 // slot is materialized. Proper fix: allocate cache/stats on the heap in
108 // InitThreadData, hang them off RedSpyThreadData (already Pin-TLS-managed
109 // via client_tls_key), and update the IS_VALID/SET_TAG/WAS_DIFFERENT macros
110 // (or their callers) to reach through tData. Do NOT replace with file-scope
111 // globals — that would introduce a real data race on every access. See
112 // git history for the full refactor sketch.
113 thread_local Stats_t stats;
114 
115 
117 
118 
119 void CacheFlush() {
120 #pragma omp simd
121  for (int i = 0; i < CACHE_NUM_LINES; i++) {
122  cache[i].isInUse = false;
123  }
124 }
125 
126 static inline void OnEvict(void** addr) {
127  uint64_t address = (uint64_t)addr;
128  uint8_t* newValue = (uint8_t*)(address & (~CACHE_LINE_MASK));
129  uint8_t* originalVal = cache[CACHE_LINE_INDEX(address)].value;
130  bool isDirty = cache[CACHE_LINE_INDEX(address)].isDirty;
131  uint8_t* curValue = (uint8_t*)(GET_TAG(address));
132 
133  if (isDirty && cache[CACHE_LINE_INDEX(((size_t)address))].isInUse) {
134  // fprintf(stderr, "\n E: address=%lx, newValue=%p, originalVal=%p, curValue=%p, idx=%lx, tag=%lx\n", address, newValue, originalVal, curValue, CACHE_LINE_INDEX(address), GET_TAG(address));
135  bool isRedundant = true;
136  for (int i = 0; i < CACHE_LINE_SZ; i++) {
137  if (originalVal[i] != curValue[i]) {
138  isRedundant = false;
139  break;
140  }
141  }
142 
143  if (!WAS_DIFFERENT(address)) {
144  stats.unchanged++;
145  }
146  if (isRedundant) {
147  stats.sameData++;
148  }
150  stats.dirtyEvicts++;
151  } else {
152  // fprintf(stderr, "\n X: address=%lx, newValue=%p, originalVal=%p, curValue=%p, idx=%lx, tag=%lx\n", address, newValue, originalVal, curValue, CACHE_LINE_INDEX(address), GET_TAG(address));
153  }
154 #pragma omp simd
155  for (int i = 0; i < CACHE_LINE_SZ; i++) {
156  originalVal[i] = newValue[i];
157  }
158  stats.evicts++;
159  SET_TAG(address);
160  WAS_DIFFERENT(address) = false;
161 }
162 
163 static inline void HandleOneCacheLine(void** address, bool isWrite) {
164  if (!IS_VALID(address)) { // NOLINT(readability-simplify-boolean-expr) -- macro expands to (a && b); the negated invocation is the readable form.
165  // cache miss, allocate it.
166  OnEvict(address);
167  }
169  // set dirty if write
170  if (isWrite)
172 }
173 
174 static inline void OnAccess(void** address, uint64_t accessLen, bool isWrite) {
175  // Is within cache line?
176  if (CACHE_LINE_INDEX(address) == CACHE_LINE_INDEX((size_t)(address) + accessLen - 1)) {
177  HandleOneCacheLine(address, isWrite);
178  } else {
179  // TODO(preexisting-bug): `address` is void**, so `address + accessLen`
180  // and `cur += CACHE_LINE_SZ` scale by sizeof(void**)=8, running off
181  // the end of the accessed region by 8x. Under Pin 4.x this causes
182  // OnEvict to memcpy through arbitrary memory and segfault on real
183  // workloads (e.g., /bin/echo). Fix: iterate byte-accurate with
184  // `char*` (`char* end = (char*)address + accessLen; for (char* cur =
185  // (char*)address; cur < end; cur += CACHE_LINE_SZ) ...`).
186  for (void** cur = address; cur < address + accessLen; cur += CACHE_LINE_SZ) {
187  HandleOneCacheLine(cur, isWrite);
188  }
189  }
190 }
191 #define MAX_FILE_PATH (1000)
192 
193 // Initialized the needed data structures before launching the target program
194 static void ClientInit(int argc, char* argv[]) {
195  // Create output file
196  char name[MAX_FILE_PATH] = "cache.out.";
197  char* envPath = getenv("CACHE_CLIENT_OUTPUT_FILE");
198 
199  if (envPath) {
200  // assumes max of MAX_FILE_PATH
201  snprintf(name, sizeof(name), "%s", envPath);
202  }
203 
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";
208  gTraceFile = fopen(name, "w");
209  fprintf(gTraceFile, "CONFIG:\n");
210  fprintf(gTraceFile, "CACHE_SZ:%lu\n", CACHE_SZ);
211  fprintf(gTraceFile, "---------------\n");
212  // print the arguments passed
213  fprintf(gTraceFile, "\n");
214 
215  for (int i = 0; i < argc; i++) {
216  fprintf(gTraceFile, "%s ", argv[i]);
217  }
218 
219  fprintf(gTraceFile, "\n");
220  fflush(gTraceFile);
221 }
222 
223 
224 template <uint16_t AccessLen, uint32_t bufferOffset>
226  static __attribute__((always_inline)) bool IsPartialWriteRedundant(size_t startOffset, size_t length, THREADID threadId) {
227  RedSpyThreadData* const tData = ClientGetTLS(threadId);
228  AddrValPair* avPair = &tData->buffer[bufferOffset];
229  return memcmp(avPair->value + startOffset, (void**)(avPair->address) + startOffset, length) == 0;
230  }
231 
232  static __attribute__((always_inline)) bool IsWriteRedundant(void*& addr, THREADID threadId) {
233  RedSpyThreadData* const tData = ClientGetTLS(threadId);
234  AddrValPair* avPair = &tData->buffer[bufferOffset];
235  addr = avPair->address;
236  switch (AccessLen) {
237  case 1:
238  return *((uint8_t*)(&avPair->value)) == *(static_cast<uint8_t*>(avPair->address));
239  case 2:
240  return *((uint16_t*)(&avPair->value)) == *(static_cast<uint16_t*>(avPair->address));
241  case 4:
242  return *((uint32_t*)(&avPair->value)) == *(static_cast<uint32_t*>(avPair->address));
243  case 8:
244  return *((uint64_t*)(&avPair->value)) == *(static_cast<uint64_t*>(avPair->address));
245  default:
246  return memcmp(&avPair->value, avPair->address, AccessLen) == 0;
247  }
248  }
249  static __attribute__((always_inline)) VOID RecordNByteValueBeforeWrite(void* addr, THREADID threadId) {
250  RedSpyThreadData* const tData = ClientGetTLS(threadId);
251  AddrValPair* avPair = &tData->buffer[bufferOffset];
252  avPair->address = addr;
253  switch (AccessLen) {
254  case 1:
255  *((uint8_t*)(&avPair->value)) = *(static_cast<uint8_t*>(addr));
256  break;
257  case 2:
258  *((uint16_t*)(&avPair->value)) = *(static_cast<uint16_t*>(addr));
259  break;
260  case 4:
261  *((uint32_t*)(&avPair->value)) = *(static_cast<uint32_t*>(addr));
262  break;
263  case 8:
264  *((uint64_t*)(&avPair->value)) = *(static_cast<uint64_t*>(addr));
265  break;
266  default:
267  memcpy(&avPair->value, addr, AccessLen);
268  }
269  }
270  static __attribute__((always_inline)) VOID CheckNByteValueAfterWrite(THREADID threadId) {
271  RedSpyThreadData* const tData = ClientGetTLS(threadId);
272  void* addr;
273  bool isRedundantWrite = IsWriteRedundant(addr, threadId);
274  if (isRedundantWrite) {
275  tData->bytesRedundant += AccessLen;
276  // increment the metric
277  } else {
278  bool isSameCacheLine = CACHE_LINE_INDEX(addr) == CACHE_LINE_INDEX((size_t)(addr) + AccessLen - 1);
279  if (isSameCacheLine) {
280  if (!WAS_DIFFERENT(addr))
281  WAS_DIFFERENT(addr) = true;
282  } else {
283  size_t firstCacheLineAccessLength = CACHE_LINE_BASE(addr) + CACHE_LINE_SZ - (size_t)(addr);
284  size_t firstCacheLineStart = 0;
285  size_t lastCacheLineAccessLength = (size_t)addr + AccessLen - CACHE_LINE_BASE((size_t)addr + AccessLen - 1);
286  size_t lastCacheLineStart = CACHE_LINE_BASE((size_t)(addr) + AccessLen - 1) - (size_t)(addr);
287 
288  if ((!WAS_DIFFERENT(addr)) && IsPartialWriteRedundant(firstCacheLineStart, firstCacheLineAccessLength, threadId)) {
289  WAS_DIFFERENT(addr) = true;
290  }
291  if ((!WAS_DIFFERENT(addr + AccessLen - 1)) && IsPartialWriteRedundant(lastCacheLineStart, lastCacheLineAccessLength, threadId)) {
292  WAS_DIFFERENT(addr + AccessLen - 1) = true;
293  }
294  for (size_t startOffset = firstCacheLineAccessLength; startOffset < lastCacheLineStart; startOffset += CACHE_LINE_SZ) {
295  if ((!WAS_DIFFERENT(addr + startOffset)) && IsPartialWriteRedundant(startOffset, CACHE_LINE_SZ, threadId))
296  WAS_DIFFERENT(addr + startOffset) = true;
297  }
298  }
299  }
300  }
301 };
302 
303 // TODO(preexisting-bug): buffer[bufferOffset].value is MAX_WRITE_OP_LENGTH
304 // (512) bytes; xsave/xsaveopt/fxsave write 512-10KB of state and modern
305 // AVX-512 tile ops write >512B too. accessLen can exceed 512 and this
306 // memcpy overflows into whatever follows AddrValPair in RedSpyThreadData.
307 // Proper fix: filter at instrumentation time -- in InstrumentInsCallback,
308 // skip the RedSpyInstrument path for any operand whose INS_MemoryOperandSize
309 // exceeds MAX_WRITE_OP_LENGTH so this analysis routine never sees an
310 // oversized accessLen. (Alternative: bump MAX_WRITE_OP_LENGTH to 16 KB and
311 // pay the ~128 KB/thread buffer cost.)
312 static inline VOID RecordValueBeforeLargeWrite(void* addr, UINT32 accessLen, uint32_t bufferOffset, THREADID threadId) {
313  RedSpyThreadData* const tData = ClientGetTLS(threadId);
314  memcpy(&(tData->buffer[bufferOffset].value), addr, accessLen);
315  tData->buffer[bufferOffset].address = addr;
316 }
317 
318 static inline VOID CheckAfterLargeWrite(UINT32 accessLen, uint32_t bufferOffset, THREADID threadId) {
319  RedSpyThreadData* const tData = ClientGetTLS(threadId);
320  size_t addr = (size_t)(tData->buffer[bufferOffset].address);
321  if (memcmp(tData->buffer[bufferOffset].value, (void*)addr, accessLen) == 0) {
322  tData->bytesRedundant += accessLen;
323  } else {
324  size_t firstCacheLineAccessLength = CACHE_LINE_BASE(addr) + CACHE_LINE_SZ - (size_t)(addr);
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;
328 
329  if ((!WAS_DIFFERENT(addr)) && (0 == memcmp((void*)(tData->buffer[bufferOffset].value + firstCacheLineStart), (void*)(addr + firstCacheLineStart), firstCacheLineAccessLength))) {
330  WAS_DIFFERENT(addr) = true;
331  }
332  if ((!WAS_DIFFERENT(addr + accessLen - 1)) && (0 == memcmp((void*)(tData->buffer[bufferOffset].value + lastCacheLineStart), (void*)(addr + lastCacheLineStart), lastCacheLineAccessLength))) {
333  WAS_DIFFERENT(addr + accessLen - 1) = true;
334  }
335  for (size_t startOffset = firstCacheLineAccessLength; startOffset < lastCacheLineStart; startOffset += CACHE_LINE_SZ) {
336  if ((!WAS_DIFFERENT(addr + startOffset)) && (0 == memcmp((void*)(tData->buffer[bufferOffset].value), (void*)(addr + startOffset), CACHE_LINE_SZ)))
337  WAS_DIFFERENT(addr + startOffset) = true;
338  }
339  }
340 }
341 #define HANDLE_CASE(NUM, BUFFER_INDEX, HAS_FALLTHRU) \
342  case (NUM): { \
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); \
345  } break
346 
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)
350 
351 static int GetNumWriteOperandsInIns(INS ins, UINT32& whichOp) {
352  int numWriteOps = 0;
353  UINT32 memOperands = INS_MemoryOperandCount(ins);
354  for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
355  if (INS_MemoryOperandIsWritten(ins, memOp)) {
356  numWriteOps++;
357  whichOp = memOp;
358  }
359  }
360  return numWriteOps;
361 }
362 
363 
364 template <uint32_t readBufferSlotIndex>
366  static __attribute__((always_inline)) void InstrumentReadValueBeforeAndAfterWriting(INS ins, UINT32 memOp, bool hasFallThru) {
367  UINT32 refSize = INS_MemoryOperandSize(ins, memOp);
368  switch (refSize) {
369  HANDLE_CASE(1, readBufferSlotIndex, hasFallThru);
370  HANDLE_CASE(2, readBufferSlotIndex, hasFallThru);
371  HANDLE_CASE(4, readBufferSlotIndex, hasFallThru);
372  HANDLE_CASE(8, readBufferSlotIndex, hasFallThru);
373  HANDLE_CASE(10, readBufferSlotIndex, hasFallThru);
374  HANDLE_CASE(16, readBufferSlotIndex, hasFallThru);
375  default: {
376  HANDLE_LARGE(hasFallThru);
377  }
378  }
379  }
380 };
381 
382 
383 static VOID InstrumentInsCallback(INS ins, VOID* v) {
384  UINT32 memOperands = INS_MemoryOperandCount(ins);
385  if (memOperands == 0)
386  return;
387 
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);
391  } else {
392  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)OnAccess, IARG_MEMORYOP_EA, memOp, IARG_MEMORYREAD_SIZE, IARG_BOOL, 0, IARG_END);
393  }
394  }
395 
396  // Now do the redSpy business
397 
398  bool hasFallThu = INS_HasFallThrough(ins);
399 
400  // Special case, if we have only one write operand
401 
402  UINT32 whichOp = 0;
403 
404  if (GetNumWriteOperandsInIns(ins, whichOp) == 1) {
405  // Read the value at location before and after the instruction
407  } else {
408  UINT32 memOperands = INS_MemoryOperandCount(ins);
409 
410  int readBufferSlotIndex = 0;
411 
412  for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
413  if (!INS_MemoryOperandIsWritten(ins, memOp))
414  continue;
415  switch (readBufferSlotIndex) {
416  case 0:
417  // Read the value at location before and after the instruction
419  break;
420  case 1:
421  // Read the value at location before and after the instruction
423  break;
424  case 2:
425  // Read the value at location before and after the instruction
427  break;
428  case 3:
429  // Read the value at location before and after the instruction
431  break;
432  case 4:
433  // Read the value at location before and after the instruction
435  break;
436  default:
437  assert(0 && "NYI");
438  break;
439  }
440  // use next slot for the next write operand
441  readBufferSlotIndex++;
442  }
443  }
444 }
445 
446 size_t getPeakRSS() {
447  struct rusage u;
448  getrusage(RUSAGE_SELF, &u);
449  return (size_t)(u.ru_maxrss);
450 }
451 
452 
453 static VOID FiniFunc(INT32 code, VOID* v) {
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());
455 }
456 
457 static VOID ImageUnload(IMG img, VOID* v) {
458  //fprintf(stderr, "\n ImageUnload\n");
459  CacheFlush();
460 }
461 
462 static void HandleSysCall(THREADID threadIndex, CONTEXT* ctxt, SYSCALL_STANDARD std, VOID* v) {
463  //fprintf(stderr, "\n HandleSysCall\n");
464  CacheFlush();
465 }
466 
467 inline VOID Update(uint32_t bytes, THREADID threadId) {
468  RedSpyThreadData* const tData = ClientGetTLS(threadId);
469  tData->bytesWritten += bytes;
470 }
471 
472 //instrument the trace, count the number of ins in the trace, decide to instrument or not
473 static void InstrumentTrace(TRACE trace, void* f) {
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)) {
478  totBytes += INS_MemoryWriteSize(ins);
479  }
480  }
481  BBL_InsertCall(bbl, IPOINT_ANYWHERE, (AFUNPTR)Update, IARG_UINT32, totBytes, IARG_THREAD_ID, IARG_END);
482  }
483 }
484 
485 
486 static VOID ThreadFiniFunc(THREADID threadId, const CONTEXT* ctxt, INT32 code, VOID* v) {
487  RedSpyThreadData* const tData = ClientGetTLS(threadId);
488  fprintf(gTraceFile, "\n Bytes written=%lu, Bytes redundant=%lu, redundant=%f \n", tData->bytesWritten, tData->bytesRedundant, 100.0 * tData->bytesRedundant / tData->bytesWritten);
489 }
490 
491 static void InitThreadData(RedSpyThreadData* tdata) {
492  tdata->bytesWritten = 0;
493  tdata->bytesRedundant = 0;
494 }
495 
496 static VOID ThreadStart(THREADID threadid, CONTEXT* ctxt, INT32 flags, VOID* v) {
497  RedSpyThreadData* tdata = new RedSpyThreadData();
498  InitThreadData(tdata);
499 #ifdef MULTI_THREADED
500  PIN_SetThreadData(client_tls_key, tdata, threadid);
501 #else
502  gSingleThreadedTData = tdata;
503 #endif
504 }
505 
506 int main(int argc, char* argv[]) {
507  // Initialize PIN
508  if (PIN_Init(argc, argv))
509  return Usage();
510 
511  // Initialize Symbols, we need them to report functions and lines
512  PIN_InitSymbols();
513 
514  // Init Client
515  ClientInit(argc, argv);
516 
517  // Obtain a key for TLS storage.
518  client_tls_key = PIN_CreateThreadDataKey(nullptr /*TODO have a destructir*/);
519  // Register ThreadStart to be called when a thread starts.
520  PIN_AddThreadStartFunction(ThreadStart, nullptr);
521 
522 
523  // fini function for post-mortem analysis
524  PIN_AddThreadFiniFunction(ThreadFiniFunc, nullptr);
525 
526  // Register SyscallEntry
527  PIN_AddSyscallEntryFunction(HandleSysCall, nullptr);
528  // PIN_AddSyscallExitFunction (HandleSysCall, 0);
529 
530  INS_AddInstrumentFunction(InstrumentInsCallback, nullptr);
531  // fini function for post-mortem analysis
532  PIN_AddFiniFunction(FiniFunc, nullptr);
533 
534  TRACE_AddInstrumentFunction(InstrumentTrace, nullptr);
535 
536 
537  // Launch program now
538  PIN_StartProgram();
539  return 0;
540 }
#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 FILE * gTraceFile
static VOID ImageUnload(IMG img, VOID *v)
#define MAX_FILE_PATH
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
size_t getPeakRSS()
static VOID InstrumentInsCallback(INS ins, VOID *v)
static INT32 Usage()
static void OnEvict(void **addr)
#define HANDLE_CASE(NUM, BUFFER_INDEX, HAS_FALLTHRU)
#define CACHE_LINE_SZ
static void HandleSysCall(THREADID threadIndex, CONTEXT *ctxt, SYSCALL_STANDARD std, VOID *v)
#define WAS_DIFFERENT(address)
#define SET_TAG(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)
#define CACHE_NUM_LINES
static VOID FiniFunc(INT32 code, VOID *v)
#define IS_VALID(address)
static int GetNumWriteOperandsInIns(INS ins, UINT32 &whichOp)
void CacheFlush()
#define SET_INUSE(address)
#define CACHE_SZ
#define HANDLE_LARGE(HAS_FALLTHRU)
#define CACHE_LINE_MASK
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 GET_TAG(address)
#define CACHE_LINE_BASE(addr)
hpcrun_metricFlags_t flags
Definition: cctlib.cpp:3425
uint16_t size_t
Definition: cctlib.cpp:3359
static USIZE INS_MemoryWriteSize(INS ins)
uint8_t value[MAX_WRITE_OP_LENGTH]
void * address
uint8_t value[MAX_WRITE_OP_LENGTH]
void * address
bool isInUse
size_t tag
bool wasDifferent
bool isDirty
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
uint64_t bytesWritten
AddrValPair buffer[MAX_WRITE_OPS_IN_INS]
uint64_t bytesRedundant
uint64_t unchanged
uint64_t dirtyEvicts
uint64_t evicts
uint64_t sameData
void f()
Definition: test1.c:23