Bugfix in recorder, fix all metrics.

This commit is contained in:
Lukas Steiner
2022-05-18 15:25:17 +02:00
parent 1741ebd59e
commit 0a5daf52ed
3 changed files with 114 additions and 106 deletions

View File

@@ -139,6 +139,7 @@ void TlmRecorder::recordPhase(tlm_generic_payload& trans, const tlm_phase& phase
{
// BEGIN_RESP is always the last phase of a normal transaction at this point
currentTransactionsInSystem.at(&trans).recordedPhases.back().interval.end = currentTime + delay;
removeTransactionFromSystem(trans);
}
else if (isFixedCommandPhase(phase))
{
@@ -169,9 +170,13 @@ void TlmRecorder::recordPhase(tlm_generic_payload& trans, const tlm_phase& phase
currentTime + delay + memSpec.getExecutionTime(Command(phase), trans))),
std::move(intervalOnDataStrobe), extension.getRank(), extension.getBankGroup(), extension.getBank(),
extension.getRow(), extension.getColumn(), extension.getBurstLength());
if (isRefreshCommandPhase(phase))
removeTransactionFromSystem(trans);
}
else if (isPowerDownEntryPhase(phase))
{
introduceTransactionToSystem(trans);
std::string phaseName = getPhaseName(phase).substr(6); // remove "BEGIN_"
const ControllerExtension& extension = ControllerExtension::getExtension(trans);
currentTransactionsInSystem.at(&trans).recordedPhases.emplace_back(std::move(phaseName),
@@ -184,10 +189,8 @@ void TlmRecorder::recordPhase(tlm_generic_payload& trans, const tlm_phase& phase
{
currentTransactionsInSystem.at(&trans).recordedPhases.back().interval.end = currentTime + delay
+ memSpec.getCommandLength(Command(phase));
}
if (phase == END_RESP || isRefreshCommandPhase(phase) || isPowerDownExitPhase(phase))
removeTransactionFromSystem(trans);
}
simulationTimeCoveredByRecording = currentTime + delay;
}

View File

@@ -768,6 +768,10 @@ protected:
{
return Granularity::Rankwise;
}
RelevantAttributes getRelevantAttributes() const override
{
return RelevantAttributes::Rank;
}
};
class SREFB : public Phase
@@ -819,6 +823,10 @@ protected:
{
return Granularity::Rankwise;
}
RelevantAttributes getRelevantAttributes() const override
{
return RelevantAttributes::Rank;
}
};
#endif // BANKPHASE_H

View File

@@ -50,7 +50,7 @@ def command_bus_utilisation_in_percent(connection):
rowBusUtil = cursor.fetchone()[0]
if rowBusUtil is None:
rowBusUtil = 0
cursor.execute("""
SELECT SUM(CommandLengths.Length)
FROM Phases
@@ -61,13 +61,13 @@ def command_bus_utilisation_in_percent(connection):
columnBusUtil = cursor.fetchone()[0]
if columnBusUtil is None:
columnBusUtil = 0
clk, _ = getClock(connection)
traceEnd = getTraceEndTime(connection)
rowBusOccupied = rowBusUtil * clk / traceEnd * 100
columnBusOccupied = columnBusUtil * clk / traceEnd * 100
return "row commands: {}, column commands: {}".format(rowBusOccupied, columnBusOccupied)
else:
else:
cursor.execute("""
SELECT SUM(CommandLengths.Length)
FROM Phases
@@ -204,14 +204,14 @@ def memory_total_in_clks(connection):
def memory_idle_in_clks(connection):
# This complex query identifies idle times when the DRAM is not used.
# The code works also if schedulers are used.
cursor = connection.cursor()
# Create a table with transactions sorted by BeginRequest:
# (RowNum, BeginRequest)
query = """DROP TABLE IF EXISTS transactionsInRequestOrder;"""
cursor.execute(query)
query = """
CREATE TEMPORARY TABLE transactionsInRequestOrder AS
SELECT
@@ -223,12 +223,12 @@ def memory_idle_in_clks(connection):
p.PhaseName = 'REQ';
"""
cursor.execute(query)
# Create a table with transactions sorted by BeginResponse:
# (RowNum, ID, EndResponse)
query = """DROP TABLE IF EXISTS transactionsInResponseOrder;"""
cursor.execute(query)
query = """
CREATE TEMPORARY TABLE transactionsInResponseOrder AS
SELECT
@@ -240,7 +240,7 @@ def memory_idle_in_clks(connection):
q.PhaseName = 'RESP';
"""
cursor.execute(query)
# Sum up the idle times:
query = """
SELECT
@@ -252,9 +252,9 @@ def memory_idle_in_clks(connection):
c.RowNum = (a.RowNum + 1) AND
c.BeginRequest > b.EndResponse;
"""
cursor.execute(query)
cursor.execute(query)
idle = cursor.fetchone()
cursor.execute("""SELECT MIN(PhaseBegin) FROM Phases WHERE PhaseName = 'REQ'""")
idle_start = cursor.fetchone()
clk, unit = getClock(connection)
@@ -265,7 +265,7 @@ def memory_idle_in_clks(connection):
return (idle[0] + idle_start[0]) / clk
@metric
@metric
def memory_delayed_in_clks(connection):
total = memory_total_in_clks(connection)
active = memory_active_in_clks(connection)
@@ -297,11 +297,11 @@ def delayed_reasons(connection):
DataStrobeBegin <> 0 AND
DataStrobeEnd <> 0;
""")
# Create a table with transactions sorted by BeginRequest:
# (RowNum, BeginRequest)
cursor.execute("""DROP TABLE IF EXISTS transactionsInRequestOrder;""")
query = """
CREATE TEMPORARY TABLE transactionsInRequestOrder AS
SELECT
@@ -313,12 +313,12 @@ def delayed_reasons(connection):
PhaseName = 'REQ';
"""
cursor.execute(query)
# Create a table with transactions sorted by BeginResponse:
# (RowNum, ID, EndResponse)
query = """DROP TABLE IF EXISTS transactionsInResponseOrder;"""
cursor.execute(query)
query = """
CREATE TEMPORARY TABLE transactionsInResponseOrder AS
SELECT
@@ -331,7 +331,7 @@ def delayed_reasons(connection):
PhaseName = 'RESP';
"""
cursor.execute(query)
# Create a table with transaction IDs that start an idle time:
# (ID)
query = """DROP TABLE IF EXISTS idleGaps;"""
@@ -354,7 +354,7 @@ def delayed_reasons(connection):
# (gapBeginID, gapEndID)
query = """DROP TABLE IF EXISTS delayedDataBusGaps;"""
cursor.execute(query)
query = """
CREATE TEMPORARY TABLE delayedDataBusGaps AS
SELECT
@@ -445,13 +445,13 @@ def delayed_reasons(connection):
"""
cursor.execute(query)
total = cursor.fetchone()[0]
other = total - RW - WR - RRM - WWM
RW /= total / 100.0
WR /= total / 100.0
RRM /= total / 100.0
WWM /= total / 100.0
RW /= total / 100.0
WR /= total / 100.0
RRM /= total / 100.0
WWM /= total / 100.0
other /= total / 100.0
result = "RW: {}, WR: {}, RRM: {}, WWM: {}, Other: {}".format(RW, WR, RRM, WWM, other)
@@ -462,21 +462,21 @@ def delayed_reasons(connection):
def memory_idle_in_percent(connection):
total = memory_total_in_clks(connection)
idle = memory_idle_in_clks(connection)
return (idle/total)*100
return (idle / total) * 100
@metric
def memory_active_in_percent(connection):
total = memory_total_in_clks(connection)
active = memory_active_in_clks(connection)
return (active/total)*100
return (active / total) * 100
@metric
def memory_delayed_in_percent(connection):
total = memory_total_in_clks(connection)
delayed = memory_delayed_in_clks(connection)
return (delayed/total)*100
return (delayed / total) * 100
@metric
@@ -490,7 +490,7 @@ def memory_utilisation_percent_without_idle(connection):
total = memory_total_in_clks(connection)
active = memory_active_in_clks(connection)
idle = memory_idle_in_clks(connection)
return (active/(total-idle))*100
return (active / (total - idle)) * 100
@metric
@@ -499,7 +499,7 @@ def memory_utilisation_in_Gibps_without_idle(connection):
# the memory_utilisation_percent_new function result.
maxDataRate = maximum_data_rate(connection)
memoryPercent = memory_utilisation_percent_without_idle(connection)
return (memoryPercent/100)*(maxDataRate/1024)
return (memoryPercent / 100) * (maxDataRate / 1024)
@metric
@@ -557,16 +557,16 @@ def memory_utilisation_percent_including_idle(connection):
# calculatedMetrics.append(("Relative Missdecisions", 0))
@threadMetric
def average_response_latency_in_ns(connection, thread):
cursor = connection.cursor()
query = """SELECT AVG(Resp.PhaseBegin - Req.PhaseBegin) / 1000 FROM Phases Req, Phases Resp INNER JOIN Transactions
ON Req.Transact = Transactions.ID WHERE Req.Transact = Resp.Transact AND Req.PhaseName = 'REQ'
AND Resp.PhaseName = 'RESP' AND Thread = :thread"""
cursor.execute(query, {"Thread": thread})
result = cursor.fetchone()
return round(result[0], 1)
# @threadMetric # FIXME: Fix thread metrics
# def average_response_latency_in_ns(connection, thread):
# cursor = connection.cursor()
# query = """SELECT AVG(Resp.PhaseBegin - Req.PhaseBegin) / 1000 FROM Phases Req, Phases Resp INNER JOIN Transactions
# ON Req.Transact = Transactions.ID WHERE Req.Transact = Resp.Transact AND Req.PhaseName = 'REQ'
# AND Resp.PhaseName = 'RESP' AND Thread = :Thread"""
#
# cursor.execute(query, {"Thread": thread})
# result = cursor.fetchone()
# return round(result[0], 1)
def addStallTime(times, begin, end):
@@ -579,33 +579,33 @@ def addStallTime(times, begin, end):
time = time + 1
# @threadMetric
def parallelism(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 Thread = :thread GROUP BY Transactions.ID """
clk, unit = getClock(connection)
cursor.execute(query, {"Thread": thread, "clk": clk})
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)
# @threadMetric # FIXME: Fix thread metrics
# def parallelism(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 Thread = :Thread GROUP BY Transactions.ID """
#
# clk, unit = getClock(connection)
# cursor.execute(query, {"Thread": thread, "clk": clk})
# 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)
@threadMetric
def thread_conclusion_in_ns(connection, thread):
cursor = connection.cursor()
query = """
SELECT max(PhaseEnd) / 1000 FROM Phases INNER JOIN Transactions
ON Phases.Transact = Transactions.ID WHERE Thread = :thread """
cursor.execute(query, {"Thread": thread})
result = cursor.fetchone()
return result[0]
# @threadMetric # FIXME: Fix thread metrics
# def thread_conclusion_in_ns(connection, thread):
# cursor = connection.cursor()
# query = """
# SELECT max(PhaseEnd) / 1000 FROM Phases INNER JOIN Transactions
# ON Phases.Transact = Transactions.ID WHERE Thread = :Thread """
# cursor.execute(query, {"Thread": thread})
# result = cursor.fetchone()
# return result[0]
@metric
@@ -618,8 +618,8 @@ def RESP_count(connection):
return get_phase_occurrences(connection, 'RESP')
#@metric
#def ACTB_count(connection):
# @metric
# def ACTB_count(connection):
# return get_phase_occurrences(connection, 'ACTB')
@@ -628,8 +628,8 @@ def ACT_count(connection):
return get_phase_occurrences(connection, 'ACT')
#@metric
#def PREB_count(connection):
# @metric
# def PREB_count(connection):
# return get_phase_occurrences(connection, 'PREB')
@@ -881,9 +881,9 @@ def time_in_SREFB_percent(connection):
@metric
def time_in_power_down_states_in_ns(connection):
mcconfig = MCConfig(connection)
#bankwiseLogic = mcconfig.getValue("BankwiseLogic")
# bankwiseLogic = mcconfig.getValue("BankwiseLogic")
bankwiseLogic = "0"
if bankwiseLogic == "0":
totalTimeInPDNA = time_in_PDNA_in_ns(connection)
totalTimeInPDNP = time_in_PDNP_in_ns(connection)
@@ -901,9 +901,9 @@ def time_in_power_down_states_in_ns(connection):
@metric
def time_in_power_down_states_percent(connection):
mcconfig = MCConfig(connection)
#bankwiseLogic = mcconfig.getValue("BankwiseLogic")
# bankwiseLogic = mcconfig.getValue("BankwiseLogic")
bankwiseLogic = "0"
if bankwiseLogic == "0":
totalTimeAllBanks = trace_length_in_ns(connection)
else:
@@ -961,24 +961,26 @@ def getMetrics(pathToTrace):
connection = sqlite3.connect(pathToTrace)
mcconfig = MCConfig(connection)
#bankwiseLogic = mcconfig.getValue("BankwiseLogic")
# bankwiseLogic = mcconfig.getValue("BankwiseLogic")
bankwiseLogic = "0"
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]
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]
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 metric in pdnMetrics:
if metric not in metrics:
metrics.append(metric)
if (len(getThreads(connection)) >= 1):
if len(getThreads(connection)) >= 1:
for metric in metrics:
res = metric.__name__.replace("_", " ")
selectedMetrics.append(res)
if (len(getThreads(connection)) > 1):
if len(getThreads(connection)) > 1:
for thread in getThreads(connection):
for threadMetric in threadMetrics:
res = "Thread {0}: {1}".format(thread, threadMetric.__name__.replace("_", " "))
@@ -990,23 +992,18 @@ def getMetrics(pathToTrace):
return selectedMetrics
def calculateMetrics(pathToTrace, selectedMetrics=[]):
def calculateMetrics(pathToTrace, selectedMetrics=None):
if selectedMetrics is None:
selectedMetrics = []
calculatedMetrics = []
connection = sqlite3.connect(pathToTrace)
mcconfig = MCConfig(connection)
#bankwiseLogic = mcconfig.getValue("BankwiseLogic")
bankwiseLogic = "0"
# bankwiseLogic = mcconfig.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]
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]
for m in pdnMetrics:
if m not in metrics:
@@ -1018,18 +1015,18 @@ def calculateMetrics(pathToTrace, selectedMetrics=[]):
print("Number of threads is {0}".format(len(getThreads(connection))))
if not selectedMetrics:
selectedMetrics = [0] * (len(metrics) + len(getThreads(connection))*len(threadMetrics) + 1)
selectedMetrics = [0] * (len(metrics) + len(getThreads(connection)) * len(threadMetrics) + 1)
for i in range(len(selectedMetrics)):
selectedMetrics[i] = True
if (len(getThreads(connection)) >= 1):
if len(getThreads(connection)) >= 1:
for metric in metrics:
if selectedMetrics[metrics.index(metric)]:
mres = metric(connection)
mname = metric.__name__.replace("_", " ")
res = (mname, mres)
if (metric.__name__ == "bank_overlap_ratio"):
if metric.__name__ == "bank_overlap_ratio":
values = mres.split(",")
nbanks = 0
for v in values:
@@ -1037,7 +1034,7 @@ def calculateMetrics(pathToTrace, selectedMetrics=[]):
nbanks = nbanks + 1
r = (name, float(v))
calculatedMetrics.append(r)
elif (metric.__name__ == "delayed_reasons" or metric.__name__ == "command_bus_utilisation_in_percent"):
elif metric.__name__ == "delayed_reasons" or metric.__name__ == "command_bus_utilisation_in_percent":
values = mres.split(",")
for v in values:
name = mname + " (" + v.partition(":")[0].strip() + ")"
@@ -1049,21 +1046,21 @@ def calculateMetrics(pathToTrace, selectedMetrics=[]):
print("{0}: {1}".format(res[0], res[1]))
if (len(getThreads(connection)) > 1):
if len(getThreads(connection)) > 1:
for thread in getThreads(connection):
for metric in threadMetrics:
if(selectedMetrics[len(metrics) + len(threadMetrics)*(thread-1) + threadMetrics.index(metric)]):
if selectedMetrics[len(metrics) + len(threadMetrics) * (thread - 1) + threadMetrics.index(metric)]:
mres = metric(connection, thread)
mname = "Thread {0} - {1}".format(thread, metric.__name__.replace("_", " "))
res = (mname, mres)
calculatedMetrics.append(res)
print("{0}: {1}".format(res[0], res[1]))
if (selectedMetrics[len(selectedMetrics) - 1]):
calculatedMetrics.extend(passRatio(connection))
# if selectedMetrics[len(selectedMetrics) - 1]: # FIXME: Add pass ratio
# calculatedMetrics.extend(passRatio(connection))
# refreshMissDecision(connection, calculatedMetrics)
if (len(getThreads(connection)) == 0):
if len(getThreads(connection)) == 0:
res = ("No accesses were performed for this channel, number of metrics generated", 0.0)
calculatedMetrics.append(res)
@@ -1071,8 +1068,8 @@ def calculateMetrics(pathToTrace, selectedMetrics=[]):
connection.close()
return calculatedMetrics
def calculateMetricsFromFuncs(pathToTrace, selectedMetrics):
def calculateMetricsFromFuncs(pathToTrace, selectedMetrics):
calculatedMetrics = []
connection = sqlite3.connect(pathToTrace)
@@ -1084,7 +1081,7 @@ def calculateMetricsFromFuncs(pathToTrace, selectedMetrics):
print("Number of threads is {0}".format(len(getThreads(connection))))
if not selectedMetrics:
selectedMetrics = [0] * (len(metrics) + len(getThreads(connection))*len(threadMetrics) + 1)
selectedMetrics = [0] * (len(metrics) + len(getThreads(connection)) * len(threadMetrics) + 1)
for i in range(len(selectedMetrics)):
selectedMetrics[i] = True
@@ -1093,7 +1090,7 @@ def calculateMetricsFromFuncs(pathToTrace, selectedMetrics):
mname = metric.__name__.replace("_", " ")
res = (mname, mres)
if (metric.__name__ == "bank_overlap_ratio"):
if metric.__name__ == "bank_overlap_ratio":
values = mres.split(",")
nbanks = 0
for v in values:
@@ -1110,6 +1107,7 @@ def calculateMetricsFromFuncs(pathToTrace, selectedMetrics):
connection.close()
return calculatedMetrics
if __name__ == "__main__":
"""
Only non-threaded metrics are implemented for selection through command line
@@ -1120,7 +1118,7 @@ if __name__ == "__main__":
dic_metric_functions = {}
for m in metrics:
parser.add_argument("--"+m.__name__, action='store_true')
parser.add_argument("--" + m.__name__, action='store_true')
dic_metric_functions[m.__name__] = m
arg_namespace = parser.parse_args(sys.argv[1:])
@@ -1132,8 +1130,7 @@ if __name__ == "__main__":
if v:
selected_metrics.append(dic_metric_functions[k])
if selected_metrics == []:
if not selected_metrics:
calculateMetrics(arg_namespace.path)
else:
calculateMetricsFromFuncs(arg_namespace.path, selected_metrics)