adds tracing functionality
This commit is contained in:
parent
f74f98f361
commit
212fb1c8ff
|
@ -304,9 +304,9 @@ protected:
|
||||||
*/
|
*/
|
||||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||||
|
|
||||||
uint64_t get_pc() override { return arch.reg.PC; };
|
uint64_t get_pc() override { return arch.reg.PC; }
|
||||||
|
|
||||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }
|
||||||
|
|
||||||
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
||||||
|
|
||||||
|
@ -316,9 +316,11 @@ protected:
|
||||||
|
|
||||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||||
|
|
||||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
|
||||||
|
|
||||||
bool is_branch_taken() override { return arch.reg.last_branch; };
|
bool is_branch_taken() override { return arch.reg.last_branch; }
|
||||||
|
|
||||||
|
unsigned get_reg_num() override {return traits<BASE>::NUM_REGS;}
|
||||||
|
|
||||||
riscv_hart_m_p<BASE, FEAT> &arch;
|
riscv_hart_m_p<BASE, FEAT> &arch;
|
||||||
};
|
};
|
||||||
|
|
|
@ -331,9 +331,9 @@ protected:
|
||||||
*/
|
*/
|
||||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||||
|
|
||||||
uint64_t get_pc() override { return arch.reg.PC; };
|
uint64_t get_pc() override { return arch.reg.PC; }
|
||||||
|
|
||||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }
|
||||||
|
|
||||||
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
||||||
|
|
||||||
|
@ -343,9 +343,11 @@ protected:
|
||||||
|
|
||||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||||
|
|
||||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
|
||||||
|
|
||||||
bool is_branch_taken() override { return arch.reg.last_branch; };
|
bool is_branch_taken() override { return arch.reg.last_branch; }
|
||||||
|
|
||||||
|
unsigned get_reg_num() override {return traits<BASE>::NUM_REGS; }
|
||||||
|
|
||||||
riscv_hart_msu_vp<BASE> &arch;
|
riscv_hart_msu_vp<BASE> &arch;
|
||||||
};
|
};
|
||||||
|
|
|
@ -329,9 +329,9 @@ protected:
|
||||||
*/
|
*/
|
||||||
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
const std::string core_type_name() const override { return traits<BASE>::core_type; }
|
||||||
|
|
||||||
uint64_t get_pc() override { return arch.reg.PC; };
|
uint64_t get_pc() override { return arch.reg.PC; }
|
||||||
|
|
||||||
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; };
|
uint64_t get_next_pc() override { return arch.reg.NEXT_PC; }
|
||||||
|
|
||||||
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
uint64_t get_instr_word() override { return arch.reg.instruction; }
|
||||||
|
|
||||||
|
@ -341,9 +341,11 @@ protected:
|
||||||
|
|
||||||
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; }
|
||||||
|
|
||||||
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; };
|
void update_last_instr_cycles(unsigned cycles) override { arch.cycle_offset += cycles - 1; }
|
||||||
|
|
||||||
bool is_branch_taken() override { return arch.reg.last_branch; };
|
bool is_branch_taken() override { return arch.reg.last_branch; }
|
||||||
|
|
||||||
|
unsigned get_reg_num() override {return traits<BASE>::NUM_REGS; }
|
||||||
|
|
||||||
riscv_hart_mu_p<BASE, FEAT> &arch;
|
riscv_hart_mu_p<BASE, FEAT> &arch;
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
# pctrace
|
||||||
|
|
||||||
|
Trace functionality to allow visualizing coverage in lcov and cachegrind tools. Use environment variables NOCOMPRES and REGDUMP to toggle functionality.
|
||||||
|
- NOCOMPRES: any value turns off the LZ4 compression
|
||||||
|
- REGDUMP: any value switches to tracing the registers instead. Also turns off compression.
|
||||||
|
|
||||||
|
Known Bugs:
|
||||||
|
- currently does not work correctly with jit backends, the plugin cant tell if instructions are compressed. Additionaly the cost of instrs that raise a trap is not known. It takes the cost of the instrid -1 (0 at the moment).
|
|
@ -29,7 +29,7 @@
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* Contributors:
|
* Contributors:
|
||||||
* alex.com - initial implementation
|
* alex@minres.com - initial implementation
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#include <iss/arch_if.h>
|
#include <iss/arch_if.h>
|
||||||
|
@ -55,11 +55,11 @@ using namespace rapidjson;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
#ifdef WITH_LZ4
|
#ifdef WITH_LZ4
|
||||||
class lz4compress_steambuf: public std::streambuf {
|
class lz4compress_streambuf: public std::streambuf {
|
||||||
public:
|
public:
|
||||||
lz4compress_steambuf(const lz4compress_steambuf&) = delete;
|
lz4compress_streambuf(const lz4compress_streambuf&) = delete;
|
||||||
lz4compress_steambuf& operator=(const lz4compress_steambuf&) = delete;
|
lz4compress_streambuf& operator=(const lz4compress_streambuf&) = delete;
|
||||||
lz4compress_steambuf(std::ostream &sink, size_t buf_size)
|
lz4compress_streambuf(std::ostream &sink, size_t buf_size)
|
||||||
: sink(sink)
|
: sink(sink)
|
||||||
, src_buf(buf_size)
|
, src_buf(buf_size)
|
||||||
, dest_buf(LZ4F_compressBound(buf_size, nullptr))
|
, dest_buf(LZ4F_compressBound(buf_size, nullptr))
|
||||||
|
@ -74,7 +74,7 @@ public:
|
||||||
sink.write(dest_buf.data(), ret);
|
sink.write(dest_buf.data(), ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
~lz4compress_steambuf() {
|
~lz4compress_streambuf() {
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,9 +126,11 @@ private:
|
||||||
pctrace::pctrace(std::string const &filename)
|
pctrace::pctrace(std::string const &filename)
|
||||||
: instr_if(nullptr)
|
: instr_if(nullptr)
|
||||||
, filename(filename)
|
, filename(filename)
|
||||||
|
, reg_dump(getenv("REGDUMP"))
|
||||||
|
, no_compres(getenv("NOCOMPRES"))
|
||||||
, output("output.trc")
|
, output("output.trc")
|
||||||
#ifdef WITH_LZ4
|
#ifdef WITH_LZ4
|
||||||
, strbuf(new lz4compress_steambuf(output, 4096))
|
, strbuf( (no_compres || reg_dump)? nullptr: new lz4compress_streambuf(output, 4096))
|
||||||
, ostr(strbuf.get())
|
, ostr(strbuf.get())
|
||||||
#endif
|
#endif
|
||||||
{}
|
{}
|
||||||
|
@ -137,6 +139,8 @@ pctrace::~pctrace() { }
|
||||||
|
|
||||||
bool pctrace::registration(const char *const version, vm_if& vm) {
|
bool pctrace::registration(const char *const version, vm_if& vm) {
|
||||||
instr_if = vm.get_arch()->get_instrumentation_if();
|
instr_if = vm.get_arch()->get_instrumentation_if();
|
||||||
|
reg_base_ptr = reinterpret_cast<uint32_t*>(vm.get_arch()->get_regs_base_ptr());
|
||||||
|
|
||||||
if(!instr_if) return false;
|
if(!instr_if) return false;
|
||||||
const string core_name = instr_if->core_type_name();
|
const string core_name = instr_if->core_type_name();
|
||||||
if (filename.length() > 0) {
|
if (filename.length() > 0) {
|
||||||
|
@ -203,12 +207,22 @@ void pctrace::callback(instr_info_t iinfo) {
|
||||||
if (entry.not_taken > 1)
|
if (entry.not_taken > 1)
|
||||||
instr_if->update_last_instr_cycles(entry.not_taken);
|
instr_if->update_last_instr_cycles(entry.not_taken);
|
||||||
}
|
}
|
||||||
#ifndef WITH_LZ4
|
if(no_compres|| reg_dump){
|
||||||
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
|
if(reg_dump){
|
||||||
#else
|
for(size_t i=0; i< instr_if->get_reg_num(); ++i){
|
||||||
auto rdbuf=ostr.rdbuf();
|
uint32_t reg_val = *(reg_base_ptr+i);
|
||||||
|
output << "0x" << std::setfill('0') << std::setw(8) << std::hex << reg_val << " ";
|
||||||
|
}
|
||||||
|
output<<"\n" ;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
|
||||||
ostr<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
|
ostr<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay <<"," << call<<","<<(compressed?2:4) <<"\n";
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}//namespace plugin
|
||||||
|
}//namespace iss
|
||||||
|
|
|
@ -39,11 +39,10 @@
|
||||||
#include "iss/instrumentation_if.h"
|
#include "iss/instrumentation_if.h"
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <cstdlib>
|
||||||
|
|
||||||
namespace iss {
|
namespace iss {
|
||||||
namespace plugin {
|
namespace plugin {
|
||||||
class lz4compress_steambuf;
|
class lz4compress_streambuf;
|
||||||
class pctrace : public iss::vm_plugin {
|
class pctrace : public iss::vm_plugin {
|
||||||
struct instr_delay {
|
struct instr_delay {
|
||||||
std::string instr_name;
|
std::string instr_name;
|
||||||
|
@ -86,9 +85,13 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
iss::instrumentation_if *instr_if {nullptr};
|
iss::instrumentation_if *instr_if {nullptr};
|
||||||
|
uint32_t* reg_base_ptr {nullptr};
|
||||||
|
bool reg_dump {false};
|
||||||
|
bool no_compres {false};
|
||||||
std::ofstream output;
|
std::ofstream output;
|
||||||
|
|
||||||
#ifdef WITH_LZ4
|
#ifdef WITH_LZ4
|
||||||
std::unique_ptr<lz4compress_steambuf> strbuf;
|
std::unique_ptr<lz4compress_streambuf> strbuf;
|
||||||
std::ostream ostr;
|
std::ostream ostr;
|
||||||
#endif
|
#endif
|
||||||
std::string filename;
|
std::string filename;
|
||||||
|
|
Loading…
Reference in New Issue