From 03bec27376adf9de7dff376c6db5f260b5ba765f Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Tue, 26 Apr 2022 17:14:33 +0200 Subject: [PATCH 1/3] implement extended instrumentation interface --- incl/iss/arch/riscv_hart_m_p.h | 4 +++- incl/iss/arch/riscv_hart_msu_vp.h | 8 ++++++-- incl/iss/arch/riscv_hart_mu_p.h | 8 ++++++-- incl/iss/arch/tgc_c.h | 2 +- src/vm/interp/vm_tgc_c.cpp | 16 ++++++++-------- 5 files changed, 24 insertions(+), 14 deletions(-) diff --git a/incl/iss/arch/riscv_hart_m_p.h b/incl/iss/arch/riscv_hart_m_p.h index 52bf1ad..09d9864 100644 --- a/incl/iss/arch/riscv_hart_m_p.h +++ b/incl/iss/arch/riscv_hart_m_p.h @@ -241,7 +241,9 @@ protected: uint64_t get_instr_word() override { return arch.instruction; } - uint64_t get_instr_count() { return arch.icount; } + uint64_t get_instr_count() override { return arch.icount; } + + uint64_t get_pendig_traps() override { return arch.trap_state; } uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; } diff --git a/incl/iss/arch/riscv_hart_msu_vp.h b/incl/iss/arch/riscv_hart_msu_vp.h index e7c86e0..ed2e677 100644 --- a/incl/iss/arch/riscv_hart_msu_vp.h +++ b/incl/iss/arch/riscv_hart_msu_vp.h @@ -340,9 +340,13 @@ protected: virtual uint64_t get_next_pc() { return arch.get_next_pc(); }; - uint64_t get_instr_count() { return arch.reg.icount; } + uint64_t get_instr_word() override { return arch.instruction; } - uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; } + uint64_t get_instr_count() { return arch.icount; } + + uint64_t get_pendig_traps() override { return arch.trap_state; } + + uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; } virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; }; diff --git a/incl/iss/arch/riscv_hart_mu_p.h b/incl/iss/arch/riscv_hart_mu_p.h index e85f1da..440664e 100644 --- a/incl/iss/arch/riscv_hart_mu_p.h +++ b/incl/iss/arch/riscv_hart_mu_p.h @@ -254,9 +254,13 @@ protected: virtual uint64_t get_next_pc() { return arch.get_next_pc(); }; - uint64_t get_instr_count() { return arch.reg.icount; } + uint64_t get_instr_word() override { return arch.instruction; } - uint64_t get_total_cycles() override { return arch.reg.icount + arch.cycle_offset; } + uint64_t get_instr_count() { return arch.icount; } + + uint64_t get_pendig_traps() override { return arch.trap_state; } + + uint64_t get_total_cycles() override { return arch.icount + arch.cycle_offset; } virtual void set_curr_instr_cycles(unsigned cycles) { arch.cycle_offset += cycles - 1; }; diff --git a/incl/iss/arch/tgc_c.h b/incl/iss/arch/tgc_c.h index 7a71f8c..5ff88a3 100644 --- a/incl/iss/arch/tgc_c.h +++ b/incl/iss/arch/tgc_c.h @@ -53,7 +53,7 @@ template <> struct traits { static constexpr std::array reg_aliases{ {"ZERO", "RA", "SP", "GP", "TP", "T0", "T1", "T2", "S0", "S1", "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S10", "S11", "T3", "T4", "T5", "T6", "PC", "NEXT_PC", "PRIV", "DPC"}}; - enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, RFS=32, XLEN=32, CSR_SIZE=4096, INSTR_ALIGNMENT=2, fence=0, fencei=1, fencevmal=2, fencevmau=3, MUL_LEN=64}; + enum constants {MISA_VAL=0b01000000000000000001000100000100, MARCHID_VAL=0x80000003, RFS=32, INSTR_ALIGNMENT=2, XLEN=32, CSR_SIZE=4096, fence=0, fencei=1, fencevmal=2, fencevmau=3, MUL_LEN=64}; constexpr static unsigned FP_REGS_SIZE = 0; diff --git a/src/vm/interp/vm_tgc_c.cpp b/src/vm/interp/vm_tgc_c.cpp index 1da214b..b366450 100644 --- a/src/vm/interp/vm_tgc_c.cpp +++ b/src/vm/interp/vm_tgc_c.cpp @@ -2001,7 +2001,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co // execute instruction try { { - uint32_t rs1_idx = rs1 + 8; + uint8_t rs1_idx = rs1 + 8; *(X+rs1_idx) = *(X+rs1_idx) >> shamt; } } catch(...){} @@ -2024,11 +2024,11 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co // execute instruction try { if(shamt) { - uint32_t rs1_idx = rs1 + 8; + uint8_t rs1_idx = rs1 + 8; *(X+rs1_idx) = ((int32_t)*(X+rs1_idx)) >> shamt; } else if(traits::XLEN == 128) { - uint32_t rs1_idx = rs1 + 8; + uint8_t rs1_idx = rs1 + 8; *(X+rs1_idx) = ((int32_t)*(X+rs1_idx)) >> 64; } } catch(...){} @@ -2051,7 +2051,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co // execute instruction try { { - uint32_t rs1_idx = rs1 + 8; + uint8_t rs1_idx = rs1 + 8; *(X+rs1_idx) = *(X+rs1_idx) & (int8_t)sext<6>(imm); } } catch(...){} @@ -2074,7 +2074,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co // execute instruction try { { - uint32_t rd_idx = rd + 8; + uint8_t rd_idx = rd + 8; *(X+rd_idx) = *(X+rd_idx) - *(X+rs2 + 8); } } catch(...){} @@ -2097,7 +2097,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co // execute instruction try { { - uint32_t rd_idx = rd + 8; + uint8_t rd_idx = rd + 8; *(X+rd_idx) = *(X+rd_idx) ^ *(X+rs2 + 8); } } catch(...){} @@ -2120,7 +2120,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co // execute instruction try { { - uint32_t rd_idx = rd + 8; + uint8_t rd_idx = rd + 8; *(X+rd_idx) = *(X+rd_idx) | *(X+rs2 + 8); } } catch(...){} @@ -2143,7 +2143,7 @@ typename vm_base::virt_addr_t vm_impl::execute_inst(finish_cond_e co // execute instruction try { { - uint32_t rd_idx = rd + 8; + uint8_t rd_idx = rd + 8; *(X+rd_idx) = *(X+rd_idx) & *(X+rs2 + 8); } } catch(...){} From e88f309ea2cfe59bffa8414fbfbb6b4478aebb3f Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Sat, 7 May 2022 17:22:06 +0200 Subject: [PATCH 2/3] add lz4 compression to pctrace --- CMakeLists.txt | 4 + gen_input/templates/CORENAME.h.gtl | 2 +- incl/iss/arch/tgc_c.h | 2 +- incl/iss/plugin/pctrace.h | 9 +- src/main.cpp | 4 +- src/plugin/pctrace.cpp | 153 ++++++++++++++++++----------- 6 files changed, 108 insertions(+), 66 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 28ba1da..e676292 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -83,6 +83,10 @@ elseif(TARGET elfio::elfio) else() message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing") endif() +if(TARGET lz4::lz4) + target_compile_definitions(${PROJECT_NAME} PUBLIC WITH_LZ4) + target_link_libraries(${PROJECT_NAME} PUBLIC lz4::lz4) +endif() if(TARGET RapidJSON) target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON) endif() diff --git a/gen_input/templates/CORENAME.h.gtl b/gen_input/templates/CORENAME.h.gtl index 4497ba3..1765fde 100644 --- a/gen_input/templates/CORENAME.h.gtl +++ b/gen_input/templates/CORENAME.h.gtl @@ -163,13 +163,13 @@ struct ${coreDef.name.toLowerCase()}: public arch_if { uint${byteSize(reg.size)}_t ${reg.name} = 0;<% }}%> } reg; +#pragma pack(pop) uint32_t trap_state = 0, pending_trap = 0; uint64_t icount = 0; uint64_t cycle = 0; uint64_t instret = 0; uint32_t instruction = 0; uint32_t last_branch = 0; -#pragma pack(pop) std::array addr_mode; uint64_t interrupt_sim=0; diff --git a/incl/iss/arch/tgc_c.h b/incl/iss/arch/tgc_c.h index 5ff88a3..8e2ae8a 100644 --- a/incl/iss/arch/tgc_c.h +++ b/incl/iss/arch/tgc_c.h @@ -252,13 +252,13 @@ struct tgc_c: public arch_if { uint8_t PRIV = 0; uint32_t DPC = 0; } reg; +#pragma pack(pop) uint32_t trap_state = 0, pending_trap = 0; uint64_t icount = 0; uint64_t cycle = 0; uint64_t instret = 0; uint32_t instruction = 0; uint32_t last_branch = 0; -#pragma pack(pop) std::array addr_mode; uint64_t interrupt_sim=0; diff --git a/incl/iss/plugin/pctrace.h b/incl/iss/plugin/pctrace.h index d227666..446094b 100644 --- a/incl/iss/plugin/pctrace.h +++ b/incl/iss/plugin/pctrace.h @@ -44,7 +44,7 @@ namespace iss { namespace plugin { - +class lz4compress_steambuf; class cov : public iss::vm_plugin { struct instr_delay { std::string instr_name; @@ -88,10 +88,13 @@ public: private: iss::instrumentation_if *instr_if {nullptr}; std::ofstream output; +#ifdef WITH_LZ4 + std::unique_ptr strbuf; + std::ostream ostr; +#endif std::string filename; std::vector delays; - bool jumped, first; - + bool jumped{false}, first{true}; }; } } diff --git a/src/main.cpp b/src/main.cpp index bbde374..d8d6bd6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -60,13 +60,13 @@ int main(int argc, char *argv[]) { desc.add_options() ("help,h", "Print help message") ("verbose,v", po::value()->implicit_value(0), "Sets logging verbosity") - ("logfile,f", po::value(), "Sets default log file.") + ("logfile,l", po::value(), "Sets default log file.") ("disass,d", po::value()->implicit_value(""), "Enables disassembly") ("gdb-port,g", po::value()->default_value(0), "enable gdb server and specify port to use") ("instructions,i", po::value()->default_value(std::numeric_limits::max()), "max. number of instructions to simulate") ("reset,r", po::value(), "reset address") ("dump-ir", "dump the intermediate representation") - ("elf", po::value>(), "ELF file(s) to load") + ("elf,f", po::value>(), "ELF file(s) to load") ("mem,m", po::value(), "the memory input file") ("plugin,p", po::value>(), "plugin to activate") ("backend", po::value()->default_value("interp"), "the memory input file") diff --git a/src/plugin/pctrace.cpp b/src/plugin/pctrace.cpp index 036b4cc..f14e8fd 100644 --- a/src/plugin/pctrace.cpp +++ b/src/plugin/pctrace.cpp @@ -9,27 +9,97 @@ #include #include #include - #include +#include +namespace iss { +namespace plugin { + using namespace rapidjson; using namespace std; -iss::plugin::cov::cov(std::string const &filename) - : instr_if(nullptr) - , filename(filename) -{ - output.open("output.trc"); - jumped = false; - first = true; -} +class lz4compress_steambuf: public std::streambuf { +public: + lz4compress_steambuf(const lz4compress_steambuf&) = delete; + lz4compress_steambuf& operator=(const lz4compress_steambuf&) = delete; + lz4compress_steambuf(std::ostream &sink, size_t buf_size) + : sink(sink) + , src_buf(buf_size) + , dest_buf(LZ4F_compressBound(buf_size, nullptr)) + { + auto errCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION); + if (LZ4F_isError(errCode) != 0) + throw std::runtime_error(std::string("Failed to create LZ4 context: ") + LZ4F_getErrorName(errCode)); + size_t ret = LZ4F_compressBegin(ctx, &dest_buf.front(), dest_buf.capacity(), nullptr); + if (LZ4F_isError(ret) != 0) + throw std::runtime_error(std::string("Failed to start LZ4 compression: ") + LZ4F_getErrorName(ret)); + setp(src_buf.data(), src_buf.data() + src_buf.size() - 1); + sink.write(dest_buf.data(), ret); + } -iss::plugin::cov::~cov() { - output.close(); -} + ~lz4compress_steambuf() { + close(); + } -bool iss::plugin::cov::registration(const char *const version, vm_if& vm) { + void close() { + if (closed) + return; + sync(); + auto ret = LZ4F_compressEnd(ctx, dest_buf.data(), dest_buf.capacity(), nullptr); + if (LZ4F_isError(ret) != 0) + throw std::runtime_error(std::string("Failed to finish LZ4 compression: ") + LZ4F_getErrorName(ret)); + sink.write(dest_buf.data(), ret); + LZ4F_freeCompressionContext(ctx); + closed = true; + } + +private: + int_type overflow(int_type ch) override { + assert(pptr() <= epptr()); + *pptr() = static_cast(ch); + pbump(1); + compress_and_write(); + return ch; + } + + int_type sync() override { + compress_and_write(); + return 0; + } + + void compress_and_write() { + if (closed) + throw std::runtime_error("Cannot write to closed stream"); + if(auto orig_size = pptr() - pbase()){ + auto ret = LZ4F_compressUpdate(ctx, dest_buf.data(), dest_buf.capacity(), pbase(), orig_size, nullptr); + if (LZ4F_isError(ret) != 0) + throw std::runtime_error(std::string("LZ4 compression failed: ") + LZ4F_getErrorName(ret)); + if(ret) sink.write(dest_buf.data(), ret); + pbump(-orig_size); + } + } + + std::ostream &sink; + std::vector src_buf; + std::vector dest_buf; + LZ4F_compressionContext_t ctx{ nullptr }; + bool closed{ false }; +}; + +cov::cov(std::string const &filename) +: instr_if(nullptr) +, filename(filename) +, output("output.trc") +#ifdef WITH_LZ4 +, strbuf(new lz4compress_steambuf(output, 4096)) +, ostr(strbuf.get()) +#endif +{ } + +cov::~cov() { } + +bool cov::registration(const char *const version, vm_if& vm) { instr_if = vm.get_arch()->get_instrumentation_if(); if(!instr_if) return false; const string core_name = instr_if->core_type_name(); @@ -63,11 +133,11 @@ bool iss::plugin::cov::registration(const char *const version, vm_if& vm) { } else { LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<get_pc()) << "," << delay; -// first = false; -// } -// if(instr_if->get_next_pc()-instr_if->get_pc() != delays[iinfo.instr_id].size/8){ -// //The goal is to keep the output in start-target pairs, so after a jump the target address needs to get written -// //to the output. If the target happens to also be a start, we keep the pairing by adding a 0-delay entry. -// if (jumped) -// output <<"\n" <get_pc()) << "," << 0; -// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay; -// jumped = true; -// } -// else{ -// if (jumped){ -// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay; -// jumped = false; -// } -// else if(delay!=1){ -// output <<"\n" << formatPC(instr_if->get_pc()) << "," << delay; -// output <<"\n" << formatPC(instr_if->get_pc()) << "," << 0; -// } -// -// } - -//source code for the full output +void cov::callback(instr_info_t iinfo, const exec_info& einfo) { auto delay = 0; size_t id = iinfo.instr_id; auto entry = delays[id]; @@ -132,6 +160,13 @@ void iss::plugin::cov::callback(instr_info_t iinfo, const exec_info& einfo) { if (einfo.branch_taken) delay = entry.taken; else - delay = entry.not_taken; + delay = entry.not_taken; +#ifndef WITH_LZ4 output<get_pc() <<"," << delay << "\n"; +#else + auto rdbuf=ostr.rdbuf(); + ostr<get_pc() <<"," << delay << "\n"; +#endif +} +} } From e56bc1278824b44db92d79b0fe09b7b3377d79af Mon Sep 17 00:00:00 2001 From: Eyck Jentzsch Date: Sat, 7 May 2022 17:25:11 +0200 Subject: [PATCH 3/3] fix non-lz4 build of plugin --- src/plugin/pctrace.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/plugin/pctrace.cpp b/src/plugin/pctrace.cpp index f14e8fd..8fa5ef7 100644 --- a/src/plugin/pctrace.cpp +++ b/src/plugin/pctrace.cpp @@ -10,8 +10,9 @@ #include #include #include +#ifdef WITH_LZ4 #include - +#endif namespace iss { namespace plugin { @@ -19,6 +20,7 @@ namespace plugin { using namespace rapidjson; using namespace std; +#ifdef WITH_LZ4 class lz4compress_steambuf: public std::streambuf { public: lz4compress_steambuf(const lz4compress_steambuf&) = delete; @@ -86,6 +88,7 @@ private: LZ4F_compressionContext_t ctx{ nullptr }; bool closed{ false }; }; +#endif cov::cov(std::string const &filename) : instr_if(nullptr)