CCTLib
Calling-context and data-object attribution library for Intel Pin
zerospy_cachepage.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 <atomic>
10 #include <malloc.h>
11 #include <iostream>
12 #include <unistd.h>
13 #include <assert.h>
14 #include <string.h>
15 #include <sys/mman.h>
16 #include <sstream>
17 #include <functional>
18 #include <unordered_set>
19 #include <vector>
20 #include <unordered_map>
21 #include <algorithm>
22 #include <list>
23 #include "pin.H"
24 #include "pin_isa_compat.H"
25 #include "cctlib.H"
26 #include "shadow_memory.H"
27 #include <xmmintrin.h>
28 #include <immintrin.h>
29 
30 extern "C" {
31 #include "xed-interface.h"
32 #include "xed-common-hdrs.h"
33 }
34 
35 #include <google/sparse_hash_map>
36 #include <google/dense_hash_map>
37 
38 using namespace std;
39 using namespace PinCCTLib;
40 
41 // have R, W representative macros
42 #define READ_ACTION (0)
43 #define WRITE_ACTION (0xff)
44 
45 #define ONE_BYTE_READ_ACTION (0)
46 #define TWO_BYTE_READ_ACTION (0)
47 #define FOUR_BYTE_READ_ACTION (0)
48 #define EIGHT_BYTE_READ_ACTION (0)
49 
50 #define ONE_BYTE_WRITE_ACTION (0xff)
51 #define TWO_BYTE_WRITE_ACTION (0xffff)
52 #define FOUR_BYTE_WRITE_ACTION (0xffffffff)
53 #define EIGHT_BYTE_WRITE_ACTION (0xffffffffffffffff)
54 
55 #define IS_ACCESS_WITHIN_PAGE_BOUNDARY(accessAddr, accessLen) (PAGE_OFFSET((accessAddr)) <= (PAGE_OFFSET_MASK - (accessLen)))
56 
57 /* Other footprint_client settings */
58 #define MAX_REDUNDANT_CONTEXTS_TO_LOG (1000)
59 #define THREAD_MAX (1024)
60 
61 #define ENCODE_ADDRESS_AND_ACCESS_LEN(addr, len) ((addr) | (((uint64_t)(len)) << 48))
62 #define DECODE_ADDRESS(addrAndLen) ((addrAndLen) & ((1L << 48) - 1))
63 #define DECODE_ACCESS_LEN(addrAndLen) ((addrAndLen) >> 48)
64 
65 
66 #define MAX_WRITE_OP_LENGTH (512)
67 #define MAX_WRITE_OPS_IN_INS (8)
68 #define MAX_REG_LENGTH (64)
69 
70 #define MAX_SIMD_LENGTH (64)
71 #define MAX_SIMD_REGS (32)
72 
73 /***********************************************
74  ****** shadow memory
75  ************************************************/
76 //ConcurrentShadowMemory<uint8_t, ContextHandle_t> sm;
77 
78 struct {
79  char dummy1[128];
80  xed_state_t xedState;
81  char dummy2[128];
83 
84 ////////////////////////////////////////////////
85 
86 struct RedSpyThreadData {
87  uint64_t bytesLoad;
88 
89  long long numIns;
90  bool sampleFlag;
91 };
92 
93 // for metric logging
96 
97 //for statistics result
101 
102 //uint64_t localTotBytesLoad[THREAD_MAX] = {0};
103 
104 // key for accessing TLS storage in the threads. initialized once in main()
105 static TLS_KEY client_tls_key;
107 
108 // function to access thread-specific data
109 inline RedSpyThreadData* ClientGetTLS(const THREADID threadId) {
110 #ifdef MULTI_THREADED
111  RedSpyThreadData* tdata =
112  static_cast<RedSpyThreadData*>(PIN_GetThreadData(client_tls_key, threadId));
113  return tdata;
114 #else
115  return gSingleThreadedTData;
116 #endif
117 }
118 
119 static INT32 Usage() {
120  PIN_ERROR("Pin tool to gather calling context on each load and store.\n" + KNOB_BASE::StringKnobSummary() + "\n");
121  return -1;
122 }
123 
124 // Main for RedSpy, initialize the tool, register instrumentation functions and call the target program.
125 static FILE* gTraceFile;
126 
127 // Initialized the needed data structures before launching the target program
128 static void ClientInit(int argc, char* argv[]) {
129  // Create output file
130  char name[MAX_FILE_PATH] = "zeroLoad.cachepage.out.";
131  char* envPath = getenv("CCTLIB_CLIENT_OUTPUT_FILE");
132 
133  if (envPath) {
134  // assumes max of MAX_FILE_PATH
135  snprintf(name, sizeof(name), "%s", envPath);
136  }
137 
138  gethostname(name + strlen(name), MAX_FILE_PATH - strlen(name));
139  pid_t pid = getpid();
140  sprintf(name + strlen(name), "%d", pid);
141  cerr << "\n Creating log file at:" << name << "\n";
142  gTraceFile = fopen(name, "w");
143  // print the arguments passed
144  fprintf(gTraceFile, "\n");
145 
146  for (int i = 0; i < argc; i++) {
147  fprintf(gTraceFile, "%s ", argv[i]);
148  }
149 
150  fprintf(gTraceFile, "\n");
151 
152  // Init Xed
153  // Init XED for decoding instructions
154  xed_state_init(&LoadSpyGlobals.xedState, XED_MACHINE_MODE_LONG_64, (xed_address_width_enum_t)0, XED_ADDRESS_WIDTH_64b);
155 }
156 
157 
158 static const uint64_t READ_ACCESS_STATES[] = {/*0 byte */ 0, /*1 byte */ ONE_BYTE_READ_ACTION, /*2 byte */ TWO_BYTE_READ_ACTION, /*3 byte */ 0, /*4 byte */ FOUR_BYTE_READ_ACTION, /*5 byte */ 0, /*6 byte */ 0, /*7 byte */ 0, /*8 byte */ EIGHT_BYTE_READ_ACTION};
159 static const uint64_t WRITE_ACCESS_STATES[] = {/*0 byte */ 0, /*1 byte */ ONE_BYTE_WRITE_ACTION, /*2 byte */ TWO_BYTE_WRITE_ACTION, /*3 byte */ 0, /*4 byte */ FOUR_BYTE_WRITE_ACTION, /*5 byte */ 0, /*6 byte */ 0, /*7 byte */ 0, /*8 byte */ EIGHT_BYTE_WRITE_ACTION};
160 static const uint8_t OVERFLOW_CHECK[] = {/*0 byte */ 0, /*1 byte */ 0, /*2 byte */ 0, /*3 byte */ 1, /*4 byte */ 2, /*5 byte */ 3, /*6 byte */ 4, /*7 byte */ 5, /*8 byte */ 6};
161 // 64 Byte Cache line
162 #define CACHELINE_ALIGNMENT 64
163 // 4 KB Page
164 #define PAGE_ALIGNMENT 0x1000
165 // masks
166 #define CACHELINE_MASK (~63)
167 #define PAGE_MASK (~0xfff)
168 #define ISSAMECACHELINE(addr, accesslen) (((uint64_t)(addr) & (CACHELINE_ALIGNMENT - 1)) + (uint64_t)(accesslen) < CACHELINE_ALIGNMENT)
169 // index
170 #define GET_CACHELINE_INDEX(x) ((x)&CACHELINE_MASK)
171 #define GET_PAGE_INDEX(x) ((x)&PAGE_MASK)
172 // inside index
173 #define GET_CACHELINE_INNER_INDEX(x) ((x) & (CACHELINE_ALIGNMENT - 1))
174 #define GET_PAGE_INNER_INDEX(x) ((x) & (PAGE_ALIGNMENT - 1))
175 // states
176 #define STATE_NONZERO 0
177 #define STATE_ZERO 1
178 #define STATE_NOVISIT 2
179 #define VAL2STAT(value) (value == 0)
180 
181 // only log for CACHELINE, for page info can be derived from cache line info
182 struct RedLogs {
183  uint64_t zerobytes; // total zero bytes (Byte level)
184  uint64_t zeroreads; // total zero reads (Instruction level)
185  uint64_t reads; // total reads (Instruction level)
186  uint8_t state; // STATE_ZERO, STATE_NONZERO, STATE_NOVISIT
187 };
188 
189 //static unordered_map<uint64_t, uint64_t> validMap[THREAD_MAX];
190 static unordered_map<uint64_t, RedLogs> RedMap[THREAD_MAX];
191 static inline void AddToRedTable(uint64_t key, uint16_t value, uint16_t zero, THREADID threadId) __attribute__((always_inline, flatten));
192 static inline void AddToRedTable(uint64_t key, uint16_t value, uint16_t zero, THREADID threadId) {
193 #ifdef MULTI_THREADED
194  LOCK_RED_MAP();
195 #endif
196  unordered_map<uint64_t, RedLogs>::iterator it = RedMap[threadId].find(key);
197  if (it == RedMap[threadId].end()) {
198  RedLogs log;
199  log.zerobytes = value;
200  log.zeroreads = zero;
201  log.reads = 1;
202  log.state = zero;
203  RedMap[threadId][key] = log;
204  } else {
205  it->second.zerobytes += value;
206  it->second.zeroreads += zero;
207  it->second.reads++;
208  it->second.state &= zero;
209  }
210 #ifdef MULTI_THREADED
211  UNLOCK_RED_MAP();
212 #endif
213 }
214 
215 // Certain FP instructions should not be approximated
216 static inline bool IsOkToApproximate(xed_decoded_inst_t& xedd) {
217  xed_iclass_enum_t iclass = xed_decoded_inst_get_iclass(&xedd);
218  switch (iclass) {
219  case XED_ICLASS_FLDENV:
220  case XED_ICLASS_FNSTENV:
221  case XED_ICLASS_FNSAVE:
222  case XED_ICLASS_FLDCW:
223  case XED_ICLASS_FNSTCW:
224  case XED_ICLASS_FXRSTOR:
225  case XED_ICLASS_FXRSTOR64:
226  case XED_ICLASS_FXSAVE:
227  case XED_ICLASS_FXSAVE64:
228  return false;
229  default:
230  return true;
231  }
232 }
233 
234 static inline bool IsFloatInstructionAndOkToApproximate(ADDRINT ip) {
235  xed_decoded_inst_t xedd;
236  xed_decoded_inst_zero_set_mode(&xedd, &LoadSpyGlobals.xedState);
237 
238  if (XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
239  xed_category_enum_t cat = xed_decoded_inst_get_category(&xedd);
240  switch (cat) {
241  case XED_CATEGORY_AES:
242  case XED_CATEGORY_CONVERT:
243  case XED_CATEGORY_PCLMULQDQ:
244  case XED_CATEGORY_SSE:
245  case XED_CATEGORY_AVX2:
246  case XED_CATEGORY_AVX:
247  case XED_CATEGORY_MMX:
248  case XED_CATEGORY_DATAXFER: {
249  // Get the mem operand
250 
251  const xed_inst_t* xi = xed_decoded_inst_inst(&xedd);
252  int noperands = xed_inst_noperands(xi);
253  int memOpIdx = -1;
254  for (int i = 0; i < noperands; i++) {
255  const xed_operand_t* op = xed_inst_operand(xi, i);
256  xed_operand_enum_t op_name = xed_operand_name(op);
257  if (XED_OPERAND_MEM0 == op_name) {
258  memOpIdx = i;
259  break;
260  }
261  }
262  if (memOpIdx == -1) {
263  return false;
264  }
265 
266  // TO DO MILIND case XED_OPERAND_MEM1:
267  xed_operand_element_type_enum_t eType = xed_decoded_inst_operand_element_type(&xedd, memOpIdx);
268  switch (eType) {
269  case XED_OPERAND_ELEMENT_TYPE_FLOAT16:
270  case XED_OPERAND_ELEMENT_TYPE_SINGLE:
271  case XED_OPERAND_ELEMENT_TYPE_DOUBLE:
272  case XED_OPERAND_ELEMENT_TYPE_LONGDOUBLE:
273  case XED_OPERAND_ELEMENT_TYPE_LONGBCD:
274  return IsOkToApproximate(xedd);
275  default:
276  return false;
277  }
278  } break;
279  case XED_CATEGORY_X87_ALU:
280  case XED_CATEGORY_FCMOV:
281  //case XED_CATEGORY_LOGICAL_FP:
282  // assumption, the access length must be either 4 or 8 bytes else assert!!!
283  //assert(*accessLen == 4 || *accessLen == 8);
284  return IsOkToApproximate(xedd);
285  case XED_CATEGORY_XSAVE:
286  case XED_CATEGORY_AVX2GATHER:
287  case XED_CATEGORY_STRINGOP:
288  default:
289  return false;
290  }
291  } else {
292  assert(0 && "failed to disassemble instruction");
293  // printf("\n Diassembly failure\n");
294  return false;
295  }
296 }
297 
298 static inline bool IsFloatInstructionOld(ADDRINT ip) {
299  xed_decoded_inst_t xedd;
300  xed_decoded_inst_zero_set_mode(&xedd, &LoadSpyGlobals.xedState);
301 
302  if (XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
303  xed_iclass_enum_t iclassType = xed_decoded_inst_get_iclass(&xedd);
304  if (iclassType >= XED_ICLASS_F2XM1 && iclassType <= XED_ICLASS_FYL2XP1) {
305  return true;
306  }
307  if (iclassType >= XED_ICLASS_VBROADCASTSD && iclassType <= XED_ICLASS_VDPPS) {
308  return true;
309  }
310  if (iclassType >= XED_ICLASS_VRCPPS && iclassType <= XED_ICLASS_VSQRTSS) {
311  return true;
312  }
313  if (iclassType >= XED_ICLASS_VSUBPD && iclassType <= XED_ICLASS_VXORPS) {
314  return true;
315  }
316  switch (iclassType) {
317  case XED_ICLASS_ADDPD:
318  case XED_ICLASS_ADDPS:
319  case XED_ICLASS_ADDSD:
320  case XED_ICLASS_ADDSS:
321  case XED_ICLASS_ADDSUBPD:
322  case XED_ICLASS_ADDSUBPS:
323  case XED_ICLASS_ANDNPD:
324  case XED_ICLASS_ANDNPS:
325  case XED_ICLASS_ANDPD:
326  case XED_ICLASS_ANDPS:
327  case XED_ICLASS_BLENDPD:
328  case XED_ICLASS_BLENDPS:
329  case XED_ICLASS_BLENDVPD:
330  case XED_ICLASS_BLENDVPS:
331  case XED_ICLASS_CMPPD:
332  case XED_ICLASS_CMPPS:
333  case XED_ICLASS_CMPSD:
334  case XED_ICLASS_CMPSD_XMM:
335  case XED_ICLASS_COMISD:
336  case XED_ICLASS_COMISS:
337  case XED_ICLASS_CVTDQ2PD:
338  case XED_ICLASS_CVTDQ2PS:
339  case XED_ICLASS_CVTPD2PS:
340  case XED_ICLASS_CVTPI2PD:
341  case XED_ICLASS_CVTPI2PS:
342  case XED_ICLASS_CVTPS2PD:
343  case XED_ICLASS_CVTSD2SS:
344  case XED_ICLASS_CVTSI2SD:
345  case XED_ICLASS_CVTSI2SS:
346  case XED_ICLASS_CVTSS2SD:
347  case XED_ICLASS_DIVPD:
348  case XED_ICLASS_DIVPS:
349  case XED_ICLASS_DIVSD:
350  case XED_ICLASS_DIVSS:
351  case XED_ICLASS_DPPD:
352  case XED_ICLASS_DPPS:
353  case XED_ICLASS_HADDPD:
354  case XED_ICLASS_HADDPS:
355  case XED_ICLASS_HSUBPD:
356  case XED_ICLASS_HSUBPS:
357  case XED_ICLASS_MAXPD:
358  case XED_ICLASS_MAXPS:
359  case XED_ICLASS_MAXSD:
360  case XED_ICLASS_MAXSS:
361  case XED_ICLASS_MINPD:
362  case XED_ICLASS_MINPS:
363  case XED_ICLASS_MINSD:
364  case XED_ICLASS_MINSS:
365  case XED_ICLASS_MOVAPD:
366  case XED_ICLASS_MOVAPS:
367  case XED_ICLASS_MOVD:
368  case XED_ICLASS_MOVHLPS:
369  case XED_ICLASS_MOVHPD:
370  case XED_ICLASS_MOVHPS:
371  case XED_ICLASS_MOVLHPS:
372  case XED_ICLASS_MOVLPD:
373  case XED_ICLASS_MOVLPS:
374  case XED_ICLASS_MOVMSKPD:
375  case XED_ICLASS_MOVMSKPS:
376  case XED_ICLASS_MOVNTPD:
377  case XED_ICLASS_MOVNTPS:
378  case XED_ICLASS_MOVNTSD:
379  case XED_ICLASS_MOVNTSS:
380  case XED_ICLASS_MOVSD:
381  case XED_ICLASS_MOVSD_XMM:
382  case XED_ICLASS_MOVSS:
383  case XED_ICLASS_MULPD:
384  case XED_ICLASS_MULPS:
385  case XED_ICLASS_MULSD:
386  case XED_ICLASS_MULSS:
387  case XED_ICLASS_ORPD:
388  case XED_ICLASS_ORPS:
389  case XED_ICLASS_ROUNDPD:
390  case XED_ICLASS_ROUNDPS:
391  case XED_ICLASS_ROUNDSD:
392  case XED_ICLASS_ROUNDSS:
393  case XED_ICLASS_SHUFPD:
394  case XED_ICLASS_SHUFPS:
395  case XED_ICLASS_SQRTPD:
396  case XED_ICLASS_SQRTPS:
397  case XED_ICLASS_SQRTSD:
398  case XED_ICLASS_SQRTSS:
399  case XED_ICLASS_SUBPD:
400  case XED_ICLASS_SUBPS:
401  case XED_ICLASS_SUBSD:
402  case XED_ICLASS_SUBSS:
403  case XED_ICLASS_VADDPD:
404  case XED_ICLASS_VADDPS:
405  case XED_ICLASS_VADDSD:
406  case XED_ICLASS_VADDSS:
407  case XED_ICLASS_VADDSUBPD:
408  case XED_ICLASS_VADDSUBPS:
409  case XED_ICLASS_VANDNPD:
410  case XED_ICLASS_VANDNPS:
411  case XED_ICLASS_VANDPD:
412  case XED_ICLASS_VANDPS:
413  case XED_ICLASS_VBLENDPD:
414  case XED_ICLASS_VBLENDPS:
415  case XED_ICLASS_VBLENDVPD:
416  case XED_ICLASS_VBLENDVPS:
417  case XED_ICLASS_VBROADCASTSD:
418  case XED_ICLASS_VBROADCASTSS:
419  case XED_ICLASS_VCMPPD:
420  case XED_ICLASS_VCMPPS:
421  case XED_ICLASS_VCMPSD:
422  case XED_ICLASS_VCMPSS:
423  case XED_ICLASS_VCOMISD:
424  case XED_ICLASS_VCOMISS:
425  case XED_ICLASS_VCVTDQ2PD:
426  case XED_ICLASS_VCVTDQ2PS:
427  case XED_ICLASS_VCVTPD2PS:
428  case XED_ICLASS_VCVTPH2PS:
429  case XED_ICLASS_VCVTPS2PD:
430  case XED_ICLASS_VCVTSD2SS:
431  case XED_ICLASS_VCVTSI2SD:
432  case XED_ICLASS_VCVTSI2SS:
433  case XED_ICLASS_VCVTSS2SD:
434  case XED_ICLASS_VDIVPD:
435  case XED_ICLASS_VDIVPS:
436  case XED_ICLASS_VDIVSD:
437  case XED_ICLASS_VDIVSS:
438  case XED_ICLASS_VDPPD:
439  case XED_ICLASS_VDPPS:
440  case XED_ICLASS_VMASKMOVPD:
441  case XED_ICLASS_VMASKMOVPS:
442  case XED_ICLASS_VMAXPD:
443  case XED_ICLASS_VMAXPS:
444  case XED_ICLASS_VMAXSD:
445  case XED_ICLASS_VMAXSS:
446  case XED_ICLASS_VMINPD:
447  case XED_ICLASS_VMINPS:
448  case XED_ICLASS_VMINSD:
449  case XED_ICLASS_VMINSS:
450  case XED_ICLASS_VMOVAPD:
451  case XED_ICLASS_VMOVAPS:
452  case XED_ICLASS_VMOVD:
453  case XED_ICLASS_VMOVHLPS:
454  case XED_ICLASS_VMOVHPD:
455  case XED_ICLASS_VMOVHPS:
456  case XED_ICLASS_VMOVLHPS:
457  case XED_ICLASS_VMOVLPD:
458  case XED_ICLASS_VMOVLPS:
459  case XED_ICLASS_VMOVMSKPD:
460  case XED_ICLASS_VMOVMSKPS:
461  case XED_ICLASS_VMOVNTPD:
462  case XED_ICLASS_VMOVNTPS:
463  case XED_ICLASS_VMOVSD:
464  case XED_ICLASS_VMOVSS:
465  case XED_ICLASS_VMOVUPD:
466  case XED_ICLASS_VMOVUPS:
467  case XED_ICLASS_VMULPD:
468  case XED_ICLASS_VMULPS:
469  case XED_ICLASS_VMULSD:
470  case XED_ICLASS_VMULSS:
471  case XED_ICLASS_VORPD:
472  case XED_ICLASS_VORPS:
473  case XED_ICLASS_VPABSD:
474  case XED_ICLASS_VPADDD:
475  case XED_ICLASS_VPCOMD:
476  case XED_ICLASS_VPCOMUD:
477  case XED_ICLASS_VPERMILPD:
478  case XED_ICLASS_VPERMILPS:
479  case XED_ICLASS_VPERMPD:
480  case XED_ICLASS_VPERMPS:
481  case XED_ICLASS_VPGATHERDD:
482  case XED_ICLASS_VPGATHERQD:
483  case XED_ICLASS_VPHADDBD:
484  case XED_ICLASS_VPHADDD:
485  case XED_ICLASS_VPHADDUBD:
486  case XED_ICLASS_VPHADDUWD:
487  case XED_ICLASS_VPHADDWD:
488  case XED_ICLASS_VPHSUBD:
489  case XED_ICLASS_VPHSUBWD:
490  case XED_ICLASS_VPINSRD:
491  case XED_ICLASS_VPMACSDD:
492  case XED_ICLASS_VPMACSSDD:
493  case XED_ICLASS_VPMASKMOVD:
494  case XED_ICLASS_VPMAXSD:
495  case XED_ICLASS_VPMAXUD:
496  case XED_ICLASS_VPMINSD:
497  case XED_ICLASS_VPMINUD:
498  case XED_ICLASS_VPROTD:
499  case XED_ICLASS_VPSUBD:
500  case XED_ICLASS_XORPD:
501  case XED_ICLASS_XORPS:
502  return true;
503 
504  default:
505  return false;
506  }
507  } else {
508  assert(0 && "failed to disassemble instruction");
509  return false;
510  }
511 }
512 
513 static inline uint16_t FloatOperandSize(ADDRINT ip, uint32_t oper) {
514  xed_decoded_inst_t xedd;
515  xed_decoded_inst_zero_set_mode(&xedd, &LoadSpyGlobals.xedState);
516 
517  if (XED_ERROR_NONE == xed_decode(&xedd, (const xed_uint8_t*)(ip), 15)) {
518  xed_operand_element_type_enum_t TypeOperand = xed_decoded_inst_operand_element_type(&xedd, oper);
519  if (TypeOperand == XED_OPERAND_ELEMENT_TYPE_SINGLE || TypeOperand == XED_OPERAND_ELEMENT_TYPE_FLOAT16)
520  return 4;
521  if (TypeOperand == XED_OPERAND_ELEMENT_TYPE_DOUBLE) {
522  return 8;
523  }
524  if (TypeOperand == XED_OPERAND_ELEMENT_TYPE_LONGDOUBLE) {
525  return 16;
526  }
527  assert(0 && "float instruction with unknown operand\n");
528  return 0;
529  } else {
530  assert(0 && "failed to disassemble instruction\n");
531  return 0;
532  }
533 }
534 
535 /***************************************************************************************/
536 /*********************** memory temporal redundancy functions **************************/
537 /***************************************************************************************/
538 
539 template <int start, int end, int step>
541  static __attribute__((always_inline)) uint32_t BodyRedZero(uint8_t* addr) {
542  return ((addr[end - 1] == 0) + UnrolledCount<start, end - 1, step>::BodyRedZero(addr));
543  }
544 };
545 template <int end, int step>
546 struct UnrolledCount<end, end, step> {
547  static __attribute__((always_inline)) uint32_t BodyRedZero(uint8_t* addr) {
548  return 0;
549  }
550 };
551 
552 template <class T, uint32_t AccessLen, bool isApprox>
554  static __attribute__((always_inline)) VOID CheckNByteValueAfterRead(void* addr, uint32_t opaqueHandle, THREADID threadId) {
555 #ifdef DEBUG_ZEROSPY
556  printf("\nINFO : In Check NBytes Value After Read\n");
557 #endif
558  uint8_t* bytes = static_cast<uint8_t*>(addr);
559  if (ISSAMECACHELINE(addr, AccessLen)) {
560  uint32_t rednum = UnrolledCount<0, AccessLen, sizeof(T)>::BodyRedZero(bytes);
561  if (rednum) {
562  uint8_t zero = (rednum == AccessLen);
563  AddToRedTable(GET_CACHELINE_INDEX((uint64_t)addr), rednum, zero, threadId);
564  } else {
565  AddToRedTable(GET_CACHELINE_INDEX((uint64_t)addr), 0, 0, threadId);
566  }
567  } else {
568  uint32_t i;
569  uint8_t zero = bytes[0] == 0;
570  uint32_t rednum = zero;
571  for (i = 1; ISSAMECACHELINE(addr, i); ++i) {
572  zero &= bytes[i] == 0;
573  rednum += zero;
574  }
575  AddToRedTable(GET_CACHELINE_INDEX((uint64_t)addr), rednum, zero, threadId);
576  uint64_t key = GET_CACHELINE_INDEX((uint64_t)(bytes + i));
577  zero = bytes[i] == 0;
578  rednum = zero;
579  for (i = i + 1; i < AccessLen; ++i) {
580  zero &= bytes[i] == 0;
581  rednum += zero;
582  }
583  AddToRedTable(key, rednum, zero, threadId);
584  }
585 
586 #ifdef DEBUG_ZEROSPY
587  printf("\nINFO : Exit Check NBytes Value After Read\n");
588 #endif
589  }
590 };
591 
592 static inline VOID CheckAfterLargeRead(void* addr, UINT32 accessLen, uint32_t opaqueHandle, THREADID threadId) {
593 #ifdef DEBUG_ZEROSPY
594  printf("\nINFO : In Check After Large Read\n");
595  if (accessLen > 32) {
596  printf("ERROR : AccessLen too large : %d\n", accessLen);
597  assert(0 && (accessLen <= 32));
598  }
599 #endif
600  uint8_t* bytes = static_cast<uint8_t*>(addr);
601  uint32_t i;
602  uint8_t zero = bytes[0] == 0;
603  uint32_t rednum = zero;
604  for (i = 1; ISSAMECACHELINE(addr, i); ++i) {
605  zero &= bytes[i] == 0;
606  rednum += zero;
607  }
608  AddToRedTable(GET_CACHELINE_INDEX((uint64_t)addr), rednum, zero, threadId);
609  uint64_t key = GET_CACHELINE_INDEX((uint64_t)(bytes + i));
610  zero = bytes[i] == 0;
611  rednum = zero;
612  for (i = i + 1; i < accessLen; ++i) {
613  zero &= bytes[i] == 0;
614  rednum += zero;
615  }
616  AddToRedTable(key, rednum, zero, threadId);
617 #ifdef DEBUG_ZEROSPY
618  printf("\nINFO : Exit Check After Large Read\n");
619 #endif
620 }
621 
622 #ifdef ENABLE_SAMPLING
623 
624 #define HANDLE_CASE(T, ACCESS_LEN, IS_APPROX) \
625  INS_InsertIfPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
626  INS_InsertThenPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)ZeroSpyAnalysis<T, (ACCESS_LEN), (IS_APPROX)>::CheckNByteValueAfterRead, IARG_MEMORYOP_EA, memOp, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_INST_PTR, IARG_END)
627 
628 #define HANDLE_LARGE() \
629  INS_InsertIfPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)IfEnableSample, IARG_THREAD_ID, IARG_END); \
630  INS_InsertThenPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)CheckAfterLargeRead, IARG_MEMORYOP_EA, memOp, IARG_MEMORYREAD_SIZE, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
631 #else
632 
633 #define HANDLE_CASE(T, ACCESS_LEN, IS_APPROX) \
634  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)ZeroSpyAnalysis<T, (ACCESS_LEN), (IS_APPROX)>::CheckNByteValueAfterRead, IARG_MEMORYOP_EA, memOp, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_INST_PTR, IARG_END)
635 
636 // #define HANDLE_CASE_LOWER(T, LOWERT, ACCESS_LEN)
637 // INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR) ZeroSpyApproxAnalysis<T, LOWERT, (ACCESS_LEN)>::CheckNByteValueAfterRead, IARG_MEMORYOP_EA, memOp, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_INST_PTR,IARG_END)
638 
639 #define HANDLE_LARGE() \
640  INS_InsertPredicatedCall(ins, IPOINT_BEFORE, (AFUNPTR)CheckAfterLargeRead, IARG_MEMORYOP_EA, memOp, IARG_MEMORYREAD_SIZE, IARG_UINT32, opaqueHandle, IARG_THREAD_ID, IARG_END)
641 #endif
642 
643 
644 static int GetNumReadOperandsInIns(INS ins, UINT32& whichOp) {
645  int numReadOps = 0;
646  UINT32 memOperands = INS_MemoryOperandCount(ins);
647  for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
648  if (INS_MemoryOperandIsRead(ins, memOp)) {
649  numReadOps++;
650  whichOp = memOp;
651  }
652  }
653  return numReadOps;
654 }
655 
656 
657 struct LoadSpyInstrument {
658  static __attribute__((always_inline)) void InstrumentReadValueBeforeAndAfterLoading(INS ins, UINT32 memOp, uint32_t opaqueHandle) {
659 #ifdef DEBUG_ZEROSPY
660  printf("\nINFO : In InstrumentReadValueBeforeAndAfterLoading\n");
661 #endif
662  UINT32 refSize = INS_MemoryOperandSize(ins, memOp);
663 
664  if (IsFloatInstructionAndOkToApproximate(INS_Address(ins))) {
665  unsigned int operSize = FloatOperandSize(INS_Address(ins), INS_MemoryOperandIndexToOperandIndex(ins, memOp));
666  switch (refSize) {
667  case 1:
668  case 2:
669  assert(0 && "memory read floating data with unexptected small size");
670  case 4:
671  HANDLE_CASE(float, 4, true);
672  break;
673  case 8:
674  HANDLE_CASE(double, 8, true);
675  break;
676  // case 8: HANDLE_CASE_LOWER(double, float, 8); break;
677  case 10:
678  HANDLE_CASE(uint8_t, 10, true);
679  break;
680  case 16: {
681  switch (operSize) {
682  case 4:
683  HANDLE_CASE(float, 16, true);
684  break;
685  case 8:
686  HANDLE_CASE(double, 16, true);
687  break;
688  // case 8: HANDLE_CASE_LOWER(double, float, 16); break;
689  default:
690  assert(0 && "handle large mem read with unexpected operand size\n");
691  break;
692  }
693  } break;
694  case 32: {
695  switch (operSize) {
696  case 4:
697  HANDLE_CASE(float, 32, true);
698  break;
699  case 8:
700  HANDLE_CASE(double, 32, true);
701  break;
702  // case 8: HANDLE_CASE_LOWER(double, float, 32); break;
703  default:
704  assert(0 && "handle large mem read with unexpected operand size\n");
705  break;
706  }
707  } break;
708  default:
709  assert(0 && "unexpected large memory read\n");
710  break;
711  }
712  } else {
713  switch (refSize) {
714 #ifdef SKIP_SMALLCASE
715  // do nothing when access is small
716  case 1:
717  break;
718  case 2:
719  break;
720 #else
721  case 1:
722  HANDLE_CASE(uint8_t, 1, false);
723  break;
724  case 2:
725  HANDLE_CASE(uint16_t, 2, false);
726  break;
727 #endif
728  case 4:
729  HANDLE_CASE(uint32_t, 4, false);
730  break;
731  case 8:
732  HANDLE_CASE(uint64_t, 8, false);
733  break;
734 
735  default: {
736  HANDLE_LARGE();
737  }
738  }
739  }
740 #ifdef DEBUG_ZEROSPY
741  printf("\nINFO : Exit InstrumentReadValueBeforeAndAfterLoading\n");
742 #endif
743  }
744 };
745 
746 /********************* instrument analysis ************************/
747 
748 static inline bool INS_IsIgnorable(INS ins) {
749  if (INS_IsFarJump(ins) || INS_IsDirectFarJump(ins) || INS_IsMaskedJump(ins))
750  return true;
751  else if (INS_IsRet(ins) || INS_IsIRet(ins))
752  return true;
753  else if (INS_IsCall(ins) || INS_IsSyscall(ins))
754  return true;
755  else if (INS_IsBranch(ins) || INS_IsRDTSC(ins) || INS_IsNop(ins))
756  return true;
757  else if (INS_IsPrefetch(ins)) // Prefetch instructions might access addresses which are invalid.
758  return true;
759  // XSAVEC and XRSTOR are problematic since its access length is variable.
760  // Execution of XSAVEC is similar to that of XSAVE. XSAVEC differs from XSAVE in that it uses compaction and that it may use the init optimization.
761  // It fails with "Cannot use IARG_MEMORYWRITE_SIZE on non-standard memory access of instruction at 0xfoo: xsavec ptr [rsp]" error.
762  // A correct solution should use INS_hasKnownMemorySize() which is not available in Pin 2.14.
763  if (INS_Mnemonic(ins) == "XSAVEC")
764  return true;
765  if (INS_Mnemonic(ins) == "XSAVE")
766  return true;
767  if (INS_Mnemonic(ins) == "XRSTOR")
768  return true;
769  return false;
770 }
771 
772 static VOID InstrumentInsCallback(INS ins, VOID* v, const uint32_t opaqueHandle) {
773 #ifdef DEBUG_ZEROSPY
774  printf("\nINFO : In InstrumentInsCallback\n");
775  if (!INS_HasFallThrough(ins)) {
776  printf("\nINFO : Exit InstrumentInsCallback !INS_HasFallThrough\n");
777  return;
778  }
779  if (INS_IsIgnorable(ins)) {
780  printf("\nINFO : Exit InstrumentInsCallback INS_IsIgnorable\n");
781  return;
782  }
783  if (INS_IsControlFlow(ins) || INS_IsRet(ins)) {
784  printf("\nINFO : Exit InstrumentInsCallback INS_IsControlFlow(ins) || INS_IsRet(ins)\n");
785  return;
786  }
787 #else
788  if (!INS_HasFallThrough(ins))
789  return;
790  if (INS_IsIgnorable(ins))
791  return;
792  if (INS_IsControlFlow(ins) || INS_IsRet(ins))
793  return;
794 #endif
795 
796  //Instrument memory reads to find redundancy
797  // Special case, if we have only one read operand
798  UINT32 whichOp = 0;
799  if (GetNumReadOperandsInIns(ins, whichOp) == 1) {
800  // Read the value at location before and after the instruction
801  LoadSpyInstrument::InstrumentReadValueBeforeAndAfterLoading(ins, whichOp, opaqueHandle);
802  } else {
803  UINT32 memOperands = INS_MemoryOperandCount(ins);
804  for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
805  if (!INS_MemoryOperandIsRead(ins, memOp))
806  continue;
807  LoadSpyInstrument::InstrumentReadValueBeforeAndAfterLoading(ins, memOp, opaqueHandle);
808  }
809  }
810 #ifdef DEBUG_ZEROSPY
811  printf("\nINFO : Exit InstrumentInsCallback\n");
812 #endif
813 }
814 
815 inline VOID Update(uint32_t bytes, THREADID threadId) {
816 #ifdef DEBUG_ZEROSPY
817  printf("\nINFO : In Update\n");
818 #endif
819  RedSpyThreadData* const tData = ClientGetTLS(threadId);
820  tData->bytesLoad += bytes;
821 #ifdef DEBUG_ZEROSPY
822  printf("\nINFO : Exit Update\n");
823 #endif
824 }
825 
826 //instrument the trace, count the number of ins in the trace, decide to instrument or not
827 static void InstrumentTrace(TRACE trace, void* f) {
828 #ifdef DEBUG_ZEROSPY
829  printf("\nINFO : In InstrumentTrace\n");
830 #endif
831  for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
832  uint32_t totBytes = 0;
833  for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins)) {
834  if (!INS_HasFallThrough(ins))
835  continue;
836  if (INS_IsIgnorable(ins))
837  continue;
838  if (INS_IsControlFlow(ins) || INS_IsRet(ins))
839  continue;
840 
841  if (INS_IsMemoryRead(ins)) {
842  totBytes += INS_MemoryReadSize(ins);
843  }
844  }
845  BBL_InsertCall(bbl, IPOINT_BEFORE, (AFUNPTR)Update, IARG_UINT32, totBytes, IARG_THREAD_ID, IARG_END);
846  }
847 #ifdef DEBUG_ZEROSPY
848  printf("\nINFO : Exit InstrumentTrace\n");
849 #endif
850 }
851 
852 struct DRedData {
853  uint64_t index;
854  uint64_t frequency;
855  uint64_t all0freq;
856  uint64_t ltot;
857  uint8_t state;
858 };
859 
860 static inline bool DRedundacyCompare(const struct DRedData& first, const struct DRedData& second) {
861  return first.frequency > second.frequency;
862 }
863 
864 #define LEVEL_1_RED_THRESHOLD 0.90
865 #define LEVEL_2_RED_THRESHOLD 0.70
866 #define LEVEL_3_RED_THRESHOLD 0.50
867 #define PRINT_ALL_PAGE_INFO
868 
869 static void PrintPageRedundancy(THREADID threadId) {
870  vector<DRedData> tmpList;
871  vector<DRedData>::iterator tmpIt;
872  unordered_map<uint64_t, DRedData> tmpMap;
873  unordered_map<uint64_t, DRedData>::iterator tmpMapIt;
874 
875  uint64_t grandTotalRedundantBytes = 0;
876  uint64_t grandTotalRedundantPage_level1 = 0;
877  uint64_t grandTotalRedundantPage_level2 = 0;
878  uint64_t grandTotalRedundantPage_level3 = 0;
879  uint64_t grandTotalPage = 0;
880  uint64_t all0page = 0;
881  float maxrate = 0;
882  float minrate = 100;
883  fprintf(gTraceFile, "\n--------------- Dumping PAGE Redundancy Info ----------------\n");
884  fprintf(gTraceFile, "\n*************** Dump Data from Thread %d ****************\n", threadId);
885 
886  for (unordered_map<uint64_t, RedLogs>::iterator it = RedMap[threadId].begin(); it != RedMap[threadId].end(); ++it) {
887  uint64_t key = GET_PAGE_INDEX((*it).first);
888  tmpMapIt = tmpMap.find(key);
889  if (tmpMapIt == tmpMap.end()) {
890  DRedData tmp = {key, (*it).second.zerobytes, (*it).second.zeroreads, (*it).second.reads, (*it).second.state};
891  tmpMap[key] = tmp;
892  } else {
893  (*tmpMapIt).second.frequency += (*it).second.zerobytes;
894  (*tmpMapIt).second.all0freq += (*it).second.zeroreads;
895  (*tmpMapIt).second.ltot += (*it).second.reads;
896  (*tmpMapIt).second.state &= (*it).second.state;
897  }
898  }
899  for (unordered_map<uint64_t, DRedData>::iterator it = tmpMap.begin(); it != tmpMap.end(); ++it) {
900  DRedData tmp = (*it).second;
901  tmpList.push_back(tmp);
902  grandTotalRedundantBytes += tmp.frequency;
903  if (maxrate < (float)tmp.all0freq / (float)tmp.ltot) {
904  maxrate = (float)tmp.all0freq / (float)tmp.ltot;
905  }
906  if (minrate > (float)tmp.all0freq / (float)tmp.ltot) {
907  minrate = (float)tmp.all0freq / (float)tmp.ltot;
908  }
909  grandTotalPage++;
910  if (tmp.state == STATE_ZERO)
911  ++all0page;
912  if ((float)tmp.all0freq / (float)tmp.ltot > LEVEL_1_RED_THRESHOLD) {
913  grandTotalRedundantPage_level1++;
914  }
915  if ((float)tmp.all0freq / (float)tmp.ltot > LEVEL_2_RED_THRESHOLD) {
916  grandTotalRedundantPage_level2++;
917  }
918  if ((float)tmp.all0freq / (float)tmp.ltot > LEVEL_3_RED_THRESHOLD) {
919  grandTotalRedundantPage_level3++;
920  }
921  }
922 
923  //__sync_fetch_and_add(&grandTotBytesRedLoad,grandTotalRedundantBytes);
924 
925  fprintf(gTraceFile, "\n Total redundant bytes = %f %%, rate range from [%f, %f] %%\n", grandTotalRedundantBytes * 100.0 / ClientGetTLS(threadId)->bytesLoad, minrate * 100, maxrate * 100);
926 
927  fprintf(gTraceFile, "\n Total redundant Pages (Only Reading 0s) = %f %%\n", all0page * 100.0 / grandTotalPage);
928  fprintf(gTraceFile, "\n Total redundant Pages (local redundant rate > %f %%) = %f %%\n", LEVEL_1_RED_THRESHOLD * 100.0, grandTotalRedundantPage_level1 * 100.0 / grandTotalPage);
929  fprintf(gTraceFile, "\n Total redundant Pages (local redundant rate > %f %%) = %f %%\n", LEVEL_2_RED_THRESHOLD * 100.0, grandTotalRedundantPage_level2 * 100.0 / grandTotalPage);
930  fprintf(gTraceFile, "\n Total redundant Pages (local redundant rate > %f %%) = %f %%\n", LEVEL_3_RED_THRESHOLD * 100.0, grandTotalRedundantPage_level3 * 100.0 / grandTotalPage);
931 #ifdef PRINT_ALL_PAGE_INFO
932  sort(tmpList.begin(), tmpList.end(), DRedundacyCompare);
933  int cntxtNum = 0;
934  for (vector<DRedData>::iterator listIt = tmpList.begin(); listIt != tmpList.end(); ++listIt) {
935  if (cntxtNum < MAX_REDUNDANT_CONTEXTS_TO_LOG) {
936  fprintf(gTraceFile, "\n\n======= PAGE %lx : (%f) %% of total Redundant (%ld Bytes), all zero ratio %f %% (%ld Zeros / %ld Reads) ======\n",
937  (*listIt).index,
938  (*listIt).frequency * 100.0 / grandTotalRedundantBytes,
939  (*listIt).frequency,
940  (*listIt).all0freq * 100.0 / (*listIt).ltot,
941  (*listIt).all0freq, (*listIt).ltot);
942  } else {
943  break;
944  }
945  cntxtNum++;
946  }
947 #endif
948  fprintf(gTraceFile, "\n------------ Dumping Page Redundancy Info Finish -------------\n");
949 }
950 
951 static void PrintCacheRedundancy(THREADID threadId) {
952  vector<DRedData> tmpList;
953  vector<DRedData>::iterator tmpIt;
954 
955  uint64_t grandTotalRedundantBytes = 0;
956  uint64_t grandTotalRedundantPage_level1 = 0;
957  uint64_t grandTotalRedundantPage_level2 = 0;
958  uint64_t grandTotalRedundantPage_level3 = 0;
959  uint64_t grandTotalPage = 0;
960  uint64_t all0page = 0;
961  float maxrate = 0;
962  float minrate = 100;
963  fprintf(gTraceFile, "\n--------------- Dumping CACHE Redundancy Info ----------------\n");
964  fprintf(gTraceFile, "\n*************** Dump Data from Thread %d ****************\n", threadId);
965 
966  for (unordered_map<uint64_t, RedLogs>::iterator it = RedMap[threadId].begin(); it != RedMap[threadId].end(); ++it) {
967  DRedData tmp = {(*it).first, (*it).second.zerobytes, (*it).second.zeroreads, (*it).second.reads, (*it).second.state};
968  tmpList.push_back(tmp);
969  grandTotalRedundantBytes += tmp.frequency;
970  if (maxrate < (float)tmp.all0freq / (float)tmp.ltot) {
971  maxrate = (float)tmp.all0freq / (float)tmp.ltot;
972  }
973  if (minrate > (float)tmp.all0freq / (float)tmp.ltot) {
974  minrate = (float)tmp.all0freq / (float)tmp.ltot;
975  }
976  grandTotalPage++;
977  if (tmp.state == STATE_ZERO)
978  ++all0page;
979  if ((float)tmp.all0freq / (float)tmp.ltot > LEVEL_1_RED_THRESHOLD) {
980  grandTotalRedundantPage_level1++;
981  }
982  if ((float)tmp.all0freq / (float)tmp.ltot > LEVEL_2_RED_THRESHOLD) {
983  grandTotalRedundantPage_level2++;
984  }
985  if ((float)tmp.all0freq / (float)tmp.ltot > LEVEL_3_RED_THRESHOLD) {
986  grandTotalRedundantPage_level3++;
987  }
988  }
989 
990  __sync_fetch_and_add(&grandTotBytesRedLoad, grandTotalRedundantBytes);
991 
992  fprintf(gTraceFile, "\n Total redundant bytes = %f %%, rate range from [%f, %f] %%\n", grandTotalRedundantBytes * 100.0 / ClientGetTLS(threadId)->bytesLoad, minrate * 100, maxrate * 100);
993 
994  fprintf(gTraceFile, "\n Total redundant Caches (Only Reading 0s) = %f %%\n", all0page * 100.0 / grandTotalPage);
995  fprintf(gTraceFile, "\n Total redundant Caches (local redundant rate > %f %%) = %f %%\n", LEVEL_1_RED_THRESHOLD * 100.0, grandTotalRedundantPage_level1 * 100.0 / grandTotalPage);
996  fprintf(gTraceFile, "\n Total redundant Caches (local redundant rate > %f %%) = %f %%\n", LEVEL_2_RED_THRESHOLD * 100.0, grandTotalRedundantPage_level2 * 100.0 / grandTotalPage);
997  fprintf(gTraceFile, "\n Total redundant Caches (local redundant rate > %f %%) = %f %%\n", LEVEL_3_RED_THRESHOLD * 100.0, grandTotalRedundantPage_level3 * 100.0 / grandTotalPage);
998 #ifdef PRINT_ALL_PAGE_INFO
999  sort(tmpList.begin(), tmpList.end(), DRedundacyCompare);
1000  int cntxtNum = 0;
1001  for (vector<DRedData>::iterator listIt = tmpList.begin(); listIt != tmpList.end(); ++listIt) {
1002  if (cntxtNum < MAX_REDUNDANT_CONTEXTS_TO_LOG) {
1003  fprintf(gTraceFile, "\n\n======= CACHE %lx : (%f) %% of total Redundant (%ld Bytes), all zero ratio %f %% (%ld Zeros / %ld Reads) ======\n",
1004  (*listIt).index,
1005  (*listIt).frequency * 100.0 / grandTotalRedundantBytes,
1006  (*listIt).frequency,
1007  (*listIt).all0freq * 100.0 / (*listIt).ltot,
1008  (*listIt).all0freq, (*listIt).ltot);
1009  } else {
1010  break;
1011  }
1012  cntxtNum++;
1013  }
1014 #endif
1015  fprintf(gTraceFile, "\n------------ Dumping CACHE Redundancy Info Finish -------------\n");
1016 }
1017 
1018 /*
1019 static void HPCRunRedundancyPairs(THREADID threadId) {
1020  vector<RedundacyData> tmpList;
1021  vector<RedundacyData>::iterator tmpIt;
1022 
1023  for (unordered_map<uint64_t, RedLogs>::iterator it = RedMap[threadId].begin(); it != RedMap[threadId].end(); ++it) {
1024  RedundacyData tmp = { DECODE_DEAD ((*it).first), DECODE_KILL((*it).first), (*it).second.red, (*it).second.tot};
1025  tmpList.push_back(tmp);
1026  }
1027 
1028  sort(tmpList.begin(), tmpList.end(), RedundacyCompare);
1029  vector<HPCRunCCT_t*> HPCRunNodes;
1030  int cntxtNum = 0;
1031  for (vector<RedundacyData>::iterator listIt = tmpList.begin(); listIt != tmpList.end(); ++listIt) {
1032  if (cntxtNum < MAX_REDUNDANT_CONTEXTS_TO_LOG) {
1033  HPCRunCCT_t *HPCRunNode = new HPCRunCCT_t();
1034  HPCRunNode->ctxtHandle1 = (*listIt).dead;
1035  HPCRunNode->ctxtHandle2 = (*listIt).kill;
1036  HPCRunNode->metric = (*listIt).frequency;
1037  HPCRunNode->metric_id = redload_metric_id;
1038  HPCRunNodes.push_back(HPCRunNode);
1039  }
1040  else {
1041  break;
1042  }
1043  cntxtNum++;
1044  }
1045  newCCT_hpcrun_build_cct(HPCRunNodes, threadId);
1046 }
1047 
1048 static void HPCRunApproxRedundancyPairs(THREADID threadId) {
1049  vector<RedundacyData> tmpList;
1050  vector<RedundacyData>::iterator tmpIt;
1051 
1052  for (unordered_map<uint64_t, RedLogs>::iterator it = ApproxRedMap[threadId].begin(); it != ApproxRedMap[threadId].end(); ++it) {
1053  RedundacyData tmp = { DECODE_DEAD ((*it).first), DECODE_KILL((*it).first), (*it).second.red, (*it).second.tot};
1054  tmpList.push_back(tmp);
1055  }
1056 
1057  sort(tmpList.begin(), tmpList.end(), RedundacyCompare);
1058  vector<HPCRunCCT_t*> HPCRunNodes;
1059  int cntxtNum = 0;
1060  for (vector<RedundacyData>::iterator listIt = tmpList.begin(); listIt != tmpList.end(); ++listIt) {
1061  if (cntxtNum < MAX_REDUNDANT_CONTEXTS_TO_LOG) {
1062  HPCRunCCT_t *HPCRunNode = new HPCRunCCT_t();
1063  HPCRunNode->ctxtHandle1 = (*listIt).dead;
1064  HPCRunNode->ctxtHandle2 = (*listIt).kill;
1065  HPCRunNode->metric = (*listIt).frequency;
1066  HPCRunNode->metric_id = redload_approx_metric_id;
1067  HPCRunNodes.push_back(HPCRunNode);
1068  }
1069  else {
1070  break;
1071  }
1072  cntxtNum++;
1073  }
1074  newCCT_hpcrun_build_cct(HPCRunNodes, threadId);
1075 }
1076 */
1077 // On each Unload of a loaded image, the accummulated redundancy information is dumped
1078 static VOID ImageUnload(IMG img, VOID* v) {
1079  printf("\nImage %s Unloading...\n", IMG_Name(img).c_str());
1080  fflush(stdout);
1081  fprintf(gTraceFile, "\n TODO .. Multi-threading is not well supported.");
1082  THREADID threadid = PIN_ThreadId();
1083  fprintf(gTraceFile, "\nUnloading %s", IMG_Name(img).c_str());
1084  if (RedMap[threadid].empty())
1085  return;
1086  PIN_LockClient();
1087  PrintCacheRedundancy(threadid);
1088  PrintPageRedundancy(threadid);
1089  PIN_UnlockClient();
1090  printf("Unlocked\n");
1091  fflush(stdout);
1092  // clear redmap now
1093  RedMap[threadid].clear();
1094  printf("...Finish\n");
1095  fflush(stdout);
1096 }
1097 
1098 static VOID ThreadFiniFunc(THREADID threadid, const CONTEXT* ctxt, INT32 code, VOID* v) {
1099  __sync_fetch_and_add(&grandTotBytesLoad, ClientGetTLS(threadid)->bytesLoad);
1100  /*
1101  // output the CCT for hpcviewer format
1102  HPCRunRedundancyPairs(threadid);
1103  HPCRunApproxRedundancyPairs(threadid);
1104  newCCT_hpcrun_selection_write(threadid);*/
1105 }
1106 
1107 static VOID FiniFunc(INT32 code, VOID* v) {
1108  // do whatever you want to the full CCT with footpirnt
1109  uint64_t redReadTmp = 0;
1110  uint64_t approxRedReadTmp = 0;
1111  for (int i = 0; i < THREAD_MAX; ++i) {
1112  unordered_map<uint64_t, RedLogs>::iterator it;
1113  if (!RedMap[i].empty()) {
1114  for (it = RedMap[i].begin(); it != RedMap[i].end(); ++it) {
1115  redReadTmp += (*it).second.zerobytes;
1116  }
1117  }
1118  }
1119  grandTotBytesRedLoad += redReadTmp;
1120  grandTotBytesApproxRedLoad += approxRedReadTmp;
1121 
1122  fprintf(gTraceFile, "\n#Redundant Read:");
1123  fprintf(gTraceFile, "\nTotalBytesLoad: %lu \n", grandTotBytesLoad);
1124  fprintf(gTraceFile, "\nRedundantBytesLoad: %lu %.2f\n", grandTotBytesRedLoad, grandTotBytesRedLoad * 100.0 / grandTotBytesLoad);
1125  fprintf(gTraceFile, "\nApproxRedundantBytesLoad: %lu %.2f\n", grandTotBytesApproxRedLoad, grandTotBytesApproxRedLoad * 100.0 / grandTotBytesLoad);
1126 }
1127 
1128 static void InitThreadData(RedSpyThreadData* tdata) {
1129  tdata->bytesLoad = 0;
1130  tdata->sampleFlag = true;
1131  tdata->numIns = 0;
1132  /* for (int i = 0; i < THREAD_MAX; ++i) {
1133  RedMap[i].set_empty_key(0);
1134  ApproxRedMap[i].set_empty_key(0);
1135  }
1136 */
1137 }
1138 
1139 static VOID ThreadStart(THREADID threadid, CONTEXT* ctxt, INT32 flags, VOID* v) {
1140  RedSpyThreadData* tdata = (RedSpyThreadData*)memalign(32, sizeof(RedSpyThreadData));
1141  InitThreadData(tdata);
1142  RedMap[threadid].reserve(10000000);
1143  // __sync_fetch_and_add(&gClientNumThreads, 1);
1144 #ifdef MULTI_THREADED
1145  PIN_SetThreadData(client_tls_key, tdata, threadid);
1146 #else
1147  gSingleThreadedTData = tdata;
1148 #endif
1149 }
1150 
1151 // user-defined function for metric computation
1152 // hpcviewer can only show the numbers for the metric
1153 uint64_t computeMetricVal(void* metric) {
1154  if (!metric)
1155  return 0;
1156  return (uint64_t)metric;
1157 }
1158 
1159 int main(int argc, char* argv[]) {
1160  // Initialize PIN
1161  if (PIN_Init(argc, argv))
1162  return Usage();
1163 
1164  // Initialize Symbols, we need them to report functions and lines
1165  PIN_InitSymbols();
1166 
1167  // Init Client
1168  ClientInit(argc, argv);
1169  // Intialize CCTLib
1171  /*
1172  // Init hpcrun format output
1173  init_hpcrun_format(argc, argv, NULL, NULL, false);
1174  // Create new metrics
1175  redload_metric_id = hpcrun_create_metric("RED_LOAD");
1176  redload_approx_metric_id = hpcrun_create_metric("RED_LOAD_APPROX");
1177  */
1178  // Obtain a key for TLS storage.
1179  client_tls_key = PIN_CreateThreadDataKey(nullptr /*TODO have a destructir*/);
1180  // Register ThreadStart to be called when a thread starts.
1181  PIN_AddThreadStartFunction(ThreadStart, nullptr);
1182 
1183 
1184  // fini function for post-mortem analysis
1185  PIN_AddThreadFiniFunction(ThreadFiniFunc, nullptr);
1186  PIN_AddFiniFunction(FiniFunc, nullptr);
1187 
1188  TRACE_AddInstrumentFunction(InstrumentTrace, nullptr);
1189 
1190  // Register ImageUnload to be called when an image is unloaded
1191  IMG_AddUnloadFunction(ImageUnload, nullptr);
1192 
1193  // Launch program now
1194  PIN_StartProgram();
1195  return 0;
1196 }
#define MAX_FILE_PATH
Definition: cctlib.H:18
#define INTERESTING_INS_ALL
Definition: cctlib.H:85
uint64_t metric
Definition: cctlib.H:60
int PinCCTLibInit(IsInterestingInsFptr isInterestingIns, FILE *logFile, CCTLibInstrumentInsCallback userCallback, VOID *userCallbackArg, BOOL doDataCentric=false)
Definition: cctlib.cpp:3132
hpcrun_metricFlags_t flags
Definition: cctlib.cpp:3425
static USIZE INS_MemoryReadSize(INS ins)
static BOOL INS_IsMaskedJump(INS ins)
struct RedSpyThreadData __attribute__
uint8_t value[MAX_WRITE_OP_LENGTH]
uint64_t all0freq
uint64_t frequency
static __attribute__((always_inline)) void InstrumentReadValueBeforeAndAfterLoading(INS ins
uint64_t zeroreads
uint64_t zerobytes
uint64_t reads
static __attribute__((always_inline)) uint32_t BodyRedZero(uint8_t *addr)
static __attribute__((always_inline)) uint32_t BodyRedZero(uint8_t *addr)
static __attribute__((always_inline)) VOID CheckNByteValueAfterRead(void *addr
AddToRedTable(GET_CACHELINE_INDEX((uint64_t) addr), rednum, zero, threadId)
AddToRedTable(key, rednum, zero, threadId)
void f()
Definition: test1.c:23
uint64_t computeMetricVal(void *metric)
static bool DRedundacyCompare(const struct DRedData &first, const struct DRedData &second)
static void ClientInit(int argc, char *argv[])
#define LEVEL_1_RED_THRESHOLD
int main(int argc, char *argv[])
#define HANDLE_LARGE()
static FILE * gTraceFile
uint64_t grandTotBytesRedLoad
xed_state_t xedState
#define MAX_REDUNDANT_CONTEXTS_TO_LOG
static unordered_map< uint64_t, RedLogs > RedMap[THREAD_MAX]
static int GetNumReadOperandsInIns(INS ins, UINT32 &whichOp)
static VOID ImageUnload(IMG img, VOID *v)
#define HANDLE_CASE(T, ACCESS_LEN, IS_APPROX)
static RedSpyThreadData * gSingleThreadedTData
#define EIGHT_BYTE_WRITE_ACTION
char dummy2[128]
static const uint64_t READ_ACCESS_STATES[]
#define THREAD_MAX
#define ONE_BYTE_READ_ACTION
int redload_approx_metric_id
static INT32 Usage()
static bool IsFloatInstructionOld(ADDRINT ip)
#define EIGHT_BYTE_READ_ACTION
#define TWO_BYTE_READ_ACTION
static void AddToRedTable(uint64_t key, uint16_t value, uint16_t zero, THREADID threadId) __attribute__((always_inline
static uint16_t FloatOperandSize(ADDRINT ip, uint32_t oper)
static const uint8_t OVERFLOW_CHECK[]
static void flatten
#define LEVEL_2_RED_THRESHOLD
#define LEVEL_3_RED_THRESHOLD
VOID Update(uint32_t bytes, THREADID threadId)
#define GET_CACHELINE_INDEX(x)
#define STATE_ZERO
#define ISSAMECACHELINE(addr, accesslen)
static VOID InstrumentInsCallback(INS ins, VOID *v, const uint32_t opaqueHandle)
static void InstrumentTrace(TRACE trace, void *f)
static void InitThreadData(RedSpyThreadData *tdata)
static bool INS_IsIgnorable(INS ins)
RedSpyThreadData * ClientGetTLS(const THREADID threadId)
#define GET_PAGE_INDEX(x)
static bool IsFloatInstructionAndOkToApproximate(ADDRINT ip)
static VOID FiniFunc(INT32 code, VOID *v)
#define TWO_BYTE_WRITE_ACTION
static const uint64_t WRITE_ACCESS_STATES[]
static VOID CheckAfterLargeRead(void *addr, UINT32 accessLen, uint32_t opaqueHandle, THREADID threadId)
uint64_t grandTotBytesLoad
#define FOUR_BYTE_READ_ACTION
static void PrintCacheRedundancy(THREADID threadId)
uint64_t grandTotBytesApproxRedLoad
static VOID ThreadFiniFunc(THREADID threadid, const CONTEXT *ctxt, INT32 code, VOID *v)
static bool IsOkToApproximate(xed_decoded_inst_t &xedd)
char dummy1[128]
#define ONE_BYTE_WRITE_ACTION
static void PrintPageRedundancy(THREADID threadId)
#define FOUR_BYTE_WRITE_ACTION
static TLS_KEY client_tls_key
static VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v)
int redload_metric_id
struct @16 LoadSpyGlobals