diff --git a/README.md b/README.md index 51401ea5..6ef92a4d 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,39 @@ dyff between baseline.yaml always_hit_DL1.yaml -l top.*.*.decode info decode_rob.log \ -l top.*.*.rob info decode_rob.log ``` +### Generate PEvents (for Correlation) + +PEvents or Performance Events are part of the Sparta Modeling +Framework typically used to correlate a performance model with RTL. +Unlike pipeout collection Name/Value Definition Pairs (see an example +in +[Inst.hpp](https://github.com/riscv-software-src/riscv-perf-model/blob/db6c2f1878381389966544d7844c7d10c557083e/core/Inst.hpp#L330)), +PEvent Name/Value Definitions are typically more compact. Below the +surface, Sparta uses the logging infrastructure to collect the data. + +Olympia has instrumented a few PEvents as an example. The following +commands are useful in listing/using this functionality. + +``` +# Dump the list of supported PEvents +./olympia --help-pevents --no-run + +# Generate RETIRE only pevents for the first 100 instructions of Dhrystone +./olympia traces/dhry_riscv.zstf --pevents retire.out RETIRE -i100 + +# Generate COMPLETE only pevents ... +./olympia traces/dhry_riscv.zstf --pevents complete.out COMPLETE -i100 + +# Generate COMPLETE pevents into complete.out and RETIRE pevents into retire.out ... +./olympia traces/dhry_riscv.zstf --pevents retire.out RETIRE --pevents complete.out COMPLETE -i100 + +# Generate RETIRE and COMPLETE pevents to the same file +./olympia traces/dhry_riscv.zstf --pevents complete_retire.out RETIRE,COMPLETE -i100 + +# Generate all pevents +./olympia traces/dhry_riscv.zstf --pevents complete_retire.out ALL -i100 +``` + ### Generate Reports ``` # Run with 1M instructions, generate a report from the top of the tree diff --git a/conda/README.md b/conda/README.md index 8d9c5f9a..fc60c766 100644 --- a/conda/README.md +++ b/conda/README.md @@ -13,6 +13,10 @@ If `conda` is not already set up or the preference is to have a local ## Create a New Environment or Update Existing Conda Environment +** If these steps do no work, follow the directions on + [Map/Sparta](https://github.com/sparcians/map/tree/master#building-map) + instead ** + A new environment can be created using `environment.yaml` file as follows: ``` diff --git a/core/ExecutePipe.cpp b/core/ExecutePipe.cpp index 6416d82f..5cc856f6 100644 --- a/core/ExecutePipe.cpp +++ b/core/ExecutePipe.cpp @@ -216,6 +216,7 @@ namespace olympia void ExecutePipe::completeInst_(const InstPtr & ex_inst) { ex_inst->setStatus(Inst::Status::COMPLETED); + complete_event_.collect(*ex_inst); ILOG("Completing inst: " << ex_inst); } diff --git a/core/ExecutePipe.hpp b/core/ExecutePipe.hpp index dcc5ee2d..2567e630 100644 --- a/core/ExecutePipe.hpp +++ b/core/ExecutePipe.hpp @@ -22,6 +22,7 @@ #include "sparta/simulation/ResourceFactory.hpp" #include "sparta/collection/Collectable.hpp" #include "sparta/resources/Scoreboard.hpp" +#include "sparta/pevents/PeventCollector.hpp" #include "Inst.hpp" #include "CoreTypes.hpp" @@ -111,6 +112,11 @@ namespace olympia // A pipeline collector sparta::collection::Collectable collected_inst_; + // For correlation activities + sparta::pevents::PeventCollector complete_event_{"COMPLETE", + getContainer(), + getClock()}; + // Counter sparta::Counter total_insts_issued_{ getStatisticSet(), "total_insts_issued", diff --git a/core/Inst.hpp b/core/Inst.hpp index 1d2bce30..a260977e 100644 --- a/core/Inst.hpp +++ b/core/Inst.hpp @@ -322,19 +322,23 @@ namespace olympia /*! * \class InstPairDef - * \brief Pair Definition class of the Example instruction that flows through the example/CoreModel + * \brief Pair Definition class of the instruction that flows through the Olympia + * + * This is the definition of the PairDefinition class of Inst. + * It's mostly used for pipeline collection (-z option). This + * PairDefinition class could be named anything but it needs to + * inherit publicly from sparta::PairDefinition templatized on the + * actual class Inst. */ - // This is the definition of the PairDefinition class of Inst. - // This PairDefinition class could be named anything but it needs to - // inherit publicly from sparta::PairDefinition templatized on the actual class Inst. - class InstPairDef : public sparta::PairDefinition{ + class InstPairDef : public sparta::PairDefinition + { public: // The SPARTA_ADDPAIRs APIs must be called during the construction of the PairDefinition class - InstPairDef() : PairDefinition(){ + InstPairDef() : PairDefinition() { SPARTA_INVOKE_PAIRS(Inst); } - SPARTA_REGISTER_PAIRS(SPARTA_ADDPAIR("DID", &Inst::getUniqueID), + SPARTA_REGISTER_PAIRS(SPARTA_ADDPAIR("DID", &Inst::getUniqueID), // Used by Argos to color code SPARTA_ADDPAIR("uid", &Inst::getUniqueID), SPARTA_ADDPAIR("mnemonic", &Inst::getMnemonic), SPARTA_ADDPAIR("complete", &Inst::getCompletedStatus), @@ -344,6 +348,22 @@ namespace olympia SPARTA_ADDPAIR("tgt_vaddr", &Inst::getTargetVAddr, std::ios::hex)) }; + /*! + * \class PEventPairs + * \brief Pair Definitions for pevents + */ + class InstPEventPairs : public sparta::PairDefinition + { + public: + using TypeCollected = Inst; + + InstPEventPairs() : sparta::PairDefinition() + { + addPEventsPair("uid", &Inst::getUniqueID); + addPEventsPair("pc", &Inst::getPC, std::ios::hex); + } + }; + // Instruction allocators using InstAllocator = sparta::SpartaSharedPointerAllocator; using InstArchInfoAllocator = sparta::SpartaSharedPointerAllocator; diff --git a/core/LoadStoreInstInfo.hpp b/core/LoadStoreInstInfo.hpp index cc21cebc..3f9151cc 100644 --- a/core/LoadStoreInstInfo.hpp +++ b/core/LoadStoreInstInfo.hpp @@ -2,8 +2,18 @@ #include "MemoryAccessInfo.hpp" +#include "sparta/simulation/State.hpp" +#include "sparta/pairs/SpartaKeyPairs.hpp" + +#include +#include + namespace olympia { + // Forward declaration of the Pair Definition class is must as we + // are friending it. + class LoadStoreInstInfoPair; + class LoadStoreInstInfo { public: @@ -31,6 +41,11 @@ namespace olympia __LAST = NUM_STATES }; + // The modeler needs to alias a type called + // "SpartaPairDefinitionType" to the Pair Definition class of + // itself + using SpartaPairDefinitionType = LoadStoreInstInfoPair; + LoadStoreInstInfo() = delete; LoadStoreInstInfo(const MemoryAccessInfoPtr & info_ptr) : @@ -56,6 +71,13 @@ namespace olympia return mem_access_info_ptr == nullptr ? 0 : mem_access_info_ptr->getInstUniqueID(); } + // Get the mnemonic of the instruction this load/store is + // associated. Will return if not associated + std::string getMnemonic() const { + return (mem_access_info_ptr_ != nullptr ? + mem_access_info_ptr_->getMnemonic() : ""); + } + void setPriority(const IssuePriority & rank) { rank_.setValue(rank); } const IssuePriority & getPriority() const { return rank_.getEnumValue(); } @@ -184,4 +206,31 @@ namespace olympia os << *ls_info; return os; } -} // namespace olympia \ No newline at end of file + + /*! + * \class LoadStoreInstInfoPair + * \brief Pair Definition class of the LoadStoreInstInfo for pipeout collection + * + * This is the definition of the PairDefinition class of LoadStoreInstInfo. + * It's mostly used for pipeline collection (-z option). This + * PairDefinition class could be named anything but it needs to + * inherit publicly from sparta::PairDefinition templatized on the + * actual class LoadStoreInstInfo. + */ + class LoadStoreInstInfoPair : public sparta::PairDefinition + { + public: + + // The SPARTA_ADDPAIRs APIs must be called during the construction of the PairDefinition class + LoadStoreInstInfoPair() : sparta::PairDefinition() { + SPARTA_INVOKE_PAIRS(LoadStoreInstInfo); + } + SPARTA_REGISTER_PAIRS(SPARTA_ADDPAIR("DID", &LoadStoreInstInfo::getInstUniqueID), // Used by Argos to color code + SPARTA_ADDPAIR("uid", &LoadStoreInstInfo::getInstUniqueID), + SPARTA_ADDPAIR("mnemonic", &LoadStoreInstInfo::getMnemonic), + SPARTA_ADDPAIR("pri:", &LoadStoreInstInfo::getPriority), + SPARTA_ADDPAIR("state", &LoadStoreInstInfo::getState)) + }; + + +} // namespace olympia diff --git a/core/MemoryAccessInfo.hpp b/core/MemoryAccessInfo.hpp index ceb6be9d..50a04b31 100644 --- a/core/MemoryAccessInfo.hpp +++ b/core/MemoryAccessInfo.hpp @@ -16,7 +16,6 @@ namespace olympia using LoadStoreInstIterator = sparta::Buffer::const_iterator; class MemoryAccessInfoPairDef; - class MemoryAccessInfo; using MemoryAccessInfoPtr = sparta::SpartaSharedPointer; @@ -59,6 +58,11 @@ namespace olympia __LAST = NUM_UNITS }; + // The modeler needs to alias a type called + // "SpartaPairDefinitionType" to the Pair Definition class of + // itself + using SpartaPairDefinitionType = MemoryAccessInfoPairDef; + MemoryAccessInfo() = delete; MemoryAccessInfo(const MemoryAccessInfo &rhs) = default; @@ -82,11 +86,17 @@ namespace olympia // and we will use this pointer to query values from functions of Inst class const InstPtr & getInstPtr() const { return ldst_inst_ptr_; } + // Get the mnemonic of the instruction this load/store is + // associated. Will return if not associated + std::string getMnemonic() const { + return (ldst_inst_ptr_ != nullptr ? + ldst_inst_ptr_->getMnemonic() : ""); + } + // This is a function which will be added in the SPARTA_ADDPAIRs API. uint64_t getInstUniqueID() const { const InstPtr & inst_ptr = getInstPtr(); - return inst_ptr == nullptr ? 0 : inst_ptr->getUniqueID(); } @@ -256,4 +266,30 @@ namespace olympia os << *mem_ptr; return os; } + + /*! + * \class MemoryAccessInfoPairDef + * \brief Pair Definition class of the MemoryAccessInfo for pipeout collection + * + * This is the definition of the PairDefinition class of MemoryAccessInfo. + * It's mostly used for pipeline collection (-z option). This + * PairDefinition class could be named anything but it needs to + * inherit publicly from sparta::PairDefinition templatized on the + * actual class MemoryAccessInfo. + */ + class MemoryAccessInfoPairDef : public sparta::PairDefinition + { + public: + + // The SPARTA_ADDPAIRs APIs must be called during the construction of the PairDefinition class + MemoryAccessInfoPairDef() : sparta::PairDefinition() { + SPARTA_INVOKE_PAIRS(MemoryAccessInfo); + } + SPARTA_REGISTER_PAIRS(SPARTA_ADDPAIR("DID", &MemoryAccessInfo::getInstUniqueID), // Used by Argos to color code + SPARTA_ADDPAIR("uid", &MemoryAccessInfo::getInstUniqueID), + SPARTA_ADDPAIR("mnemonic", &MemoryAccessInfo::getMnemonic), + SPARTA_ADDPAIR("mmu", &MemoryAccessInfo::getMMUState), + SPARTA_ADDPAIR("dcs", &MemoryAccessInfo::getCacheState)) + }; + }; // namespace olympia diff --git a/core/ROB.cpp b/core/ROB.cpp index 25a53169..6d41bcc1 100644 --- a/core/ROB.cpp +++ b/core/ROB.cpp @@ -145,6 +145,8 @@ namespace olympia ILOG("retiring " << ex_inst); + retire_event_.collect(*ex_inst_ptr); + // Use the program ID to verify that the program order has been maintained. sparta_assert(ex_inst.getProgramID() == expected_program_id_, "Unexpected program ID when retiring instruction" @@ -177,7 +179,6 @@ namespace olympia FlushManager::FlushingCriteria criteria(FlushManager::FlushCause::POST_SYNC, ex_inst_ptr); out_retire_flush_.send(criteria); - ++num_flushes_; break; } diff --git a/core/ROB.hpp b/core/ROB.hpp index 8d11daff..2e09eebb 100644 --- a/core/ROB.hpp +++ b/core/ROB.hpp @@ -1,5 +1,4 @@ -// -*- C++ -*- - +// -*- C++ -*- #pragma once #include @@ -10,6 +9,7 @@ #include "sparta/simulation/ParameterSet.hpp" #include "sparta/simulation/TreeNode.hpp" #include "sparta/log/MessageSource.hpp" +#include "sparta/pevents/PeventCollector.hpp" #include "sparta/statistics/Counter.hpp" #include "sparta/statistics/StatisticDef.hpp" @@ -112,6 +112,9 @@ namespace olympia sparta::UniqueEvent<> ev_retire_ {&unit_event_set_, "retire_insts", CREATE_SPARTA_HANDLER(ROB, retireEvent_)}; + // For correlation activities + sparta::pevents::PeventCollector retire_event_{"RETIRE", getContainer(), getClock()}; + // A nice checker to make sure forward progress is being made // Note that in the ROB constructor, this event is set as non-continuing sparta::Clock::Cycle last_retirement_ = 0; // Last retirement cycle for checking stalled retire diff --git a/reports/dhry_report.yaml b/reports/dhry_report.yaml index 086931da..57dd02f6 100644 --- a/reports/dhry_report.yaml +++ b/reports/dhry_report.yaml @@ -6,13 +6,13 @@ content: top: "cpu.core0.rob.stats.ipc" : "IPC" - # Assuming 1 iteration is about 265 instructions, calculate the + # Assuming 1 iteration is about 239 instructions, calculate the # cycles per iteration - "265 / cpu.core0.rob.stats.ipc" : "Cycles Per Iteration" + "239 / cpu.core0.rob.stats.ipc" : "Cycles Per Iteration" # Assume a 1MHz part, determine the iterations per second - "1e6 / (265 / cpu.core0.rob.stats.ipc)" : "Iterations Per Second" + "1e6 / (239 / cpu.core0.rob.stats.ipc)" : "Iterations Per Second" # Assume a 1MHz part, determine the DMIPs based on the VAX 1780 # achieving a 1757 Dhrystones per second score - "(1e6 / (265 / cpu.core0.rob.stats.ipc)) / 1757" : "DMIPS Per MHz" + "(1e6 / (239 / cpu.core0.rob.stats.ipc)) / 1757" : "DMIPS Per MHz" diff --git a/test/sim/CMakeLists.txt b/test/sim/CMakeLists.txt index d17dd2d3..23c5f351 100644 --- a/test/sim/CMakeLists.txt +++ b/test/sim/CMakeLists.txt @@ -48,12 +48,23 @@ sparta_named_test(olympia_coremark_test_report_html olympia -i 1M --report reports/core_report.def --workload traces/core_riscv.zstf) +# Test missing opcodes sparta_named_test(olympia_json_test_missing_opcodes olympia --workload json_tests/missing_opcodes.json) +# Test FP transfers sparta_named_test(olympia_json_test_fp_transfers olympia --workload json_tests/fp_transfers.json) +# Test PEvent generation +sparta_named_test(olympia_json_test_pevents olympia + --workload traces/dhry_riscv.zstf + --pevents test_pevent.out RETIRE + --pevents test_pevent.out COMPLETE) +sparta_named_test(olympia_json_test_pevents_all olympia + --workload traces/dhry_riscv.zstf + --pevents test_pevent.out all) + ## Test the arches file(GLOB TEST_YAML "${SIM_BASE}/arches/*.yaml") foreach(ARCH_FULL_PATH ${TEST_YAML})