add lz4 compression to pctrace
This commit is contained in:
parent
03bec27376
commit
e88f309ea2
|
@ -83,6 +83,10 @@ elseif(TARGET elfio::elfio)
|
||||||
else()
|
else()
|
||||||
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
|
message(FATAL_ERROR "No elfio library found, maybe a find_package() call is missing")
|
||||||
endif()
|
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)
|
if(TARGET RapidJSON)
|
||||||
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
|
target_link_libraries(${PROJECT_NAME} PUBLIC RapidJSON)
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -163,13 +163,13 @@ struct ${coreDef.name.toLowerCase()}: public arch_if {
|
||||||
uint${byteSize(reg.size)}_t ${reg.name} = 0;<%
|
uint${byteSize(reg.size)}_t ${reg.name} = 0;<%
|
||||||
}}%>
|
}}%>
|
||||||
} reg;
|
} reg;
|
||||||
|
#pragma pack(pop)
|
||||||
uint32_t trap_state = 0, pending_trap = 0;
|
uint32_t trap_state = 0, pending_trap = 0;
|
||||||
uint64_t icount = 0;
|
uint64_t icount = 0;
|
||||||
uint64_t cycle = 0;
|
uint64_t cycle = 0;
|
||||||
uint64_t instret = 0;
|
uint64_t instret = 0;
|
||||||
uint32_t instruction = 0;
|
uint32_t instruction = 0;
|
||||||
uint32_t last_branch = 0;
|
uint32_t last_branch = 0;
|
||||||
#pragma pack(pop)
|
|
||||||
std::array<address_type, 4> addr_mode;
|
std::array<address_type, 4> addr_mode;
|
||||||
|
|
||||||
uint64_t interrupt_sim=0;
|
uint64_t interrupt_sim=0;
|
||||||
|
|
|
@ -252,13 +252,13 @@ struct tgc_c: public arch_if {
|
||||||
uint8_t PRIV = 0;
|
uint8_t PRIV = 0;
|
||||||
uint32_t DPC = 0;
|
uint32_t DPC = 0;
|
||||||
} reg;
|
} reg;
|
||||||
|
#pragma pack(pop)
|
||||||
uint32_t trap_state = 0, pending_trap = 0;
|
uint32_t trap_state = 0, pending_trap = 0;
|
||||||
uint64_t icount = 0;
|
uint64_t icount = 0;
|
||||||
uint64_t cycle = 0;
|
uint64_t cycle = 0;
|
||||||
uint64_t instret = 0;
|
uint64_t instret = 0;
|
||||||
uint32_t instruction = 0;
|
uint32_t instruction = 0;
|
||||||
uint32_t last_branch = 0;
|
uint32_t last_branch = 0;
|
||||||
#pragma pack(pop)
|
|
||||||
std::array<address_type, 4> addr_mode;
|
std::array<address_type, 4> addr_mode;
|
||||||
|
|
||||||
uint64_t interrupt_sim=0;
|
uint64_t interrupt_sim=0;
|
||||||
|
|
|
@ -44,7 +44,7 @@
|
||||||
|
|
||||||
namespace iss {
|
namespace iss {
|
||||||
namespace plugin {
|
namespace plugin {
|
||||||
|
class lz4compress_steambuf;
|
||||||
class cov : public iss::vm_plugin {
|
class cov : public iss::vm_plugin {
|
||||||
struct instr_delay {
|
struct instr_delay {
|
||||||
std::string instr_name;
|
std::string instr_name;
|
||||||
|
@ -88,10 +88,13 @@ public:
|
||||||
private:
|
private:
|
||||||
iss::instrumentation_if *instr_if {nullptr};
|
iss::instrumentation_if *instr_if {nullptr};
|
||||||
std::ofstream output;
|
std::ofstream output;
|
||||||
|
#ifdef WITH_LZ4
|
||||||
|
std::unique_ptr<lz4compress_steambuf> strbuf;
|
||||||
|
std::ostream ostr;
|
||||||
|
#endif
|
||||||
std::string filename;
|
std::string filename;
|
||||||
std::vector<instr_desc> delays;
|
std::vector<instr_desc> delays;
|
||||||
bool jumped, first;
|
bool jumped{false}, first{true};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,13 +60,13 @@ int main(int argc, char *argv[]) {
|
||||||
desc.add_options()
|
desc.add_options()
|
||||||
("help,h", "Print help message")
|
("help,h", "Print help message")
|
||||||
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
|
("verbose,v", po::value<int>()->implicit_value(0), "Sets logging verbosity")
|
||||||
("logfile,f", po::value<std::string>(), "Sets default log file.")
|
("logfile,l", po::value<std::string>(), "Sets default log file.")
|
||||||
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
|
("disass,d", po::value<std::string>()->implicit_value(""), "Enables disassembly")
|
||||||
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
|
("gdb-port,g", po::value<unsigned>()->default_value(0), "enable gdb server and specify port to use")
|
||||||
("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
|
("instructions,i", po::value<uint64_t>()->default_value(std::numeric_limits<uint64_t>::max()), "max. number of instructions to simulate")
|
||||||
("reset,r", po::value<std::string>(), "reset address")
|
("reset,r", po::value<std::string>(), "reset address")
|
||||||
("dump-ir", "dump the intermediate representation")
|
("dump-ir", "dump the intermediate representation")
|
||||||
("elf", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
("elf,f", po::value<std::vector<std::string>>(), "ELF file(s) to load")
|
||||||
("mem,m", po::value<std::string>(), "the memory input file")
|
("mem,m", po::value<std::string>(), "the memory input file")
|
||||||
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
|
("plugin,p", po::value<std::vector<std::string>>(), "plugin to activate")
|
||||||
("backend", po::value<std::string>()->default_value("interp"), "the memory input file")
|
("backend", po::value<std::string>()->default_value("interp"), "the memory input file")
|
||||||
|
|
|
@ -9,27 +9,97 @@
|
||||||
#include <rapidjson/ostreamwrapper.h>
|
#include <rapidjson/ostreamwrapper.h>
|
||||||
#include <rapidjson/error/en.h>
|
#include <rapidjson/error/en.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <lz4frame.h>
|
||||||
|
|
||||||
|
|
||||||
|
namespace iss {
|
||||||
|
namespace plugin {
|
||||||
|
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
iss::plugin::cov::cov(std::string const &filename)
|
class lz4compress_steambuf: public std::streambuf {
|
||||||
: instr_if(nullptr)
|
public:
|
||||||
, filename(filename)
|
lz4compress_steambuf(const lz4compress_steambuf&) = delete;
|
||||||
{
|
lz4compress_steambuf& operator=(const lz4compress_steambuf&) = delete;
|
||||||
output.open("output.trc");
|
lz4compress_steambuf(std::ostream &sink, size_t buf_size)
|
||||||
jumped = false;
|
: sink(sink)
|
||||||
first = true;
|
, 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() {
|
~lz4compress_steambuf() {
|
||||||
output.close();
|
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<char_type>(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<char> src_buf;
|
||||||
|
std::vector<char> 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();
|
instr_if = vm.get_arch()->get_instrumentation_if();
|
||||||
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();
|
||||||
|
@ -63,11 +133,11 @@ bool iss::plugin::cov::registration(const char *const version, vm_if& vm) {
|
||||||
} else {
|
} else {
|
||||||
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
|
LOG(ERR)<<"plugin cycle_estimate: could not find an entry for "<<core_name<<" in JSON file"<<endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
|
LOG(ERR)<<"plugin cycle_estimate: could not parse in JSON file at "<< ok.Offset()<<": "<<GetParseError_En(ok.Code())<<endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (runtime_error &e) {
|
} catch (runtime_error &e) {
|
||||||
LOG(ERR) << "Could not parse input file " << filename << ", reason: " << e.what();
|
LOG(ERR) << "Could not parse input file " << filename << ", reason: " << e.what();
|
||||||
return false;
|
return false;
|
||||||
|
@ -78,51 +148,9 @@ bool iss::plugin::cov::registration(const char *const version, vm_if& vm) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline string formatPC(uint64_t pc) {
|
void cov::callback(instr_info_t iinfo, const exec_info& einfo) {
|
||||||
stringstream stream;
|
|
||||||
stream << "0x" << std::hex << pc;
|
|
||||||
return stream.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
void iss::plugin::cov::callback(instr_info_t iinfo, const exec_info& einfo) {
|
|
||||||
// auto delay = 0;
|
|
||||||
// auto entry = delays[iinfo.instr_id];
|
|
||||||
// bool taken = einfo.branch_taken;
|
|
||||||
// if (einfo.branch_taken)
|
|
||||||
// delay = entry.taken;
|
|
||||||
// else
|
|
||||||
// delay = entry.not_taken;
|
|
||||||
//
|
|
||||||
// if (first){
|
|
||||||
// output << formatPC(instr_if->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" <<formatPC(instr_if->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
|
|
||||||
auto delay = 0;
|
auto delay = 0;
|
||||||
size_t id = iinfo.instr_id;
|
size_t id = iinfo.instr_id;
|
||||||
auto entry = delays[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)
|
if (einfo.branch_taken)
|
||||||
delay = entry.taken;
|
delay = entry.taken;
|
||||||
else
|
else
|
||||||
delay = entry.not_taken;
|
delay = entry.not_taken;
|
||||||
|
#ifndef WITH_LZ4
|
||||||
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay << "\n";
|
output<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay << "\n";
|
||||||
|
#else
|
||||||
|
auto rdbuf=ostr.rdbuf();
|
||||||
|
ostr<<std::hex <<"0x" << instr_if->get_pc() <<"," << delay << "\n";
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue