Compare commits
	
		
			1 Commits
		
	
	
		
			03bec27376
			...
			e88f309ea2
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 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 | ||||||
|  | } | ||||||
|  | } | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user