diff --git a/DRAMSys/library/src/common/TlmRecorder.cpp b/DRAMSys/library/src/common/TlmRecorder.cpp index 83d062c0..a7011685 100644 --- a/DRAMSys/library/src/common/TlmRecorder.cpp +++ b/DRAMSys/library/src/common/TlmRecorder.cpp @@ -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(lround(memSpec->getCommandLength(Command::NOP) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 2, static_cast(lround(memSpec->getCommandLength(Command::RD) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 3, static_cast(lround(memSpec->getCommandLength(Command::WR) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 4, static_cast(lround(memSpec->getCommandLength(Command::RDA) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 5, static_cast(lround(memSpec->getCommandLength(Command::WRA) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 6, static_cast(lround(memSpec->getCommandLength(Command::ACT) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 7, static_cast(lround(memSpec->getCommandLength(Command::PREPB) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 8, static_cast(lround(memSpec->getCommandLength(Command::REFPB) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 9, static_cast(lround(memSpec->getCommandLength(Command::RFMPB) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 10, static_cast(lround(memSpec->getCommandLength(Command::REFP2B) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 11, static_cast(lround(memSpec->getCommandLength(Command::RFMP2B) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 12, static_cast(lround(memSpec->getCommandLength(Command::PRESB) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 13, static_cast(lround(memSpec->getCommandLength(Command::REFSB) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 14, static_cast(lround(memSpec->getCommandLength(Command::RFMSB) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 15, static_cast(lround(memSpec->getCommandLength(Command::PREAB) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 16, static_cast(lround(memSpec->getCommandLength(Command::REFAB) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 17, static_cast(lround(memSpec->getCommandLength(Command::RFMAB) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 18, static_cast(lround(memSpec->getCommandLength(Command::PDEA) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 19, static_cast(lround(memSpec->getCommandLength(Command::PDXA) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 20, static_cast(lround(memSpec->getCommandLength(Command::PDEP) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 21, static_cast(lround(memSpec->getCommandLength(Command::PDXP) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 22, static_cast(lround(memSpec->getCommandLength(Command::SREFEN) / memSpec->tCK))); - sqlite3_bind_int(insertCommandLengthsStatement, 23, static_cast(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(lround(memSpec->getCommandLength(command) / memSpec->tCK))); + executeSqlStatement(insertCommandLengthsStatement); + }; + + for (unsigned int command = 0; command < Command::END_ENUM; ++command) + insertCommandLength(static_cast(command)); } void TlmRecorder::insertTransactionInDB(Transaction &recordingData) diff --git a/DRAMSys/library/src/common/TlmRecorder.h b/DRAMSys/library/src/common/TlmRecorder.h index dabe3ec5..4231c952 100644 --- a/DRAMSys/library/src/common/TlmRecorder.h +++ b/DRAMSys/library/src/common/TlmRecorder.h @@ -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 diff --git a/DRAMSys/traceAnalyzer/businessObjects/pythoncaller.cpp b/DRAMSys/traceAnalyzer/businessObjects/pythoncaller.cpp index b99f3141..741295a3 100644 --- a/DRAMSys/traceAnalyzer/businessObjects/pythoncaller.cpp +++ b/DRAMSys/traceAnalyzer/businessObjects/pythoncaller.cpp @@ -45,8 +45,6 @@ #include #include -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 list) +PyObject *PythonCaller::callMetricsFunction(PyObject *function, QString argument, std::vector 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 list) +TraceCalculatedMetrics PythonCaller::calculateMetricsOnTrace(QString pathToTrace, std::vector list) { TraceCalculatedMetrics result(QFileInfo(pathToTrace).baseName()); PyObject *pResult = callMetricsFunction(pCalculateMetricsFunction, pathToTrace, @@ -230,9 +223,9 @@ TraceCalculatedMetrics PythonCaller::calculateMetricsOnTrace( return result; } -vector PythonCaller::getMetrics(QString pathToTrace) +std::vector PythonCaller::getMetrics(QString pathToTrace) { - vector result; + std::vector result; PyObject *pResult = callFunctionWithStringArgument(pGetMetricsFunction, pathToTrace); diff --git a/DRAMSys/traceAnalyzer/businessObjects/pythoncaller.h b/DRAMSys/traceAnalyzer/businessObjects/pythoncaller.h index 0f843189..eeb04d7e 100644 --- a/DRAMSys/traceAnalyzer/businessObjects/pythoncaller.h +++ b/DRAMSys/traceAnalyzer/businessObjects/pythoncaller.h @@ -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; diff --git a/DRAMSys/traceAnalyzer/scripts/memUtil.py b/DRAMSys/traceAnalyzer/scripts/memUtil.py index ce928d4d..102f3abf 100755 --- a/DRAMSys/traceAnalyzer/scripts/memUtil.py +++ b/DRAMSys/traceAnalyzer/scripts/memUtil.py @@ -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") diff --git a/DRAMSys/traceAnalyzer/scripts/metrics.py b/DRAMSys/traceAnalyzer/scripts/metrics.py index 303626f1..83d586f5 100644 --- a/DRAMSys/traceAnalyzer/scripts/metrics.py +++ b/DRAMSys/traceAnalyzer/scripts/metrics.py @@ -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 diff --git a/DRAMSys/traceAnalyzer/scripts/plots.py b/DRAMSys/traceAnalyzer/scripts/plots.py index e3c469a0..5addcac8 100755 --- a/DRAMSys/traceAnalyzer/scripts/plots.py +++ b/DRAMSys/traceAnalyzer/scripts/plots.py @@ -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)