Skip to content

Commit

Permalink
Add an example of PEvent generation (#145)
Browse files Browse the repository at this point in the history
This SHA is an example of how to generate PEvents (Performance Events)
typically used for correlation
efforts between a perf model and hardware.

PEvents are a more "compact" form of the pipeout collection pairs,
allowing a modeler to specify more direct items
for collection. Pipeout pairs can be more elaborate/detailed. However,
with some clever coding, there can be
reuse -- it's not done here.

To generate performance events, use the command line parameter
`--pevents <filename> <pevent1,pevent2,...|all>`.

Examples:
```
# All pevents
./olympia traces/dhry_riscv.zstf --pevents retire.out all -i100

# Just RETIRE pevent
./olympia traces/dhry_riscv.zstf --pevents retire.out RETIRE -i100

# RETIRE and COMPLETE pevent
./olympia traces/dhry_riscv.zstf --pevents retire.out COMPLETE,RETIRE -i100
```

While I was at it, I removed the generated annotation for pipeline
collection for LoadStore/MemoryAccess classes -- uses NVP which
generates faster, as well as creates smaller pipeouts.

---------

Signed-off-by: Knute <[email protected]>
  • Loading branch information
klingaard committed Feb 4, 2024
1 parent 4d200b9 commit 8694a71
Show file tree
Hide file tree
Showing 11 changed files with 181 additions and 17 deletions.
33 changes: 33 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions conda/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:

```
Expand Down
1 change: 1 addition & 0 deletions core/ExecutePipe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
6 changes: 6 additions & 0 deletions core/ExecutePipe.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -111,6 +112,11 @@ namespace olympia
// A pipeline collector
sparta::collection::Collectable<InstPtr> collected_inst_;

// For correlation activities
sparta::pevents::PeventCollector<InstPEventPairs> complete_event_{"COMPLETE",
getContainer(),
getClock()};

// Counter
sparta::Counter total_insts_issued_{
getStatisticSet(), "total_insts_issued",
Expand Down
34 changes: 27 additions & 7 deletions core/Inst.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Inst>{
class InstPairDef : public sparta::PairDefinition<Inst>
{
public:

// The SPARTA_ADDPAIRs APIs must be called during the construction of the PairDefinition class
InstPairDef() : PairDefinition<Inst>(){
InstPairDef() : PairDefinition<Inst>() {
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),
Expand All @@ -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<Inst>
{
public:
using TypeCollected = Inst;

InstPEventPairs() : sparta::PairDefinition<Inst>()
{
addPEventsPair("uid", &Inst::getUniqueID);
addPEventsPair("pc", &Inst::getPC, std::ios::hex);
}
};

// Instruction allocators
using InstAllocator = sparta::SpartaSharedPointerAllocator<Inst>;
using InstArchInfoAllocator = sparta::SpartaSharedPointerAllocator<InstArchInfo>;
Expand Down
51 changes: 50 additions & 1 deletion core/LoadStoreInstInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,18 @@

#include "MemoryAccessInfo.hpp"

#include "sparta/simulation/State.hpp"
#include "sparta/pairs/SpartaKeyPairs.hpp"

#include <cinttypes>
#include <string>

namespace olympia
{
// Forward declaration of the Pair Definition class is must as we
// are friending it.
class LoadStoreInstInfoPair;

class LoadStoreInstInfo
{
public:
Expand Down Expand Up @@ -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) :
Expand All @@ -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 <unassoc> if not associated
std::string getMnemonic() const {
return (mem_access_info_ptr_ != nullptr ?
mem_access_info_ptr_->getMnemonic() : "<unassoc>");
}

void setPriority(const IssuePriority & rank) { rank_.setValue(rank); }

const IssuePriority & getPriority() const { return rank_.getEnumValue(); }
Expand Down Expand Up @@ -184,4 +206,31 @@ namespace olympia
os << *ls_info;
return os;
}
} // namespace olympia

/*!
* \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<LoadStoreInstInfo>
{
public:

// The SPARTA_ADDPAIRs APIs must be called during the construction of the PairDefinition class
LoadStoreInstInfoPair() : sparta::PairDefinition<LoadStoreInstInfo>() {
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
40 changes: 38 additions & 2 deletions core/MemoryAccessInfo.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ namespace olympia
using LoadStoreInstIterator = sparta::Buffer<LoadStoreInstInfoPtr>::const_iterator;

class MemoryAccessInfoPairDef;

class MemoryAccessInfo;

using MemoryAccessInfoPtr = sparta::SpartaSharedPointer<MemoryAccessInfo>;
Expand Down Expand Up @@ -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;
Expand All @@ -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 <unassoc> if not associated
std::string getMnemonic() const {
return (ldst_inst_ptr_ != nullptr ?
ldst_inst_ptr_->getMnemonic() : "<unassoc>");
}

// 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();
}

Expand Down Expand Up @@ -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<MemoryAccessInfo>
{
public:

// The SPARTA_ADDPAIRs APIs must be called during the construction of the PairDefinition class
MemoryAccessInfoPairDef() : sparta::PairDefinition<MemoryAccessInfo>() {
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
3 changes: 2 additions & 1 deletion core/ROB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -177,7 +179,6 @@ namespace olympia
FlushManager::FlushingCriteria criteria(FlushManager::FlushCause::POST_SYNC, ex_inst_ptr);
out_retire_flush_.send(criteria);


++num_flushes_;
break;
}
Expand Down
7 changes: 5 additions & 2 deletions core/ROB.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
// <ROB.h> -*- C++ -*-

// <ROB.hpp> -*- C++ -*-

#pragma once
#include <string>
Expand All @@ -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"
Expand Down Expand Up @@ -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<InstPEventPairs> 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
Expand Down
8 changes: 4 additions & 4 deletions reports/dhry_report.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
11 changes: 11 additions & 0 deletions test/sim/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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})
Expand Down

0 comments on commit 8694a71

Please sign in to comment.