From b09aced9edc1acdd83fb720288dcbdc935133a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 9 Feb 2016 16:21:43 -0200 Subject: [PATCH 1/9] Implemented a new menu option to reload databases (issue#46). Other improvements: - Added option to save changes to databases (e.g., save comments). - When a database file changes on disk (overwritten by a rerun of DRAMSys or changed by any external agent) the action save changes to DB is disabled, since it is not safe anymore. - Implemented menu options coherence. All actions except for "Open" (reload, close, save, test and metrics) remain disabled until some database file is open. - Created a shortcut to close all: CTRL+Q - Status messages containing a timestamp are displayed in the lower left corner of the traceAnalyzer window when: - User reloads the databases. - User saves changes to the databases. - Any of the open database files has changed on disk. --- DRAMSys/analyzer/data/tracedb.cpp | 12 ++++- DRAMSys/analyzer/traceanalyzer.cpp | 80 +++++++++++++++++++++++++++--- DRAMSys/analyzer/traceanalyzer.h | 5 +- DRAMSys/analyzer/traceanalyzer.ui | 21 ++++++++ DRAMSys/analyzer/tracefiletab.cpp | 33 ++++++++---- DRAMSys/analyzer/tracefiletab.h | 6 ++- 6 files changed, 134 insertions(+), 23 deletions(-) diff --git a/DRAMSys/analyzer/data/tracedb.cpp b/DRAMSys/analyzer/data/tracedb.cpp index 06f35f9b..89cd17cb 100644 --- a/DRAMSys/analyzer/data/tracedb.cpp +++ b/DRAMSys/analyzer/data/tracedb.cpp @@ -52,10 +52,18 @@ using namespace std; -TraceDB::TraceDB(QString path,bool openExisting) +TraceDB::TraceDB(QString path, bool openExisting) { this->pathToDB = path; - database = QSqlDatabase::addDatabase("QSQLITE",path); + + database = QSqlDatabase::database(path); + if (database.isValid() && database.isOpen()) { + // Close the database connection if it exists and was not closed yet. + database.removeDatabase(path); + database.close(); + } + + database = QSqlDatabase::addDatabase("QSQLITE", path); database.setDatabaseName(path); database.open(); if(!openExisting) diff --git a/DRAMSys/analyzer/traceanalyzer.cpp b/DRAMSys/analyzer/traceanalyzer.cpp index 11b96392..c3e9e3e2 100644 --- a/DRAMSys/analyzer/traceanalyzer.cpp +++ b/DRAMSys/analyzer/traceanalyzer.cpp @@ -63,9 +63,14 @@ TraceAnalyzer::TraceAnalyzer(QWidget *parent) : ui(new Ui::TraceAnalyzer) { setUpGui(); + // Disable actions except for "Open" until some file is open. + ui->actionReload_all->setEnabled(false); + ui->actionSaveChangesToDB->setEnabled(false); + ui->actionClose_all->setEnabled(false); + ui->actionTest->setEnabled(false); + ui->actionMetrics->setEnabled(false); } - TraceAnalyzer::TraceAnalyzer(QSet paths, StartupOption option, QWidget *parent): QMainWindow(parent), ui(new Ui::TraceAnalyzer) @@ -104,9 +109,18 @@ void TraceAnalyzer::openTracefile(const QString &path) return; TraceFileTab* tab = new TraceFileTab(this, path); - connect(tab, SIGNAL(statusChanged(QString)), this, SLOT(statusChanged(QString))); + connect(tab, SIGNAL(statusChanged(QString, bool)), this, SLOT(statusChanged(QString, bool))); ui->traceFileTabs->addTab(tab,QFileInfo(path).baseName()); openedTraceFiles.insert(path); + + // Enable actions + ui->actionReload_all->setEnabled(true); + ui->actionSaveChangesToDB->setEnabled(true); + ui->actionClose_all->setEnabled(true); + ui->actionTest->setEnabled(true); + ui->actionMetrics->setEnabled(true); + + statusLabel->clear(); } void TraceAnalyzer::on_traceFileTabs_tabCloseRequested(int index) @@ -121,13 +135,65 @@ void TraceAnalyzer::on_actionClose_all_triggered() { while(ui->traceFileTabs->count()) on_traceFileTabs_tabCloseRequested(0); + + // All files closed. Disable actions except for "Open". + ui->actionReload_all->setEnabled(false); + ui->actionSaveChangesToDB->setEnabled(false); + ui->actionClose_all->setEnabled(false); + ui->actionTest->setEnabled(false); + ui->actionMetrics->setEnabled(false); + + statusLabel->clear(); } - - -void TraceAnalyzer::statusChanged(QString message) +void TraceAnalyzer::on_actionReload_all_triggered() { - statusLabel->setText(message + " - (" + QTime::currentTime().toString() + ")"); + TraceFileTab *traceFileTab; + + // Remove all tabs + int tabIndex = 0; + while (ui->traceFileTabs->count() != 0) { + traceFileTab = static_cast(ui->traceFileTabs->widget(0)); + std::cout << "Closing tab #" << tabIndex << " \"" << traceFileTab->getPathToTraceFile().toStdString() << "\"" << std::endl; + + ui->traceFileTabs->removeTab(0); + delete traceFileTab; + + tabIndex++; + } + + QList list = openedTraceFiles.toList(); + qSort(list); + + // Recreate all tabs + tabIndex = 0; + for (auto path : list) { + std::cout << "Reopening tab# " << tabIndex << " \"" << path.toStdString() << "\"" << std::endl; + + traceFileTab = new TraceFileTab(this, path); + connect(traceFileTab, SIGNAL(statusChanged(QString, bool)), this, SLOT(statusChanged(QString, bool))); + ui->traceFileTabs->addTab(traceFileTab, QFileInfo(path).baseName()); + + tabIndex++; + } + + this->statusChanged(QString("All databases reloaded "), true); +} + +void TraceAnalyzer::on_actionSaveChangesToDB_triggered() +{ + for (int index = 0; index < ui->traceFileTabs->count(); index++) { + // Changes in the database files will trigger the file watchers from + // the TraceFileTab class. They generate signals connected to TraceAnalyzer::statusChanged(). + TraceFileTab *traceFileTab = static_cast(ui->traceFileTabs->widget(index)); + traceFileTab->commitChangesToDB(); + } +} + +void TraceAnalyzer::statusChanged(QString message, bool saveChangesEnable) +{ + statusLabel->setText(message + QTime::currentTime().toString()); + ui->actionSaveChangesToDB->setEnabled(saveChangesEnable); } void TraceAnalyzer::on_actionTest_triggered() @@ -142,5 +208,5 @@ void TraceAnalyzer::on_actionMetrics_triggered() evaluationTool.raise(); evaluationTool.activateWindow(); evaluationTool.showAndEvaluateMetrics(openedTraceFiles.toList()); - } + diff --git a/DRAMSys/analyzer/traceanalyzer.h b/DRAMSys/analyzer/traceanalyzer.h index e0b16a0f..f1c04887 100644 --- a/DRAMSys/analyzer/traceanalyzer.h +++ b/DRAMSys/analyzer/traceanalyzer.h @@ -73,6 +73,8 @@ private: private Q_SLOTS: void on_actionOpen_triggered(); + void on_actionReload_all_triggered(); + void on_actionSaveChangesToDB_triggered(); void on_traceFileTabs_tabCloseRequested(int index); void on_actionClose_all_triggered(); void on_actionTest_triggered(); @@ -80,10 +82,11 @@ private Q_SLOTS: void on_actionMetrics_triggered(); public Q_SLOTS: - void statusChanged(QString message); + void statusChanged(QString message, bool saveChangesEnable = false); private: Ui::TraceAnalyzer *ui; }; #endif // TRACEANALYZER_H + diff --git a/DRAMSys/analyzer/traceanalyzer.ui b/DRAMSys/analyzer/traceanalyzer.ui index d99934c7..9dec9288 100644 --- a/DRAMSys/analyzer/traceanalyzer.ui +++ b/DRAMSys/analyzer/traceanalyzer.ui @@ -57,6 +57,8 @@ File + + @@ -81,10 +83,29 @@ Ctrl+O + + + Reload databases + + + CTRL+R + + + + + Save changes to DB + + + CTRL+S + + Close all + + CTRL+Q + diff --git a/DRAMSys/analyzer/tracefiletab.cpp b/DRAMSys/analyzer/tracefiletab.cpp index eb7353da..e2132d84 100644 --- a/DRAMSys/analyzer/tracefiletab.cpp +++ b/DRAMSys/analyzer/tracefiletab.cpp @@ -41,14 +41,15 @@ #include "QFileInfo" #include "qmessagebox.h" #include -#include TraceFileTab::TraceFileTab(QWidget *parent,const QString& path) : - QWidget(parent), - ui(new Ui::TraceFileTab) + QWidget(parent), ui(new Ui::TraceFileTab), savingChangesToDB(false) { ui->setupUi(this); this->path = path; + + std::cout << "Opening new tab for \"" << path.toStdString() << "\"" << std::endl; + initNavigatorAndItsDependentWidgets(path); setUpFileWatcher(path); ui->fileDescriptionEdit->setPlainText(navigator->GeneralTraceInfo().description); @@ -57,10 +58,15 @@ TraceFileTab::TraceFileTab(QWidget *parent,const QString& path) : TraceFileTab::~TraceFileTab() { - navigator->commitChangesToDB(); delete ui; } +void TraceFileTab::commitChangesToDB() +{ + savingChangesToDB = true; + navigator->commitChangesToDB(); +} + void TraceFileTab::initNavigatorAndItsDependentWidgets(QString path) { navigator = new TraceNavigator(path,this); @@ -82,15 +88,20 @@ void TraceFileTab::setUpFileWatcher(QString path) QObject::connect(fileWatcher,SIGNAL(fileChanged(QString)),this,SLOT(tracefileChanged())); } - - void TraceFileTab::tracefileChanged() { - Q_EMIT statusChanged(QString("Last Database Refresh")); + if (savingChangesToDB == true) { + // Database has changed due to user action (e.g., saving comments). + // No need to disable the "Save changes to DB" menu. + savingChangesToDB = false; + Q_EMIT statusChanged(QString("Changes saved "), true); + } else { + // External event changed the database file (e.g., the database file + // was overwritten when running a new test). + // The "Save changes to DB" menu must be disabled to avoid saving + // changes to a corrupted or inconsistent file. + Q_EMIT statusChanged(QString("At least one database has changed on disk "), false); + } navigator->refreshData(); } - - - - diff --git a/DRAMSys/analyzer/tracefiletab.h b/DRAMSys/analyzer/tracefiletab.h index bf57bd88..5acaa96a 100644 --- a/DRAMSys/analyzer/tracefiletab.h +++ b/DRAMSys/analyzer/tracefiletab.h @@ -60,6 +60,7 @@ public: void setUpFileWatcher(QString filename); void initNavigatorAndItsDependentWidgets(QString path); QString getPathToTraceFile(){return path;} + void commitChangesToDB(void); private: QString path; @@ -67,14 +68,15 @@ private: TraceNavigator *navigator; QFileSystemWatcher *fileWatcher; void setUpQueryEditor(QString path); + bool savingChangesToDB; public Q_SLOTS: void tracefileChanged(); Q_SIGNALS: - void statusChanged(QString); + void statusChanged(QString message, bool saveChangesEnable = false); void colorGroupingChanged(ColorGrouping colorgrouping); - }; #endif // TRACEFILETAB_H + From 3085b3949bbd7cfa6bf1f4e92377ac01bc306f8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Thu, 11 Feb 2016 10:35:44 -0200 Subject: [PATCH 2/9] Test script improved Created classes to get easily memory specifications and memory configurations. Each class handles the peculiarities of the related XML file. Other changes: - git ignore file updated. --- .gitignore | 2 + DRAMSys/analyzer/scripts/tests.py | 171 +++++++++++++++++------------- 2 files changed, 100 insertions(+), 73 deletions(-) diff --git a/.gitignore b/.gitignore index 06b27a1f..f1ef5004 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,6 @@ build*/ ._.DS_Store .DS_Store *.swp +*.swo cscope* +DRAMSys/analyzer/scripts/__pycache__/ diff --git a/DRAMSys/analyzer/scripts/tests.py b/DRAMSys/analyzer/scripts/tests.py index 37d9baa1..e824378a 100644 --- a/DRAMSys/analyzer/scripts/tests.py +++ b/DRAMSys/analyzer/scripts/tests.py @@ -4,34 +4,52 @@ import sqlite3 import os import xml.etree.ElementTree as ET -def getPathToConfigs(): - return os.path.dirname(os.path.abspath(__file__).replace("/scripts","/configs")) -def getValueFromConfigXML(root, id): - return root.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value'] +class MemConfig(object): + """ Memory Configuration Class -def getIntValueFromConfigXML(root, id): - return int(root.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value']) + The format used in memory specification XML files differs from the + format used in memory configuration XML files. Each class uses the + proper format when searching for elements. + """ + def getValue(self, id): + return self.xmlMemSpec.findall(id)[0].attrib['value'] -def getMemconfig(connection): - cursor = connection.cursor() - cursor.execute("SELECT Memconfig FROM GeneralInfo") - result = cursor.fetchone() - memconfig = result[0] - return ET.parse(memconfig) + def getIntValue(self, id): + return int(self.getValue(id)) + + def __init__(self, dbconnection): + cursor = dbconnection.cursor() + cursor.execute("SELECT Memconfig FROM GeneralInfo") + result = cursor.fetchone() + self.xmlMemSpec = ET.parse(result[0]) + + +class MemSpec(object): + """ Memory Specification Class + + The format used in memory specification XML files differs from the + format used in memory configuration XML files. Each class uses the + proper format when searching for elements. + """ + def getValue(self, id): + return self.xmlMemSpec.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value'] + + def getIntValue(self, id): + return int(self.getValue(id)) + + def __init__(self, dbconnection): + cursor = dbconnection.cursor() + cursor.execute("SELECT Memspec FROM GeneralInfo") + result = cursor.fetchone() + self.xmlMemSpec = ET.parse(result[0]) -def getMemspec(connection): - cursor = connection.cursor() - cursor.execute("SELECT Memspec FROM GeneralInfo") - result = cursor.fetchone() - memspec = result[0] - return ET.parse(memspec) def getClock(connection): cursor = connection.cursor() cursor.execute("SELECT clk, UnitOfTime FROM GeneralInfo") result = cursor.fetchone() - return (result[0],result[1]) + return (result[0], result[1]) class DramConfig(object): memoryType = "" @@ -70,71 +88,74 @@ class DramConfig(object): def readConfigFromFiles(self, connection): print("Parsing dram configuration") - memspec = getMemspec(connection) + + memconfig = MemConfig(connection) + memspec = MemSpec(connection) clkWithUnit = getClock(connection) self.clk = clkWithUnit[0] self.unitOfTime = clkWithUnit[1].lower() - print(getMemconfig(connection)) - self.bankwiseLogic = getMemconfig(connection).findall("BankwiseLogic")[0].attrib['value'] - self.scheduler = getMemconfig(connection).findall("Scheduler")[0].attrib['value'] - self.numberOfBanks = getIntValueFromConfigXML(memspec, "nbrOfBanks") - self.burstLength = getIntValueFromConfigXML(memspec, "burstLength") - self.memoryType = getValueFromConfigXML(memspec, "memoryType") - self.dataRate = getIntValueFromConfigXML(memspec, "dataRate") + self.bankwiseLogic = memconfig.getValue("BankwiseLogic") + self.scheduler = memconfig.getValue("Scheduler") + + self.numberOfBanks = memspec.getIntValue("nbrOfBanks") + print(self.numberOfBanks) + self.burstLength = memspec.getIntValue("burstLength") + self.memoryType = memspec.getValue("memoryType") + self.dataRate = memspec.getIntValue("dataRate") if(self.memoryType == "WIDEIO_SDR"): self.nActivateWindow = 2; - self.tRP = self.clk * getIntValueFromConfigXML(memspec, "RP") - self.tRAS = self.clk * getIntValueFromConfigXML(memspec, "RAS") - self.tRC = self.clk * getIntValueFromConfigXML(memspec, "RC") - self.tRRD_S = self.clk * getIntValueFromConfigXML(memspec, "RRD") + self.tRP = self.clk * memspec.getIntValue("RP") + self.tRAS = self.clk * memspec.getIntValue("RAS") + self.tRC = self.clk * memspec.getIntValue("RC") + self.tRRD_S = self.clk * memspec.getIntValue("RRD") self.tRRD_L = self.tRRD_S - self.tCCD_S = self.clk * getIntValueFromConfigXML(memspec, "CCD") + self.tCCD_S = self.clk * memspec.getIntValue("CCD") self.tCCD_L = self.tCCD_S - self.tRCD = self.clk * getIntValueFromConfigXML(memspec, "RCD") - self.tNAW = self.clk * getIntValueFromConfigXML(memspec, "TAW") - self.tRL = self.clk * getIntValueFromConfigXML(memspec, "RL") - self.tWL = self.clk * getIntValueFromConfigXML(memspec, "WL") - self.tWR = self.clk * getIntValueFromConfigXML(memspec, "WR") - self.tWTR_S = self.clk * getIntValueFromConfigXML(memspec, "WTR") + self.tRCD = self.clk * memspec.getIntValue("RCD") + self.tNAW = self.clk * memspec.getIntValue("TAW") + self.tRL = self.clk * memspec.getIntValue("RL") + self.tWL = self.clk * memspec.getIntValue("WL") + self.tWR = self.clk * memspec.getIntValue("WR") + self.tWTR_S = self.clk * memspec.getIntValue("WTR") self.tWTR_L = self.tWTR_S - self.tRTP = self.clk * getIntValueFromConfigXML(memspec, "RTP"); - self.tCKESR = self.clk * getIntValueFromConfigXML(memspec, "CKESR") - self.tCKE = self.clk * getIntValueFromConfigXML(memspec, "CKE") - self.tXP = self.clk * getIntValueFromConfigXML(memspec, "XP") + self.tRTP = self.clk * memspec.getIntValue("RTP"); + self.tCKESR = self.clk * memspec.getIntValue("CKESR") + self.tCKE = self.clk * memspec.getIntValue("CKE") + self.tXP = self.clk * memspec.getIntValue("XP") self.tXPDLL = self.tXP - self.tXSR = self.clk * getIntValueFromConfigXML(memspec, "XS") + self.tXSR = self.clk * memspec.getIntValue("XS") self.tXSRDLL = self.tXSR - self.tAL = self.clk * getIntValueFromConfigXML(memspec, "AL") - self.tRFC = self.clk * getIntValueFromConfigXML(memspec, "RFC") + self.tAL = self.clk * memspec.getIntValue("AL") + self.tRFC = self.clk * memspec.getIntValue("RFC") elif(self. memoryType == "DDR4"): - self.nActivateWindow = 4; - self.tRP = self.clk * getIntValueFromConfigXML(memspec, "RP"); - self.tRAS = self.clk * getIntValueFromConfigXML(memspec, "RAS"); - self.tRC = self.clk * getIntValueFromConfigXML(memspec, "RC"); - self.tRTP = self.clk * getIntValueFromConfigXML(memspec, "RTP"); - self.tRRD_S = self.clk * getIntValueFromConfigXML(memspec, "RRD_S"); - self.tRRD_L = self.clk * getIntValueFromConfigXML(memspec, "RRD_L"); - self.tCCD_S = self.clk * getIntValueFromConfigXML(memspec, "CCD_S"); - self.tCCD_L = self.clk * getIntValueFromConfigXML(memspec, "CCD_L"); - self.tRCD = self.clk * getIntValueFromConfigXML(memspec, "RCD"); - self.tNAW = self.clk * getIntValueFromConfigXML(memspec, "FAW"); - self.tRL = self.clk * getIntValueFromConfigXML(memspec, "RL"); - self.tWL = self.clk * getIntValueFromConfigXML(memspec, "WL"); - self.tWR = self.clk * getIntValueFromConfigXML(memspec, "WR"); - self.tWTR_S = self.clk * getIntValueFromConfigXML(memspec, "WTR_S"); - self.tWTR_L = self.clk * getIntValueFromConfigXML(memspec, "WTR_L"); - self.tCKESR = self.clk * getIntValueFromConfigXML(memspec, "CKESR"); - self.tCKE = self.clk * getIntValueFromConfigXML(memspec, "CKE"); - self.tXP = self.clk * getIntValueFromConfigXML(memspec, "XP"); - self.tXPDLL = self.clk * getIntValueFromConfigXML(memspec, "XPDLL"); - self.tXSR = self.clk * getIntValueFromConfigXML(memspec, "XS"); - self.tXSRDLL = self.clk * getIntValueFromConfigXML(memspec, "XSDLL"); - self.tAL = self.clk * getIntValueFromConfigXML(memspec, "AL"); - self.tRFC = self.clk * getIntValueFromConfigXML(memspec, "RFC"); + self.nActivateWindow = 4 + self.tRP = self.clk * memspec.getIntValue("RP") + self.tRAS = self.clk * memspec.getIntValue("RAS") + self.tRC = self.clk * memspec.getIntValue("RC") + self.tRTP = self.clk * memspec.getIntValue("RTP") + self.tRRD_S = self.clk * memspec.getIntValue("RRD_S") + self.tRRD_L = self.clk * memspec.getIntValue("RRD_L") + self.tCCD_S = self.clk * memspec.getIntValue("CCD_S") + self.tCCD_L = self.clk * memspec.getIntValue("CCD_L") + self.tRCD = self.clk * memspec.getIntValue("RCD") + self.tNAW = self.clk * memspec.getIntValue("FAW") + self.tRL = self.clk * memspec.getIntValue("RL") + self.tWL = self.clk * memspec.getIntValue("WL") + self.tWR = self.clk * memspec.getIntValue("WR") + self.tWTR_S = self.clk * memspec.getIntValue("WTR_S") + self.tWTR_L = self.clk * memspec.getIntValue("WTR_L") + self.tCKESR = self.clk * memspec.getIntValue("CKESR") + self.tCKE = self.clk * memspec.getIntValue("CKE") + self.tXP = self.clk * memspec.getIntValue("XP") + self.tXPDLL = self.clk * memspec.getIntValue("XPDLL") + self.tXSR = self.clk * memspec.getIntValue("XS"); + self.tXSRDLL = self.clk * memspec.getIntValue("XSDLL") + self.tAL = self.clk * memspec.getIntValue("AL") + self.tRFC = self.clk * memspec.getIntValue("RFC") else: raise Exception("MemoryType not supported yet. Insert a coin into the coin machine and try again") @@ -152,7 +173,6 @@ class DramConfig(object): def getReadAccessTime(self): return self.burstLength/self.dataRate * dramconfig.clk - def __init__(self): pass @@ -172,6 +192,7 @@ def test(function): tests.append(function) return function + class TestResult(object): passed = True message = '' @@ -179,12 +200,15 @@ class TestResult(object): self.passed = passed self.message = message + def TestSuceeded(): return TestResult() + def TestFailed(message): return TestResult(False,message); + def formatTime(time): return ('{0} {1}'.format(time, dramconfig.unitOfTime)) @@ -205,6 +229,7 @@ def commands_are_clockaligned(connection): .format(result[0], formatTime(result[1]), formatTime(result[2]), formatTime(dramconfig.clk))) return TestSuceeded() + @test def commandbus_slots_are_used_once(connection): """Checks that no two phases on the command bus start at the same time""" @@ -342,9 +367,10 @@ def timing_constraint(FirstPhase, SecondPhase): return 0 + @test def timing_constraits_on_the_same_bank_hold(connection): - """Checks that all transitions of two consequtive phases on the same bank meet their timing constraints""" + """Checks that all transitions of two consecutive phases on the same bank meet their timing constraints""" cursor = connection.cursor() validTransitions = {} @@ -363,6 +389,7 @@ def timing_constraits_on_the_same_bank_hold(connection): lastRow = currentRow return TestSuceeded() + @test def row_buffer_is_used_correctly(connection): """Checks that each bank's row buffer is used correctly""" @@ -394,8 +421,6 @@ def row_buffer_is_used_correctly(connection): rowBufferIsClosed = True - - for currentRow in cursor: if(currentRow[0] in accessingPhases and rowBufferIsClosed == True): return TestFailed("Phase {0}({1}) acesses a closed rowbuffer".format(currentRow[1], currentRow[0])) From da28a5242b3fbb1d3ccaf47ee80f6f503f33bd6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 12 Feb 2016 11:55:57 -0200 Subject: [PATCH 3/9] PEP8 related changes. These changes are a step forward in the direction of the PEP8 style guide for python code. They do not affect functionality itself. See also: https://www.python.org/dev/peps/pep-0008/ --- DRAMSys/analyzer/scripts/tests.py | 331 +++++++++++++++--------------- 1 file changed, 168 insertions(+), 163 deletions(-) diff --git a/DRAMSys/analyzer/scripts/tests.py b/DRAMSys/analyzer/scripts/tests.py index e824378a..7e447357 100644 --- a/DRAMSys/analyzer/scripts/tests.py +++ b/DRAMSys/analyzer/scripts/tests.py @@ -13,7 +13,7 @@ class MemConfig(object): proper format when searching for elements. """ def getValue(self, id): - return self.xmlMemSpec.findall(id)[0].attrib['value'] + return self.xmlMemConfig.findall(id)[0].attrib['value'] def getIntValue(self, id): return int(self.getValue(id)) @@ -22,7 +22,7 @@ class MemConfig(object): cursor = dbconnection.cursor() cursor.execute("SELECT Memconfig FROM GeneralInfo") result = cursor.fetchone() - self.xmlMemSpec = ET.parse(result[0]) + self.xmlMemConfig = ET.parse(result[0]) class MemSpec(object): @@ -51,6 +51,7 @@ def getClock(connection): result = cursor.fetchone() return (result[0], result[1]) + class DramConfig(object): memoryType = "" scheduler = "" @@ -61,30 +62,29 @@ class DramConfig(object): nActivateWindow = numberOfBanks = 0 clk = 0 - tRP = 0 #precharge-time (pre -> act same bank) - tRAS = 0 #active-time (act -> pre same bank) - tRC = 0 #RAS-cycle-time (min time bw 2 succesive ACT to same bank) - tCCD_S = 0 #TODO: relevant? max(bl, tCCD) + tRP = 0 # precharge-time (pre -> act same bank) + tRAS = 0 # active-time (act -> pre same bank) + tRC = 0 # RAS-cycle-time (min time bw 2 succesive ACT to same bank) + tCCD_S = 0 # TODO: relevant? max(bl, tCCD) tCCD_L = 0 - tRTP = 0 #Read to precharge - tRRD_S = 0 #min time bw 2 succesive ACT to different banks (different bank group) - tRRD_L = 0 #.. (same bank group) - tRCD = 0 #act -> read/write - tNAW = 0 #n activate window - tRL = 0 #read latency (read command start to data strobe) - tWL = 0 #write latency - tWR = 0 #write recovery (write to precharge) - tWTR_S = 0 #write to read (different bank group) - tWTR_L = 0 #.. (same bank group) - tCKESR = 0 #min time in sref - tCKE = 0 #min time in pdna or pdnp - tXP = 0 #min delay to row access command after pdnpx pdnax - tXPDLL = 0 #min delay to row access command after pdnpx pdnax for dll commands - tXSR = 0 #min delay to row access command after srefx - tXSRDLL = 0 #min delay to row access command after srefx for dll commands - tAL = 0 #additive delay (delayed execution in dram) - tRFC = 0 #min ref->act delay - + tRTP = 0 # Read to precharge + tRRD_S = 0 # min time between 2 succesive ACT to different banks (different bank group) + tRRD_L = 0 # min time between 2 succesive ACT to different banks (same bank group) + tRCD = 0 # act -> read/write + tNAW = 0 # n activate window + tRL = 0 # read latency (read command start to data strobe) + tWL = 0 # write latency + tWR = 0 # write recovery (write to precharge) + tWTR_S = 0 # write to read (different bank group) + tWTR_L = 0 # write to read (same bank group) + tCKESR = 0 # min time in sref + tCKE = 0 # min time in pdna or pdnp + tXP = 0 # min delay to row access command after pdnpx pdnax + tXPDLL = 0 # min delay to row access command after pdnpx pdnax for dll commands + tXSR = 0 # min delay to row access command after srefx + tXSRDLL = 0 # min delay to row access command after srefx for dll commands + tAL = 0 # additive delay (delayed execution in dram) + tRFC = 0 # min ref->act delay def readConfigFromFiles(self, connection): print("Parsing dram configuration") @@ -100,13 +100,12 @@ class DramConfig(object): self.scheduler = memconfig.getValue("Scheduler") self.numberOfBanks = memspec.getIntValue("nbrOfBanks") - print(self.numberOfBanks) self.burstLength = memspec.getIntValue("burstLength") self.memoryType = memspec.getValue("memoryType") - self.dataRate = memspec.getIntValue("dataRate") + self.dataRate = memspec.getIntValue("dataRate") - if(self.memoryType == "WIDEIO_SDR"): - self.nActivateWindow = 2; + if (self.memoryType == "WIDEIO_SDR"): + self.nActivateWindow = 2 self.tRP = self.clk * memspec.getIntValue("RP") self.tRAS = self.clk * memspec.getIntValue("RAS") self.tRC = self.clk * memspec.getIntValue("RC") @@ -121,7 +120,7 @@ class DramConfig(object): self.tWR = self.clk * memspec.getIntValue("WR") self.tWTR_S = self.clk * memspec.getIntValue("WTR") self.tWTR_L = self.tWTR_S - self.tRTP = self.clk * memspec.getIntValue("RTP"); + self.tRTP = self.clk * memspec.getIntValue("RTP") self.tCKESR = self.clk * memspec.getIntValue("CKESR") self.tCKE = self.clk * memspec.getIntValue("CKE") self.tXP = self.clk * memspec.getIntValue("XP") @@ -131,7 +130,7 @@ class DramConfig(object): self.tAL = self.clk * memspec.getIntValue("AL") self.tRFC = self.clk * memspec.getIntValue("RFC") - elif(self. memoryType == "DDR4"): + elif (self. memoryType == "DDR4"): self.nActivateWindow = 4 self.tRP = self.clk * memspec.getIntValue("RP") self.tRAS = self.clk * memspec.getIntValue("RAS") @@ -152,7 +151,7 @@ class DramConfig(object): self.tCKE = self.clk * memspec.getIntValue("CKE") self.tXP = self.clk * memspec.getIntValue("XP") self.tXPDLL = self.clk * memspec.getIntValue("XPDLL") - self.tXSR = self.clk * memspec.getIntValue("XS"); + self.tXSR = self.clk * memspec.getIntValue("XS") self.tXSRDLL = self.clk * memspec.getIntValue("XSDLL") self.tAL = self.clk * memspec.getIntValue("AL") self.tRFC = self.clk * memspec.getIntValue("RFC") @@ -165,7 +164,7 @@ class DramConfig(object): return math.ceil(1.0*value/self.clk)*self.clk def getWriteAccessTime(self): - if(self.dataRate == 1): + if (self.dataRate == 1): return self.clk*(self.burstLength - 1) elif (self.memoryType == "DDR4"): return self.clk*self.burstLength/self.dataRate @@ -176,18 +175,23 @@ class DramConfig(object): def __init__(self): pass + dramconfig = DramConfig() + def calculateReadLength(burstLength): return dramconfig.tRL + burstLength * dramconfig.clk + def calculateWriteLength(burstLength): return dramconfig.tWL + burstLength * dramconfig.clk + # ----------- test utils --------------------------------------- tests = [] + def test(function): tests.append(function) return function @@ -196,7 +200,8 @@ def test(function): class TestResult(object): passed = True message = '' - def __init__(self, passed = True, message = ''): + + def __init__(self, passed=True, message=''): self.passed = passed self.message = message @@ -206,7 +211,7 @@ def TestSuceeded(): def TestFailed(message): - return TestResult(False,message); + return TestResult(False, message) def formatTime(time): @@ -214,6 +219,7 @@ def formatTime(time): # ----------- checks --------------------------------------- + @test def commands_are_clockaligned(connection): """Checks that all commands on the command bus are aligned to the system clock""" @@ -224,9 +230,8 @@ def commands_are_clockaligned(connection): result = cursor.fetchone() - if(result != None): - return TestFailed("Command with PhaseID {0} starts at {1} and ends at. One of those times. is not aligned to system clock ({2})" - .format(result[0], formatTime(result[1]), formatTime(result[2]), formatTime(dramconfig.clk))) + if (result is not None): + return TestFailed("Command with PhaseID {0} starts at {1} and ends at. One of those times. is not aligned to system clock ({2})".format(result[0], formatTime(result[1]), formatTime(result[2]), formatTime(dramconfig.clk))) return TestSuceeded() @@ -246,7 +251,7 @@ def commandbus_slots_are_used_once(connection): cursor.execute(query) result = cursor.fetchone() - if(result != None): + if (result is not None): return TestFailed("Slot on commandbus at time {0} is used multiple times".format(formatTime(result[0]))) return TestSuceeded() @@ -260,37 +265,36 @@ def phase_transitions_are_valid(connection): # validTransitions tells you which phases are allowed to follow the last transaction. - if(dramconfig.bankwiseLogic == "1"): + if (dramconfig.bankwiseLogic == "1"): validTransitions['PRE'] = set(['ACT', 'REFB']) validTransitions['ACT'] = set(['RD', 'RDA', 'WR', 'WRA', 'PRE', 'PRE_ALL']) - validTransitions['RD'] = set(['PRE','RD','RDA', 'WR', 'WRA', 'PDNAB']) - validTransitions['WR'] = set(['PRE', 'RD','RDA', 'WR', 'WRA', 'PDNAB']) + validTransitions['RD'] = set(['PRE', 'RD', 'RDA', 'WR', 'WRA', 'PDNAB']) + validTransitions['WR'] = set(['PRE', 'RD', 'RDA', 'WR', 'WRA', 'PDNAB']) validTransitions['RDA'] = set(['ACT', 'REFB', 'PDNPB']) validTransitions['WRA'] = set(['ACT', 'REFB', 'PDNPB']) validTransitions['REFB'] = set(['ACT', 'PDNPB', 'SREFB']) - validTransitions['PDNAB'] = set(['PRE', 'RD','RDA', 'WR', 'WRA', 'REFB']) + validTransitions['PDNAB'] = set(['PRE', 'RD', 'RDA', 'WR', 'WRA', 'REFB']) validTransitions['PDNPB'] = set(['ACT', 'REFB']) validTransitions['SREFB'] = set(['ACT']) else: - validTransitions['PRE'] = set(['ACT','PRE_ALL']) + validTransitions['PRE'] = set(['ACT', 'PRE_ALL']) validTransitions['PRE_ALL'] = set(['REFA']) validTransitions['ACT'] = set(['RD', 'RDA', 'WR', 'WRA', 'PRE_ALL']) - validTransitions['RD'] = set(['PRE', 'PRE_ALL','RD','RDA', 'WR', 'WRA', 'PDNA']) - validTransitions['WR'] = set(['PRE', 'PRE_ALL','RD','RDA', 'WR', 'WRA', 'PDNA']) + validTransitions['RD'] = set(['PRE', 'PRE_ALL', 'RD', 'RDA', 'WR', 'WRA', 'PDNA']) + validTransitions['WR'] = set(['PRE', 'PRE_ALL', 'RD', 'RDA', 'WR', 'WRA', 'PDNA']) validTransitions['RDA'] = set(['PRE_ALL', 'ACT', 'REFA', 'PDNA', 'PDNP']) validTransitions['WRA'] = set(['PRE_ALL', 'ACT', 'REFA', 'PDNA', 'PDNP']) - validTransitions['REFA'] = set(['PRE_ALL', 'ACT','REFA', 'PDNA', 'PDNP', 'SREF']) + validTransitions['REFA'] = set(['PRE_ALL', 'ACT', 'REFA', 'PDNA', 'PDNP', 'SREF']) - validTransitions['PDNA'] = set(['PRE','PRE_ALL','ACT', 'RD', 'RDA', 'WR', 'WRA', 'REFA', 'PDNA', 'PDNP']) + validTransitions['PDNA'] = set(['PRE', 'PRE_ALL', 'ACT', 'RD', 'RDA', 'WR', 'WRA', 'REFA', 'PDNA', 'PDNP']) validTransitions['PDNP'] = set(['PRE_ALL', 'ACT', 'REFA', 'PDNA', 'PDNP']) validTransitions['SREF'] = set(['PRE_ALL', 'ACT', 'REFA', 'PDNA', 'PDNP']) - # This was the original query: # query = """SELECT PhaseName, phases.ID FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin""" # However, refreshes and pre_all are attributed to Bank 0 therefore this must be added to the order evaluation: @@ -307,10 +311,10 @@ def phase_transitions_are_valid(connection): lastRow = cursor.fetchone() for currentRow in cursor: currentPhase = currentRow[0] - lastPhase = lastRow[0] + lastPhase = lastRow[0] - if(currentPhase not in validTransitions[lastPhase]): - return TestFailed("Phase {0}({1}) is not allowed to follow phase {2}({3})".format(currentRow[1],currentPhase,lastRow[1],lastPhase)) + if (currentPhase not in validTransitions[lastPhase]): + return TestFailed("Phase {0}({1}) is not allowed to follow phase {2}({3})".format(currentRow[1], currentPhase, lastRow[1], lastPhase)) lastRow = currentRow return TestSuceeded() @@ -320,49 +324,54 @@ def timing_constraint(FirstPhase, SecondPhase): FirstPhaseName = FirstPhase[0] SecondPhaseName = SecondPhase[0] - if(FirstPhaseName == "PRE" or FirstPhaseName == "PRE_ALL"): + if (FirstPhaseName == "PRE" or FirstPhaseName == "PRE_ALL"): return dramconfig.tRP - elif(FirstPhaseName == "ACT"): + elif (FirstPhaseName == "ACT"): return dramconfig.tRCD - elif(FirstPhaseName == "RD"): - if(SecondPhaseName in ["PRE, PRE_ALL"]): + elif (FirstPhaseName == "RD"): + if (SecondPhaseName in ["PRE, PRE_ALL"]): return dramconfig.tRTP - elif(SecondPhaseName in ["RD, RDA"]): + elif (SecondPhaseName in ["RD, RDA"]): return max(dramconfig.tCCD_L, getReadAccessTime()) - elif(SecondPhase in ["WR","WRA"]): - return dramconfig.tRL + getReadAccessTime() - dramconfig.tWL + 2*dramconfig.clk - elif(SecondPhase == "PDNA" ): + elif (SecondPhase in ["WR", "WRA"]): + return dramconfig.tRL + getReadAccessTime() - dramconfig.tWL + 2 * dramconfig.clk + elif (SecondPhase == "PDNA"): return dramconfig.tRL + getReadAccessTime() + dramconfig.clk - elif(FirstPhaseName == "WR"): - if(SecondPhaseName in ["PRE, PRE_ALL", "PDNA"]): + elif (FirstPhaseName == "WR"): + if (SecondPhaseName in ["PRE, PRE_ALL", "PDNA"]): return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWR - elif(SecondPhaseName in ["RD, RDA"]): + elif (SecondPhaseName in ["RD, RDA"]): return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWTR_L - elif(SecondPhaseName in ["WR, WRA"]): + elif (SecondPhaseName in ["WR, WRA"]): return max(dramconfig.tCCD_L, burstlength/dramconfig.dataRate) - elif(FirstPhaseName == "RDA"): - if(SecondPhaseName in ["ACT", "PRE_ALL", "REFA"]): + elif (FirstPhaseName == "RDA"): + if (SecondPhaseName in ["ACT", "PRE_ALL", "REFA"]): return dramconfig.tRTP + dramconfig.tRP - elif(SecondPhaseName in ["PDNA","PDNP"]): + elif (SecondPhaseName in ["PDNA", "PDNP"]): return dramconfig.tRL + getReadAccessTime() + dramconfig.clk - elif(FirstPhaseName == "WRA"): - if(SecondPhaseName in ["ACT", "PRE_ALL", "REFA"]): + elif (FirstPhaseName == "WRA"): + if (SecondPhaseName in ["ACT", "PRE_ALL", "REFA"]): return dramconfig.tWL + getWriteAccessTime() + dramconfig.tWR + dramconfig.tRP - elif(SecondPhaseName in ["PDNA","PDNP"]): + elif (SecondPhaseName in ["PDNA", "PDNP"]): return dramconfig.tWL + dramconfig.getWriteAccessTime() + dramconfig.tWR + dramconfig.clk - elif(FirstPhaseName == "REFA"): + elif (FirstPhaseName == "REFA"): return dramconfig.tRFC - elif(FirstPhaseName in ["PDNA","PDNP"]): + elif (FirstPhaseName in ["PDNA", "PDNP"]): + print("{0}".format(FirstPhaseName)) + print("{0}".format(formatTime(FirstPhase[3]))) + print("{0}".format(formatTime(FirstPhase[2]))) + print("{0}".format(formatTime(dramconfig.tXP))) + print("{0}".format(formatTime(dramconfig.clk))) return (FirstPhase[3] - FirstPhase[2]) + dramconfig.tXP - dramconfig.clk - elif(FirstPhaseName == "SREF"): + elif (FirstPhaseName == "SREF"): return (FirstPhase[3] - FirstPhase[2]) + dramconfig.tXSR - dramconfig.clk return 0 @@ -374,7 +383,7 @@ def timing_constraits_on_the_same_bank_hold(connection): cursor = connection.cursor() validTransitions = {} - query = """SELECT PhaseName, phases.ID,PhaseBegin,PhaseEnd FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank + query = """SELECT PhaseName, phases.ID, PhaseBegin, PhaseEnd FROM phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE TBank=:bank AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin""" for bankNumber in range(dramconfig.numberOfBanks): @@ -382,11 +391,11 @@ def timing_constraits_on_the_same_bank_hold(connection): lastRow = cursor.fetchone() for currentRow in cursor: - constraint = timing_constraint(lastRow,currentRow) - if(currentRow[2] - lastRow[2] + constraint < 0): - return TestFailed("Phase {0}({1}) starts {2} after Start of Phase {3}({4}). Minimal time is {5}".format( - currentRow[1],currentRow[0],formatTime(currentRow[2]-lastRow[2]),lastRow[1],lastRow[0], formatTime(constraint))) + constraint = timing_constraint(lastRow, currentRow) + if (currentRow[2] - (lastRow[2] + constraint) < 0): + return TestFailed("Phase {0}({1}) starts {2} after Start of Phase {3}({4}). Minimal time is {5}".format(currentRow[1], currentRow[0], formatTime(currentRow[2] - lastRow[2]), lastRow[1], lastRow[0], formatTime(constraint))) lastRow = currentRow + return TestSuceeded() @@ -406,37 +415,37 @@ def row_buffer_is_used_correctly(connection): ((TBank=:bank) OR (PhaseNAME = "REFA" AND TBank=0) OR (PhaseNAME = "PRE_ALL" AND TBank=0)) AND PhaseName NOT IN ('REQ','RESP') ORDER BY PhaseBegin""" + # phases that precharge the bank and close the rowbuffer + prechargingPhases = set(['PRE', 'PRE_ALL', 'RDA', 'WRA']) - #phases that precharge the bank and close the rowbuffer - prechargingPhases = set(['PRE','PRE_ALL','RDA','WRA']) + # phases that require the bank to be in active state and the rowbuffer to be opened + accessingPhases = set(['RD', 'RDA', 'WR', 'WRA', 'PRE']) - #phases that require the bank to be in active state and the rowbuffer to be opened - accessingPhases = set(['RD','RDA', 'WR', 'WRA', 'PRE']) - - #phases that require the bank to be in precharged state and the robuffer to be closed - idlePhases = set(['ACT', 'PDNP', 'REFA', 'SREF']) + # phases that require the bank to be in precharged state and the robuffer to be closed + idlePhases = set(['ACT', 'PDNP', 'REFA', 'SREF']) for bankNumber in range(dramconfig.numberOfBanks): - cursor.execute(query,{"bank": bankNumber}) + cursor.execute(query, {"bank": bankNumber}) rowBufferIsClosed = True for currentRow in cursor: - if(currentRow[0] in accessingPhases and rowBufferIsClosed == True): + if ((currentRow[0] in accessingPhases) and (rowBufferIsClosed is True)): return TestFailed("Phase {0}({1}) acesses a closed rowbuffer".format(currentRow[1], currentRow[0])) - if(currentRow[0] in idlePhases and rowBufferIsClosed == False): + if ((currentRow[0] in idlePhases) and (rowBufferIsClosed is False)): return TestFailed("Phase {0}({1}) needs a closed rowbuffer".format(currentRow[1], currentRow[0])) - if(currentRow[0] == 'ACT'): + if (currentRow[0] == 'ACT'): rowBufferIsClosed = False - if(currentRow[0] in prechargingPhases): + if (currentRow[0] in prechargingPhases): rowBufferIsClosed = True return TestSuceeded() -#----------- activate checks --------------------------------------- + +# ----------- activate checks --------------------------------------- @test def activate_to_activate_holds(connection): """Checks that all activates are far enough apart(JESD229 229, P. 27)""" @@ -445,14 +454,13 @@ def activate_to_activate_holds(connection): lastRow = cursor.fetchone() for currentRow in cursor: - timeBetweenActivates = currentRow[1] - lastRow[1] + timeBetweenActivates = currentRow[1] - lastRow[1] if (currentRow[2] == lastRow[2]): minTime = dramconfig.tRRD_L else: minTime = dramconfig.tRRD_S - if(timeBetweenActivates < minTime): - return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}". - format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), formatTime(minTime))) + if (timeBetweenActivates < minTime): + return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}".format(currentRow[0], lastRow[0], formatTime(timeBetweenActivates), formatTime(minTime))) lastRow = currentRow @@ -466,19 +474,19 @@ def activate_to_activate_on_same_bank_holds(connection): query = "SELECT Phases.ID,PhaseBegin from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName = 'ACT' AND TBANK = :bank ORDER BY PhaseBegin" for bankNumber in range(dramconfig.numberOfBanks): - cursor.execute(query,{"bank": bankNumber}) + cursor.execute(query, {"bank": bankNumber}) lastRow = cursor.fetchone() for currentRow in cursor: - timeBetweenActivates = currentRow[1] - lastRow[1]; - if(timeBetweenActivates < dramconfig.tRC): - return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}, since they are on the same bank({4})". - format(currentRow[0], lastRow[0],formatTime(timeBetweenActivates), dramconfig.tRC)) + timeBetweenActivates = currentRow[1] - lastRow[1] + if (timeBetweenActivates < dramconfig.tRC): + return TestFailed("Activates with PhaseIDs {0} and {1} are {2} apart. Minimum time between two activates is {3}, since they are on the same bank({4})".format(currentRow[0], lastRow[0], formatTime(timeBetweenActivates), dramconfig.tRC)) else: lastRow = currentRow return TestSuceeded() + @test def n_activate_window_holds(connection): """Checks that the n-Activate constraint is met everywhere(JEDEC 229, P. 27)""" @@ -488,15 +496,14 @@ def n_activate_window_holds(connection): for currentRow in cursor: activateWindow.append(currentRow[1]) - if(len(activateWindow) > dramconfig.nActivateWindow + 1): + if (len(activateWindow) > dramconfig.nActivateWindow + 1): activateWindow.pop(0) - if(activateWindow[dramconfig.nActivateWindow] - activateWindow[0] < dramconfig.tNAW): - return TestFailed("Activate with PhaseID {0} and the {1} preceeding activates violate the '{1} activate window' constraint." - " No more than {1} activates should be in rolling time window of {2}".format(currentRow[0], dramconfig.nActivateWindow,formatTime(dramconfig.tNAW))) + if (activateWindow[dramconfig.nActivateWindow] - activateWindow[0] < dramconfig.tNAW): + return TestFailed("Activate with PhaseID {0} and the {1} preceeding activates violate the '{1} activate window' constraint. No more than {1} activates should be in rolling time window of {2}".format(currentRow[0], dramconfig.nActivateWindow, formatTime(dramconfig.tNAW))) return TestSuceeded() - # ----------- read/write checks --------------------------------------- +# ----------- read/write checks --------------------------------------- @test def read_to_read_holds(connection): """Check that the read operations do not intefere with each other on the data bus""" @@ -505,13 +512,13 @@ def read_to_read_holds(connection): lastRow = cursor.fetchone() for currentRow in cursor: - timeBetweenReads = currentRow[1] - lastRow[1] + timeBetweenReads = currentRow[1] - lastRow[1] if (currentRow[2] == lastRow[2]): - minTime = max(dramconfig.tCCD_L,dramconfig.getReadAccessTime()) + minTime = max(dramconfig.tCCD_L, dramconfig.getReadAccessTime()) else: - minTime = max(dramconfig.tCCD_S,dramconfig.getReadAccessTime()) - if(timeBetweenReads < minTime): - return TestFailed("Reads with PhaseIDs {0} and {1} are {2} apart. Minimum time between two reads is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenReads), minTime)) + minTime = max(dramconfig.tCCD_S, dramconfig.getReadAccessTime()) + if (timeBetweenReads < minTime): + return TestFailed("Reads with PhaseIDs {0} and {1} are {2} apart. Minimum time between two reads is {3}".format(currentRow[0], lastRow[0], formatTime(timeBetweenReads), minTime)) lastRow = currentRow return TestSuceeded() @@ -526,16 +533,17 @@ def write_to_write_holds(connection): lastRow = cursor.fetchone() for currentRow in cursor: - timeBetweenWrites = currentRow[1] - lastRow[1] + timeBetweenWrites = currentRow[1] - lastRow[1] if (currentRow[2] == lastRow[2]): - minTime = max(dramconfig.tCCD_L,dramconfig.getWriteAccessTime()) + minTime = max(dramconfig.tCCD_L, dramconfig.getWriteAccessTime()) else: - minTime = max(dramconfig.tCCD_S,dramconfig.getWriteAccessTime()) - if(timeBetweenWrites < minTime): - return TestFailed("Writes with PhaseIDs {0} and {1} are {2} apart. Minimum time between two writes is {3}".format(currentRow[0], lastRow[0],formatTime(timeBetweenWrites), minTime)) + minTime = max(dramconfig.tCCD_S, dramconfig.getWriteAccessTime()) + if (timeBetweenWrites < minTime): + return TestFailed("Writes with PhaseIDs {0} and {1} are {2} apart. Minimum time between two writes is {3}".format(currentRow[0], lastRow[0], formatTime(timeBetweenWrites), minTime)) lastRow = currentRow return TestSuceeded() + @test def write_to_read_and_read_to_write_hold(connection): """Checks that read and write operation do not interfere with each other on the data bus @@ -549,9 +557,8 @@ def write_to_read_and_read_to_write_hold(connection): lastRow = cursor.fetchone() for currentRow in cursor: - - if(currentRow[2] in ["RD","RDA"] and lastRow[2] in ["WR","WRA"]): - #write to read + if (currentRow[2] in ["RD", "RDA"] and lastRow[2] in ["WR", "WRA"]): + # write to read if (currentRow[3] == lastRow[3]): tWTR = dramconfig.tWTR_L else: @@ -560,22 +567,21 @@ def write_to_read_and_read_to_write_hold(connection): minWriteToRead = dramconfig.tWL + dramconfig.getWriteAccessTime() + tWTR writeToRead = currentRow[1] - lastRow[1] - if(writeToRead < minWriteToRead ): - return TestFailed("Read {0} starts {1} after start of write {2}. Minimum time is {3}". - format(currentRow[0],formatTime(writeToRead),lastRow[0], formatTime(minWriteToRead))) + if (writeToRead < minWriteToRead): + return TestFailed("Read {0} starts {1} after start of write {2}. Minimum time is {3}".format(currentRow[0], formatTime(writeToRead), lastRow[0], formatTime(minWriteToRead))) - elif(currentRow[2] in ["WR","WRA"] and lastRow[2] in ["RD","RDA"]): - #read to write + elif (currentRow[2] in ["WR", "WRA"] and lastRow[2] in ["RD", "RDA"]): + # read to write minReadToWrite = dramconfig.tRL + dramconfig.getReadAccessTime() - dramconfig.tWL + dramconfig.clk * 2 readToWrite = currentRow[1] - lastRow[1] - if(readToWrite < minReadToWrite ): - return TestFailed("Write {0} starts {1} after start of read {2}. Minimum time is {3}". - format(currentRow[0],formatTime(readToWrite),lastRow[0], formatTime(minWriteToRead))) + if (readToWrite < minReadToWrite): + return TestFailed("Write {0} starts {1} after start of read {2}. Minimum time is {3}".format(currentRow[0], formatTime(readToWrite), lastRow[0], formatTime(minWriteToRead))) lastRow = currentRow return TestSuceeded() + # TODO: Check if this test still is correct! @test def read_holds_dll_constraint_after_sref(connection): @@ -586,17 +592,17 @@ def read_holds_dll_constraint_after_sref(connection): WHERE PhaseName IN ('RD', 'RDA', 'SREF') ORDER BY PhaseBegin""" for bankNumber in range(dramconfig.numberOfBanks): - cursor.execute(query,{"bank": bankNumber}) + cursor.execute(query, {"bank": bankNumber}) lastRow = cursor.fetchone() for currentRow in cursor: - if(currentRow[2] in ["RD","RDA"] and lastRow[2] == 'SREF'): + if (currentRow[2] in ["RD", "RDA"] and lastRow[2] == 'SREF'): srefEndToRead = currentRow[1] - (lastRow[1] - dramconfig.clk) - if(srefEndToRead < dramconfig.tXSRDLL ): - return TestFailed("Read {0} starts {1} after end of sref {2}. Minimum time is {3}". - format(currentRow[0],formatTime(srefEndToRead),lastRow[0], formatTime(dramconfig.tXSRDLL))) + if (srefEndToRead < dramconfig.tXSRDLL): + return TestFailed("Read {0} starts {1} after end of sref {2}. Minimum time is {3}".format(currentRow[0], formatTime(srefEndToRead), lastRow[0], formatTime(dramconfig.tXSRDLL))) lastRow = currentRow return TestSuceeded() + @test def strict_transaction_order(connection): """Checks that all transactions are processed in the right order""" @@ -609,14 +615,14 @@ def strict_transaction_order(connection): for currentRow in cursor: transactions += str(currentRow[0]) + "," - if(transactions != ""): - if(dramconfig.scheduler == "FIFO_STRICT"): + if (transactions != ""): + if (dramconfig.scheduler == "FIFO_STRICT"): return TestFailed("Transactions {0} is/are not in Order ".format(transactions)) else: - return TestResult(True, "Transactions are not in Order, however this is okay since no FIFO_STRICT was choosen"); + return TestResult(True, "Transactions are not in Order, however this is okay since no FIFO_STRICT was choosen") return TestSuceeded() - # ----------- powerdown checks --------------------------------------- +# ----------- powerdown checks --------------------------------------- # @test # def sref_active_for_minimal_time(connection): @@ -625,7 +631,7 @@ def strict_transaction_order(connection): # cursor = connection.cursor() # cursor.execute("SELECT ID, PhaseEnd-clk-PhaseBegin FROM Phases, GeneralInfo WHERE PhaseName = 'SREF'") # for currentRow in cursor: -# if(currentRow[1] < dramconfig.tCKESR): +# if (currentRow[1] < dramconfig.tCKESR): # return TestFailed("SREF with ID {0} is {1} long. Minimal time in SREF is {2}".format(currentRow[0], formatTime(currentRow[1]), dramconfig.tCKESR)) # return TestSuceeded() @@ -636,48 +642,47 @@ def strict_transaction_order(connection): # cursor = connection.cursor() # cursor.execute("SELECT ID,PhaseName, PhaseEnd-PhaseBegin FROM Phases, GeneralInfo WHERE PhaseName IN ('PDNA', 'PDNP') ") # for currentRow in cursor: -# if(currentRow[2] < dramconfig.tCKE): +# if (currentRow[2] < dramconfig.tCKE): # return TestFailed("{0} with ID {1} is {2} long. Minimal time in SREF is {3}".format(currentRow[1], currentRow[0], formatTime(currentRow[2]), dramconfig.tCKE)) # return TestSuceeded() # -------------------------- interface methods -------------------- + def runTests(pathToTrace): - connection = sqlite3.connect(pathToTrace) - dramconfig.readConfigFromFiles(connection) + connection = sqlite3.connect(pathToTrace) + dramconfig.readConfigFromFiles(connection) - testResults = [] - numberOfFailedTest = 0 - print("================================") - print("RUNNING TEST ON {0}".format(pathToTrace)) + testResults = [] + numberOfFailedTest = 0 + print("================================") + print("RUNNING TEST ON {0}".format(pathToTrace)) - print("-----------------------------\n") + print("-----------------------------\n") - for test in tests: - testResult = test(connection) - testName = test.__name__.replace("_"," ") - testResults.append((testName, testResult.passed,testResult.message)) + for test in tests: + testResult = test(connection) + testName = test.__name__.replace("_", " ") + testResults.append((testName, testResult.passed, testResult.message)) + if (testResult.passed): + print("[passed] {0}".format(testName)) + else: + print("[failed] {0} failed. Message: {1}".format(testName, testResult.message)) + numberOfFailedTest = numberOfFailedTest + 1 - if(testResult.passed): - print("[passed] {0}".format(testName)) - else: - print("[failed] {0} failed. Message: {1}".format(testName, testResult.message)) - numberOfFailedTest = numberOfFailedTest + 1 + print("\n-----------------------------") - print("\n-----------------------------") - - if(numberOfFailedTest == 0): + if (numberOfFailedTest == 0): print("All tests passed") - else: - print("{0} of {1} tests passed".format(len(tests) - numberOfFailedTest,len(tests))) + else: + print("{0} of {1} tests passed".format(len(tests) - numberOfFailedTest, len(tests))) - print("================================") - connection.close() + print("================================") + connection.close() - return testResults + return testResults if __name__ == "__main__": sys.stdout = os.fdopen(sys.stdout.fileno(), 'w') - for i in range(1,len(sys.argv)): + for i in range(1, len(sys.argv)): runTests(sys.argv[i]) - From 5ed7c56c353f38b3fc7d554f57c167504ebca6c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Fri, 12 Feb 2016 20:36:41 -0200 Subject: [PATCH 4/9] PEP8 related changes. These changes are a step forward in the direction of the PEP8 style guide for python code. They do not affect functionality itself. See also: https://www.python.org/dev/peps/pep-0008/ --- DRAMSys/analyzer/scripts/metrics.py | 540 ++++++++++++++-------------- 1 file changed, 278 insertions(+), 262 deletions(-) diff --git a/DRAMSys/analyzer/scripts/metrics.py b/DRAMSys/analyzer/scripts/metrics.py index 5a8e01c6..ef59987b 100644 --- a/DRAMSys/analyzer/scripts/metrics.py +++ b/DRAMSys/analyzer/scripts/metrics.py @@ -4,60 +4,68 @@ import sqlite3 metrics = [] threadMetrics = [] + def metric(function): - metrics.append(function) - return function + metrics.append(function) + return function + def threadMetric(function): - threadMetrics.append(function) - return function + threadMetrics.append(function) + return function + def getThreads(connection): - cursor = connection.cursor() - cursor.execute("SELECT DISTINCT(TThread) FROM transactions WHERE TThread != 0 ORDER BY TThread") - result = [] - for currentRow in cursor: - result.append(currentRow[0]) - return result + cursor = connection.cursor() + cursor.execute("SELECT DISTINCT(TThread) FROM transactions WHERE TThread != 0 ORDER BY TThread") + result = [] + for currentRow in cursor: + result.append(currentRow[0]) + return result + def getNumberOfBanks(connection): - cursor = connection.cursor() - cursor.execute("SELECT NumberOfBanks FROM generalInfo") - result = cursor.fetchone() - return result[0] + cursor = connection.cursor() + cursor.execute("SELECT NumberOfBanks FROM generalInfo") + result = cursor.fetchone() + return result[0] + def getTraceLength(connection): - cursor = connection.cursor() - cursor.execute("SELECT TraceEnd FROM GeneralInfo") - result = cursor.fetchone() - return result[0] + cursor = connection.cursor() + cursor.execute("SELECT TraceEnd FROM GeneralInfo") + result = cursor.fetchone() + return result[0] + def getClock(connection): - cursor = connection.cursor() - cursor.execute("SELECT clk FROM GeneralInfo") - result = cursor.fetchone() - return result[0] + cursor = connection.cursor() + cursor.execute("SELECT clk FROM GeneralInfo") + result = cursor.fetchone() + return result[0] -#@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() -# cursor.execute("""SELECT avg(PhaseBegin-timeOfGeneration)/1000 FROM transactions INNER JOIN Phases -# ON phases.transact = transactions.ID WHERE PhaseName='RESP' """) +# @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() +# cursor.execute("""SELECT avg(PhaseBegin-timeOfGeneration)/1000 FROM transactions INNER JOIN Phases ON phases.transact = transactions.ID WHERE PhaseName='RESP' """) # -# result = cursor.fetchone() -# return round(result[0],1) +# result = cursor.fetchone() +# return round(result[0],1) + @metric def trace_length_in_ns(connection): @@ -66,300 +74,308 @@ def trace_length_in_ns(connection): result = cursor.fetchone() return result[0] + @metric def average_response_latency_in_ns(connection): - cursor = connection.cursor() - cursor.execute("""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 """) + cursor = connection.cursor() + cursor.execute("""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 """) + + result = cursor.fetchone() + return round(result[0], 1) - result = cursor.fetchone() - return round(result[0],1) @metric def trans_with_max_response_latency(connection): - cursor = connection.cursor() - cursor.execute(""" SELECT REQ.TRANSACT, max(RESP.PHASEBEGIN - REQ.PHASEBEGIN)/1000 FROM PHASES REQ, PHASES RESP WHERE REQ.PHASENAME = 'REQ' AND RESP.PHASENAME='RESP' AND REQ.TRANSACT = RESP.TRANSACT """) + cursor = connection.cursor() + cursor.execute(""" SELECT REQ.TRANSACT, 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] - result = cursor.fetchone() - return result[0] @metric def memory_active(connection): - cursor = connection.cursor() - cursor.execute(""" SELECT sum(DataStrobeEnd - DataStrobeBegin) FROM transactions """) - active = cursor.fetchone() - cursor = connection.cursor() - cursor.execute(""" SELECT clk FROM GeneralInfo """) - clk = cursor.fetchone() - return (active[0]/clk[0]) + cursor = connection.cursor() + cursor.execute(""" SELECT sum(DataStrobeEnd - DataStrobeBegin) FROM transactions """) + active = cursor.fetchone() + cursor = connection.cursor() + cursor.execute(""" SELECT clk FROM GeneralInfo """) + clk = cursor.fetchone() + return (active[0]/clk[0]) + @metric def memory_total(connection): - cursor = connection.cursor() - cursor.execute(""" SELECT max(DataStrobeEnd) FROM Transactions """) - total = cursor.fetchone() - cursor = connection.cursor() - cursor.execute(""" SELECT clk FROM GeneralInfo """) - clk = cursor.fetchone() - return (total[0]/clk[0]) + cursor = connection.cursor() + cursor.execute(""" SELECT max(DataStrobeEnd) FROM Transactions """) + total = cursor.fetchone() + cursor = connection.cursor() + cursor.execute(""" SELECT clk FROM GeneralInfo """) + clk = cursor.fetchone() + return (total[0]/clk[0]) + @metric def memory_idle(connection): - cursor = connection.cursor() - cursor.execute(""" SELECT sum(p1.PhaseEnd - p2.PhaseBegin) FROM Phases p1, Phases p2 Where p1.PhaseName = "REQ" and p2.PhaseName = "RESP" and ((p1.Transact-1) = (p2.Transact)) and (p1.PhaseEnd > p2.PhaseBegin) """) - idle = cursor.fetchone() - cursor = connection.cursor() - cursor.execute(""" SELECT clk FROM GeneralInfo """) - clk = cursor.fetchone() - if idle[0] == None: - return 0; - else: - return (idle[0]/clk[0]) + cursor = connection.cursor() + cursor.execute(""" SELECT sum(p1.PhaseEnd - p2.PhaseBegin) FROM Phases p1, Phases p2 Where p1.PhaseName = "REQ" and p2.PhaseName = "RESP" and ((p1.Transact-1) = (p2.Transact)) and (p1.PhaseEnd > p2.PhaseBegin) """) + idle = cursor.fetchone() + cursor = connection.cursor() + cursor.execute(""" SELECT clk FROM GeneralInfo """) + clk = cursor.fetchone() + if (idle[0] is None): + return 0 + else: + return (idle[0]/clk[0]) + @metric def memory_utilisation_percent_new(connection): - total = memory_total(connection) - active = memory_active(connection) - idle = memory_idle(connection) - return (active/(total-idle))*100 + total = memory_total(connection) + active = memory_active(connection) + idle = memory_idle(connection) + return (active/(total-idle))*100 + @metric def memory_utilisation_percent_old(connection): - cursor = connection.cursor() - cursor.execute(""" SELECT sum(DataStrobeEnd - DataStrobeBegin) FROM transactions """) - active = cursor.fetchone() - cursor = connection.cursor() - cursor.execute(""" SELECT max(DataStrobeEnd) FROM Transactions """) - total = cursor.fetchone() - return (active[0]/total[0])*100 + cursor = connection.cursor() + cursor.execute(""" SELECT sum(DataStrobeEnd - DataStrobeBegin) FROM transactions """) + active = cursor.fetchone() + cursor = connection.cursor() + cursor.execute(""" SELECT max(DataStrobeEnd) FROM Transactions """) + total = cursor.fetchone() + return (active[0]/total[0])*100 +def refreshMissDecision(connection, calculatedMetrics): + cursor = connection.cursor() + cursor.execute("""SELECT phases.ID,PhaseBegin,PhaseEnd,TBank FROM Phases INNER JOIN transactions on transactions.id = phases.transact WHERE PhaseName='AUTO_REFRESH' """) + queryMinREQ = """SELECT id,min(PhaseBegin) FROM (SELECT transactions.id, PhaseBegin FROM transactions + inner join ranges on ranges.id = transactions.range inner join phases on phases.transact = transactions.id + where tthread != 0 and tbank = :bank and PhaseName = "REQ" and ranges.begin<:begin and ranges.end>:end)""" -def refreshMissDecision(connection,calculatedMetrics): - cursor = connection.cursor() - cursor.execute("""SELECT phases.ID,PhaseBegin,PhaseEnd,TBank FROM Phases INNER JOIN transactions on transactions.id = phases.transact WHERE PhaseName='AUTO_REFRESH' """) - queryMinREQ = """SELECT id,min(PhaseBegin) FROM (SELECT transactions.id, PhaseBegin FROM transactions - inner join ranges on ranges.id = transactions.range inner join phases on phases.transact = transactions.id - where tthread != 0 and tbank = :bank and PhaseName = "REQ" and ranges.begin<:begin and ranges.end>:end)""" - - queryMinRESP = """SELECT id,min(PhaseBegin) FROM (SELECT transactions.id, PhaseBegin FROM transactions - inner join ranges on ranges.id = transactions.range inner join phases on phases.transact = transactions.id - where tthread != 0 and tbank = :bank and PhaseName = "RESP" and ranges.begin<:begin and ranges.end>:end) """ + queryMinRESP = """SELECT id,min(PhaseBegin) FROM (SELECT transactions.id, PhaseBegin FROM transactions + inner join ranges on ranges.id = transactions.range inner join phases on phases.transact = transactions.id + where tthread != 0 and tbank = :bank and PhaseName = "RESP" and ranges.begin<:begin and ranges.end>:end) """ - missDecisions = 0 - totalDecisios = 0 + missDecisions = 0 + totalDecisios = 0 - for refresh in cursor: - id = refresh[0] - begin = refresh[1] - end = refresh[2] - bank = refresh[3] - #print('Refresh: {0} {1} {2} {3}'.format(id,begin,end,bank)) - - cursorMinREQ = connection.cursor() - cursorMinRESP = connection.cursor() - - cursorMinREQ.execute(queryMinREQ, {"bank":bank, "begin":begin, "end":end}) - cursorMinRESP.execute(queryMinRESP, {"bank":bank, "begin":begin, "end":end}) + for refresh in cursor: + id = refresh[0] + begin = refresh[1] + end = refresh[2] + bank = refresh[3] + # print('Refresh: {0} {1} {2} {3}'.format(id,begin,end,bank)) - earliestReq = cursorMinREQ.fetchone() - earliestResp = cursorMinRESP.fetchone() - if(earliestReq[0] != None): - totalDecisios = totalDecisios + 1 + cursorMinREQ = connection.cursor() + cursorMinRESP = connection.cursor() + + cursorMinREQ.execute(queryMinREQ, {"bank": bank, "begin": begin, "end": end}) + cursorMinRESP.execute(queryMinRESP, {"bank": bank, "begin": begin, "end": end}) + + earliestReq = cursorMinREQ.fetchone() + earliestResp = cursorMinRESP.fetchone() + if (earliestReq[0] is not None): + totalDecisios = totalDecisios + 1 if(earliestReq[0] != earliestResp[0]): - missDecisions = missDecisions + 1 - #print("earliest Req: {0}| earliest Res: {1}".format(earliestReq[0], earliestResp[0])) - end + missDecisions = missDecisions + 1 + # print("earliest Req: {0}| earliest Res: {1}".format(earliestReq[0], earliestResp[0])) + if (totalDecisios != 0): + # calculatedMetrics.append(("Total Missdecisions", missDecisions)) + calculatedMetrics.append(("Relative Missdecisions", 1.0*missDecisions/totalDecisios)) + else: + calculatedMetrics.append(("Total Missdecisions", 0)) + calculatedMetrics.append(("Relative Missdecisions", 0)) - - if(totalDecisios != 0): - #calculatedMetrics.append(("Total Missdecisions", missDecisions)) - calculatedMetrics.append(("Relative Missdecisions", 1.0*missDecisions/totalDecisios)) - else: - calculatedMetrics.append(("Total Missdecisions", 0)) - calculatedMetrics.append(("Relative Missdecisions", 0)) @threadMetric def average_response_latency_in_ns(connection, thread): - cursor = connection.cursor() - query = """SELECT avg(PhaseBegin-timeOfGeneration)/1000 FROM transactions INNER JOIN Phases - ON phases.transact = transactions.ID WHERE PhaseName='RESP' AND TThread = :Thread """ + cursor = connection.cursor() + query = """SELECT avg(PhaseBegin-timeOfGeneration)/1000 FROM transactions INNER JOIN Phases + ON phases.transact = transactions.ID WHERE PhaseName='RESP' AND TThread = :Thread """ - cursor.execute(query, {"Thread": thread}) - result = cursor.fetchone() - return round(result[0],1) + cursor.execute(query, {"Thread": thread}) + result = cursor.fetchone() + return round(result[0], 1) -def addStallTime(times,begin,end): - time = begin - while time <= end: - if(time in times): - times[time] = times[time] + 1 - else: - times[time] = 1 - time = time + 1 -#@threadMetric +def addStallTime(times, begin, end): + time = begin + while time <= end: + if(time in times): + times[time] = times[time] + 1 + else: + times[time] = 1 + time = time + 1 + + +# @threadMetric def paralellism(connection, thread): - cursor = connection.cursor() - stalltimes = {} - query = """SELECT transactions.ID,MIN(phaseBegin)/:clk,MAX(phaseEnd)/:clk - from phases inner join transactions on phases.transact=transactions.id - where phaseName Not in ('REQ','RESP') and tthread=:Thread group by transactions.ID """ + cursor = connection.cursor() + stalltimes = {} + query = """SELECT transactions.ID,MIN(phaseBegin)/:clk,MAX(phaseEnd)/:clk + from phases inner join transactions on phases.transact=transactions.id + where phaseName Not in ('REQ','RESP') and tthread=:Thread group by transactions.ID """ + + cursor.execute(query, {"Thread": thread, "clk": getClock(connection)}) + for currentRow in cursor: + addStallTime(stalltimes, currentRow[1], currentRow[2]) + para = 0 + for time in stalltimes: + para = para + stalltimes[time] + return round(para/len(stalltimes), 2) - cursor.execute(query, {"Thread": thread, "clk" : getClock(connection)}) - for currentRow in cursor: - addStallTime(stalltimes,currentRow[1],currentRow[2]) - para = 0 - for time in stalltimes: - para = para + stalltimes[time] - return round(para/len(stalltimes),2) @metric def number_of_activates(connection): - cursor = connection.cursor() - cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName = 'ACT'") - result = cursor.fetchone() - return result[0] + cursor = connection.cursor() + cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName = 'ACT'") + result = cursor.fetchone() + return result[0] + @metric def number_of_accesses(connection): - cursor = connection.cursor() - cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName IN ('REQ')") - result = cursor.fetchone() - return result[0] + cursor = connection.cursor() + cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName IN ('REQ')") + result = cursor.fetchone() + return result[0] + # @metric # def number_of_precharges(connection): -# cursor = connection.cursor() -# cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName IN ('PRE','PRE_ALL','RDA','WRA')") -# result = cursor.fetchone() -# return result[0] +# cursor = connection.cursor() +# cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName IN ('PRE','PRE_ALL','RDA','WRA')") +# result = cursor.fetchone() +# return result[0] + @metric def accesses_per_activate(connection): - cursor = connection.cursor() - cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName IN ('REQ')") - result = cursor.fetchone() - return round(result[0]*1.0/number_of_activates(connection),1) + cursor = connection.cursor() + cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName IN ('REQ')") + result = cursor.fetchone() + return round(result[0]*1.0/number_of_activates(connection), 1) + @metric def timeInPowerStates(connection): - totalTimeAllBanks = getTraceLength(connection)#*getNumberOfBanks(connection) - cursor = connection.cursor() - result = [] + totalTimeAllBanks = getTraceLength(connection) # *getNumberOfBanks(connection) + cursor = connection.cursor() + result = [] - cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = 'PDNA'") - timeInPDNA = cursor.fetchone() - totalTimeInPDNA = timeInPDNA[0] - if(totalTimeInPDNA == None): - totalTimeInPDNA = 0.0 - fractionInPDNA = totalTimeInPDNA*1.0/totalTimeAllBanks - result.append(("Time in PDNA (%)", fractionInPDNA*100)) - print("{0} {1}".format(result[-1][0],result[-1][1])) + cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = 'PDNA'") + timeInPDNA = cursor.fetchone() + totalTimeInPDNA = timeInPDNA[0] + if (totalTimeInPDNA is None): + totalTimeInPDNA = 0.0 + fractionInPDNA = totalTimeInPDNA*1.0/totalTimeAllBanks + result.append(("Time in PDNA (%)", fractionInPDNA*100)) + print("{0} {1}".format(result[-1][0], result[-1][1])) - cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = 'PDNP'") - timeInPDNP = cursor.fetchone() - totalTimeInPDNP = timeInPDNP[0] - if(totalTimeInPDNP == None): - totalTimeInPDNP = 0.0 - fractionInPDNP = totalTimeInPDNP*1.0/totalTimeAllBanks - result.append(("Time in PDNP (%)", fractionInPDNP*100)) - print("{0} {1}".format(result[-1][0],result[-1][1])) + cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = 'PDNP'") + timeInPDNP = cursor.fetchone() + totalTimeInPDNP = timeInPDNP[0] + if (totalTimeInPDNP is None): + totalTimeInPDNP = 0.0 + fractionInPDNP = totalTimeInPDNP*1.0/totalTimeAllBanks + result.append(("Time in PDNP (%)", fractionInPDNP*100)) + print("{0} {1}".format(result[-1][0], result[-1][1])) - cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = 'SREF'") - timeInSREF = cursor.fetchone() - totalTimeInSREF = timeInSREF[0] - if(totalTimeInSREF == None): - totalTimeInSREF = 0.0 - fractionInSREF = totalTimeInSREF*1.0/totalTimeAllBanks - result.append(("Time in SREF (%)", fractionInSREF*100)) - print("{0} {1}".format(result[-1][0],result[-1][1])) - result.insert(0,("Active time (%)", (1-fractionInPDNA-fractionInPDNP-fractionInSREF)*100)) - print("{0} {1}".format(result[0][0],result[0][1])) + cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = 'SREF'") + timeInSREF = cursor.fetchone() + totalTimeInSREF = timeInSREF[0] + if (totalTimeInSREF is None): + totalTimeInSREF = 0.0 + fractionInSREF = totalTimeInSREF*1.0/totalTimeAllBanks + result.append(("Time in SREF (%)", fractionInSREF*100)) + print("{0} {1}".format(result[-1][0], result[-1][1])) + result.insert(0, ("Active time (%)", (1-fractionInPDNA-fractionInPDNP-fractionInSREF)*100)) + print("{0} {1}".format(result[0][0], result[0][1])) + + return result - return result def passRatio(connection): - numberOfPassWins = {} - numberOfPassLosses = {} + numberOfPassWins = {} + numberOfPassLosses = {} - for thread in getThreads(connection): - numberOfPassWins[thread] = 0 - numberOfPassLosses[thread] = 0 + for thread in getThreads(connection): + numberOfPassWins[thread] = 0 + numberOfPassLosses[thread] = 0 - for bankNumber in range(getNumberOfBanks(connection)): - cursor = connection.cursor() - query = """SELECT begin,end,transactions.ID,TThread, - TBank from transactions inner join ranges on transactions.range = ranges.id WHERE TBank = :Bank AND TThread != 0""" - cursor.execute(query, {"Bank":bankNumber}) + for bankNumber in range(getNumberOfBanks(connection)): + cursor = connection.cursor() + query = """SELECT begin,end,transactions.ID,TThread, + TBank from transactions inner join ranges on transactions.range = ranges.id WHERE TBank = :Bank AND TThread != 0""" + cursor.execute(query, {"Bank": bankNumber}) - for passedRequest in cursor: - passedBegin = passedRequest[0] - passedEnd = passedRequest[1] - passedId = passedRequest[2] - passedThread = passedRequest[3] - - cursor2 = connection.cursor() - query2 = """SELECT begin,end,transactions.ID,TThread, - TBank from transactions inner join ranges on transactions.range = ranges.id - WHERE TBank = :Bank AND :Begin 0): - passRatio = numberOfPassWins[thread]*1.0/(numberOfPassWins[thread]+numberOfPassLosses[thread]) - else: - passRatio = 0.5 - print("Thread {0} passed other threads {1} times and was passed {2} times. Pass ratio is {3}".format - (thread, numberOfPassWins[thread], numberOfPassLosses[thread],passRatio)) - result.append(("Thread {0} pass ratio".format(thread), passRatio)) - return result + for passedRequest in cursor: + passedBegin = passedRequest[0] + passedEnd = passedRequest[1] + passedId = passedRequest[2] + passedThread = passedRequest[3] + cursor2 = connection.cursor() + query2 = """SELECT begin,end,transactions.ID,TThread, + TBank from transactions inner join ranges on transactions.range = ranges.id + WHERE TBank = :Bank AND :Begin 0): + passRatio = numberOfPassWins[thread]*1.0/(numberOfPassWins[thread]+numberOfPassLosses[thread]) + else: + passRatio = 0.5 + print("Thread {0} passed other threads {1} times and was passed {2} times. Pass ratio is {3}".format(thread, numberOfPassWins[thread], numberOfPassLosses[thread], passRatio)) + result.append(("Thread {0} pass ratio".format(thread), passRatio)) + return result def calculateMetrics(pathToTrace): - connection = sqlite3.connect(pathToTrace) - calculatedMetrics = [] + connection = sqlite3.connect(pathToTrace) + calculatedMetrics = [] - print("================================") - print("Calculating metrics for {0}".format(pathToTrace)) + print("================================") + print("Calculating metrics for {0}".format(pathToTrace)) + if (len(getThreads(connection)) == 1): + for metric in metrics: + res = (metric.__name__.replace("_", " "), metric(connection)) + print("{0}: {1}".format(res[0], res[1])) + calculatedMetrics.append(res) - if(len(getThreads(connection))==1): - for metric in metrics: - res = (metric.__name__.replace("_"," "), metric(connection)) - print("{0}: {1}".format(res[0],res[1])) - calculatedMetrics.append(res) + if (len(getThreads(connection)) > 1): + # for thread in getThreads(connection): + # for metric in threadMetrics: + # res = ("Thread " + str(thread) + " " + metric.__name__.replace("_"," "), metric(connection, thread)) + # print("{0}: {1}".format(res[0],res[1])) + # calculatedMetrics.append(res) + calculatedMetrics.extend(passRatio(connection)) + # refreshMissDecision(connection, calculatedMetrics) - if(len(getThreads(connection))>1): - # for thread in getThreads(connection): - # for metric in threadMetrics: - # res = ("Thread " + str(thread) + " " + metric.__name__.replace("_"," "), metric(connection, thread)) - # print("{0}: {1}".format(res[0],res[1])) - # calculatedMetrics.append(res) - calculatedMetrics.extend(passRatio(connection)) - #refreshMissDecision(connection, calculatedMetrics) + # calculatedMetrics.extend(timeInPowerStates(connection)) + # print(calculatedMetrics[-1]) + # print(calculatedMetrics[-2]) - #calculatedMetrics.extend(timeInPowerStates(connection)) - #print(calculatedMetrics[-1]) - #print(calculatedMetrics[-2]) - - #refreshMissDecision(connection, calculatedMetrics) - print(calculatedMetrics[-1]) - print(calculatedMetrics[-2]) - connection.close() - return calculatedMetrics + # refreshMissDecision(connection, calculatedMetrics) + print(calculatedMetrics[-1]) + print(calculatedMetrics[-2]) + connection.close() + return calculatedMetrics if __name__ == "__main__": - path = sys.argv[1] - calculateMetrics(path) - + path = sys.argv[1] + calculateMetrics(path) From 642899d8b98c6bbc645f47f61f2e8b79ff730975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 16 Feb 2016 11:46:32 -0200 Subject: [PATCH 5/9] Power down related metrics properly displayed (issue#59) The following metrics will be generated: - time in PDNA in ns - time in PDNA percent - time in PDNP in ns - time in PDNP percent - time in SREF in ns - time in SREF percent - time in power down states in ns - time in power down states percent Other changes: Avoid a crash that was generated for channels which no accesses performed by trace players. Now a message will be displayed explained that no metrics were generated due to the lack of accesses. --- DRAMSys/analyzer/scripts/metrics.py | 86 ++++++++++++++++++----------- 1 file changed, 54 insertions(+), 32 deletions(-) diff --git a/DRAMSys/analyzer/scripts/metrics.py b/DRAMSys/analyzer/scripts/metrics.py index ef59987b..143d9a45 100644 --- a/DRAMSys/analyzer/scripts/metrics.py +++ b/DRAMSys/analyzer/scripts/metrics.py @@ -31,13 +31,6 @@ def getNumberOfBanks(connection): return result[0] -def getTraceLength(connection): - cursor = connection.cursor() - cursor.execute("SELECT TraceEnd FROM GeneralInfo") - result = cursor.fetchone() - return result[0] - - def getClock(connection): cursor = connection.cursor() cursor.execute("SELECT clk FROM GeneralInfo") @@ -79,7 +72,6 @@ def trace_length_in_ns(connection): def average_response_latency_in_ns(connection): cursor = connection.cursor() cursor.execute("""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 """) - result = cursor.fetchone() return round(result[0], 1) @@ -88,7 +80,6 @@ def average_response_latency_in_ns(connection): def trans_with_max_response_latency(connection): cursor = connection.cursor() cursor.execute(""" SELECT REQ.TRANSACT, 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] @@ -262,41 +253,72 @@ def accesses_per_activate(connection): @metric -def timeInPowerStates(connection): - totalTimeAllBanks = getTraceLength(connection) # *getNumberOfBanks(connection) +def time_in_PDNA_in_ns(connection): cursor = connection.cursor() result = [] - - cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = 'PDNA'") + cursor.execute("SELECT SUM(PhaseEnd - PhaseBegin)/1000 from Phases where PhaseName = 'PDNA'") timeInPDNA = cursor.fetchone() totalTimeInPDNA = timeInPDNA[0] if (totalTimeInPDNA is None): totalTimeInPDNA = 0.0 - fractionInPDNA = totalTimeInPDNA*1.0/totalTimeAllBanks - result.append(("Time in PDNA (%)", fractionInPDNA*100)) - print("{0} {1}".format(result[-1][0], result[-1][1])) + return totalTimeInPDNA - cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = 'PDNP'") + +@metric +def time_in_PDNA_percent(connection): + totalTimeAllBanks = trace_length_in_ns(connection) + return time_in_PDNA_in_ns(connection) * 1.0 / totalTimeAllBanks + + +@metric +def time_in_PDNP_in_ns(connection): + cursor = connection.cursor() + result = [] + cursor.execute("SELECT SUM(PhaseEnd - PhaseBegin)/1000 from Phases where PhaseName = 'PDNP'") timeInPDNP = cursor.fetchone() totalTimeInPDNP = timeInPDNP[0] if (totalTimeInPDNP is None): totalTimeInPDNP = 0.0 - fractionInPDNP = totalTimeInPDNP*1.0/totalTimeAllBanks - result.append(("Time in PDNP (%)", fractionInPDNP*100)) - print("{0} {1}".format(result[-1][0], result[-1][1])) + return totalTimeInPDNP - cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = 'SREF'") + +@metric +def time_in_PDNP_percent(connection): + totalTimeAllBanks = trace_length_in_ns(connection) + return (time_in_PDNP_in_ns(connection) * 1.0 / totalTimeAllBanks) * 100 + + +@metric +def time_in_SREF_in_ns(connection): + cursor = connection.cursor() + result = [] + cursor.execute("SELECT SUM(PhaseEnd - PhaseBegin)/1000 from Phases where PhaseName = 'SREF'") timeInSREF = cursor.fetchone() totalTimeInSREF = timeInSREF[0] if (totalTimeInSREF is None): totalTimeInSREF = 0.0 - fractionInSREF = totalTimeInSREF*1.0/totalTimeAllBanks - result.append(("Time in SREF (%)", fractionInSREF*100)) - print("{0} {1}".format(result[-1][0], result[-1][1])) - result.insert(0, ("Active time (%)", (1-fractionInPDNA-fractionInPDNP-fractionInSREF)*100)) - print("{0} {1}".format(result[0][0], result[0][1])) + return totalTimeInSREF - return result + +@metric +def time_in_SREF_percent(connection): + totalTimeAllBanks = trace_length_in_ns(connection) + return (time_in_SREF_in_ns(connection) * 1.0 / totalTimeAllBanks) * 100 + + +@metric +def time_in_power_down_states_in_ns(connection): + totalTimeInPDNA = time_in_PDNA_in_ns(connection) + totalTimeInPDNP = time_in_PDNP_in_ns(connection) + totalTimeInSREF = time_in_SREF_in_ns(connection) + totalTimePdnStates = totalTimeInPDNA + totalTimeInPDNP + totalTimeInSREF + return totalTimePdnStates + + +@metric +def time_in_power_down_states_percent(connection): + totalTimeAllBanks = trace_length_in_ns(connection) + return (time_in_power_down_states_in_ns(connection) * 1.0 / totalTimeAllBanks) * 100 def passRatio(connection): @@ -351,6 +373,8 @@ def calculateMetrics(pathToTrace): print("================================") print("Calculating metrics for {0}".format(pathToTrace)) + print("Number of threads is {0}".format(len(getThreads(connection)))) + if (len(getThreads(connection)) == 1): for metric in metrics: res = (metric.__name__.replace("_", " "), metric(connection)) @@ -366,13 +390,11 @@ def calculateMetrics(pathToTrace): calculatedMetrics.extend(passRatio(connection)) # refreshMissDecision(connection, calculatedMetrics) - # calculatedMetrics.extend(timeInPowerStates(connection)) - # print(calculatedMetrics[-1]) - # print(calculatedMetrics[-2]) + if (len(getThreads(connection)) == 0): + res = ("No accesses were performed for this channel, number of metrics generated", 0.0) + calculatedMetrics.append(res) # refreshMissDecision(connection, calculatedMetrics) - print(calculatedMetrics[-1]) - print(calculatedMetrics[-2]) connection.close() return calculatedMetrics From 9c195a42c897fe680a6f3df7893de61acd60a9bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 16 Feb 2016 17:23:20 -0200 Subject: [PATCH 6/9] Improvements in tests scripts Created an extra file memUtil.py which contains utilities that can be imported and used by other script files. The idea is to improve maintainability by avoiding duplicate code. --- DRAMSys/analyzer/scripts/memUtil.py | 57 +++++++++++++++++++++++++++++ DRAMSys/analyzer/scripts/metrics.py | 18 ++------- DRAMSys/analyzer/scripts/tests.py | 48 +----------------------- 3 files changed, 61 insertions(+), 62 deletions(-) create mode 100644 DRAMSys/analyzer/scripts/memUtil.py diff --git a/DRAMSys/analyzer/scripts/memUtil.py b/DRAMSys/analyzer/scripts/memUtil.py new file mode 100644 index 00000000..2bc5a26e --- /dev/null +++ b/DRAMSys/analyzer/scripts/memUtil.py @@ -0,0 +1,57 @@ +import sys +import sqlite3 +import xml.etree.ElementTree as ET + + +class MemConfig(object): + """ Memory Configuration Class + + The format used in memory specification XML files differs from the + format used in memory configuration XML files. Each class uses the + proper format when searching for elements. + """ + def getValue(self, id): + return self.xmlMemConfig.findall(id)[0].attrib['value'] + + def getIntValue(self, id): + return int(self.getValue(id)) + + def __init__(self, dbconnection): + cursor = dbconnection.cursor() + cursor.execute("SELECT Memconfig FROM GeneralInfo") + result = cursor.fetchone() + self.xmlMemConfig = ET.parse(result[0]) + + +class MemSpec(object): + """ Memory Specification Class + + The format used in memory specification XML files differs from the + format used in memory configuration XML files. Each class uses the + proper format when searching for elements. + """ + def getValue(self, id): + return self.xmlMemSpec.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value'] + + def getIntValue(self, id): + return int(self.getValue(id)) + + def __init__(self, dbconnection): + cursor = dbconnection.cursor() + cursor.execute("SELECT Memspec FROM GeneralInfo") + result = cursor.fetchone() + self.xmlMemSpec = ET.parse(result[0]) + + +def getClock(dbconnection): + cursor = dbconnection.cursor() + cursor.execute("SELECT clk, UnitOfTime FROM GeneralInfo") + clock, unit = cursor.fetchone() + return (clock, unit) + + +def getNumberOfBanks(dbconnection): + cursor = dbconnection.cursor() + cursor.execute("SELECT NumberOfBanks FROM generalInfo") + result = cursor.fetchone() + return result[0] diff --git a/DRAMSys/analyzer/scripts/metrics.py b/DRAMSys/analyzer/scripts/metrics.py index 143d9a45..3b0e6970 100644 --- a/DRAMSys/analyzer/scripts/metrics.py +++ b/DRAMSys/analyzer/scripts/metrics.py @@ -1,5 +1,6 @@ import sys import sqlite3 +from memUtil import * metrics = [] threadMetrics = [] @@ -24,20 +25,6 @@ def getThreads(connection): return result -def getNumberOfBanks(connection): - cursor = connection.cursor() - cursor.execute("SELECT NumberOfBanks FROM generalInfo") - result = cursor.fetchone() - return result[0] - - -def getClock(connection): - cursor = connection.cursor() - cursor.execute("SELECT clk FROM GeneralInfo") - result = cursor.fetchone() - return result[0] - - # @metric # def latency_histogram(connection): # cursor = connection.cursor() @@ -211,7 +198,8 @@ def paralellism(connection, thread): from phases inner join transactions on phases.transact=transactions.id where phaseName Not in ('REQ','RESP') and tthread=:Thread group by transactions.ID """ - cursor.execute(query, {"Thread": thread, "clk": getClock(connection)}) + clk, unit = getClock(connection) + cursor.execute(query, {"Thread": thread, "clk": clk}) for currentRow in cursor: addStallTime(stalltimes, currentRow[1], currentRow[2]) para = 0 diff --git a/DRAMSys/analyzer/scripts/tests.py b/DRAMSys/analyzer/scripts/tests.py index 7e447357..ee844236 100644 --- a/DRAMSys/analyzer/scripts/tests.py +++ b/DRAMSys/analyzer/scripts/tests.py @@ -3,53 +3,7 @@ import traceback import sqlite3 import os import xml.etree.ElementTree as ET - - -class MemConfig(object): - """ Memory Configuration Class - - The format used in memory specification XML files differs from the - format used in memory configuration XML files. Each class uses the - proper format when searching for elements. - """ - def getValue(self, id): - return self.xmlMemConfig.findall(id)[0].attrib['value'] - - def getIntValue(self, id): - return int(self.getValue(id)) - - def __init__(self, dbconnection): - cursor = dbconnection.cursor() - cursor.execute("SELECT Memconfig FROM GeneralInfo") - result = cursor.fetchone() - self.xmlMemConfig = ET.parse(result[0]) - - -class MemSpec(object): - """ Memory Specification Class - - The format used in memory specification XML files differs from the - format used in memory configuration XML files. Each class uses the - proper format when searching for elements. - """ - def getValue(self, id): - return self.xmlMemSpec.findall(".//parameter[@id='{0}']".format(id))[0].attrib['value'] - - def getIntValue(self, id): - return int(self.getValue(id)) - - def __init__(self, dbconnection): - cursor = dbconnection.cursor() - cursor.execute("SELECT Memspec FROM GeneralInfo") - result = cursor.fetchone() - self.xmlMemSpec = ET.parse(result[0]) - - -def getClock(connection): - cursor = connection.cursor() - cursor.execute("SELECT clk, UnitOfTime FROM GeneralInfo") - result = cursor.fetchone() - return (result[0], result[1]) +from memUtil import * class DramConfig(object): From 6d8a31a9044eda0ece3331a35ad2fd2e610e6059 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Tue, 16 Feb 2016 21:17:58 -0200 Subject: [PATCH 7/9] More improvements --- DRAMSys/analyzer/scripts/metrics.py | 47 +++++++++++------------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/DRAMSys/analyzer/scripts/metrics.py b/DRAMSys/analyzer/scripts/metrics.py index 3b0e6970..b4f39884 100644 --- a/DRAMSys/analyzer/scripts/metrics.py +++ b/DRAMSys/analyzer/scripts/metrics.py @@ -240,58 +240,45 @@ def accesses_per_activate(connection): return round(result[0]*1.0/number_of_activates(connection), 1) +def get_total_time_in_phase(connection, phase): + cursor = connection.cursor() + query = "SELECT SUM(PhaseEnd - PhaseBegin) / 1000 from Phases where PhaseName = :phase" + cursor.execute(query, {"phase": phase}) + time = cursor.fetchone() + totalTime = time[0] + if (totalTime is None): + totalTime = 0.0 + return totalTime + + @metric def time_in_PDNA_in_ns(connection): - cursor = connection.cursor() - result = [] - cursor.execute("SELECT SUM(PhaseEnd - PhaseBegin)/1000 from Phases where PhaseName = 'PDNA'") - timeInPDNA = cursor.fetchone() - totalTimeInPDNA = timeInPDNA[0] - if (totalTimeInPDNA is None): - totalTimeInPDNA = 0.0 - return totalTimeInPDNA + return get_total_time_in_phase(connection, "PDNA") @metric def time_in_PDNA_percent(connection): - totalTimeAllBanks = trace_length_in_ns(connection) - return time_in_PDNA_in_ns(connection) * 1.0 / totalTimeAllBanks + return (time_in_PDNA_in_ns(connection) * 1.0 / trace_length_in_ns(connection)) * 100 @metric def time_in_PDNP_in_ns(connection): - cursor = connection.cursor() - result = [] - cursor.execute("SELECT SUM(PhaseEnd - PhaseBegin)/1000 from Phases where PhaseName = 'PDNP'") - timeInPDNP = cursor.fetchone() - totalTimeInPDNP = timeInPDNP[0] - if (totalTimeInPDNP is None): - totalTimeInPDNP = 0.0 - return totalTimeInPDNP + return get_total_time_in_phase(connection, "PDNP") @metric def time_in_PDNP_percent(connection): - totalTimeAllBanks = trace_length_in_ns(connection) - return (time_in_PDNP_in_ns(connection) * 1.0 / totalTimeAllBanks) * 100 + return (time_in_PDNP_in_ns(connection) * 1.0 / trace_length_in_ns(connection)) * 100 @metric def time_in_SREF_in_ns(connection): - cursor = connection.cursor() - result = [] - cursor.execute("SELECT SUM(PhaseEnd - PhaseBegin)/1000 from Phases where PhaseName = 'SREF'") - timeInSREF = cursor.fetchone() - totalTimeInSREF = timeInSREF[0] - if (totalTimeInSREF is None): - totalTimeInSREF = 0.0 - return totalTimeInSREF + return get_total_time_in_phase(connection, "SREF") @metric def time_in_SREF_percent(connection): - totalTimeAllBanks = trace_length_in_ns(connection) - return (time_in_SREF_in_ns(connection) * 1.0 / totalTimeAllBanks) * 100 + return (time_in_SREF_in_ns(connection) * 1.0 / trace_length_in_ns(connection)) * 100 @metric From 636ff65a38cd4389e9995f62a9e35852580c960f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Wed, 17 Feb 2016 13:24:10 -0200 Subject: [PATCH 8/9] Added support to single-line comments in STL files (issue#45). Lines which start with '#' will be ignored by trace players. From IP_GFRBM.pdf: STL syntax supports only single line comments. A single-line comment is everything on a line following but not including the first occurrence of the # character and up to, but not including the end of the line. For example: # this is a comment Comments should always begin in a new line. --- .../simulator/src/simulation/Simulation.cpp | 2 +- .../simulator/src/simulation/StlDataPlayer.h | 33 ++++++++---------- DRAMSys/simulator/src/simulation/StlPlayer.h | 34 ++++++++----------- 3 files changed, 31 insertions(+), 38 deletions(-) diff --git a/DRAMSys/simulator/src/simulation/Simulation.cpp b/DRAMSys/simulator/src/simulation/Simulation.cpp index 55bd4c0d..e19496e0 100644 --- a/DRAMSys/simulator/src/simulation/Simulation.cpp +++ b/DRAMSys/simulator/src/simulation/Simulation.cpp @@ -109,7 +109,7 @@ void Simulation::setupTlmRecorders(const string &traceName, const string &pathTo void Simulation::instantiateModules(const string &traceName, const string &pathToResources, const std::vector &devices) { // The first call to getInstance() creates the Temperature Controller. - // The same instance will can be accessed by all other modules. + // The same instance will be accessed by all other modules. TemperatureController::getInstance(); for (size_t i = 0; i < Configuration::getInstance().NumberOfTracePlayers; i++) { diff --git a/DRAMSys/simulator/src/simulation/StlDataPlayer.h b/DRAMSys/simulator/src/simulation/StlDataPlayer.h index fbe6a67a..d4b55638 100644 --- a/DRAMSys/simulator/src/simulation/StlDataPlayer.h +++ b/DRAMSys/simulator/src/simulation/StlDataPlayer.h @@ -49,18 +49,21 @@ template struct StlDataPlayer: public TracePlayer { public: - StlDataPlayer(sc_module_name /*name*/, string pathToTrace, unsigned int clkMhz, - TracePlayerListener* listener); + StlDataPlayer(sc_module_name /*name*/, string pathToTrace, unsigned int clkMhz, TracePlayerListener* listener); + virtual void nextPayload() override { - string line; - while(line.empty() && file) - { + std::string line; + while (line.empty() && file) { std::getline(file, line); + + // Ignore lines which begin with '#' (commented lines) + if (!line.empty() && line.at(0) == '#') { + line.clear(); + } } - if(!file) - { + if(!file) { this->terminate(); return; } @@ -118,26 +121,19 @@ public: dataElement[i] = std::stoi(byteString.c_str(), 0, 16); } } - } - else - { - SC_REPORT_FATAL(0, - (string("Corrupted tracefile, command ") + command + string(" unknown")).c_str()); + } else { + SC_REPORT_FATAL(0, (string("Corrupted tracefile, command ") + command + string(" unknown")).c_str()); } sc_time sendingTime = std::stoull(time.c_str())*clk; - if (sendingTime <= sc_time_stamp()) - { + if (sendingTime <= sc_time_stamp()) { this->payloadEventQueue.notify(*payload, BEGIN_REQ, SC_ZERO_TIME); - } - else - { + } else { this->payloadEventQueue.notify(*payload, BEGIN_REQ, sendingTime - sc_time_stamp()); } } - private: ifstream file; unsigned int burstlength; @@ -164,3 +160,4 @@ StlDataPlayer::StlDataPlayer(sc_module_name /*name*/, string pathToTra } #endif // STLDATAPLAYER_H + diff --git a/DRAMSys/simulator/src/simulation/StlPlayer.h b/DRAMSys/simulator/src/simulation/StlPlayer.h index 355e7e5e..918eae84 100644 --- a/DRAMSys/simulator/src/simulation/StlPlayer.h +++ b/DRAMSys/simulator/src/simulation/StlPlayer.h @@ -49,23 +49,25 @@ template struct StlPlayer: public TracePlayer { public: - StlPlayer(sc_module_name /*name*/, string pathToTrace, unsigned int clkMhz, - TracePlayerListener* listener); + StlPlayer(sc_module_name /*name*/, string pathToTrace, unsigned int clkMhz, TracePlayerListener *listener); + virtual void nextPayload() override { - string line; - while(line.empty() && file) - { + std::string line; + while (line.empty() && file) { std::getline(file, line); + + // Ignore lines which begin with '#' (commented lines) + if (!line.empty() && line.at(0) == '#') { + line.clear(); + } } - if(!file) - { + if(!file) { this->terminate(); return; } - std::istringstream iss(line); string time, command, address; iss >> time >> command >> address; @@ -105,26 +107,19 @@ public: dataElement[i] = std::stoi(byteString.c_str(), 0, 16); } } - } - else - { - SC_REPORT_FATAL(0, - (string("Corrupted tracefile, command ") + command + string(" unknown")).c_str()); + } else { + SC_REPORT_FATAL(0, (string("Corrupted tracefile, command ") + command + string(" unknown")).c_str()); } sc_time sendingTime = std::stoull(time.c_str())*clk; - if (sendingTime <= sc_time_stamp()) - { + if (sendingTime <= sc_time_stamp()) { this->payloadEventQueue.notify(*payload, BEGIN_REQ, SC_ZERO_TIME); - } - else - { + } else { this->payloadEventQueue.notify(*payload, BEGIN_REQ, sendingTime - sc_time_stamp()); } } - private: ifstream file; unsigned int burstlength; @@ -151,3 +146,4 @@ StlPlayer::StlPlayer(sc_module_name /*name*/, string pathToTrace, unsi } #endif // STLPLAYER_H + From c1084c21fb507d43c63b7b0932cf7672026808c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89der=20F=2E=20Zulian?= Date: Wed, 17 Feb 2016 16:55:13 -0200 Subject: [PATCH 9/9] Power down related metrics are generated according to config bankwise logic. IMPORTANT: Though the mechanism to choose the proper metrics according to the bankwise logic configuraiton is working fine, we need to check if all calculations are correct. For exmple: check if the calculation of the total time in SREFB is correct. --- DRAMSys/analyzer/scripts/metrics.py | 71 ++++++++++++++++++++++++----- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/DRAMSys/analyzer/scripts/metrics.py b/DRAMSys/analyzer/scripts/metrics.py index b4f39884..80b01972 100644 --- a/DRAMSys/analyzer/scripts/metrics.py +++ b/DRAMSys/analyzer/scripts/metrics.py @@ -251,48 +251,83 @@ def get_total_time_in_phase(connection, phase): return totalTime -@metric def time_in_PDNA_in_ns(connection): return get_total_time_in_phase(connection, "PDNA") -@metric def time_in_PDNA_percent(connection): return (time_in_PDNA_in_ns(connection) * 1.0 / trace_length_in_ns(connection)) * 100 -@metric def time_in_PDNP_in_ns(connection): return get_total_time_in_phase(connection, "PDNP") -@metric def time_in_PDNP_percent(connection): return (time_in_PDNP_in_ns(connection) * 1.0 / trace_length_in_ns(connection)) * 100 -@metric def time_in_SREF_in_ns(connection): return get_total_time_in_phase(connection, "SREF") -@metric def time_in_SREF_percent(connection): return (time_in_SREF_in_ns(connection) * 1.0 / trace_length_in_ns(connection)) * 100 +def time_in_PDNAB_in_ns(connection): + return get_total_time_in_phase(connection, "PDNAB") + + +def time_in_PDNAB_percent(connection): + totalTimeAllBanks = trace_length_in_ns(connection) * getNumberOfBanks(connection) + return (time_in_PDNAB_in_ns(connection) * 1.0 / totalTimeAllBanks) * 100 + + +def time_in_PDNPB_in_ns(connection): + return get_total_time_in_phase(connection, "PDNPB") + + +def time_in_PDNPB_percent(connection): + totalTimeAllBanks = trace_length_in_ns(connection) * getNumberOfBanks(connection) + return (time_in_PDNPB_in_ns(connection) * 1.0 / totalTimeAllBanks) * 100 + + +def time_in_SREFB_in_ns(connection): + return get_total_time_in_phase(connection, "SREFB") + + +def time_in_SREFB_percent(connection): + totalTimeAllBanks = trace_length_in_ns(connection) * getNumberOfBanks(connection) + return (time_in_SREFB_in_ns(connection) * 1.0 / totalTimeAllBanks) * 100 + + @metric def time_in_power_down_states_in_ns(connection): - totalTimeInPDNA = time_in_PDNA_in_ns(connection) - totalTimeInPDNP = time_in_PDNP_in_ns(connection) - totalTimeInSREF = time_in_SREF_in_ns(connection) - totalTimePdnStates = totalTimeInPDNA + totalTimeInPDNP + totalTimeInSREF + memconfig = MemConfig(connection) + bankwiseLogic = memconfig.getValue("BankwiseLogic") + if bankwiseLogic == "0": + totalTimeInPDNA = time_in_PDNA_in_ns(connection) + totalTimeInPDNP = time_in_PDNP_in_ns(connection) + totalTimeInSREF = time_in_SREF_in_ns(connection) + totalTimePdnStates = totalTimeInPDNA + totalTimeInPDNP + totalTimeInSREF + else: + totalTimeInPDNAB = time_in_PDNAB_in_ns(connection) + totalTimeInPDNPB = time_in_PDNPB_in_ns(connection) + totalTimeInSREFB = time_in_SREFB_in_ns(connection) + totalTimePdnStates = totalTimeInPDNAB + totalTimeInPDNPB + totalTimeInSREFB + return totalTimePdnStates @metric def time_in_power_down_states_percent(connection): - totalTimeAllBanks = trace_length_in_ns(connection) + memconfig = MemConfig(connection) + bankwiseLogic = memconfig.getValue("BankwiseLogic") + if bankwiseLogic == "0": + totalTimeAllBanks = trace_length_in_ns(connection) + else: + totalTimeAllBanks = trace_length_in_ns(connection) * getNumberOfBanks(connection) return (time_in_power_down_states_in_ns(connection) * 1.0 / totalTimeAllBanks) * 100 @@ -342,8 +377,20 @@ def passRatio(connection): def calculateMetrics(pathToTrace): - connection = sqlite3.connect(pathToTrace) calculatedMetrics = [] + connection = sqlite3.connect(pathToTrace) + + memconfig = MemConfig(connection) + bankwiseLogic = memconfig.getValue("BankwiseLogic") + + if bankwiseLogic == "0": + pdnMetrics = [time_in_PDNA_in_ns, time_in_PDNA_percent, time_in_PDNP_in_ns, time_in_PDNP_percent, time_in_SREF_in_ns, time_in_SREF_percent] + else: + pdnMetrics = [time_in_PDNAB_in_ns, time_in_PDNAB_percent, time_in_PDNPB_in_ns, time_in_PDNPB_percent, time_in_SREFB_in_ns, time_in_SREFB_percent] + + for m in pdnMetrics: + if m not in metrics: + metrics.append(m) print("================================") print("Calculating metrics for {0}".format(pathToTrace))