diff --git a/DRAMSys/analyzer/businessObjects/pythoncaller.cpp b/DRAMSys/analyzer/businessObjects/pythoncaller.cpp index c300431b..27693d37 100644 --- a/DRAMSys/analyzer/businessObjects/pythoncaller.cpp +++ b/DRAMSys/analyzer/businessObjects/pythoncaller.cpp @@ -50,7 +50,9 @@ PythonCaller::PythonCaller() : testFunctionName("runTests"), metricModuleName("metrics"), metricFunctionName("calculateMetrics"), - pathToScripts(QApplication::applicationDirPath().toStdString() + "/../../DRAMSys/analyzer/scripts/") + pathToScripts(QApplication::applicationDirPath().toStdString() + "/../../DRAMSys/analyzer/scripts/"), + plotsModuleName("plots"), + plotsFunctionName("generatePlots") { Py_Initialize(); PyObject *sysPath = PySys_GetObject((char*)"path"); @@ -59,10 +61,13 @@ PythonCaller::PythonCaller() : Py_DECREF(path); qDebug() << testModuleName.c_str() << testFunctionName.c_str(); + qDebug() << metricModuleName.c_str() << metricFunctionName.c_str(); + qDebug() << plotsModuleName.c_str() << plotsFunctionName.c_str(); qDebug() << "XXX: " << pathToScripts.c_str(); pRunTestsFunction = loadFunctionFromModule(testModuleName, testFunctionName); pCalculateMetricsFunction = loadFunctionFromModule(metricModuleName, metricFunctionName); + pGenPlotsFunction = loadFunctionFromModule(plotsModuleName, plotsFunctionName); } @@ -93,6 +98,7 @@ PythonCaller::~PythonCaller() { Py_DECREF(pRunTestsFunction); Py_DECREF(pCalculateMetricsFunction); + Py_DECREF(pGenPlotsFunction); Py_Finalize(); } @@ -149,3 +155,14 @@ TraceCalculatedMetrics PythonCaller::calculateMetricsOnTrace(QString pathToTrace Py_DECREF(pResult); return result; } + +void PythonCaller::generatePlotsOnTrace(QString pathToTrace) +{ + assert(PyCallable_Check(pGenPlotsFunction)); + + PyObject *pArgs = PyTuple_New(1); + PyObject *pArgument = PyUnicode_FromString(pathToTrace.toStdString().c_str()); + PyTuple_SetItem(pArgs, 0, pArgument); + PyObject_CallObject(pGenPlotsFunction, pArgs); + Py_DECREF(pArgument); +} diff --git a/DRAMSys/analyzer/businessObjects/pythoncaller.h b/DRAMSys/analyzer/businessObjects/pythoncaller.h index 3251a7fb..361078c3 100644 --- a/DRAMSys/analyzer/businessObjects/pythoncaller.h +++ b/DRAMSys/analyzer/businessObjects/pythoncaller.h @@ -50,11 +50,16 @@ public: ~PythonCaller(); TraceTestResults runTestsOnTrace(QString pathToTrace); TraceCalculatedMetrics calculateMetricsOnTrace(QString pathToTrace); + void generatePlotsOnTrace(QString pathToTrace); private: PyObject *pRunTestsFunction, *pCalculateMetricsFunction; + PyObject *pGenPlotsFunction; PyObject* loadFunctionFromModule(std::string moduleName, std::string functionName); std::string testModuleName, testFunctionName, metricModuleName, metricFunctionName, pathToScripts; + std::string plotsModuleName; + std::string plotsFunctionName; + PyObject *callFunctionWithStringArgument(PyObject *function, QString argument); }; diff --git a/DRAMSys/analyzer/evaluationtool.cpp b/DRAMSys/analyzer/evaluationtool.cpp index e36b117a..f9d21323 100644 --- a/DRAMSys/analyzer/evaluationtool.cpp +++ b/DRAMSys/analyzer/evaluationtool.cpp @@ -33,6 +33,7 @@ * Janik Schlemminger * Robert Gernhardt * Matthias Jung + * Éder F. Zulian */ #include @@ -203,3 +204,23 @@ void EvaluationTool::on_btn_exportCSV_clicked() } } + +void EvaluationTool::on_btn_genPlots_clicked() +{ + genPlots(); +} + +void EvaluationTool::genPlots() +{ + ui->traceMetricTreeWidget->clear(); + + if(traceFilesModel->rowCount() == 0) + return; + + PythonCaller pythonCaller; + for (int row = 0; row < traceFilesModel->rowCount(); ++row) { + TraceFileItem *item = static_cast(traceFilesModel->item(row)); + pythonCaller.generatePlotsOnTrace(item->getPath()); + } + ui->traceMetricTreeWidget->expandAll(); +} diff --git a/DRAMSys/analyzer/evaluationtool.h b/DRAMSys/analyzer/evaluationtool.h index 36f250c1..e6e66a7c 100644 --- a/DRAMSys/analyzer/evaluationtool.h +++ b/DRAMSys/analyzer/evaluationtool.h @@ -33,6 +33,7 @@ * Janik Schlemminger * Robert Gernhardt * Matthias Jung + * Éder F. Zulian */ #ifndef EVALUATIONTOOL_H @@ -69,14 +70,16 @@ private Q_SLOTS: void on_btn_test_clicked(); void setTestMessage(QString message); void on_btn_calculateMetrics_clicked(); - void on_btn_exportCSV_clicked(); + void on_btn_genPlots_clicked(); + private: void fillFileList(QList paths); void runTests(); void calculateMetrics(); void cleanUpUI(); + void genPlots(); Ui::EvaluationTool *ui; diff --git a/DRAMSys/analyzer/evaluationtool.ui b/DRAMSys/analyzer/evaluationtool.ui index 0b773843..cec14f63 100644 --- a/DRAMSys/analyzer/evaluationtool.ui +++ b/DRAMSys/analyzer/evaluationtool.ui @@ -137,6 +137,13 @@ + + + + Generate plots + + + diff --git a/DRAMSys/analyzer/scripts/memUtil.py b/DRAMSys/analyzer/scripts/memUtil.py old mode 100644 new mode 100755 index 2bc5a26e..037e936b --- a/DRAMSys/analyzer/scripts/memUtil.py +++ b/DRAMSys/analyzer/scripts/memUtil.py @@ -55,3 +55,17 @@ def getNumberOfBanks(dbconnection): cursor.execute("SELECT NumberOfBanks FROM generalInfo") result = cursor.fetchone() return result[0] + + +def maximum_data_rate(connection): + memspec = MemSpec(connection) + memoryType = memspec.getValue("memoryType") + if (memoryType.find("DDR") != -1): + width = 64 + else: + if (memoryType.find("WIDEIO") != -1): + width = memspec.getValue("width") + clk = memspec.getValue("clkMhz") + rate = memspec.getValue("dataRate") + maxDataRate = float(clk)*float(width)*float(rate) + return maxDataRate diff --git a/DRAMSys/analyzer/scripts/metrics.py b/DRAMSys/analyzer/scripts/metrics.py index 80b01972..6f2d3bc2 100644 --- a/DRAMSys/analyzer/scripts/metrics.py +++ b/DRAMSys/analyzer/scripts/metrics.py @@ -1,6 +1,7 @@ import sys import sqlite3 from memUtil import * +from math import * metrics = [] threadMetrics = [] @@ -24,20 +25,6 @@ def getThreads(connection): result.append(currentRow[0]) return result - -# @metric -# def latency_histogram(connection): -# cursor = connection.cursor() -# cursor.execute("SELECT ((p2.PhaseEnd - p1.PhaseEnd)/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\" ") -# result = cursor.fetchall() -# #result.sort() -# #print(max(result)[0]) -# import matplotlib.pyplot as plt -# plt.hist(result, bins=max(result)[0], histtype='barstacked') -# plt.savefig('hist.png') -# return "Saved as hist.png" - - # @metric # def average_response_latency_in_ns(connection): # cursor = connection.cursor() @@ -115,6 +102,14 @@ def memory_utilisation_percent_new(connection): return (active/(total-idle))*100 +@metric +def memory_utilisation_in_Gibps(connection): + # This function calculates the memory utilisation in Gibit/s considering the memory_utilisation_percent_new function result. + maxDataRate = maximum_data_rate(connection) + memoryPercent = memory_utilisation_percent_new(connection) + return (memoryPercent/100)*(maxDataRate/1024) + + @metric def memory_utilisation_percent_old(connection): cursor = connection.cursor() diff --git a/DRAMSys/analyzer/scripts/plots.py b/DRAMSys/analyzer/scripts/plots.py new file mode 100644 index 00000000..3b2d16fd --- /dev/null +++ b/DRAMSys/analyzer/scripts/plots.py @@ -0,0 +1,121 @@ +import sys +import sqlite3 +from memUtil import * +from math import * + +plots = [] + + +def plot(function): + plots.append(function) + return function + + +@plot +def memory_utilisation_window(connection): + # This function determines the average memory bandwidth over time in percentage and in Gbit/s. + # The average bandwidth over time is done dividing the time into windows of the same length and getting the average bandwidth in each window. + # Through the data from the database, DataStrobeEnd and DataStrobeBegin, it is possible to assess when a data transfer begins or ends. + # Hence, it is possible to ckeck when a data transfer happens and if it occupies or is inside a time window. Then, it is possible to determine the average bandwidth in percentage. + # Besides, extracting the data from the memory specs, it is possible to calculate the maximum data rate of the memory and then determine the bandwidth in Gbit/s. + # The bandwidth data are then plotted in two graphics. + + windowSize = 1000000 + cursor = connection.cursor() + cursor.execute(""" SELECT max(DataStrobeEnd) FROM Transactions """) + total = cursor.fetchone() + steps = ceil(float(total[0])/float(windowSize)) + # print(steps) + # 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 + maxDataRate = maximum_data_rate(connection) + # print(width) + # print(clk) + # print(rate) + bandwidthPercentage = [0] * steps + bandwidth = [0] * steps + for i in range(steps): + # print(i) + bandwidthPercentage[i] = 0 + cursor.execute(queryPart, (i*windowSize, (i+1)*windowSize)) + result = cursor.fetchone() + if(result is None): + cursor.execute(queryFull, (i*windowSize, (i+1)*windowSize)) + result = cursor.fetchone() + if(result[0] is not None): + bandwidthPercentage[i] += int(result[0]) + # print(bandwidthPercentage[i]) + cursor.execute(queryEnd, (i*windowSize, i*windowSize, i*windowSize, (i+1)*windowSize)) + result = cursor.fetchone() + if(result[0] is not None): + bandwidthPercentage[i] += int(result[0]) + # print(bandwidthPercentage[i]) + cursor.execute(queryBegin, ((i+1)*windowSize, i*windowSize, (i+1)*windowSize, (i+1)*windowSize)) + result = cursor.fetchone() + if(result[0] is not None): + bandwidthPercentage[i] += int(result[0]) + # print(bandwidthPercentage[i]) + else: + bandwidthPercentage[i] = windowSize + # print(bandwidthPercentage[i]) + bandwidthPercentage[i] = float(bandwidthPercentage[i]/windowSize) + bandwidth[i] = float(bandwidthPercentage[i])*float(maxDataRate)/1024 + bandwidthPercentage[i] *= 100 + + import matplotlib.pyplot as plt + import numpy as np + from matplotlib.backends.backend_pdf import PdfPages + + time = np.arange(0, steps*windowSize, windowSize) + + plt.figure(1) + plt.plot(time/1000, bandwidthPercentage) + plt.xlabel('Time (ns)') + plt.ylabel('Bandwidth (%)') + plt.ylim(0, 120) + plt.grid(True) + windowPercentage = PdfPages('windowPercentage.pdf') + windowPercentage.savefig() + windowPercentage.close() + + plt.figure(2) + plt.plot(time/1000, bandwidth) + plt.xlabel('Time (ns)') + plt.ylabel('Bandwidth (Gibit/s)') + plt.grid(True) + window = PdfPages('window.pdf') + window.savefig() + window.close() + +@plot +def latency_histogram(connection): + # This function plots an histogram with access latencys + cursor = connection.cursor() + cursor.execute("SELECT ((p2.PhaseEnd - p1.PhaseEnd)/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\" ") + result = cursor.fetchall() + #result.sort() + #print(max(result)[0]) + import matplotlib.pyplot as plt + plt.hist(result, bins=max(result)[0], histtype='barstacked') + plt.savefig('hist.png') + return "Saved as hist.png" + + +def generatePlots(pathToTrace): + connection = sqlite3.connect(pathToTrace) + + print("================================") + print("Generating plots for {0}".format(pathToTrace)) + + for p in plots: + p(connection) + + connection.close() + + +if __name__ == "__main__": + path = sys.argv[1] + generatePlots(path) diff --git a/DRAMSys/analyzer/scripts/tests.py b/DRAMSys/analyzer/scripts/tests.py old mode 100644 new mode 100755 diff --git a/DRAMSys/analyzer/traceAnalyzer.pro b/DRAMSys/analyzer/traceAnalyzer.pro index d0b2fd81..f40ce1c1 100644 --- a/DRAMSys/analyzer/traceAnalyzer.pro +++ b/DRAMSys/analyzer/traceAnalyzer.pro @@ -118,4 +118,5 @@ FORMS += \ OTHER_FILES += \ common/static/createTraceDB.sql \ scripts/metrics.py \ - scripts/tests.py + scripts/tests.py \ + scripts/plots.py diff --git a/DRAMSys/analyzer/traceanalyzer.cpp b/DRAMSys/analyzer/traceanalyzer.cpp index c3e9e3e2..bffd186b 100644 --- a/DRAMSys/analyzer/traceanalyzer.cpp +++ b/DRAMSys/analyzer/traceanalyzer.cpp @@ -209,4 +209,3 @@ void TraceAnalyzer::on_actionMetrics_triggered() evaluationTool.activateWindow(); evaluationTool.showAndEvaluateMetrics(openedTraceFiles.toList()); } -