Add new response time/ utilisation metrics/plots and update CommandsLengths table

This commit is contained in:
2022-02-09 15:36:28 +01:00
parent 6d593f1a93
commit 71aa3fa83d
7 changed files with 440 additions and 286 deletions

View File

@@ -306,10 +306,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)";
@@ -376,31 +374,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

@@ -153,123 +153,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

@@ -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

@@ -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,23 @@ 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]
clk, _ = getClock(connection)
traceEnd = getTraceEndTime(connection)
cmdBusOccupied = result / clk * 1_000_000
return cmdBusOccupied / traceEnd * 100
@metric
def average_response_latency_in_ns(connection):
@@ -44,11 +62,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 +1096,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()
@@ -95,13 +102,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
@@ -131,10 +132,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 +193,209 @@ 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 = """
SELECT
SUM(CommandLengths.Length)
FROM
Phases
INNER JOIN
CommandLengths
ON Phases.PhaseName = CommandLengths.Command
WHERE
Phases.PhaseBegin >= ?
AND Phases.PhaseBegin < ?
"""
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):
cursor.execute(query, (i * windowSize, (i + 1) * windowSize))
result = cursor.fetchone()[0]
cmdBusOccupied = result / clk * 1_000_000
time[i] = ((i * windowSize) - (windowSize / 2)) / 1000 # ps to ns
utilization[i] = cmdBusOccupied / windowSize * 100
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 +450,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 +475,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 +491,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)