Tejas/src/emulator/pin/printingTool.cpp

375 lines
8.9 KiB
C++
Executable File

#include <iostream>
#include <fstream>
#include "pin.H"
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <cstdlib>
#include <cstring>
#include <sched.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <time.h>
#include <sys/timeb.h>
#include "IPCBase.h"
#include "shmem.h"
#include "encoding.h"
#ifdef _LP64
#define MASK 0xffffffffffffffff
#else
#define MASK 0x00000000ffffffff
#endif
// Defining command line arguments
KNOB<UINT64> KnobLong(KNOB_MODE_WRITEONCE, "pintool", "map", "1", "Maps");
PIN_LOCK lock;
INT32 numThreads = 0;
UINT64 checkSum = 0;
//IPC::IPCBase *tst;
bool pumpingStatus[MaxNumThreads];
ADDRINT curSynchVar[MaxNumThreads];
#define PacketEpoch 50
uint32_t countPacket[MaxNumThreads];
// needs -lrt (real-time lib)
// 1970-01-01 epoch UTC time, 1 nanosecond resolution
uint64_t ClockGetTime() {
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
return (uint64_t) ts.tv_sec * 1000000000LL + (uint64_t) ts.tv_nsec;
}
// this compulsory is true if it is entering some function
// so that even if halts we have a timer packet here.
void sendTimerPacket(int tid, bool compulsory) {
if ((countPacket[tid]++ % PacketEpoch)==0 || compulsory){
GetLock(&lock, tid + 1);
checkSum +=TIMER;
ReleaseLock(&lock);
countPacket[tid]=0;
/*uint64_t time = ClockGetTime();
while (tst->analysisFn(tid, time, TIMER, 0) == -1) {
PIN_Yield();
}*/
}
}
#define cmp(a) (rtn_name->find(a) != string::npos)
/*
bool isActive(int tid) {
return pumpingStatus[tid];
}
void reActivate(int tid) {
pumpingStatus[tid] = true;
curSynchVar[tid] = 0;
}
void deActivate(int tid, ADDRINT addr) {
curSynchVar[tid] = addr;
pumpingStatus[tid] = false;
}
bool hasEntered(int tid, ADDRINT addr) {
return (curSynchVar[tid] == addr);
}
*/
VOID ThreadStart(THREADID threadid, CONTEXT *ctxt, INT32 flags, VOID *v) {
GetLock(&lock, threadid + 1);
numThreads++;
printf("threads till now %d\n", numThreads);
fflush(stdout);
ReleaseLock(&lock);
ASSERT(numThreads <= MaxNumThreads, "Maximum number of threads exceeded\n");
pumpingStatus[numThreads - 1] = true;
/*tst->onThread_start(threadid);*/
}
VOID ThreadFini(THREADID tid, const CONTEXT *ctxt, INT32 flags, VOID *v) {
/*while (tst->onThread_finish(tid) == -1) {
PIN_Yield();
}*/
}
//Pass a memory read record
VOID RecordMemRead(THREADID tid, VOID * ip, VOID * addr) {
/*
if (!isActive(tid))
return;
*/
sendTimerPacket(tid,false);
GetLock(&lock, tid + 1);
checkSum +=MEMREAD;
ReleaseLock(&lock);
/*uint64_t nip = MASK & (uint64_t) ip;
uint64_t naddr = MASK & (uint64_t) addr;
while (tst->analysisFn(tid, nip, MEMREAD, naddr) == -1) {
PIN_Yield();
}
*/}
// Pass a memory write record
VOID RecordMemWrite(THREADID tid, VOID * ip, VOID * addr) {
/*
if (!isActive(tid))
return;
*/
sendTimerPacket(tid,false);
GetLock(&lock, tid + 1);
checkSum +=MEMWRITE;
ReleaseLock(&lock);
/*
uint64_t nip = MASK & (uint64_t) ip;
uint64_t naddr = MASK & (uint64_t) addr;
while (tst->analysisFn(tid, nip, MEMWRITE, naddr) == -1) {
PIN_Yield();
}
*/
}
VOID BrnFun(THREADID tid, ADDRINT tadr, BOOL taken, VOID *ip) {
/*
if (!isActive(tid))
return;
*/
sendTimerPacket(tid,false);
/*
uint64_t nip = MASK & (uint64_t) ip;
uint64_t ntadr = MASK & (uint64_t) tadr;
if (taken) {
GetLock(&lock, tid + 1);
checkSum +=TAKEN;
ReleaseLock(&lock);
while (tst->analysisFn(tid, nip, TAKEN, ntadr) == -1) {
PIN_Yield();
}
} else {
GetLock(&lock, tid + 1);
checkSum +=NOTTAKEN;
ReleaseLock(&lock);
while (tst->analysisFn(tid, nip, NOTTAKEN, ntadr) == -1) {
PIN_Yield();
}
}
*/
}
//VOID FunEntry(ADDRINT first_arg, const string * name, THREADID threadid)
VOID FunEntry(ADDRINT first_arg, UINT32 encode, THREADID tid) {
uint64_t time = ClockGetTime();
/*
if (!isActive(tid)) {
// printf("tid %d could not register %d entry as not active\n", tid,
// encode);
// fflush(stdout);
return;
}
*/
// deActivate(tid, first_arg);
sendTimerPacket(tid,true);
if (true){//(encode == LOCK || encode == UNLOCK) {
const char *temp = findType(encode);
GetLock(&lock, tid + 1);
printf("%d %s with first arg %p --%llu \n", tid, temp,
(void *) first_arg, time);
fflush(stdout);
ReleaseLock(&lock);
}
GetLock(&lock, tid + 1);
checkSum +=encode;
ReleaseLock(&lock);
/*
uint64_t uarg = MASK & (uint64_t) first_arg;
while (tst->analysisFn(tid, time, encode, uarg) == -1) {
PIN_Yield();
}
*/
}
VOID FunExit(ADDRINT first_arg, UINT32 encode, THREADID tid) {
// uint64_t time = ClockGetTime();
/*
if (!isActive(tid) && !hasEntered(tid,first_arg)) {
// printf("tid %d could not register %d exit as not active\n", tid,
// encode);
// fflush(stdout);
return;
}
*/
// reActivate(tid);
sendTimerPacket(tid,false);
/*
if (true){//(encode == LOCK+1) {
char* temp = findType(encode);
GetLock(&lock, tid + 1);
printf("%d %s with first arg %p --%llu\n", tid, temp,
(void *) first_arg, time);
//TraceFile << threadid <<" exit "<< *name << " returns " << ret << endl;
ReleaseLock(&lock);
}
*/
GetLock(&lock, tid + 1);
checkSum +=encode;
ReleaseLock(&lock);
/*
uint64_t uarg = MASK & (uint64_t) first_arg;
while (tst->analysisFn(tid, time, encode, uarg) == -1) {
PIN_Yield();
}
*/
}
// Pin calls this function every time a new instruction is encountered
VOID Instruction(INS ins, VOID *v) {
UINT32 memOperands = INS_MemoryOperandCount(ins);
if (INS_IsBranchOrCall(ins))//INS_IsIndirectBranchOrCall(ins))
{
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR) BrnFun, IARG_THREAD_ID,
IARG_BRANCH_TARGET_ADDR, IARG_BRANCH_TAKEN, IARG_INST_PTR,
IARG_END);
}
// Iterate over each memory operand of the instruction.
for (UINT32 memOp = 0; memOp < memOperands; memOp++) {
if (INS_MemoryOperandIsRead(ins, memOp)) {
INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
(AFUNPTR) RecordMemRead, IARG_THREAD_ID, IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp, IARG_END);
}
// Note that in some architectures a single memory operand can be
// both read and written (for instance incl (%eax) on IA-32)
// In that case we instrument it once for read and once for write.
if (INS_MemoryOperandIsWritten(ins, memOp)) {
INS_InsertPredicatedCall(ins, IPOINT_BEFORE,
(AFUNPTR) RecordMemWrite, IARG_THREAD_ID, IARG_INST_PTR,
IARG_MEMORYOP_EA, memOp, IARG_END);
}
}
}
//if (RTN_Valid(rtn) && RtnMatchesName(RTN_Name(rtn), name))
// This is a routine level instrumentation
VOID FlagRtn(RTN rtn, VOID* v) {
RTN_Open(rtn);
const string* rtn_name = new string(RTN_Name(rtn));
INT32 encode;
if (cmp("pthread_cond_broadcast"))
encode = BCAST;
else if (cmp("pthread_cond_signal"))
encode = SIGNAL;
else if (cmp("pthread_mutex_lock"))
encode = LOCK;
else if (cmp("pthread_mutex_unlock_"))
encode = UNLOCK; //pthread_mutex_unlock is just a wrapper
else if (cmp("pthread_join"))
encode = JOIN;
else if (cmp("pthread_cond_wait"))
encode = CONDWAIT;
else if (cmp("pthread_barrier_wait"))
encode = BARRIERWAIT;
else
encode = -1;
if (encode != -1 && RTN_Valid(rtn)) {
RTN_InsertCall(rtn, IPOINT_BEFORE, (AFUNPTR) FunEntry,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_UINT32, encode,
IARG_THREAD_ID, IARG_END);
RTN_InsertCall(rtn, IPOINT_AFTER, (AFUNPTR) FunExit,
IARG_FUNCARG_ENTRYPOINT_VALUE, 0, IARG_UINT32, encode + 1,
IARG_THREAD_ID, IARG_END);
}
RTN_Close(rtn);
}
// This function is called when the application exits
VOID Fini(INT32 code, VOID *v) {
printf("checkSum is %lld\n", checkSum);
/* tst->unload();*/
}
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage() {
cerr << "This tool instruments the benchmarks" << endl;
cerr << endl << KNOB_BASE::StringKnobSummary() << endl;
return -1;
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
// argc, argv are the entire command line, including pin -t <toolname> -- ...
int main(int argc, char * argv[]) {
UINT64 mask = KnobLong;
printf("mask for pin %lld\n", mask);
fflush(stdout);
if (sched_setaffinity(0, sizeof(mask), (cpu_set_t *) &mask) < 0) {
perror("sched_setaffinity");
}
PIN_InitSymbols();
// Initialize pin
if (PIN_Init(argc, argv))
return Usage();
/* tst = new IPC::Shm();*/
PIN_AddThreadStartFunction(ThreadStart, 0);
// Register Instruction to be called to instrument instructions
INS_AddInstrumentFunction(Instruction, 0);
// Register ThreadFini to be called when a thread exits
PIN_AddThreadFiniFunction(ThreadFini, 0);
// Register FlagRtn whenever you get a routine
RTN_AddInstrumentFunction(FlagRtn, 0);
// Register Fini to be called when the application exits
PIN_AddFiniFunction(Fini, 0);
// Start the program, never returns
PIN_StartProgram();
return 0;
}