changed metrics

This commit is contained in:
robert
2014-04-20 17:28:05 +02:00
parent c501985573
commit 354c871047
12 changed files with 206 additions and 80 deletions

View File

@@ -1 +1,3 @@
*.pyc
configs
simulations

View File

@@ -52,9 +52,10 @@ CREATE TABLE Transactions(
TBankgroup INTEGER,
TRow INTEGER,
TColumn INTEGER,
Command TEXT,
DataStrobeBegin INTEGER,
DataStrobeEnd INTEGER
DataStrobeEnd INTEGER,
TimeOfGeneration INTEGER,
Command TEXT
);
CREATE INDEX ranges_index ON Transactions(Range);

View File

@@ -1,6 +1,7 @@
import sys
import sqlite3
import pystaggrelite3
metrics = []
threadMetrics = []
@@ -35,17 +36,60 @@ def getTraceLength(connection):
@metric
def average_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""SELECT avg(transactions.DataStrobeEnd-ranges.begin)/1000 FROM transactions INNER JOIN ranges
ON transactions.range = ranges.ID where TThread != 0""")
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)
@metric
def median_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""SELECT median(PhaseBegin-timeOfGeneration)/1000 FROM transactions INNER JOIN Phases
ON phases.transact = transactions.ID WHERE PhaseName='RESP' """)
result = cursor.fetchone()
return round(result[0],1)
@metric
def max_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""SELECT max(PhaseBegin-timeOfGeneration)/1000 FROM transactions INNER JOIN Phases
ON phases.transact = transactions.ID WHERE PhaseName='RESP' """)
result = cursor.fetchone()
return round(result[0],1)
@metric
def min_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""SELECT min(PhaseBegin-timeOfGeneration)/1000 FROM transactions INNER JOIN Phases
ON phases.transact = transactions.ID WHERE PhaseName='RESP' """)
result = cursor.fetchone()
return round(result[0],1)
@metric
def stdDev_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""SELECT stdev(PhaseBegin-timeOfGeneration)/1000 FROM transactions INNER JOIN Phases
ON phases.transact = transactions.ID WHERE PhaseName='RESP' """)
result = cursor.fetchone()
return round(result[0],1)
@threadMetric
def average_response_latency_in_ns(connection, thread):
cursor = connection.cursor()
query = """SELECT avg(transactions.DataStrobeEnd-ranges.begin)/1000 FROM transactions INNER JOIN ranges
ON transactions.range = ranges.ID where TThread = :Thread """
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)
@threadMetric
def median_response_latency_in_ns(connection, thread):
cursor = connection.cursor()
query = """SELECT median(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()
@@ -65,6 +109,13 @@ def number_of_precharges(connection):
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)
def timeInPowerStates(connection):
totalTimeAllBanks = getTraceLength(connection)*getNumberOfBanks(connection)
@@ -151,6 +202,9 @@ def passRatio(connection):
def calculateMetrics(pathToTrace):
connection = sqlite3.connect(pathToTrace)
connection.create_aggregate("median", 1, pystaggrelite3.median)
connection.create_aggregate("stdev", 1, pystaggrelite3.stdev)
calculatedMetrics = []
print("================================")

View File

@@ -186,9 +186,10 @@ def formatTime(time):
# ----------- checks ---------------------------------------
#@test
@test
def commands_are_clockaligned(connection):
"""Checks that all commands on the command bus are aligned to the system clock"""
cursor = connection.cursor()
query = "select ID,PhaseBegin,PhaseEnd from phases where phaseName NOT IN ('REQ','RESP') AND (phaseBegin%:clk!=0 OR phaseEnd%:clk!=0)"
cursor.execute(query, {"clk": dramconfig.clk})
@@ -196,16 +197,16 @@ def commands_are_clockaligned(connection):
result = cursor.fetchone()
if(result != None):
return TestFailed("Command with PhaseID {0} starts at {1} and ends at, which is not aligned to system clock ({2})".format(
result[0], formatTime(result[1]), formatTime(result[2]), formatTime(dramconfig.clk)))
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()
#@test
@test
def commandbus_slots_are_used_once(connection):
"""Checks that no two phases on the command bus start at the same time"""
cursor = connection.cursor()
if dramconfig.bankwiseLogic:
excludedPhases = "('REQ','RESP','PRE_ALL')"
else:
@@ -221,9 +222,10 @@ def commandbus_slots_are_used_once(connection):
return TestSuceeded()
#@test
@test
def phase_transitions_are_valid(connection):
"""Checks if the transition of two consequtive phases is valid"""
"""Checks that all transition of two consequtive phases on the same bank are valid"""
cursor = connection.cursor()
validTransitions = {}
@@ -325,9 +327,9 @@ def timing_constraint(FirstPhase, SecondPhase):
return 0
#@test
def timing_constraits_same_bank(connection):
"""Checks that two consecutive phases on the same bank satisfy timing constraint"""
@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"""
cursor = connection.cursor()
validTransitions = {}
@@ -348,23 +350,28 @@ def timing_constraits_same_bank(connection):
@test
def row_buffer_is_used_correctly(connection):
"""Checks that each bank's row buffer is used correctly"""
cursor = connection.cursor()
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"""
#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 precharged state and the robuffer to be closed
idlePhases = set(['ACT', 'PDNP', 'AUTO_REFRESH', 'SREF'])
for bankNumber in range(dramconfig.numberOfBanks):
cursor.execute(query,{"bank": bankNumber})
rowBufferIsClosed = True
#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'])
#phases that require the bank to be in precharged state and the robuffer to be closed
idlePhases = set(['PDNP', 'AUTO_REFRESH', 'SREF'])
for currentRow in cursor:
if(currentRow[0] in accessingPhases and rowBufferIsClosed == True):
@@ -374,22 +381,17 @@ def row_buffer_is_used_correctly(connection):
return TestFailed("Phase {0}({1}) needs a closed rowbuffer".format(currentRow[1], currentRow[0]))
if(currentRow[0] == 'ACT'):
if(rowBufferIsClosed == True):
rowBufferIsClosed = False
else:
return TestFailed("Phase {0}({1}) opens an already opened rowbuffer".format(currentRow[1],currentRow[0]))
rowBufferIsClosed = False
if(currentRow[0] in prechargingPhases):
if(rowBufferIsClosed == True and currentRow[0] != 'PRE_ALL'):
return TestFailed("Phase {0}({1}) closes an already closed rowbuffer".format(currentRow[1],currentRow[0]))
else:
rowBufferIsClosed = True
rowBufferIsClosed = True
return TestSuceeded()
#----------- activate checks ---------------------------------------
@test
def activate_to_activate(connection):
"""Checks minimal time between two activates (JESD229 229, P. 27)"""
def activate_to_activate_holds(connection):
"""Checks that all activates are far enough apart(JESD229 229, P. 27)"""
cursor = connection.cursor()
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
lastRow = cursor.fetchone()
@@ -401,15 +403,17 @@ def activate_to_activate(connection):
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), 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
return TestSuceeded()
@test
def activate_to_activate_on_same_bank(connection):
"""Checks minimal time between two activates on the same bank (JEDEC 229, P. 27)"""
def activate_to_activate_on_same_bank_holds(connection):
"""Checks that all activates on the same bank are far enough apart (JEDEC 229, P. 27)"""
cursor = connection.cursor()
query = "SELECT Phases.ID,PhaseBegin from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID WHERE PhaseName = 'ACT' AND TBANK = :bank ORDER BY PhaseBegin"
@@ -428,8 +432,8 @@ def activate_to_activate_on_same_bank(connection):
return TestSuceeded()
@test
def n_activate_window(connection):
"""Checks n-Activate constraint (JEDEC 229, P. 27)"""
def n_activate_window_holds(connection):
"""Checks that the n-Activate constraint is met everywhere(JEDEC 229, P. 27)"""
cursor = connection.cursor()
cursor.execute("SELECT ID,PhaseBegin from Phases WHERE PhaseName = 'ACT' ORDER BY PhaseBegin")
activateWindow = []
@@ -446,7 +450,8 @@ def n_activate_window(connection):
# ----------- read/write checks ---------------------------------------
@test
def read_to_read(connection):
def read_to_read_holds(connection):
"""Check that the read operations do not intefere with each other on the data bus"""
cursor = connection.cursor()
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName IN ('RD','RDA') ORDER BY PhaseBegin")
lastRow = cursor.fetchone()
@@ -465,7 +470,9 @@ def read_to_read(connection):
@test
def write_to_write(connection):
def write_to_write_holds(connection):
"""Check that the write operations do not intefere with each other on the data bus"""
cursor = connection.cursor()
cursor.execute("SELECT phases.ID,PhaseBegin,TBankGroup FROM Phases INNER JOIN transactions ON phases.transact=transactions.ID WHERE PhaseName IN ('WR','WRA') ORDER BY PhaseBegin")
lastRow = cursor.fetchone()
@@ -482,8 +489,10 @@ def write_to_write(connection):
return TestSuceeded()
@test
def write_to_read_and_read_to_write(connection):
"""Checks minimal time between write and read/read and write (JEDEC 229, P. 33/34)"""
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
and that the write-to-read constraint is met"""
cursor = connection.cursor()
query = """SELECT Phases.ID,PhaseBegin,PhaseName,TBankGroup from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID
WHERE PhaseName IN ('RD','WR','RDA','WRA') ORDER BY PhaseBegin"""
@@ -522,6 +531,8 @@ def write_to_read_and_read_to_write(connection):
@test
def read_holds_dll_constraint_after_sref(connection):
"""Checks that all read operations are delayed long enough after the end of the self refresh powerdown state"""
cursor = connection.cursor()
query = """SELECT Phases.ID,PhaseBegin,PhaseName,TBankGroup from Phases INNER JOIN Transactions ON Phases.Transact = Transactions.ID AND TBank = :bank
WHERE PhaseName IN ('RD', 'RDA', 'SREF') ORDER BY PhaseBegin"""
@@ -539,25 +550,29 @@ def read_holds_dll_constraint_after_sref(connection):
lastRow = currentRow
return TestSuceeded()
@test
def sref_active_for_minimal_time(connection):
"""Checks that SREF is active for a minimal time (JEDEC 229, P. 41)"""
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):
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()
# ----------- powerdown checks ---------------------------------------
@test
def pdna_pdnp_active_for_minimal_time(connection):
"""Checks that PDNA,PDNP are active for a minimal time (JEDEC 229, P. 41)"""
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):
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()
# @test
# def sref_active_for_minimal_time(connection):
# """Checks that after entering self refresh powerndown state, the state is active for a minimal time (JEDEC 229, P. 41)"""
#
# 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):
# 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()
# @test
# def pdna_pdnp_active_for_minimal_time(connection):
# """Checks that after entering active/precharged powerdown, the state is active for a minimal time (JEDEC 229, P. 41)"""
#
# 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):
# 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 --------------------

View File

@@ -1,13 +1,16 @@
<simulation id = "first">
<memspec>JEDEC_256Mb_WIDEIO_SDR-266_128bit.xml</memspec>
<!-- <memspec>JEDEC_256Mb_WIDEIO_SDR-266_128bit.xml</memspec>
<addressmapping>am_wideioFourBanks.xml</addressmapping>
-->
<memspec>MICRON_4Gb_DDR4-2400_8bit_A.xml</memspec>
<addressmapping>am_ddr4.xml</addressmapping>
<memconfigs>
<memconfig>fr_fcfs.xml</memconfig>
<memconfig>fr_fcfs_bankwise.xml</memconfig>
</memconfigs>
<!-- <memconfig>fr_fcfs_bankwise.xml</memconfig>
--> </memconfigs>
<trace-setups>
<trace-setup id="1">
<device >mediabench-fractal_32.stl</device>
<device >chstone-jpeg_32.stl</device>
</trace-setup>
</trace-setups>
</simulation>

View File

@@ -81,7 +81,7 @@ void TlmRecorder::setUpTransactionTerminatingPhases()
void TlmRecorder::prepareSqlStatements()
{
insertTransactionString =
"INSERT INTO Transactions VALUES (:id,:rangeID,:address,:burstlength,:thread,:channel,:bank,:bankgroup,:row,:column,:command,:dataStrobeBegin,:dataStrobeEnd)";
"INSERT INTO Transactions VALUES (:id,:rangeID,:address,:burstlength,:thread,:channel,:bank,:bankgroup,:row,:column,:dataStrobeBegin,:dataStrobeEnd, :timeOfGeneration,:command)";
insertRangeString = "INSERT INTO Ranges VALUES (:id,:begin,:end)";
updateRangeString = "UPDATE Ranges SET End = :end WHERE ID = :id";
updateDataStrobeString = "UPDATE Transactions SET DataStrobeBegin = :begin, DataStrobeEnd = :end WHERE ID = :id";
@@ -152,6 +152,11 @@ void TlmRecorder::insertTransactionInDB(unsigned int id, tlm::tlm_generic_payloa
sqlite3_bind_int(insertTransactionStatement, 11, 0);
sqlite3_bind_int(insertTransactionStatement, 12, 0);
if(extension.getThread().ID() == 0)
sqlite3_bind_int64(insertTransactionStatement, 13, 0);
else
sqlite3_bind_int64(insertTransactionStatement, 13, GenerationExtension::getExtension(&trans).TimeOfGeneration().value());
executeSqlStatement(insertTransactionStatement);
}
void TlmRecorder::insertRangeInDB(unsigned int id, const sc_time& time)

View File

@@ -168,3 +168,23 @@ void DramExtension::increaseRow()
{
++row;
}
tlm_extension_base* GenerationExtension::clone() const
{
return new GenerationExtension(timeOfGeneration);
}
void GenerationExtension::copy_from(const tlm_extension_base& ext)
{
const GenerationExtension& cpyFrom = static_cast<const GenerationExtension&>(ext);
timeOfGeneration = cpyFrom.timeOfGeneration;
}
GenerationExtension& GenerationExtension::getExtension(const tlm::tlm_generic_payload* payload)
{
GenerationExtension *result = NULL;
payload->get_extension(result);
sc_assert(result!=NULL);
return *result;
}

View File

@@ -10,6 +10,7 @@
#include <tlm.h>
#include <iostream>
#include <systemc.h>
class Thread
{
@@ -197,4 +198,19 @@ public:
static DramExtension& getExtension(const tlm::tlm_generic_payload &payload);
};
class GenerationExtension : public tlm::tlm_extension<GenerationExtension>
{
public:
GenerationExtension(sc_time timeOfGeneration) : timeOfGeneration(timeOfGeneration) {}
virtual tlm_extension_base* clone() const;
virtual void copy_from(const tlm_extension_base& ext);
static GenerationExtension& getExtension(const tlm::tlm_generic_payload *payload);
sc_time TimeOfGeneration() const {return timeOfGeneration;}
private:
sc_time timeOfGeneration;
};
#endif /* DRAMEXTENSION_H_ */

View File

@@ -82,7 +82,7 @@ public:
{
for (Bank bank : controller->getBanks())
{
controller->powerDownManager->wakeUp(bank, sc_time_stamp());
controller->powerDownManager->wakeUp(bank, clkAlign(sc_time_stamp()));
}
}

View File

@@ -35,16 +35,12 @@ void SimulationManager::loadSimulationsFromXML(string uri)
cout << "\t-> parsing simulation objects .." << endl;
for (XMLElement* element = doc.FirstChildElement("simulation"); element != NULL;
element = element->NextSiblingElement("simulation"))
{
parseSimulationBatch(element);
}
cout << "\t-> checking paths .." << endl;
checkPaths();
@@ -61,14 +57,16 @@ void SimulationManager::runSimulations()
system(string("rm -rf " + exportPath).c_str());
for (auto& batch : simulationsBatches)
{
system(string("mkdir -p " + exportPath + "/"+batch.simulationName).c_str());
system(string("mkdir -p " + exportPath + "/" + batch.simulationName).c_str());
for (auto& dramSetup : batch.dramSetups)
{
string memconfig = getFileName(dramSetup.memconfig);
string memspec = getFileName(dramSetup.memspec);
for (auto& traceSetup : batch.traceSetups)
{
runSimulation(exportPath + "/" + batch.simulationName + "/" + memconfig + "-" + traceSetup.first + ".tdb",
runSimulation(exportPath + "/" + batch.simulationName + "/" + traceSetup.first + "-" + memconfig + "-" + memspec + ".tdb",
dramSetup, traceSetup.second);
}
}
@@ -80,13 +78,20 @@ void SimulationManager::parseSimulationBatch(XMLElement* simulation)
SimulationBatch batch;
batch.simulationName = simulation->Attribute("id");
string memspecUri = simulation->FirstChildElement("memspec")->GetText();
string memspecUri;
string addressmappingUri = simulation->FirstChildElement("addressmapping")->GetText();
for (XMLElement* element = simulation->FirstChildElement("memconfigs")->FirstChildElement("memconfig"); element != NULL;
element = element->NextSiblingElement("memconfig"))
for (XMLElement* element = simulation->FirstChildElement("memspec"); element != NULL;
element = element->NextSiblingElement("memspec"))
{
batch.dramSetups.push_back(DramSetup(element->GetText(), memspecUri, addressmappingUri));
memspecUri = element->GetText();
for (XMLElement* element = simulation->FirstChildElement("memconfigs")->FirstChildElement("memconfig"); element != NULL;
element = element->NextSiblingElement("memconfig"))
{
batch.dramSetups.push_back(DramSetup(element->GetText(), memspecUri, addressmappingUri));
}
}
for (XMLElement* element = simulation->FirstChildElement("trace-setups")->FirstChildElement("trace-setup"); element != NULL;
@@ -96,6 +101,7 @@ void SimulationManager::parseSimulationBatch(XMLElement* simulation)
}
simulationsBatches.push_back(batch);
}
void SimulationManager::checkPaths()
@@ -122,7 +128,7 @@ void SimulationManager::startTraceAnalyzer()
{
string p = getenv("trace");
string run_tpr = p + " -f ";
for(auto batch : simulationsBatches)
for (auto batch : simulationsBatches)
{
run_tpr += exportPath + "/" + batch.simulationName + " ";

View File

@@ -21,6 +21,7 @@
#include "../common/DebugManager.h"
#include "../common/xmlAddressdecoder.h"
#include "../common/TlmRecorder.h"
#include "../common/dramExtension.h"
using namespace std;
using namespace tlm;
@@ -99,6 +100,9 @@ private:
payload->set_streaming_width(burstlenght);
sc_time sendingTime = sc_time(std::stoi(time.c_str()), SC_NS);
GenerationExtension* genExtension = new GenerationExtension(sendingTime);
payload->set_auto_extension(genExtension);
if (sendingTime <= sc_time_stamp())
{
payloadEventQueue.notify(*payload, BEGIN_REQ, SC_ZERO_TIME);

View File

@@ -40,7 +40,7 @@ int sc_main(int argc, char **argv)
if(argc > 1)
simulationToRun = argv[1];
else
simulationToRun = "datasizes.xml";
simulationToRun = "first.xml";
SimulationManager manager(resources);
manager.loadSimulationsFromXML(resources + "/simulations/" + simulationToRun);