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.

272 lines
7.1 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.
*/
/*! @file
* This file contains a static and dynamic register mix profiler
*/
#include "pin.H"
#include <list>
#include <iostream>
#include <fstream>
using std::list;
using std::cerr;
using std::string;
using std::endl;
/* ===================================================================== */
/* Commandline Switches */
/* ===================================================================== */
KNOB<string> KnobOutputFile(KNOB_MODE_WRITEONCE, "pintool",
"o", "regmix.out", "specify profile file name");
KNOB<BOOL> KnobProfilePredicated(KNOB_MODE_WRITEONCE, "pintool",
"p", "0", "enable accurate profiling for predicated instructions");
KNOB<BOOL> KnobProfileStaticOnly(KNOB_MODE_WRITEONCE, "pintool",
"s", "0", "terminate after collection of static profile for main image");
KNOB<BOOL> KnobNoSharedLibs(KNOB_MODE_WRITEONCE, "pintool",
"no_shared_libs", "0", "do not instrument shared libraries");
/* ===================================================================== */
/* Print Help Message */
/* ===================================================================== */
INT32 Usage()
{
cerr <<
"This pin tool computes a dynamic register usage mix profile\n"
"\n";
cerr << KNOB_BASE::StringKnobSummary();
cerr << endl;
return -1;
}
/* ===================================================================== */
/* Global Variables */
/* ===================================================================== */
const UINT16 MAX_REG = 4096;
typedef UINT64 COUNTER;
/* zero initialized */
struct GLOBALSTATS
{
COUNTER reg_r[MAX_REG];
COUNTER reg_w[MAX_REG];
}GlobalStats;
class BBLSTATS
{
public:
BBLSTATS(UINT16 * stats) : _stats(stats),_counter(0) {};
const UINT16 * _stats;
COUNTER _counter;
};
list<const BBLSTATS*> statsList;
/* ===================================================================== */
VOID ComputeGlobalStats()
{
// We have the count for each bbl and its stats, compute the summary
for (list<const BBLSTATS*>::iterator bi = statsList.begin(); bi != statsList.end(); bi++)
{
for (const UINT16 * stats = (*bi)->_stats; *stats; stats++)
{
GlobalStats.reg_r[*stats] += (*bi)->_counter;
}
}
}
/* ===================================================================== */
UINT16 REG_GetStatsIndex(REG reg, BOOL is_write)
{
if( is_write )
return MAX_REG + reg;
else
return reg;
}
/* ===================================================================== */
VOID docount(COUNTER * counter)
{
(*counter)++;
}
INT32 RecordRegisters(BBL bbl, UINT16 * stats)
{
INT32 count = 0;
for (INS ins = BBL_InsHead(bbl); INS_Valid(ins); ins = INS_Next(ins))
{
const UINT32 max_r = INS_MaxNumRRegs(ins);
for( UINT32 i=0; i < max_r; i++ )
{
const REG reg = INS_RegR(ins, i );
if( REG_is_gr(reg) )
{
stats[count++] = REG_GetStatsIndex(reg,FALSE);
}
#if 0
// This is for arm
else if( REG_is_aggregate(reg) )
{
REGSET regset = INS_RegAggregateR(ins);
for( REG reg = REGSET_PopNext(regset); REG_valid(reg); reg = REGSET_PopNext(regset) )
{
stats[count++] = REG_GetStatsIndex(reg,FALSE);
}
}
#endif
}
const UINT32 max_w = INS_MaxNumWRegs(ins);
for( UINT32 i=0; i < max_w; i++ )
{
const REG reg = INS_RegW(ins, i );
if( REG_is_gr(reg) )
{
stats[count++] = REG_GetStatsIndex(reg,TRUE);
}
#if 0
else if( REG_is_aggregate(reg) )
{
REGSET regset = INS_RegAggregateW(ins);
for( REG reg = REGSET_PopNext(regset); REG_valid(reg); reg = REGSET_PopNext(regset) )
{
stats[count++] = REG_GetStatsIndex(reg,TRUE);
}
}
#endif
}
}
stats[count++] = 0;
return count;
}
/* ===================================================================== */
VOID Trace(TRACE trace, VOID *v)
{
const RTN rtn = TRACE_Rtn(trace);
if (! RTN_Valid(rtn))
return;
const SEC sec = RTN_Sec(rtn);
ASSERTX(SEC_Valid(sec));
const IMG img = SEC_Img(sec);
if (!IMG_Valid(img))
return;
if ( KnobNoSharedLibs.Value() && IMG_Type(img) == IMG_TYPE_SHAREDLIB)
return;
for (BBL bbl = TRACE_BblHead(trace); BBL_Valid(bbl); bbl = BBL_Next(bbl))
{
// Record the registers into a dummy buffer so we can count them
UINT16 buffer[128 * 1024];
INT32 count = RecordRegisters(bbl, buffer);
ASSERTX(count < 128 * 1024);
// Summarize the stats for the bbl in a 0 terminated list
// This is done at instrumentation time
UINT16 * stats = new UINT16[count];
RecordRegisters(bbl, stats);
// Insert instrumentation to count the number of times the bbl is executed
BBLSTATS * bblstats = new BBLSTATS(stats);
INS_InsertCall(BBL_InsHead(bbl), IPOINT_BEFORE, AFUNPTR(docount), IARG_PTR, &(bblstats->_counter), IARG_END);
// Remember the counter and stats so we can compute a summary at the end
statsList.push_back(bblstats);
}
}
/* ===================================================================== */
static std::ofstream* out = 0;
VOID Fini(int, VOID * v)
{
ComputeGlobalStats();
*out <<
"#\n"
"#num reg count-read count-written\n"
"#\n";
for ( UINT32 i = 0; i < MAX_REG; i++)
{
if( GlobalStats.reg_w[i] == 0 && GlobalStats.reg_r[i] == 0 ) continue;
*out << decstr(i,3) << " " << ljstr(REG_StringShort(REG(i)),15) <<
decstr( GlobalStats.reg_r[i],12) <<
decstr( GlobalStats.reg_w[i],12) << endl;
}
*out << "# eof" << endl;
out->close();
}
/* ===================================================================== */
/* Main */
/* ===================================================================== */
int main(int argc, CHAR *argv[])
{
PIN_InitSymbols();
if( PIN_Init(argc,argv) )
{
return Usage();
}
out = new std::ofstream(KnobOutputFile.Value().c_str());
TRACE_AddInstrumentFunction(Trace, 0);
PIN_AddFiniFunction(Fini, 0);
// Never returns
PIN_StartProgram();
return 0;
}
/* ===================================================================== */
/* eof */
/* ===================================================================== */