You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
282 lines
9.0 KiB
282 lines
9.0 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
/* footprint.H
|
|
|
|
Measures the number of references to unique (16B default) chunks of
|
|
memory. The references can be code, data loads or data stores.
|
|
|
|
The output includes such things as a count of unique chunks that were just
|
|
loaded, just stored, just code fetches, both loaded and stored to, both
|
|
loaded-from and code-fetched from, etc. 7 valid combinations of 3 bits.
|
|
|
|
Whenever a reference to a chunk occurs, I OR on a bit indicating load,
|
|
store or code fetch.
|
|
|
|
With a small tweak, I can count references to the chunks if one wants to
|
|
know where all the action is, from a chunk referencing perspective.
|
|
|
|
optimization opportunity: do all the code fetches for a basic block at one time.
|
|
*/
|
|
#include "pin.H"
|
|
#include <map>
|
|
#include <iostream>
|
|
#include <sstream>
|
|
#include <iomanip>
|
|
#include <fstream>
|
|
using std::map;
|
|
using std::string;
|
|
using std::cout;
|
|
using std::endl;
|
|
using std::cerr;
|
|
|
|
const unsigned int FOOTPRINT_LOAD=1;
|
|
const unsigned int FOOTPRINT_STORE=2;
|
|
const unsigned int FOOTPRINT_CODE=4;
|
|
|
|
class footprint_thread_data_t {
|
|
map<ADDRINT,unsigned int> mem;
|
|
UINT64 block_total[8]; // 8 combinations of load, store, code
|
|
public:
|
|
|
|
footprint_thread_data_t() {
|
|
}
|
|
|
|
void load(ADDRINT ea) {
|
|
map<ADDRINT,unsigned int>::iterator it = mem.find(ea);
|
|
if (it == mem.end()) {
|
|
mem[ea] = FOOTPRINT_LOAD;
|
|
}
|
|
else {
|
|
mem[ea] = it->second | FOOTPRINT_LOAD;
|
|
}
|
|
}
|
|
void store(ADDRINT ea) {
|
|
map<ADDRINT,unsigned int>::iterator it = mem.find(ea);
|
|
if (it == mem.end()) {
|
|
mem[ea] = FOOTPRINT_STORE;
|
|
}
|
|
else {
|
|
mem[ea] = it->second | FOOTPRINT_STORE;
|
|
}
|
|
}
|
|
void code(ADDRINT ea) {
|
|
map<ADDRINT,unsigned int>::iterator it = mem.find(ea);
|
|
if (it == mem.end()) {
|
|
mem[ea] = FOOTPRINT_CODE;
|
|
}
|
|
else {
|
|
mem[ea] = it->second | FOOTPRINT_CODE;
|
|
}
|
|
}
|
|
void summary(std::ofstream* out) {
|
|
/*
|
|
1 = load
|
|
2 = store
|
|
4 = code
|
|
3 = load+store
|
|
5 = load+code
|
|
6 = store+code
|
|
7 = load+store+code
|
|
0 = nothing - error
|
|
*/
|
|
const char* header[] = {
|
|
/*0*/ "error",
|
|
/*1*/ "load",
|
|
/*2*/ "store",
|
|
/*3*/ "load+store",
|
|
/*4*/ "code",
|
|
/*5*/ "load+code",
|
|
/*6*/ "store+code",
|
|
/*7*/ "load+store+code"
|
|
};
|
|
|
|
for(unsigned int i=0;i<8;i++)
|
|
block_total[i] = 0;
|
|
|
|
map<ADDRINT,unsigned int>::iterator it = mem.begin();
|
|
for( ; it != mem.end() ; it++ ) {
|
|
block_total[it->second]++;
|
|
}
|
|
|
|
for(unsigned int i=0;i<8;i++) {
|
|
*out << std::setw(30) << header[i] << " " << std::setw(12) << block_total[i] << endl;
|
|
}
|
|
}
|
|
|
|
void update_totals(UINT64* out_total) {
|
|
for(unsigned int i=0;i<8;i++)
|
|
out_total[i] += block_total[i];
|
|
}
|
|
};
|
|
|
|
class footprint_t
|
|
{
|
|
KNOB<string> knob_output_file;
|
|
std::ofstream* out;
|
|
TLS_KEY tls_key;
|
|
unsigned int num_threads;
|
|
static const unsigned int chunk_size = 16;
|
|
footprint_thread_data_t* get_tls(THREADID tid) {
|
|
footprint_thread_data_t* tdata =
|
|
static_cast<footprint_thread_data_t*>(PIN_GetThreadData(tls_key, tid));
|
|
return tdata;
|
|
}
|
|
|
|
void summary() {
|
|
UINT64 block_total[8];
|
|
for(unsigned int j=0;j<8;j++)
|
|
block_total[j] = 0;
|
|
for(unsigned int i=0;i<num_threads;i++) {
|
|
footprint_thread_data_t* tdata = get_tls(i);
|
|
*out << "# FINI TID " << i << endl;
|
|
tdata->summary(out);
|
|
tdata->update_totals(block_total);
|
|
}
|
|
|
|
*out << "# FINI GLOBAL SUMMARY" << endl;
|
|
const char* header[] = {
|
|
/*0*/ "error",
|
|
/*1*/ "load",
|
|
/*2*/ "store",
|
|
/*3*/ "load+store",
|
|
/*4*/ "code",
|
|
/*5*/ "load+code",
|
|
/*6*/ "store+code",
|
|
/*7*/ "load+store+code"
|
|
};
|
|
|
|
for(unsigned int i=0;i<8;i++) {
|
|
*out << std::setw(30) << header[i] << " " << std::setw(12) << block_total[i] << endl;
|
|
}
|
|
|
|
}
|
|
|
|
public:
|
|
|
|
|
|
footprint_t()
|
|
: knob_output_file(KNOB_MODE_WRITEONCE, "pintool",
|
|
"o", "footprint.out", "specify output file name") {
|
|
num_threads = 0;
|
|
string file_name = knob_output_file.Value();
|
|
out = new std::ofstream(file_name.c_str());
|
|
}
|
|
|
|
void activate() {
|
|
tls_key = PIN_CreateThreadDataKey(0);
|
|
TRACE_AddInstrumentFunction(reinterpret_cast<TRACE_INSTRUMENT_CALLBACK>(instrument_trace), this);
|
|
PIN_AddThreadStartFunction(reinterpret_cast<THREAD_START_CALLBACK>(thread_start), this);
|
|
PIN_AddFiniFunction(reinterpret_cast<FINI_CALLBACK>(fini), this);
|
|
}
|
|
|
|
static ADDRINT mask(ADDRINT ea) {
|
|
const ADDRINT mask = ~static_cast<ADDRINT>(chunk_size-1);
|
|
return ea & mask;
|
|
}
|
|
|
|
static void load(footprint_t* xthis, THREADID tid, ADDRINT memea, UINT32 length) {
|
|
ADDRINT start = mask(memea);
|
|
ADDRINT end = mask(memea+length-1);
|
|
footprint_thread_data_t* tdata = xthis->get_tls(tid);
|
|
for(ADDRINT addr = start ; addr <= end ; addr += chunk_size) {
|
|
tdata->load(addr);
|
|
}
|
|
}
|
|
static void store(footprint_t* xthis, THREADID tid, ADDRINT memea, UINT32 length) {
|
|
ADDRINT start = mask(memea);
|
|
ADDRINT end = mask(memea+length-1);
|
|
footprint_thread_data_t* tdata = xthis->get_tls(tid);
|
|
for(ADDRINT addr = start ; addr <= end ; addr += chunk_size) {
|
|
tdata->store(addr);
|
|
}
|
|
}
|
|
static void code(footprint_t* xthis, THREADID tid, ADDRINT memea, UINT32 length) {
|
|
ADDRINT start = mask(memea);
|
|
ADDRINT end = mask(memea+length-1);
|
|
footprint_thread_data_t* tdata = xthis->get_tls(tid);
|
|
for(ADDRINT addr = start ; addr <= end ; addr += chunk_size) {
|
|
tdata->code(addr);
|
|
}
|
|
}
|
|
|
|
static void thread_start(THREADID tid, CONTEXT* ctxt, INT32 flags, footprint_t* xthis) {
|
|
footprint_thread_data_t* tdata = new footprint_thread_data_t;
|
|
PIN_SetThreadData(xthis->tls_key, tdata, tid);
|
|
xthis->num_threads++;
|
|
}
|
|
|
|
void instrument_instruction(INS ins, ADDRINT pc, unsigned int ins_bytes) {
|
|
// instrument the code reference
|
|
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR) code,
|
|
IARG_PTR, this,
|
|
IARG_THREAD_ID,
|
|
IARG_INST_PTR,
|
|
IARG_UINT32, ins_bytes,
|
|
IARG_END);
|
|
|
|
// instrument the load(s)
|
|
if (INS_IsMemoryRead(ins) && INS_IsStandardMemop(ins)) {
|
|
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR) load,
|
|
IARG_PTR, this,
|
|
IARG_THREAD_ID,
|
|
IARG_MEMORYREAD_EA,
|
|
IARG_MEMORYREAD_SIZE,
|
|
IARG_END);
|
|
|
|
}
|
|
if (INS_HasMemoryRead2(ins) && INS_IsStandardMemop(ins)) {
|
|
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR) load,
|
|
IARG_PTR, this,
|
|
IARG_THREAD_ID,
|
|
IARG_MEMORYREAD2_EA,
|
|
IARG_MEMORYREAD_SIZE,
|
|
IARG_END);
|
|
|
|
}
|
|
// instrument the store
|
|
if (INS_IsMemoryWrite(ins) && INS_IsStandardMemop(ins)) {
|
|
INS_InsertCall(ins, IPOINT_BEFORE, (AFUNPTR) store,
|
|
IARG_PTR, this,
|
|
IARG_THREAD_ID,
|
|
IARG_MEMORYWRITE_EA,
|
|
IARG_MEMORYWRITE_SIZE,
|
|
IARG_END);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static void instrument_trace(TRACE trace, footprint_t* xthis) {
|
|
ADDRINT pc = TRACE_Address(trace);
|
|
for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl)) {
|
|
const INS head = BBL_InsHead(bbl);
|
|
if (! INS_Valid(head)) continue;
|
|
for (INS ins = head; INS_Valid(ins); ins = INS_Next(ins)) {
|
|
if (!INS_IsStandardMemop(ins))
|
|
continue;
|
|
unsigned int instruction_size = INS_Size(ins);
|
|
xthis->instrument_instruction(ins, pc, instruction_size);
|
|
pc = pc + instruction_size;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void fini(int, footprint_t* xthis) {
|
|
*(xthis->out) << "# Chunk size " << xthis->chunk_size << " bytes " << endl;
|
|
xthis->summary();
|
|
*(xthis->out) << "# EOF" << endl;
|
|
xthis->out->close();
|
|
}
|
|
|
|
|
|
};
|