Files
DRAMSys/extensions/apps/traceAnalyzer/scripts/metrics.py

1135 lines
36 KiB
Python

import sys
import sqlite3
import argparse
from memUtil import *
from math import *
metrics = []
threadMetrics = []
def metric(function):
metrics.append(function)
return function
def threadMetric(function):
threadMetrics.append(function)
return function
def getThreads(connection):
cthread = getControllerThread(connection)
cursor = connection.cursor()
cursor.execute("SELECT DISTINCT(Thread) FROM Transactions WHERE Thread != " + str(cthread) + " ORDER BY Thread")
result = []
for currentRow in cursor:
result.append(currentRow[0])
return result
@metric
def trace_length_in_ns(connection):
cursor = connection.cursor()
cursor.execute("SELECT MAX(PhaseEnd) / 1000 FROM Phases")
result = cursor.fetchone()
return result[0]
@metric
def command_bus_utilisation_in_percent(connection):
cursor = connection.cursor()
if getRowColumnCommandBus(connection):
cursor.execute("""
SELECT SUM(CommandLengths.Length)
FROM Phases
INNER JOIN CommandLengths
ON Phases.PhaseName = CommandLengths.Command
WHERE PhaseName <> 'RD' AND PhaseName <> 'RDA' AND PhaseName <> 'WR' AND PhaseName <> 'WRA'
""")
rowBusUtil = cursor.fetchone()[0]
if rowBusUtil is None:
rowBusUtil = 0
cursor.execute("""
SELECT SUM(CommandLengths.Length)
FROM Phases
INNER JOIN CommandLengths
ON Phases.PhaseName = CommandLengths.Command
WHERE PhaseName = 'RD' OR PhaseName = 'RDA' OR PhaseName = 'WR' OR PhaseName = 'WRA'
""")
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:
cursor.execute("""
SELECT SUM(CommandLengths.Length)
FROM Phases
INNER JOIN CommandLengths
ON Phases.PhaseName = CommandLengths.Command
""")
util = cursor.fetchone()[0]
if util is None:
util = 0
clk, _ = getClock(connection)
traceEnd = getTraceEndTime(connection)
commandBusOccupied = util * clk / traceEnd * 100
return ": {}".format(commandBusOccupied)
@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
""")
result = cursor.fetchone()
return round(result[0], 1)
@metric
def average_rd_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""
SELECT AVG(Resp.PhaseBegin - Req.PhaseBegin) / 1000
FROM Phases Req, Phases Resp
INNER JOIN Transactions
ON Req.Transact = Transactions.ID
WHERE Req.PhaseName = 'REQ' AND Resp.PhaseName = 'RESP'
AND Req.Transact = Resp.Transact AND Transactions.Command = 'R'
""")
result = cursor.fetchone()
return round(result[0], 1)
@metric
def average_wr_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""
SELECT AVG(Resp.PhaseBegin - Req.PhaseBegin) / 1000
FROM Phases Req, Phases Resp
INNER JOIN Transactions
ON Req.Transact = Transactions.ID
WHERE Req.PhaseName = 'REQ' AND Resp.PhaseName = 'RESP'
AND Req.Transact = Resp.Transact AND Transactions.Command = 'W'
""")
result = cursor.fetchone()
return round(result[0], 1)
@metric
def max_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""
SELECT MAX(Resp.PhaseBegin - Req.PhaseBegin) / 1000
FROM Phases Req, Phases Resp
WHERE Req.PhaseName = 'REQ' AND Resp.PhaseName = 'RESP' AND Req.Transact = Resp.Transact
""")
result = cursor.fetchone()
return result[0]
@metric
def max_rd_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""
SELECT MAX(Resp.PhaseBegin - Req.PhaseBegin) / 1000
FROM Phases Req, Phases Resp
INNER JOIN Transactions
ON Req.Transact = Transactions.ID
WHERE Req.PhaseName = 'REQ' AND Resp.PhaseName = 'RESP'
AND Req.Transact = Resp.Transact AND Transactions.Command = 'R'
""")
result = cursor.fetchone()
return round(result[0], 1)
@metric
def max_wr_response_latency_in_ns(connection):
cursor = connection.cursor()
cursor.execute("""
SELECT MAX(Resp.PhaseBegin - Req.PhaseBegin) / 1000
FROM Phases Req, Phases Resp
INNER JOIN Transactions
ON Req.Transact = Transactions.ID
WHERE Req.PhaseName = 'REQ' AND Resp.PhaseName = 'RESP'
AND Req.Transact = Resp.Transact AND Transactions.Command = 'W'
""")
result = cursor.fetchone()
return round(result[0], 1)
@metric
def 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]
@metric
def memory_active_in_clks(connection):
cursor = connection.cursor()
cursor.execute("SELECT SUM(DataStrobeEnd - DataStrobeBegin) FROM Phases")
active = cursor.fetchone()[0]
if getPseudoChannelMode(connection):
active /= 2
clk, _ = getClock(connection)
return active / clk
@metric
def memory_total_in_clks(connection):
cursor = connection.cursor()
cursor.execute("SELECT MAX(DataStrobeEnd) FROM Phases")
total = cursor.fetchone()
clk, _ = getClock(connection)
return total[0] / clk
@metric
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
ROW_NUMBER () OVER (ORDER BY p.PhaseBegin) RowNum,
p.PhaseBegin AS BeginRequest
FROM
Phases p
WHERE
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
ROW_NUMBER () OVER (ORDER BY q.PhaseBegin) RowNum,
q.PhaseEnd AS EndResponse
FROM
Phases q
WHERE
q.PhaseName = 'RESP';
"""
cursor.execute(query)
# Sum up the idle times:
query = """
SELECT
SUM(c.BeginRequest - b.EndResponse) AS idle
FROM
transactionsInRequestOrder AS a, transactionsInResponseOrder AS b, transactionsInRequestOrder AS c
WHERE
a.RowNum = b.RowNum AND
c.RowNum = (a.RowNum + 1) AND
c.BeginRequest > b.EndResponse;
"""
cursor.execute(query)
idle = cursor.fetchone()
cursor.execute("""SELECT MIN(PhaseBegin) FROM Phases WHERE PhaseName = 'REQ'""")
idle_start = cursor.fetchone()
clk, unit = getClock(connection)
if idle[0] is None:
return idle_start[0] / clk
else:
return (idle[0] + idle_start[0]) / clk
@metric
def memory_delayed_in_clks(connection):
total = memory_total_in_clks(connection)
active = memory_active_in_clks(connection)
idle = memory_idle_in_clks(connection)
return total - active - idle
@metric
def delayed_reasons(connection):
cursor = connection.cursor()
# Create a table with sorted data strobes:
# (RowNum, ID, Begin, End)
cursor.execute("DROP TABLE IF EXISTS dataStrobesInOrder;")
cursor.execute("""
CREATE TEMPORARY TABLE dataStrobesInOrder AS
SELECT
ROW_NUMBER () OVER (ORDER BY DataStrobeBegin) RowNum,
Transact AS ID,
DataStrobeBegin AS Begin,
DataStrobeEnd AS End,
Row,
Bank,
PhaseName AS Command
FROM
Phases
WHERE
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
ROW_NUMBER () OVER (ORDER BY PhaseBegin) RowNum,
PhaseBegin AS BeginRequest
FROM
Phases
WHERE
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
ROW_NUMBER () OVER (ORDER BY PhaseBegin) RowNum,
Transact AS ID,
PhaseEnd AS EndResponse
FROM
Phases
WHERE
PhaseName = 'RESP';
"""
cursor.execute(query)
# Create a table with transaction IDs that start an idle time:
# (ID)
query = """DROP TABLE IF EXISTS idleGaps;"""
cursor.execute(query)
query = """
CREATE TEMPORARY TABLE idleGaps AS
SELECT
b.ID AS ID
FROM
transactionsInRequestOrder AS a, transactionsInResponseOrder AS b, transactionsInRequestOrder AS c
WHERE
a.RowNum = b.RowNum AND
c.RowNum = (a.RowNum + 1) AND
c.BeginRequest > b.EndResponse;
"""
cursor.execute(query)
# Create a table which features IDs that form gaps on the data bus:
# (gapBeginID, gapEndID)
query = """DROP TABLE IF EXISTS delayedDataBusGaps;"""
cursor.execute(query)
query = """
CREATE TEMPORARY TABLE delayedDataBusGaps AS
SELECT
a.ID AS gapBeginID,
b.ID AS gapEndID,
a.Command AS gapBeginCommand,
b.Command AS gapEndCommand
FROM
dataStrobesInOrder a,
dataStrobesInOrder b
WHERE
a.RowNum = b.RowNum - 1 AND
b.Begin > a.End AND
a.ID NOT IN (SELECT ID FROM idleGaps);
"""
cursor.execute(query)
# Count RW
query = """
SELECT
COUNT(*)
FROM delayedDataBusGaps
WHERE
(gapBeginCommand = 'RD' OR gapBeginCommand = 'RDA') AND
(gapEndCommand = 'WR' OR gapEndCommand = 'WRA');
"""
cursor.execute(query)
RW = cursor.fetchone()[0]
# Count WR
query = """
SELECT
COUNT(*)
FROM
delayedDataBusGaps
WHERE
(gapBeginCommand = 'WR' OR gapBeginCommand = 'WRA') AND
(gapEndCommand = 'RD' OR gapEndCommand = 'RDA');
"""
cursor.execute(query)
WR = cursor.fetchone()[0]
# Count RR Miss
query = """
SELECT COUNT(*) FROM
(
SELECT
COUNT(*)
FROM
delayedDataBusGaps d, Phases p
WHERE
(d.gapBeginCommand = 'RD' OR d.gapBeginCommand = 'RDA') AND
(d.gapEndCommand = 'RD' OR d.gapEndCommand = 'RDA') AND
p.Transact = d.gapEndID AND
p.PhaseName = 'ACT'
GROUP BY
d.gapBeginID
)
"""
cursor.execute(query)
RRM = cursor.fetchone()[0]
# Count WW Miss
query = """
SELECT COUNT(*) FROM
(
SELECT
COUNT(*)
FROM
delayedDataBusGaps d, Phases p
WHERE
(d.gapBeginCommand = 'WR' OR d.gapBeginCommand = 'WRA') AND
(d.gapEndCommand = 'WR' OR d.gapEndCommand = 'WRA') AND
p.Transact = d.gapEndID AND
p.PhaseName = 'ACT'
GROUP BY
d.gapBeginID
)
"""
cursor.execute(query)
WWM = cursor.fetchone()[0]
# Count All Gaps
query = """
SELECT
COUNT(*)
FROM delayedDataBusGaps;
"""
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
other /= total / 100.0
result = "RW: {}, WR: {}, RRM: {}, WWM: {}, Other: {}".format(RW, WR, RRM, WWM, other)
return result
@metric
def memory_idle_in_percent(connection):
total = memory_total_in_clks(connection)
idle = memory_idle_in_clks(connection)
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
@metric
def memory_delayed_in_percent(connection):
total = memory_total_in_clks(connection)
delayed = memory_delayed_in_clks(connection)
return (delayed / total) * 100
@metric
def memory_idle_active_delayed_check(connection):
return memory_idle_in_percent(connection) + memory_active_in_percent(connection) \
+ memory_delayed_in_percent(connection)
@metric
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
@metric
def memory_utilisation_in_Gibps_without_idle(connection):
# This function calculates the memory utilisation in Gibit/s considering
# the memory_utilisation_percent_new function result.
maxDataRate = maximum_data_rate(connection)
memoryPercent = memory_utilisation_percent_without_idle(connection)
return (memoryPercent / 100) * (maxDataRate / 1024)
@metric
def memory_utilisation_percent_including_idle(connection):
cursor = connection.cursor()
cursor.execute("""SELECT SUM(DataStrobeEnd - DataStrobeBegin) FROM Phases""")
active = cursor.fetchone()
cursor = connection.cursor()
cursor.execute("""SELECT MAX(DataStrobeEnd) FROM Phases""")
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 IN ('REFAB')' """)
# 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) """
#
# missDecisions = 0
# totalDecisions = 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})
#
# earliestReq = cursorMinREQ.fetchone()
# earliestResp = cursorMinRESP.fetchone()
# if earliestReq[0] is not None:
# totalDecisions = totalDecisions + 1
# if earliestReq[0] != earliestResp[0]:
# missDecisions = missDecisions + 1
# # print("earliest Req: {0}| earliest Res: {1}".format(earliestReq[0], earliestResp[0]))
#
# if totalDecisions != 0:
# # calculatedMetrics.append(("Total Missdecisions", missDecisions))
# calculatedMetrics.append(("Relative Missdecisions", 1.0*missDecisions/totalDecisions))
# else:
# calculatedMetrics.append(("Total Missdecisions", 0))
# calculatedMetrics.append(("Relative Missdecisions", 0))
# @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):
time = begin
while time <= end:
if time in times:
times[time] = times[time] + 1
else:
times[time] = 1
time = time + 1
# @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 # 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
def REQ_count(connection):
return get_phase_occurrences(connection, 'REQ')
@metric
def RESP_count(connection):
return get_phase_occurrences(connection, 'RESP')
# @metric
# def ACTB_count(connection):
# return get_phase_occurrences(connection, 'ACTB')
@metric
def ACT_count(connection):
return get_phase_occurrences(connection, 'ACT')
# @metric
# def PREB_count(connection):
# return get_phase_occurrences(connection, 'PREB')
@metric
def PREPB_count(connection):
return get_phase_occurrences(connection, 'PREPB') + get_phase_occurrences(connection, 'PRE')
@metric
def PRESB_count(connection):
return get_phase_occurrences(connection, 'PRESB')
@metric
def PREAB_count(connection):
return get_phase_occurrences(connection, 'PREAB') + get_phase_occurrences(connection, 'PREA')
@metric
def REFPB_count(connection):
return get_phase_occurrences(connection, 'REFPB') + get_phase_occurrences(connection, 'REFB')
@metric
def REFP2B_count(connection):
return get_phase_occurrences(connection, 'REFP2B')
@metric
def REFSB_count(connection):
return get_phase_occurrences(connection, 'REFSB')
@metric
def REFAB_count(connection):
return get_phase_occurrences(connection, 'REFAB') + get_phase_occurrences(connection, 'REFA')
@metric
def RFMPB_count(connection):
return get_phase_occurrences(connection, 'RFMPB')
@metric
def RFMP2B_count(connection):
return get_phase_occurrences(connection, 'RFMP2B')
@metric
def RFMSB_count(connection):
return get_phase_occurrences(connection, 'RFMSB')
@metric
def RFMAB_count(connection):
return get_phase_occurrences(connection, 'RFMAB')
@metric
def RD_count(connection):
return get_phase_occurrences(connection, 'RD')
@metric
def RDA_count(connection):
return get_phase_occurrences(connection, 'RDA')
@metric
def WR_count(connection):
return get_phase_occurrences(connection, 'WR')
@metric
def WRA_count(connection):
return get_phase_occurrences(connection, 'WRA')
@metric
def PDNA_count(connection):
return get_phase_occurrences(connection, 'PDNA')
@metric
def PDNB_count(connection):
return get_phase_occurrences(connection, 'PDNAB')
@metric
def PDNP_count(connection):
return get_phase_occurrences(connection, 'PDNP')
@metric
def PDNPB_count(connection):
return get_phase_occurrences(connection, 'PDNPB')
@metric
def SREF_count(connection):
return get_phase_occurrences(connection, 'SREF')
@metric
def SREFB_count(connection):
return get_phase_occurrences(connection, 'SREFB')
@metric
def number_of_accesses(connection):
return RD_count(connection) + RDA_count(connection) + WR_count(connection) + WRA_count(connection)
@metric
def accesses_per_activate(connection):
return round(float(number_of_accesses(connection)) / ACT_count(connection), 1)
@metric
def bank_overlap_ratio(connection):
# Calculates how many banks are open in parallel
clk, unit = getClock(connection)
numberOfRanks = getNumberOfRanks(connection)
numberOfBankGroups = getNumberOfBankGroups(connection)
numberOfBanks = getNumberOfBanks(connection)
per2BankOffset = getPer2BankOffset(connection)
banksPerRank = int(numberOfBanks / numberOfRanks)
banksPerGroup = int(numberOfBanks / numberOfBankGroups)
cursor = connection.cursor()
traceEnd = getTraceEndTime(connection)
trace = []
cursor.execute("""
SELECT PhaseBegin, PhaseName, Rank, BankGroup, Bank
FROM Phases
WHERE (PhaseName = 'ACT' OR PhaseName = 'PREPB' OR PhaseName = 'PREP2B' OR PhaseName = 'PRESB'
OR PhaseName = 'PREAB' OR PhaseName = 'RDA' OR PhaseName = 'WRA')
ORDER BY PhaseBegin
""")
# prevPhase = "PREAB"
# prevTime = 0
# clk of command, name, rank, bank group, bank
for c in cursor:
trace.append([(int(c[0] / clk)), c[1], c[2], c[3], c[4]])
# Insert a pseudo precharge all to mark the end of the trace on all ranks
for i in range(numberOfRanks):
trace.append([traceEnd, "PREAB", i, 0, 0])
bankCounter = [False] * numberOfBanks
# + 1 because we have #banks + 1 active states (0 to all banks active)
bankTime = [0.0] * (numberOfBanks + 1)
currentTime = 0
for t in trace:
interval = t[0] - currentTime
bankTime[sum(bankCounter)] += interval
currentTime = t[0]
if t[1] == "ACT":
bankCounter[t[4]] = True
elif t[1] in ["PREPB", "RDA", "WRA"]:
bankCounter[t[4]] = False
elif t[1] == "PREP2B":
bankCounter[t[4]] = False
bankCounter[t[4] + per2BankOffset] = False
elif t[1] == "PRESB":
for i in range(t[4], t[4] + banksPerRank, banksPerGroup):
bankCounter[i] = False
elif t[1] == "PREAB":
for i in range(t[2] * banksPerRank, (t[2] + 1) * banksPerRank):
bankCounter[i] = False
else:
print("ERROR")
return 0
for i in range(numberOfBanks + 1):
bankTime[i] = round(bankTime[i] / traceEnd * 100, 2)
return ",".join(format(x, "6.2f") for x in bankTime)
# @metric
# def number_of_precharges(connection):
# cursor = connection.cursor()
# cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName IN ('PRE','PREA','RDA','WRA')")
# result = cursor.fetchone()
# return result[0]
def time_in_PDNA_in_ns(connection):
return get_total_time_in_phase(connection, "PDNA")
def time_in_PDNA_percent(connection):
return (time_in_PDNA_in_ns(connection) * 1.0 / trace_length_in_ns(connection)) * 100
def time_in_PDNP_in_ns(connection):
return get_total_time_in_phase(connection, "PDNP")
def time_in_PDNP_percent(connection):
return (time_in_PDNP_in_ns(connection) * 1.0 / trace_length_in_ns(connection)) * 100
def time_in_SREF_in_ns(connection):
return get_total_time_in_phase(connection, "SREF")
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):
mcconfig = MCConfig(connection)
# bankwiseLogic = mcconfig.getValue("BankwiseLogic")
bankwiseLogic = "0"
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):
mcconfig = MCConfig(connection)
# bankwiseLogic = mcconfig.getValue("BankwiseLogic")
bankwiseLogic = "0"
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
def passRatio(connection):
numberOfPassWins = {}
numberOfPassLosses = {}
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 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<begin AND end<:End AND TThread != :Thread AND TThread != 0"""
cursor2.execute(query2, {"Bank": bankNumber, "Thread": passedThread, "Begin": passedBegin, "End": passedEnd})
for passingRequest in cursor2:
numberOfPassLosses[passedThread] += 1
numberOfPassWins[passingRequest[3]] += 1
# print("""Transaction {0} (thread:{1} begin:{2} end:{3}) was passed by Transaction {4} (thread:{5} begin:{6} end:{7}) on bank {8}""".format(passedId,passedThread, passedBegin,passedEnd,
# passingRequest[2], passingRequest[3], passingRequest[0], passingRequest[1], bankNumber))
result = []
for thread in getThreads(connection):
totalPassedInvolved = numberOfPassWins[thread]+numberOfPassLosses[thread]
if(totalPassedInvolved > 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 getMetrics(pathToTrace):
selectedMetrics = []
connection = sqlite3.connect(pathToTrace)
mcconfig = MCConfig(connection)
# 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]
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 metric in pdnMetrics:
if metric not in metrics:
metrics.append(metric)
if len(getThreads(connection)) >= 1:
for metric in metrics:
res = metric.__name__.replace("_", " ")
selectedMetrics.append(res)
if len(getThreads(connection)) > 1:
for thread in getThreads(connection):
for threadMetric in threadMetrics:
res = "Thread {0}: {1}".format(thread, threadMetric.__name__.replace("_", " "))
selectedMetrics.append(res)
res = "pass ratio"
selectedMetrics.append(res)
connection.close()
return selectedMetrics
def calculateMetrics(pathToTrace, selectedMetrics=None):
if selectedMetrics is None:
selectedMetrics = []
calculatedMetrics = []
connection = sqlite3.connect(pathToTrace)
mcconfig = MCConfig(connection)
# bankwiseLogic = mcconfig.getValue("BankwiseLogic")
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:
metrics.append(m)
print("================================")
print("Calculating metrics for {0}".format(pathToTrace))
print("Number of threads is {0}".format(len(getThreads(connection))))
if not selectedMetrics:
selectedMetrics = [0] * (len(metrics) + len(getThreads(connection)) * len(threadMetrics) + 1)
for i in range(len(selectedMetrics)):
selectedMetrics[i] = True
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":
values = mres.split(",")
nbanks = 0
for v in values:
name = mname + " (" + str(nbanks) + " banks active)"
nbanks = nbanks + 1
r = (name, float(v))
calculatedMetrics.append(r)
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() + ")"
value = v.partition(":")[2].strip()
r = (name, float(value))
calculatedMetrics.append(r)
else:
calculatedMetrics.append(res)
print("{0}: {1}".format(res[0], res[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)]:
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]: # FIXME: Add pass ratio
# calculatedMetrics.extend(passRatio(connection))
# refreshMissDecision(connection, calculatedMetrics)
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)
connection.close()
return calculatedMetrics
def calculateMetricsFromFuncs(pathToTrace, selectedMetrics):
calculatedMetrics = []
connection = sqlite3.connect(pathToTrace)
mcconfig = MCConfig(connection)
print("================================")
print("Calculating metrics for {0}".format(pathToTrace))
print("Number of threads is {0}".format(len(getThreads(connection))))
if not selectedMetrics:
selectedMetrics = [0] * (len(metrics) + len(getThreads(connection)) * len(threadMetrics) + 1)
for i in range(len(selectedMetrics)):
selectedMetrics[i] = True
for metric in selectedMetrics:
mres = metric(connection)
mname = metric.__name__.replace("_", " ")
res = (mname, mres)
if metric.__name__ == "bank_overlap_ratio":
values = mres.split(",")
nbanks = 0
for v in values:
name = mname + " (" + str(nbanks) + " banks active)"
nbanks = nbanks + 1
r = (name, float(v))
calculatedMetrics.append(r)
else:
calculatedMetrics.append(res)
print("{0}: {1}".format(res[0], res[1]))
# refreshMissDecision(connection, calculatedMetrics)
connection.close()
return calculatedMetrics
if __name__ == "__main__":
"""
Only non-threaded metrics are implemented for selection through command line
"""
parser = argparse.ArgumentParser(description="Calculates metrics of a given .tdb file")
parser.add_argument('path', type=str, help="The path to the .tdb file to be used")
dic_metric_functions = {}
for m in metrics:
parser.add_argument("--" + m.__name__, action='store_true')
dic_metric_functions[m.__name__] = m
arg_namespace = parser.parse_args(sys.argv[1:])
selected_metrics = []
for k, v in arg_namespace.__dict__.items():
if k == 'path':
continue
if v:
selected_metrics.append(dic_metric_functions[k])
if not selected_metrics:
calculateMetrics(arg_namespace.path)
else:
calculateMetricsFromFuncs(arg_namespace.path, selected_metrics)