Merge branch 'develop' into work/new_json_format_rebased

This commit is contained in:
2022-02-18 15:20:57 +01:00
19 changed files with 708 additions and 445 deletions

View File

@@ -36,6 +36,7 @@
* Eder F. Zulian
* Derek Christ
* Lukas Steiner
* Derek Christ
*/
#include <fstream>
@@ -221,7 +222,9 @@ void TlmRecorder::terminateRemainingTransactions()
{
while (!currentTransactionsInSystem.empty())
{
auto transaction = currentTransactionsInSystem.begin();
auto transaction = std::min_element(currentTransactionsInSystem.begin(),
currentTransactionsInSystem.end(), [](decltype(currentTransactionsInSystem)::value_type& l,
decltype(currentTransactionsInSystem)::value_type& r) -> bool {return l.second.id < r.second.id;});
if (transaction->second.cmd == 'X')
{
std::string beginPhase = transaction->second.recordedPhases.front().name;
@@ -307,10 +310,8 @@ void TlmRecorder::prepareSqlStatements()
":mcconfig, :memspec, :traces, :windowSize, :refreshMaxPostponed, :refreshMaxPulledin, :controllerThread, "
":maxBufferDepth, :per2BankOffset)";
insertCommandLengthsString =
"INSERT INTO CommandLengths VALUES"
"(:NOP, :RD, :WR, :RDA, :WRA, :ACT, :PREPB, :REFPB, :RFMPB, :REFP2B, :RFMP2B, :PRESB, :REFSB, :RFMSB, "
":PREAB, :REFAB, :RFMAB, :PDEA, :PDXA, :PDEP, :PDXP, :SREFEN, :SREFEX)";
insertCommandLengthsString = "INSERT INTO CommandLengths VALUES"
"(:command, :length)";
insertDebugMessageString =
"INSERT INTO DebugMessages (Time,Message) Values (:time,:message)";
@@ -371,31 +372,17 @@ void TlmRecorder::insertCommandLengths()
{
const MemSpec *memSpec = Configuration::getInstance().memSpec;
sqlite3_bind_int(insertCommandLengthsStatement, 1, static_cast<int>(lround(memSpec->getCommandLength(Command::NOP) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 2, static_cast<int>(lround(memSpec->getCommandLength(Command::RD) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 3, static_cast<int>(lround(memSpec->getCommandLength(Command::WR) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 4, static_cast<int>(lround(memSpec->getCommandLength(Command::RDA) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 5, static_cast<int>(lround(memSpec->getCommandLength(Command::WRA) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 6, static_cast<int>(lround(memSpec->getCommandLength(Command::ACT) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 7, static_cast<int>(lround(memSpec->getCommandLength(Command::PREPB) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 8, static_cast<int>(lround(memSpec->getCommandLength(Command::REFPB) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 9, static_cast<int>(lround(memSpec->getCommandLength(Command::RFMPB) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 10, static_cast<int>(lround(memSpec->getCommandLength(Command::REFP2B) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 11, static_cast<int>(lround(memSpec->getCommandLength(Command::RFMP2B) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 12, static_cast<int>(lround(memSpec->getCommandLength(Command::PRESB) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 13, static_cast<int>(lround(memSpec->getCommandLength(Command::REFSB) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 14, static_cast<int>(lround(memSpec->getCommandLength(Command::RFMSB) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 15, static_cast<int>(lround(memSpec->getCommandLength(Command::PREAB) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 16, static_cast<int>(lround(memSpec->getCommandLength(Command::REFAB) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 17, static_cast<int>(lround(memSpec->getCommandLength(Command::RFMAB) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 18, static_cast<int>(lround(memSpec->getCommandLength(Command::PDEA) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 19, static_cast<int>(lround(memSpec->getCommandLength(Command::PDXA) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 20, static_cast<int>(lround(memSpec->getCommandLength(Command::PDEP) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 21, static_cast<int>(lround(memSpec->getCommandLength(Command::PDXP) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 22, static_cast<int>(lround(memSpec->getCommandLength(Command::SREFEN) / memSpec->tCK)));
sqlite3_bind_int(insertCommandLengthsStatement, 23, static_cast<int>(lround(memSpec->getCommandLength(Command::SREFEX) / memSpec->tCK)));
auto insertCommandLength = [this, memSpec](Command command) {
auto commandName = command.toString();
executeSqlStatement(insertCommandLengthsStatement);
sqlite3_bind_text(insertCommandLengthsStatement, 1, commandName.c_str(), commandName.length(), nullptr);
sqlite3_bind_int(insertCommandLengthsStatement, 2,
static_cast<int>(lround(memSpec->getCommandLength(command) / memSpec->tCK)));
executeSqlStatement(insertCommandLengthsStatement);
};
for (unsigned int command = 0; command < Command::END_ENUM; ++command)
insertCommandLength(static_cast<Command::Type>(command));
}
void TlmRecorder::insertTransactionInDB(Transaction &recordingData)

View File

@@ -35,6 +35,7 @@
* Matthias Jung
* Eder F. Zulian
* Lukas Steiner
* Derek Christ
*/
#ifndef TLMRECORDER_H
@@ -153,123 +154,102 @@ private:
insertBufferDepthString, insertBandwidthString;
std::string initialCommand =
"DROP TABLE IF EXISTS Phases; \n"
"DROP TABLE IF EXISTS GeneralInfo; \n"
"DROP TABLE IF EXISTS CommandLengths; \n"
"DROP TABLE IF EXISTS Comments; \n"
"DROP TABLE IF EXISTS ranges; \n"
"DROP TABLE IF EXISTS Transactions; \n"
"DROP TABLE IF EXISTS DebugMessages; \n"
"DROP TABLE IF EXISTS Power; \n"
"DROP TABLE IF EXISTS BufferDepth; \n"
"DROP TABLE IF EXISTS Bandwidth; \n"
" \n"
"CREATE TABLE Phases( \n"
" ID INTEGER PRIMARY KEY, \n"
" PhaseName TEXT, \n"
" PhaseBegin INTEGER, \n"
" PhaseEnd INTEGER, \n"
" Transact INTEGER \n"
"); \n"
" \n"
"CREATE TABLE GeneralInfo( \n"
" NumberOfTransactions INTEGER, \n"
" TraceEnd INTEGER, \n"
" NumberOfRanks INTEGER, \n"
" NumberOfBankgroups INTEGER, \n"
" NumberOfBanks INTEGER, \n"
" clk INTEGER, \n"
" UnitOfTime TEXT, \n"
" MCconfig TEXT, \n"
" Memspec TEXT, \n"
" Traces TEXT, \n"
" WindowSize INTEGER, \n"
" RefreshMaxPostponed INTEGER, \n"
" RefreshMaxPulledin INTEGER, \n"
" ControllerThread INTEGER, \n"
" MaxBufferDepth INTEGER, \n"
" Per2BankOffset INTEGER \n"
"); \n"
" \n"
"CREATE TABLE CommandLengths( \n"
" NOP INTEGER, \n"
" RD INTEGER, \n"
" WR INTEGER, \n"
" RDA INTEGER, \n"
" WRA INTEGER, \n"
" ACT INTEGER, \n"
" PREPB INTEGER, \n"
" REFPB INTEGER, \n"
" RFMPB INTEGER, \n"
" REFP2B INTEGER, \n"
" RFMP2B INTEGER, \n"
" PRESB INTEGER, \n"
" REFSB INTEGER, \n"
" RFMSB INTEGER, \n"
" PREAB INTEGER, \n"
" REFAB INTEGER, \n"
" RFMAB INTEGER, \n"
" PDEA INTEGER, \n"
" PDXA INTEGER, \n"
" PDEP INTEGER, \n"
" PDXP INTEGER, \n"
" SREFEN INTEGER, \n"
" SREFEX INTEGER \n"
"); \n"
" \n"
"CREATE TABLE Power( \n"
" time DOUBLE, \n"
" AveragePower DOUBLE \n"
"); \n"
" \n"
"CREATE TABLE BufferDepth( \n"
" Time DOUBLE, \n"
" BufferNumber INTEGER, \n"
" AverageBufferDepth DOUBLE \n"
"); \n"
" \n"
"CREATE TABLE Bandwidth( \n"
" Time DOUBLE, \n"
" AverageBandwidth DOUBLE \n"
"); \n"
" \n"
"CREATE TABLE Comments( \n"
" Time INTEGER, \n"
" Text TEXT \n"
"); \n"
" \n"
"CREATE TABLE DebugMessages( \n"
" Time INTEGER, \n"
" Message TEXT \n"
"); \n"
" \n"
"-- use SQLITE R* TREE Module to make queries on timespans effecient (see http://www.sqlite.org/rtree.html)\n"
"CREATE VIRTUAL TABLE ranges USING rtree( \n"
" id, \n"
" begin, end \n"
"); \n"
" \n"
"CREATE TABLE Transactions( \n"
" ID INTEGER, \n"
" Range INTEGER, \n"
" Address INTEGER, \n"
" Burstlength INTEGER, \n"
" TThread INTEGER, \n"
" TChannel INTEGER, \n"
" TRank INTEGER, \n"
" TBankgroup INTEGER, \n"
" TBank INTEGER, \n"
" TRow INTEGER, \n"
" TColumn INTEGER, \n"
" DataStrobeBegin INTEGER, \n"
" DataStrobeEnd INTEGER, \n"
" TimeOfGeneration INTEGER, \n"
" Command TEXT \n"
"); \n"
" \n"
"CREATE INDEX ranges_index ON Transactions(Range); \n"
"CREATE INDEX \"phasesTransactions\" ON \"Phases\" (\"Transact\" ASC); \n"
"CREATE INDEX \"messageTimes\" ON \"DebugMessages\" (\"Time\" ASC); \n";
"DROP TABLE IF EXISTS Phases; \n"
"DROP TABLE IF EXISTS GeneralInfo; \n"
"DROP TABLE IF EXISTS CommandLengths; \n"
"DROP TABLE IF EXISTS Comments; \n"
"DROP TABLE IF EXISTS ranges; \n"
"DROP TABLE IF EXISTS Transactions; \n"
"DROP TABLE IF EXISTS DebugMessages; \n"
"DROP TABLE IF EXISTS Power; \n"
"DROP TABLE IF EXISTS BufferDepth; \n"
"DROP TABLE IF EXISTS Bandwidth; \n"
" \n"
"CREATE TABLE Phases( \n"
" ID INTEGER PRIMARY KEY, \n"
" PhaseName TEXT, \n"
" PhaseBegin INTEGER, \n"
" PhaseEnd INTEGER, \n"
" Transact INTEGER \n"
"); \n"
" \n"
"CREATE TABLE GeneralInfo( \n"
" NumberOfTransactions INTEGER, \n"
" TraceEnd INTEGER, \n"
" NumberOfRanks INTEGER, \n"
" NumberOfBankgroups INTEGER, \n"
" NumberOfBanks INTEGER, \n"
" clk INTEGER, \n"
" UnitOfTime TEXT, \n"
" MCconfig TEXT, \n"
" Memspec TEXT, \n"
" Traces TEXT, \n"
" WindowSize INTEGER, \n"
" RefreshMaxPostponed INTEGER, \n"
" RefreshMaxPulledin INTEGER, \n"
" ControllerThread INTEGER, \n"
" MaxBufferDepth INTEGER, \n"
" Per2BankOffset INTEGER \n"
"); \n"
" \n"
"CREATE TABLE CommandLengths( \n"
" Command TEXT, \n"
" Length INTEGER \n"
"); \n"
" \n"
"CREATE TABLE Power( \n"
" time DOUBLE, \n"
" AveragePower DOUBLE \n"
"); \n"
" \n"
"CREATE TABLE BufferDepth( \n"
" Time DOUBLE, \n"
" BufferNumber INTEGER, \n"
" AverageBufferDepth DOUBLE \n"
"); \n"
" \n"
"CREATE TABLE Bandwidth( \n"
" Time DOUBLE, \n"
" AverageBandwidth DOUBLE \n"
"); \n"
" \n"
"CREATE TABLE Comments( \n"
" Time INTEGER, \n"
" Text TEXT \n"
"); \n"
" \n"
"CREATE TABLE DebugMessages( \n"
" Time INTEGER, \n"
" Message TEXT \n"
"); \n"
" \n"
"-- use SQLITE R* TREE Module to make queries on timespans effecient (see http://www.sqlite.org/rtree.html)\n"
"CREATE VIRTUAL TABLE ranges USING rtree( \n"
" id, \n"
" begin, end \n"
"); \n"
" \n"
"CREATE TABLE Transactions( \n"
" ID INTEGER, \n"
" Range INTEGER, \n"
" Address INTEGER, \n"
" Burstlength INTEGER, \n"
" TThread INTEGER, \n"
" TChannel INTEGER, \n"
" TRank INTEGER, \n"
" TBankgroup INTEGER, \n"
" TBank INTEGER, \n"
" TRow INTEGER, \n"
" TColumn INTEGER, \n"
" DataStrobeBegin INTEGER, \n"
" DataStrobeEnd INTEGER, \n"
" TimeOfGeneration INTEGER, \n"
" Command TEXT \n"
"); \n"
" \n"
"CREATE INDEX ranges_index ON Transactions(Range); \n"
"CREATE INDEX \"phasesTransactions\" ON \"Phases\" (\"Transact\" ASC); \n"
"CREATE INDEX \"messageTimes\" ON \"DebugMessages\" (\"Time\" ASC); \n";
};
#endif // TLMRECORDER_H

View File

@@ -96,6 +96,15 @@ DRAMSys::DRAMSys(const sc_core::sc_module_name &name,
}
}
void DRAMSys::end_of_simulation()
{
if (Configuration::getInstance().powerAnalysis)
{
for (auto& dram : drams)
dram->reportPower();
}
}
void DRAMSys::logo()
{
#define GREENTXT(s) std::string(("\u001b[38;5;28m"+std::string((s))+"\033[0m"))

View File

@@ -70,6 +70,8 @@ protected:
const DRAMSysConfiguration::Configuration &config,
bool initAndBind);
void end_of_simulation() override;
//TLM 2.0 Protocol Checkers
std::vector<tlm_utils::tlm2_base_protocol_checker<>*> controllersTlmCheckers;

View File

@@ -78,7 +78,7 @@ DRAMSysRecordable::DRAMSysRecordable(const sc_module_name &name,
void DRAMSysRecordable::end_of_simulation()
{
// Report power before TLM recorders are deleted
// Report power before TLM recorders are finalized
if (Configuration::getInstance().powerAnalysis)
{
for (auto& dram : drams)

View File

@@ -48,13 +48,14 @@ public:
DRAMSysRecordable(const sc_core::sc_module_name &name,
const DRAMSysConfiguration::Configuration &configuration);
protected:
void end_of_simulation() override;
private:
// Transaction Recorders (one per channel).
// They generate the output databases.
std::vector<TlmRecorder> tlmRecorders;
void end_of_simulation() override;
void setupTlmRecorders(const std::string &traceName, const DRAMSysConfiguration::Configuration &configuration);
void instantiateModules(const std::string &traceName,

View File

@@ -95,38 +95,28 @@ Dram::Dram(const sc_module_name &name) : sc_module(name), tSocket("socket")
Dram::~Dram()
{
if (Configuration::getInstance().powerAnalysis)
{
Dram::reportPower();
delete DRAMPower;
}
if (Configuration::getInstance().useMalloc)
free(memory);
}
void Dram::reportPower()
{
if (!powerReported)
{
powerReported = true;
DRAMPower->calcEnergy();
DRAMPower->calcEnergy();
// Print the final total energy and the average power for
// the simulation:
std::cout << name() << std::string(" Total Energy: ")
<< std::fixed << std::setprecision( 2 )
<< DRAMPower->getEnergy().total_energy
* Configuration::getInstance().memSpec->numberOfDevices
<< std::string(" pJ")
<< std::endl;
// Print the final total energy and the average power for
// the simulation:
std::cout << name() << std::string(" Total Energy: ")
<< std::fixed << std::setprecision( 2 )
<< DRAMPower->getEnergy().total_energy
* Configuration::getInstance().memSpec->numberOfDevices
<< std::string(" pJ")
<< std::endl;
std::cout << name() << std::string(" Average Power: ")
<< std::fixed << std::setprecision( 2 )
<< DRAMPower->getPower().average_power
* Configuration::getInstance().memSpec->numberOfDevices
<< std::string(" mW") << std::endl;
}
std::cout << name() << std::string(" Average Power: ")
<< std::fixed << std::setprecision( 2 )
<< DRAMPower->getPower().average_power
* Configuration::getInstance().memSpec->numberOfDevices
<< std::string(" mW") << std::endl;
}
tlm_sync_enum Dram::nb_transport_fw(tlm_generic_payload &payload,

View File

@@ -40,6 +40,8 @@
#ifndef DRAM_H
#define DRAM_H
#include <memory>
#include <systemc>
#include <tlm>
#include <tlm_utils/simple_target_socket.h>
@@ -49,9 +51,6 @@
class Dram : public sc_core::sc_module
{
private:
bool powerReported = false;
protected:
explicit Dram(const sc_core::sc_module_name &name);
SC_HAS_PROCESS(Dram);
@@ -63,7 +62,7 @@ protected:
unsigned char *memory;
libDRAMPower *DRAMPower = nullptr;
std::unique_ptr<libDRAMPower> DRAMPower;
virtual tlm::tlm_sync_enum nb_transport_fw(tlm::tlm_generic_payload &payload,
tlm::tlm_phase &phase, sc_core::sc_time &delay);

View File

@@ -138,6 +138,6 @@ DramDDR3::DramDDR3(const sc_module_name &name) : Dram(name)
powerSpec.memPowerSpec = memPowerSpec;
powerSpec.memArchSpec = memArchSpec;
DRAMPower = new libDRAMPower(powerSpec, false);
DRAMPower = std::unique_ptr<libDRAMPower>(new libDRAMPower(powerSpec, false));
}
}

View File

@@ -138,6 +138,6 @@ DramDDR4::DramDDR4(const sc_module_name &name) : Dram(name)
powerSpec.memPowerSpec = memPowerSpec;
powerSpec.memArchSpec = memArchSpec;
DRAMPower = new libDRAMPower(powerSpec, false);
DRAMPower = std::unique_ptr<libDRAMPower>(new libDRAMPower(powerSpec, false));
}
}

View File

@@ -139,7 +139,7 @@ DramWideIO::DramWideIO(const sc_module_name &name) : Dram(name)
powerSpec.memPowerSpec = memPowerSpec;
powerSpec.memArchSpec = memArchSpec;
DRAMPower = new libDRAMPower(powerSpec, false);
DRAMPower = std::unique_ptr<libDRAMPower>(new libDRAMPower(powerSpec, false));
// For each bank in a channel a error Model is created:
if (storeMode == Configuration::StoreMode::ErrorModel)
@@ -148,7 +148,7 @@ DramWideIO::DramWideIO(const sc_module_name &name) : Dram(name)
{
errorModel *em;
std::string errorModelStr = "errorModel_bank" + std::to_string(i);
em = new errorModel(errorModelStr.c_str(), DRAMPower);
em = new errorModel(errorModelStr.c_str(), DRAMPower.get());
ememory.push_back(em);
}
}

View File

@@ -116,7 +116,7 @@ protected:
friend class PhaseDependency;
};
class REQ : public Phase
class REQ final : public Phase
{
public:
using Phase::Phase;
@@ -136,8 +136,7 @@ protected:
}
};
class RESP : public Phase
class RESP final : public Phase
{
public:
using Phase::Phase;
@@ -158,7 +157,7 @@ protected:
};
/*
class PREB: public Phase
class PREB final : public Phase
{
public:
using Phase::Phase;
@@ -173,7 +172,7 @@ protected:
}
};
*/
class PREPB : public Phase
class PREPB final : public Phase
{
public:
using Phase::Phase;
@@ -188,7 +187,7 @@ protected:
}
};
class PRESB : public Phase
class PRESB final : public Phase
{
public:
using Phase::Phase;
@@ -216,7 +215,7 @@ protected:
}
};
class PREAB : public Phase
class PREAB final : public Phase
{
public:
using Phase::Phase;
@@ -244,7 +243,7 @@ protected:
}
};
/*
class ACTB : public Phase
class ACTB final : public Phase
{
public:
using Phase::Phase;
@@ -259,7 +258,7 @@ protected:
}
};
*/
class ACT : public Phase
class ACT final : public Phase
{
public:
using Phase::Phase;
@@ -274,7 +273,7 @@ protected:
}
};
class RD : public Phase
class RD final : public Phase
{
public:
using Phase::Phase;
@@ -289,7 +288,7 @@ protected:
}
};
class RDA : public Phase
class RDA final : public Phase
{
public:
using Phase::Phase;
@@ -304,7 +303,7 @@ protected:
}
};
class WR : public Phase
class WR final : public Phase
{
public:
using Phase::Phase;
@@ -319,7 +318,7 @@ protected:
}
};
class WRA : public Phase
class WRA final : public Phase
{
public:
using Phase::Phase;
@@ -360,7 +359,7 @@ protected:
}
};
class REFAB : public AUTO_REFRESH
class REFAB final : public AUTO_REFRESH
{
public:
using AUTO_REFRESH::AUTO_REFRESH;
@@ -375,7 +374,7 @@ protected:
}
};
class RFMAB : public AUTO_REFRESH
class RFMAB final : public AUTO_REFRESH
{
public:
using AUTO_REFRESH::AUTO_REFRESH;
@@ -396,8 +395,7 @@ protected:
}
};
class REFPB : public AUTO_REFRESH
class REFPB final : public AUTO_REFRESH
{
public:
using AUTO_REFRESH::AUTO_REFRESH;
@@ -408,7 +406,7 @@ protected:
}
};
class REFP2B : public AUTO_REFRESH
class REFP2B final : public AUTO_REFRESH
{
public:
using AUTO_REFRESH::AUTO_REFRESH;
@@ -423,7 +421,7 @@ protected:
}
};
class RFMP2B : public AUTO_REFRESH
class RFMP2B final : public AUTO_REFRESH
{
public:
using AUTO_REFRESH::AUTO_REFRESH;
@@ -444,7 +442,7 @@ protected:
}
};
class REFSB : public AUTO_REFRESH
class REFSB final : public AUTO_REFRESH
{
public:
using AUTO_REFRESH::AUTO_REFRESH;
@@ -459,7 +457,7 @@ protected:
}
};
class RFMSB : public AUTO_REFRESH
class RFMSB final : public AUTO_REFRESH
{
public:
using AUTO_REFRESH::AUTO_REFRESH;
@@ -484,6 +482,8 @@ class PDNAB : public Phase
{
public:
using Phase::Phase;
virtual ~PDNAB() = default;
protected:
QString Name() const override
{
@@ -508,7 +508,7 @@ protected:
}
};
class PDNA : public PDNAB
class PDNA final : public PDNAB
{
public:
using PDNAB::PDNAB;
@@ -527,6 +527,8 @@ class PDNPB : public Phase
{
public:
using Phase::Phase;
virtual ~PDNPB() = default;
protected:
QString Name() const override
{
@@ -551,7 +553,7 @@ protected:
}
};
class PDNP : public PDNPB
class PDNP final : public PDNPB
{
public:
using PDNPB::PDNPB;
@@ -570,6 +572,8 @@ class SREFB : public Phase
{
public:
using Phase::Phase;
virtual ~SREFB() = default;
protected:
QString Name() const override
{

View File

@@ -45,8 +45,6 @@
#include <QDebug>
#include <QApplication>
using namespace std;
PythonCaller &PythonCaller::instance()
{
static PythonCaller instance;
@@ -98,21 +96,20 @@ PythonCaller::PythonCaller() :
//returns new reference to the function (see: http://edcjones.tripod.com/refcount.html for the difference between "new reference" and "borrowed reference")
PyObject *PythonCaller::loadFunctionFromModule(string moduleName,
string functionName)
PyObject *PythonCaller::loadFunctionFromModule(std::string moduleName, std::string functionName)
{
PyObject *pModuleName = PyUnicode_FromString(moduleName.c_str());
PyObject *pModule = PyImport_Import(pModuleName);
if (!pModule) {
throw runtime_error(string("Could not load module " + moduleName));
throw std::runtime_error(std::string("Could not load module " + moduleName));
}
PyObject *pFunction = PyObject_GetAttrString(pModule, functionName.c_str());
if (!pFunction || !PyCallable_Check(pFunction)) {
throw runtime_error(string("Could not load test function " + functionName +
"in module " + moduleName));
throw std::runtime_error(
std::string("Could not load test function " + functionName + "in module " + moduleName));
}
Py_DECREF(pModuleName);
@@ -134,8 +131,7 @@ PythonCaller::~PythonCaller()
Py_Finalize();
}
PyObject *PythonCaller::callMetricsFunction(PyObject *function,
QString argument, vector<long> list)
PyObject *PythonCaller::callMetricsFunction(PyObject *function, QString argument, std::vector<long> list)
{
assert(PyCallable_Check(function));
@@ -153,8 +149,7 @@ PyObject *PythonCaller::callMetricsFunction(PyObject *function,
if (!pResult) {
PyErr_Print();
throw runtime_error(string("Error in calling " + testFunctionName +
" in module " + testModuleName));
throw std::runtime_error(std::string("Error in calling " + testFunctionName + " in module " + testModuleName));
}
return pResult;
@@ -174,8 +169,7 @@ PyObject *PythonCaller::callFunctionWithStringArgument(PyObject *function,
if (!pResult) {
PyErr_Print();
throw runtime_error(string("Error in calling " + testFunctionName +
" in module " + testModuleName));
throw std::runtime_error(std::string("Error in calling " + testFunctionName + " in module " + testModuleName));
}
return pResult;
@@ -188,7 +182,7 @@ PyObject *PythonCaller::callFunctionWithoutArguments(PyObject *function)
if (!pResult) {
PyErr_Print();
throw runtime_error(string("Error in calling python function"));
throw std::runtime_error(std::string("Error in calling python function"));
}
return pResult;
@@ -212,8 +206,7 @@ TraceTestResults PythonCaller::runTestsOnTrace(QString pathToTrace)
return traceTestResult;
}
TraceCalculatedMetrics PythonCaller::calculateMetricsOnTrace(
QString pathToTrace, vector<long> list)
TraceCalculatedMetrics PythonCaller::calculateMetricsOnTrace(QString pathToTrace, std::vector<long> list)
{
TraceCalculatedMetrics result(QFileInfo(pathToTrace).baseName());
PyObject *pResult = callMetricsFunction(pCalculateMetricsFunction, pathToTrace,
@@ -230,9 +223,9 @@ TraceCalculatedMetrics PythonCaller::calculateMetricsOnTrace(
return result;
}
vector<string> PythonCaller::getMetrics(QString pathToTrace)
std::vector<std::string> PythonCaller::getMetrics(QString pathToTrace)
{
vector<string> result;
std::vector<std::string> result;
PyObject *pResult = callFunctionWithStringArgument(pGetMetricsFunction,
pathToTrace);

View File

@@ -56,7 +56,6 @@ class PythonCaller
{
public:
static PythonCaller &instance();
PythonCaller(const PythonCaller &other) = delete;
TraceTestResults runTestsOnTrace(QString pathToTrace);
TraceCalculatedMetrics calculateMetricsOnTrace(QString pathToTrace,
@@ -70,6 +69,8 @@ public:
private:
PythonCaller();
~PythonCaller();
PythonCaller(const PythonCaller &other) = delete;
PythonCaller &operator=(const PythonCaller &other) = delete;
PyObject *pRunTestsFunction, *pCalculateMetricsFunction, *pGetMetricsFunction;
PyObject *pGenPlotsFunction;

View File

@@ -334,101 +334,80 @@ GeneralInfo TraceDB::getGeneralInfoFromDB()
CommandLengths TraceDB::getCommandLengthsFromDB()
{
QVariant parameter;
parameter = getParameterFromTable("NOP", "CommandLengths");
unsigned NOP = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("RD", "CommandLengths");
unsigned RD = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("WR", "CommandLengths");
unsigned WR = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("RDA", "CommandLengths");
unsigned RDA = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("WRA", "CommandLengths");
unsigned WRA = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("ACT", "CommandLengths");
unsigned ACT = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("PREPB", "CommandLengths");
unsigned PREPB;
if (parameter.isValid())
const std::string table = "CommandLengths";
auto getLengthFromDb = [=, &table](const std::string &command) -> QVariant
{
PREPB = parameter.toUInt();
}
else
{
parameter = getParameterFromTable("PRE", "CommandLengths");
if (parameter.isValid())
PREPB = parameter.toUInt();
QSqlQuery query(("SELECT Length FROM " + table + " WHERE Command = \"" + command + "\"").c_str(), database);
if (query.first())
return query.value(0);
else
PREPB = 1;
}
parameter = getParameterFromTable("REFPB", "CommandLengths");
unsigned REFPB;
if (parameter.isValid())
return {};
};
auto getCommandLength = [=, &table](const std::string &command) -> unsigned
{
REFPB = parameter.toUInt();
}
else
{
parameter = getParameterFromTable("REFB", "CommandLengths");
if (parameter.isValid())
REFPB = parameter.toUInt();
QVariant length = getLengthFromDb(command);
if (length.isValid())
return length.toUInt();
else
REFPB = 1;
}
parameter = getParameterFromTable("RFMPB", "CommandLengths");
unsigned RFMPB = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("REFP2B", "CommandLengths");
unsigned REFP2B = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("RFMP2B", "CommandLengths");
unsigned RFMP2B = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("PRESB", "CommandLengths");
unsigned PRESB = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("REFSB", "CommandLengths");
unsigned REFSB = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("RFMSB", "CommandLengths");
unsigned RFMSB = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("PREAB", "CommandLengths");
unsigned PREAB;
if (parameter.isValid())
{
qDebug() << "CommandLength for" << command.c_str() << "not present in table" << table.c_str()
<< ". Defaulting to 1.";
return 1;
}
};
auto getCommandLengthOrElse = [=, &table](const std::string &command, const std::string &elseCommand) -> unsigned
{
PREAB = parameter.toUInt();
}
else
{
parameter = getParameterFromTable("PREA", "CommandLengths");
if (parameter.isValid())
PREAB = parameter.toUInt();
QVariant length = getLengthFromDb(command);
if (length.isValid())
return length.toUInt();
else
PREAB = 1;
}
parameter = getParameterFromTable("REFAB", "CommandLengths");
unsigned REFAB;
if (parameter.isValid())
{
REFAB = parameter.toUInt();
}
else
{
parameter = getParameterFromTable("REFA", "CommandLengths");
if (parameter.isValid())
REFAB = parameter.toUInt();
else
REFAB = 1;
}
parameter = getParameterFromTable("RFMAB", "CommandLengths");
unsigned RFMAB = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("PDEA", "CommandLengths");
unsigned PDEA = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("PDXA", "CommandLengths");
unsigned PDXA = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("PDEP", "CommandLengths");
unsigned PDEP = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("PDXP", "CommandLengths");
unsigned PDXP = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("SREFEN", "CommandLengths");
unsigned SREFEN = parameter.isValid() ? parameter.toUInt() : 1;
parameter = getParameterFromTable("SREFEX", "CommandLengths");
unsigned SREFEX = parameter.isValid() ? parameter.toUInt() : 1;
{
length = getLengthFromDb(command);
if (length.isValid())
return length.toUInt();
else
{
qDebug() << "CommandLength for" << command.c_str() << "and" << elseCommand.c_str()
<< "not present in table" << table.c_str() << ". Defaulting to 1.";
return 1;
}
}
};
unsigned NOP = getCommandLength("NOP");
unsigned RD = getCommandLength("RD");
unsigned WR = getCommandLength("RD");
unsigned RDA = getCommandLength("RDA");
unsigned WRA = getCommandLength("WRA");
unsigned ACT = getCommandLength("ACT");
unsigned PREPB = getCommandLengthOrElse("PREPB", "PRE");
unsigned REFPB = getCommandLengthOrElse("REFPB", "REFB");
unsigned RFMPB = getCommandLength("RFMPB");
unsigned REFP2B = getCommandLength("REFP2B");
unsigned RFMP2B = getCommandLength("RFMP2B");
unsigned PRESB = getCommandLength("PRESB");
unsigned REFSB = getCommandLength("REFSB");
unsigned RFMSB = getCommandLength("RFMSB");
unsigned PREAB = getCommandLengthOrElse("PREAB", "PREA");
unsigned REFAB = getCommandLengthOrElse("REFAB", "REFA");
unsigned RFMAB = getCommandLength("RFMAB");
unsigned PDEA = getCommandLength("PDEA");
unsigned PDXA = getCommandLength("PDXA");
unsigned PDEP = getCommandLength("PDEP");
unsigned PDXP = getCommandLength("PDXP");
unsigned SREFEN = getCommandLength("SREFEN");
unsigned SREFEX = getCommandLength("SREFEX");
return {NOP, RD, WR, RDA, WRA, ACT, PREPB, REFPB, RFMPB, REFP2B, RFMP2B, PRESB, REFSB, RFMSB,
PREAB, REFAB, RFMAB, PDEA, PDXA, PDEP, PDXP, SREFEN, SREFEX};

View File

@@ -115,7 +115,7 @@ private:
QString pathToDB;
QSqlDatabase database;
GeneralInfo generalInfo;
CommandLengths commandLengths{};
CommandLengths commandLengths;
QSqlQuery insertPhaseQuery;
QSqlQuery insertTransactionQuery;

View File

@@ -54,6 +54,12 @@ def getNumberOfTransactions(dbconnection):
result = cursor.fetchone()
return result[0]
def getTraceEndTime(dbconnection):
cursor = dbconnection.cursor()
cursor.execute("SELECT TraceEnd FROM GeneralInfo")
result = cursor.fetchone()
return result[0]
def getNumberOfBanks(dbconnection):
cursor = dbconnection.cursor()
cursor.execute("SELECT NumberOfBanks FROM generalInfo")

View File

@@ -1,5 +1,6 @@
import sys
import sqlite3
import argparse
from memUtil import *
from math import *
@@ -35,6 +36,27 @@ def trace_length_in_ns(connection):
result = cursor.fetchone()
return result[0]
@metric
def command_bus_utilisation_in_percent(connection):
cursor = connection.cursor()
cursor.execute("""
SELECT
SUM(CommandLengths.Length)
FROM
Phases
INNER JOIN
CommandLengths
ON Phases.PhaseName = CommandLengths.Command
""")
result = cursor.fetchone()[0]
if (result is None):
result = 0
clk, _ = getClock(connection)
traceEnd = getTraceEndTime(connection)
cmdBusOccupied = result * clk
return cmdBusOccupied / traceEnd * 100
@metric
def average_response_latency_in_ns(connection):
@@ -44,11 +66,94 @@ def average_response_latency_in_ns(connection):
result = cursor.fetchone()
return round(result[0], 1)
@metric
def average_rd_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""
SELECT
AVG(RESP.PHASEBEGIN - REQ.PHASEBEGIN) / 1000
FROM
PHASES REQ,
PHASES RESP
INNER JOIN
Transactions
ON REQ.TRANSACT = Transactions.ID
WHERE
REQ.PHASENAME = 'REQ'
AND RESP.PHASENAME = 'RESP'
AND REQ.TRANSACT = RESP.TRANSACT
AND Transactions.Command = "R"
""")
result = cursor.fetchone()
return round(result[0], 1)
@metric
def average_wr_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""
SELECT
AVG(RESP.PHASEBEGIN - REQ.PHASEBEGIN) / 1000
FROM
PHASES REQ,
PHASES RESP
INNER JOIN
Transactions
ON REQ.TRANSACT = Transactions.ID
WHERE
REQ.PHASENAME = 'REQ'
AND RESP.PHASENAME = 'RESP'
AND REQ.TRANSACT = RESP.TRANSACT
AND Transactions.Command = "W"
""")
result = cursor.fetchone()
return round(result[0], 1)
@metric
def max_rd_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""
SELECT
max(RESP.PHASEBEGIN - REQ.PHASEBEGIN) / 1000
FROM
PHASES REQ,
PHASES RESP
INNER JOIN
Transactions
ON REQ.TRANSACT = Transactions.ID
WHERE
REQ.PHASENAME = 'REQ'
AND RESP.PHASENAME = 'RESP'
AND REQ.TRANSACT = RESP.TRANSACT
AND Transactions.Command = "R"
""")
result = cursor.fetchone()
return round(result[0], 1)
@metric
def max_wr_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""
SELECT
max(RESP.PHASEBEGIN - REQ.PHASEBEGIN) / 1000
FROM
PHASES REQ,
PHASES RESP
INNER JOIN
Transactions
ON REQ.TRANSACT = Transactions.ID
WHERE
REQ.PHASENAME = 'REQ'
AND RESP.PHASENAME = 'RESP'
AND REQ.TRANSACT = RESP.TRANSACT
AND Transactions.Command = "W"
""")
result = cursor.fetchone()
return round(result[0], 1)
@metric
def max_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute(""" SELECT max(RESP.PHASEBEGIN - REQ.PHASEBEGIN)/1000 FROM PHASES REQ, PHASES RESP
cursor.execute(""" SELECT max(RESP.PHASEBEGIN - REQ.PHASEBEGIN)/1000 FROM PHASES REQ, PHASES RESP
WHERE REQ.PHASENAME = 'REQ' AND RESP.PHASENAME='RESP' AND REQ.TRANSACT = RESP.TRANSACT """)
result = cursor.fetchone()
return result[0]
@@ -995,8 +1100,6 @@ def calculateMetricsFromFuncs(pathToTrace, selectedMetrics):
connection.close()
return calculatedMetrics
import argparse
if __name__ == "__main__":
"""
Only non-threaded metrics are implemented for selection through command line

View File

@@ -1,14 +1,21 @@
import sys
import sqlite3
from memUtil import *
from math import *
import ntpath
import os
import matplotlib.pyplot as plt
import numpy as np
from memUtil import *
from math import *
from matplotlib.backends.backend_pdf import PdfPages
numberOfBins = "auto"
latencyRange = None
plots = []
def plot(function):
plots.append(function)
return function
def getThreads(connection):
cursor = connection.cursor()
@@ -77,11 +84,57 @@ def calculate_bandwidth_util(connection, windowSize, steps, queryFull, queryEnd,
def memory_utilisation_window_thread(connection, tracePath, steps, thread_ID):
# All possible cases of data transfers inside a time window
queryFull = """ SELECT sum(DataStrobeEnd - DataStrobeBegin) FROM transactions Where DataStrobeBegin >= ? and DataStrobeEnd <= ? and TThread = {0}""" # The data transfer begins and ends inside the time window
queryEnd = """ SELECT sum(DataStrobeEnd - ?) FROM transactions Where DataStrobeBegin < ? and DataStrobeEnd > ? and DataStrobeEnd <=? and TThread = {0}""" # Only the end of the data transfer is inside the time window
queryBegin = """ SELECT sum(? - DataStrobeBegin) FROM transactions Where DataStrobeBegin >= ? and DataStrobeBegin < ? and DataStrobeEnd > ? and TThread = {0}""" # Only the beginning of the data transfer is inside the time window
queryPart = """ SELECT DataStrobeBegin FROM transactions Where DataStrobeBegin <= ? and DataStrobeEnd >= ? and TThread = {0}""" # The data transfer occupies all the time window
## All possible cases of data transfers inside a time window:
# The data transfer begins and ends inside the time window
queryFull = """
SELECT
SUM(DataStrobeEnd - DataStrobeBegin)
FROM
transactions
WHERE
DataStrobeBegin >= ?
AND DataStrobeEnd <= ?
AND TThread = {0}
"""
# Only the end of the data transfer is inside the time window
queryEnd = """
SELECT
SUM(DataStrobeEnd - ? )
FROM
transactions
WHERE
DataStrobeBegin < ?
AND DataStrobeEnd > ?
AND DataStrobeEnd <=?
AND TThread = {0}
"""
# Only the beginning of the data transfer is inside the time window
queryBegin = """
SELECT
SUM( ? - DataStrobeBegin)
FROM
transactions
WHERE
DataStrobeBegin >= ?
AND DataStrobeBegin < ?
AND DataStrobeEnd > ?
AND TThread = {0}
"""
# The data transfer occupies all the time window
queryPart = """
SELECT
DataStrobeBegin
FROM
transactions
WHERE
DataStrobeBegin <= ?
AND DataStrobeEnd >= ?
AND TThread = {0}
"""
queryFull = queryFull.format(thread_ID)
queryEnd = queryEnd.format(thread_ID)
@@ -95,13 +148,7 @@ def memory_utilisation_window_thread(connection, tracePath, steps, thread_ID):
outputFileNameBWMatlab, basename = createOutputFilename(tracePath, 'memory_utilization_percent', 'thread_' + str(thread_ID) + '_', 'txt')
return bandwidthPercentage, bandwidth, outputFileNameBWMatlab
def plot(function):
plots.append(function)
return function
#@plot
@plot
def memory_utilisation_window(connection, tracePath, steps):
# This function determines the average memory bandwidth over time in
# percentage and in Gbit/s. The average bandwidth over time is done
@@ -118,11 +165,53 @@ def memory_utilisation_window(connection, tracePath, steps):
windowSize = getWindowSize(connection)
maxDataRate = maximum_data_rate(connection)
# All possible cases of data transfers inside a time window
queryFull = """ SELECT sum(DataStrobeEnd - DataStrobeBegin) FROM transactions Where DataStrobeBegin >= ? and DataStrobeEnd <= ?""" # The data transfer begins and ends inside the time window
queryEnd = """ SELECT sum(DataStrobeEnd - ?) FROM transactions Where DataStrobeBegin < ? and DataStrobeEnd > ? and DataStrobeEnd <=?""" # Only the end of the data transfer is inside the time window
queryBegin = """ SELECT sum(? - DataStrobeBegin) FROM transactions Where DataStrobeBegin >= ? and DataStrobeBegin < ? and DataStrobeEnd > ?""" # Only the beginning of the data transfer is inside the time window
queryPart = """ SELECT DataStrobeBegin FROM transactions Where DataStrobeBegin <= ? and DataStrobeEnd >= ?""" # The data transfer occupies all the time window
## All possible cases of data transfers inside a time window:
# The data transfer begins and ends inside the time window
queryFull = """
SELECT
SUM(DataStrobeEnd - DataStrobeBegin)
FROM
transactions
WHERE
DataStrobeBegin >= ?
AND DataStrobeEnd <= ?
"""
# Only the end of the data transfer is inside the time window
queryEnd = """
SELECT
SUM(DataStrobeEnd - ?)
FROM
transactions
WHERE
DataStrobeBegin < ?
AND DataStrobeEnd > ?
AND DataStrobeEnd <= ?
"""
# Only the beginning of the data transfer is inside the time window
queryBegin = """
SELECT
SUM(? - DataStrobeBegin)
FROM
transactions
WHERE
DataStrobeBegin >= ?
AND DataStrobeBegin < ?
AND DataStrobeEnd > ?
"""
# The data transfer occupies all the time window
queryPart = """
SELECT
DataStrobeBegin
FROM
transactions
WHERE
DataStrobeBegin <= ?
AND DataStrobeEnd >= ?
"""
bandwidthPercentage, bandwidth, maximumPercentage = calculate_bandwidth_util(connection, windowSize, steps, queryFull, queryEnd, queryBegin, queryPart)
@@ -131,10 +220,6 @@ def memory_utilisation_window(connection, tracePath, steps):
outputFileNameBWMatlab, basename = createOutputFilename(tracePath, 'memory_utilization_percent', '', 'txt')
outputFiles = "{0}\n\t{1}\n\t{2}\n\t".format(outputFileNameGBPS, outputFileNamePercent, outputFileNameBWMatlab)
import matplotlib.pyplot as plt
import numpy as np
from matplotlib.backends.backend_pdf import PdfPages
# windowSize/1000: picoseconds to nanoseconds conversion
time = np.arange(0, (steps+1)*windowSize/1000, windowSize/1000)
maxBandwidth = [maxDataRate/1024] * (steps+1)
@@ -196,12 +281,238 @@ def memory_utilisation_window(connection, tracePath, steps):
return outputFiles
@plot
def response_latency_window(connection, tracePath, steps):
windowSize = getWindowSize(connection)
cursor = connection.cursor()
query = """
SELECT
avg(RESP.PHASEBEGIN - REQ.PHASEBEGIN) / 1000
FROM
PHASES REQ,
PHASES RESP
WHERE
REQ.PHASENAME = 'REQ'
AND RESP.PHASENAME = 'RESP'
AND REQ.TRANSACT = RESP.TRANSACT
AND RESP.PHASEBEGIN >= ? and RESP.PHASEEND <= ?
"""
outputFileName, basename = createOutputFilename(tracePath, 'response_latency', '', 'pdf')
outputFile = "{0}\n\t".format(outputFileName)
LatencyFigure = plt.figure(figsize=(10, 5), dpi=300)
LatencyFigurePlot = LatencyFigure.add_subplot(111)
LatencyFigurePlot.set_xlabel('Time [ns]')
LatencyFigurePlot.set_ylabel('Response Latency [ns]')
LatencyFigurePlot.set_title('Average Response Latency: ' + str(basename))
LatencyFigurePlot.grid(True)
time = [None] * steps
latency = [None] * steps
for i in range(steps):
cursor.execute(query, (i * windowSize, (i + 1) * windowSize))
result = cursor.fetchone()[0]
time[i] = ((i * windowSize) - (windowSize / 2)) / 1000 # ps to ns
latency[i] = result
LatencyFigurePlot.plot(time, latency, linewidth=0.5, label="Latency")
LatencyFigurePlot.legend(loc="upper left")
pdf = PdfPages(outputFileName)
pdf.savefig(LatencyFigure)
pdf.close()
LatencyFigurePlot.clear()
plt.close()
return outputFile
@plot
def wr_response_latency_window(connection, tracePath, steps):
windowSize = getWindowSize(connection)
cursor = connection.cursor()
query = """
SELECT
avg(RESP.PHASEBEGIN - REQ.PHASEBEGIN) / 1000
FROM
PHASES REQ,
PHASES RESP
INNER JOIN
Transactions
ON REQ.TRANSACT = Transactions.ID
WHERE
REQ.PHASENAME = 'REQ'
AND RESP.PHASENAME = 'RESP'
AND REQ.TRANSACT = RESP.TRANSACT
AND RESP.PHASEBEGIN >= ? and RESP.PHASEEND <= ?
AND Transactions.Command = "W"
"""
outputFileName, basename = createOutputFilename(tracePath, 'wr_response_latency', '', 'pdf')
outputFile = "{0}\n\t".format(outputFileName)
LatencyFigure = plt.figure(figsize=(10, 5), dpi=300)
LatencyFigurePlot = LatencyFigure.add_subplot(111)
LatencyFigurePlot.set_xlabel('Time [ns]')
LatencyFigurePlot.set_ylabel('Response Latency [ns]')
LatencyFigurePlot.set_title('Average Write Response Latency: ' + str(basename))
LatencyFigurePlot.grid(True)
time = [None] * steps
latency = [None] * steps
for i in range(steps):
cursor.execute(query, (i * windowSize, (i + 1) * windowSize))
result = cursor.fetchone()[0]
time[i] = ((i * windowSize) - (windowSize / 2)) / 1000 # ps to ns
latency[i] = result
LatencyFigurePlot.plot(time, latency, linewidth=0.5, label="Latency")
LatencyFigurePlot.legend(loc="upper left")
pdf = PdfPages(outputFileName)
pdf.savefig(LatencyFigure)
pdf.close()
LatencyFigurePlot.clear()
plt.close()
return outputFile
@plot
def rd_response_latency_window(connection, tracePath, steps):
windowSize = getWindowSize(connection)
cursor = connection.cursor()
query = """
SELECT
avg(RESP.PHASEBEGIN - REQ.PHASEBEGIN) / 1000
FROM
PHASES REQ,
PHASES RESP
INNER JOIN
Transactions
ON REQ.TRANSACT = Transactions.ID
WHERE
REQ.PHASENAME = 'REQ'
AND RESP.PHASENAME = 'RESP'
AND REQ.TRANSACT = RESP.TRANSACT
AND RESP.PHASEBEGIN >= ? and RESP.PHASEEND <= ?
AND Transactions.Command = "R"
"""
outputFileName, basename = createOutputFilename(tracePath, 'rd_response_latency', '', 'pdf')
outputFile = "{0}\n\t".format(outputFileName)
LatencyFigure = plt.figure(figsize=(10, 5), dpi=300)
LatencyFigurePlot = LatencyFigure.add_subplot(111)
LatencyFigurePlot.set_xlabel('Time [ns]')
LatencyFigurePlot.set_ylabel('Response Latency [ns]')
LatencyFigurePlot.set_title('Average Read Response Latency: ' + str(basename))
LatencyFigurePlot.grid(True)
time = [None] * steps
latency = [None] * steps
for i in range(steps):
cursor.execute(query, (i * windowSize, (i + 1) * windowSize))
result = cursor.fetchone()[0]
time[i] = ((i * windowSize) - (windowSize / 2)) / 1000 # ps to ns
latency[i] = result
LatencyFigurePlot.plot(time, latency, linewidth=0.5, label="Latency")
LatencyFigurePlot.legend(loc="upper left")
pdf = PdfPages(outputFileName)
pdf.savefig(LatencyFigure)
pdf.close()
LatencyFigurePlot.clear()
plt.close()
return outputFile
@plot
def command_bus_utilisation_window(connection, tracePath, steps):
windowSize = getWindowSize(connection)
cursor = connection.cursor()
# Query that sums all lengths that are completely contained in the window
query_full = """
SELECT
SUM(CommandLengths.Length)
FROM
Phases,
GeneralInfo
INNER JOIN
CommandLengths
ON Phases.PhaseName = CommandLengths.Command
WHERE
Phases.PhaseBegin >= ?
AND (Phases.PhaseBegin + (CommandLengths.Length * GeneralInfo.clk)) < ?
"""
# Gets the PhaseBegin of the command that reaches out of the window
# query_border = """
# SELECT
# Phases.PhaseBegin
# FROM
# Phases,
# GeneralInfo
# INNER JOIN
# CommandLengths
# ON Phases.PhaseName = CommandLengths.Command
# WHERE
# Phases.PhaseBegin >= ?
# AND Phases.PhaseBegin < ?
# AND (Phases.PhaseBegin + (CommandLengths.Length * GeneralInfo.clk)) >= ?
# """
outputFileName, basename = createOutputFilename(tracePath, 'command_bus_utilisation', '', 'pdf')
outputFile = "{0}\n\t".format(outputFileName)
LatencyFigure = plt.figure(figsize=(10, 5), dpi=300)
LatencyFigurePlot = LatencyFigure.add_subplot(111)
LatencyFigurePlot.set_xlabel('Time [ns]')
LatencyFigurePlot.set_ylabel('Utilization [%]')
LatencyFigurePlot.set_title('Command Bus Utilization: ' + str(basename))
LatencyFigurePlot.grid(True)
clk, _ = getClock(connection)
time = [None] * steps
utilization = [None] * steps
for i in range(steps):
left_limit = i * windowSize
right_limit = (i + 1) * windowSize
cursor.execute(query_full, (left_limit, right_limit))
result = cursor.fetchone()[0]
if (result is None):
result = 0
cmdBusOccupied = result * clk
time[i] = ((i * windowSize) - (windowSize / 2)) / 1000 # ps to ns
utilization[i] = cmdBusOccupied / windowSize * 100
if (utilization[i] > 100):
print(left_limit, right_limit)
LatencyFigurePlot.plot(time, utilization, linewidth=0.5, label="Utilization")
LatencyFigurePlot.legend(loc="upper left")
pdf = PdfPages(outputFileName)
pdf.savefig(LatencyFigure)
pdf.close()
LatencyFigurePlot.clear()
plt.close()
return outputFile
@plot
def queue_window(connection, tracePath, steps):
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
cursor = connection.cursor()
cursor.execute("select max(BufferNumber) from BufferDepth;")
bufferNumber = int(cursor.fetchone()[0]) + 1
@@ -256,7 +567,6 @@ def power_window(connection, tracePath, steps):
cursor.execute(" SELECT * FROM Power")
import numpy as np
window = float(windowSize) / pow(10, 12)
time = np.arange(0, (windowSize * (steps + 1)) / pow(10, 6), windowSize / pow(10, 6))
power = np.full(len(time), 0)
@@ -282,9 +592,6 @@ def power_window(connection, tracePath, steps):
outputFileName, basename = createOutputFilename(tracePath, 'power', '', 'pdf')
outputFile = "{0}\n\t".format(outputFileName)
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
PowFigure = plt.figure(figsize=(10, 5), dpi=300)
PowFigurePlot = PowFigure.add_subplot(111)
PowFigurePlot.set_xlabel('Time [us]')
@@ -301,104 +608,6 @@ def power_window(connection, tracePath, steps):
return outputFile
def latency_analysis(connection, tracePath, steps):
from collections import Counter
query = """ SELECT ((p2.PhaseEnd - p1.PhaseBegin)/1000), t.id
FROM Transactions t, Phases p1, Phases p2
WHERE t.id = p1.Transact
AND t.id = p2.Transact
AND p1.PhaseName = "REQ"
AND p2.PhaseName = "RESP" """
cursor = connection.cursor()
cursor.execute(query)
results = []
while True:
result = cursor.fetchone()
if (result is not None):
results.append([result[0], result[1]])
else:
break
# Create histogram for analysis:
hist = {}
transactions = {}
for i in results:
hist[i[0]] = hist.get(i[0], 0) + 1
if i[0] in transactions:
transactions[i[0]].append(i[1])
else:
transactions[i[0]] = []
# Find N highest bins
N = 3
k = Counter(hist)
high = k.most_common(3)
for i in high:
print(i[0]," :",i[1]," ")
print(transactions[i[0]])
return "none\n"
#@plot
def latency_histogram(connection, tracePath, steps):
# This function plots an histogram with access latencys
def plot_latency_histogram(dataArray, outputFileName, basename):
# plot into PDF file
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_pdf import PdfPages
plt.hist(dataArray, bins=numberOfBins, range=latencyRange, histtype='bar', facecolor='green')
plt.grid(True)
plt.xlabel("Access Time [ns]")
plt.ylabel("Number of Accesses (Frequency)")
plt.title("Latency Histogram " + str(basename))
pdf = PdfPages(outputFileName)
pdf.savefig()
pdf.close()
plt.close()
def create_latency_hist(connection, tracePath, target_measurement, query):
# form output file name
ofbname = 'access_latency_hist'
outputFileName, basename = createOutputFilename(tracePath, ofbname, target_measurement, 'pdf')
# return log string
outputFile = "{0}\n\t".format(outputFileName)
# access database
resultArray = accessDatabase(connection, query)
# plot
plot_latency_histogram(resultArray, outputFileName, basename)
return outputFile
# create overal latency histogram
query = """ SELECT ((p2.PhaseEnd - p1.PhaseBegin)/1000)
FROM Transactions t, Phases p1, Phases p2
WHERE t.id = p1.Transact
AND t.id = p2.Transact
AND p1.PhaseName = "REQ"
AND p2.PhaseName = "RESP" """
outputFile = create_latency_hist(connection, tracePath, '', query)
# create per-thread latency histogram
threads = getThreads(connection)
if (len(threads) > 1):
queryThread = """ SELECT ((p2.PhaseEnd - p1.PhaseBegin)/1000)
FROM Transactions t, Phases p1, Phases p2
WHERE t.id = p1.Transact
AND t.id = p2.Transact
AND p1.PhaseName = "REQ"
AND p2.PhaseName = "RESP"
AND t.TThread = {0} """
for thread in threads:
thrname = 'thread_' + str(thread) + '_'
outputFile += create_latency_hist(connection, tracePath, thrname, queryThread.format(thread))
return outputFile
def generatePlots(pathToTrace):
connection = sqlite3.connect(pathToTrace)