Merge remote-tracking branch 'upstream/master'
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -14,4 +14,6 @@ build*/
|
||||
._.DS_Store
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
cscope*
|
||||
DRAMSys/analyzer/scripts/__pycache__/
|
||||
|
||||
@@ -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)
|
||||
|
||||
57
DRAMSys/analyzer/scripts/memUtil.py
Normal file
57
DRAMSys/analyzer/scripts/memUtil.py
Normal file
@@ -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]
|
||||
@@ -1,63 +1,51 @@
|
||||
import sys
|
||||
import sqlite3
|
||||
from memUtil import *
|
||||
|
||||
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]
|
||||
|
||||
def getTraceLength(connection):
|
||||
cursor = connection.cursor()
|
||||
cursor.execute("SELECT TraceEnd 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"
|
||||
|
||||
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()
|
||||
# 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 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 +54,372 @@ 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 """
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
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 timeInPowerStates(connection):
|
||||
totalTimeAllBanks = getTraceLength(connection)#*getNumberOfBanks(connection)
|
||||
cursor = connection.cursor()
|
||||
result = []
|
||||
def time_in_power_down_states_in_ns(connection):
|
||||
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
|
||||
|
||||
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]))
|
||||
return totalTimePdnStates
|
||||
|
||||
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 = '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]))
|
||||
@metric
|
||||
def time_in_power_down_states_percent(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
|
||||
|
||||
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<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
|
||||
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 calculateMetrics(pathToTrace):
|
||||
connection = sqlite3.connect(pathToTrace)
|
||||
calculatedMetrics = []
|
||||
calculatedMetrics = []
|
||||
connection = sqlite3.connect(pathToTrace)
|
||||
|
||||
print("================================")
|
||||
print("Calculating metrics for {0}".format(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]
|
||||
|
||||
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)
|
||||
for m in pdnMetrics:
|
||||
if m not in metrics:
|
||||
metrics.append(m)
|
||||
|
||||
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)
|
||||
print("================================")
|
||||
print("Calculating metrics for {0}".format(pathToTrace))
|
||||
|
||||
#calculatedMetrics.extend(timeInPowerStates(connection))
|
||||
#print(calculatedMetrics[-1])
|
||||
#print(calculatedMetrics[-2])
|
||||
|
||||
#refreshMissDecision(connection, calculatedMetrics)
|
||||
print(calculatedMetrics[-1])
|
||||
print(calculatedMetrics[-2])
|
||||
connection.close()
|
||||
return calculatedMetrics
|
||||
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))
|
||||
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)) == 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
|
||||
|
||||
if __name__ == "__main__":
|
||||
path = sys.argv[1]
|
||||
calculateMetrics(path)
|
||||
|
||||
path = sys.argv[1]
|
||||
calculateMetrics(path)
|
||||
|
||||
@@ -3,35 +3,8 @@ import traceback
|
||||
import sqlite3
|
||||
import os
|
||||
import xml.etree.ElementTree as ET
|
||||
from memUtil import *
|
||||
|
||||
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']
|
||||
|
||||
def getIntValueFromConfigXML(root, id):
|
||||
return int(root.findall(".//parameter[@id='{0}']".format(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 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])
|
||||
|
||||
class DramConfig(object):
|
||||
memoryType = ""
|
||||
@@ -43,98 +16,99 @@ 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")
|
||||
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")
|
||||
|
||||
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.numberOfBanks = memspec.getIntValue("nbrOfBanks")
|
||||
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 * 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");
|
||||
elif (self. memoryType == "DDR4"):
|
||||
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")
|
||||
|
||||
@@ -144,7 +118,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
|
||||
@@ -152,44 +126,54 @@ class DramConfig(object):
|
||||
def getReadAccessTime(self):
|
||||
return self.burstLength/self.dataRate * dramconfig.clk
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
class TestResult(object):
|
||||
passed = True
|
||||
message = ''
|
||||
def __init__(self, passed = True, message = ''):
|
||||
|
||||
def __init__(self, passed=True, message=''):
|
||||
self.passed = passed
|
||||
self.message = message
|
||||
|
||||
|
||||
def TestSuceeded():
|
||||
return TestResult()
|
||||
|
||||
|
||||
def TestFailed(message):
|
||||
return TestResult(False,message);
|
||||
return TestResult(False, message)
|
||||
|
||||
|
||||
def formatTime(time):
|
||||
return ('{0} {1}'.format(time, dramconfig.unitOfTime))
|
||||
|
||||
# ----------- checks ---------------------------------------
|
||||
|
||||
|
||||
@test
|
||||
def commands_are_clockaligned(connection):
|
||||
"""Checks that all commands on the command bus are aligned to the system clock"""
|
||||
@@ -200,11 +184,11 @@ 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()
|
||||
|
||||
|
||||
@test
|
||||
def commandbus_slots_are_used_once(connection):
|
||||
"""Checks that no two phases on the command bus start at the same time"""
|
||||
@@ -221,7 +205,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()
|
||||
|
||||
@@ -235,37 +219,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:
|
||||
@@ -282,10 +265,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()
|
||||
@@ -295,60 +278,66 @@ 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
|
||||
|
||||
|
||||
@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 = {}
|
||||
|
||||
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):
|
||||
@@ -356,13 +345,14 @@ 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()
|
||||
|
||||
|
||||
@test
|
||||
def row_buffer_is_used_correctly(connection):
|
||||
"""Checks that each bank's row buffer is used correctly"""
|
||||
@@ -379,39 +369,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)"""
|
||||
@@ -420,14 +408,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
|
||||
|
||||
@@ -441,19 +428,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)"""
|
||||
@@ -463,15 +450,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"""
|
||||
@@ -480,13 +466,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()
|
||||
@@ -501,16 +487,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
|
||||
@@ -524,9 +511,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:
|
||||
@@ -535,22 +521,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):
|
||||
@@ -561,17 +546,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"""
|
||||
@@ -584,14 +569,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):
|
||||
@@ -600,7 +585,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()
|
||||
|
||||
@@ -611,48 +596,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])
|
||||
|
||||
|
||||
@@ -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<QString> 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<TraceFileTab*>(ui->traceFileTabs->widget(0));
|
||||
std::cout << "Closing tab #" << tabIndex << " \"" << traceFileTab->getPathToTraceFile().toStdString() << "\"" << std::endl;
|
||||
|
||||
ui->traceFileTabs->removeTab(0);
|
||||
delete traceFileTab;
|
||||
|
||||
tabIndex++;
|
||||
}
|
||||
|
||||
QList<QString> 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<TraceFileTab *>(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());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -57,6 +57,8 @@
|
||||
<string>File</string>
|
||||
</property>
|
||||
<addaction name="actionOpen"/>
|
||||
<addaction name="actionReload_all"/>
|
||||
<addaction name="actionSaveChangesToDB"/>
|
||||
<addaction name="actionClose_all"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionTest"/>
|
||||
@@ -81,10 +83,29 @@
|
||||
<string>Ctrl+O</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionReload_all">
|
||||
<property name="text">
|
||||
<string>Reload databases</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>CTRL+R</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSaveChangesToDB">
|
||||
<property name="text">
|
||||
<string>Save changes to DB</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>CTRL+S</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionClose_all">
|
||||
<property name="text">
|
||||
<string>Close all</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>CTRL+Q</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionInfo">
|
||||
<property name="text">
|
||||
|
||||
@@ -41,14 +41,15 @@
|
||||
#include "QFileInfo"
|
||||
#include "qmessagebox.h"
|
||||
#include <iostream>
|
||||
#include <iostream>
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ void Simulation::setupTlmRecorders(const string &traceName, const string &pathTo
|
||||
void Simulation::instantiateModules(const string &traceName, const string &pathToResources, const std::vector<Device> &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++) {
|
||||
|
||||
@@ -49,18 +49,21 @@ template<unsigned int BUSWIDTH = 128>
|
||||
struct StlDataPlayer: public TracePlayer<BUSWIDTH>
|
||||
{
|
||||
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<BUSWIDTH>::StlDataPlayer(sc_module_name /*name*/, string pathToTra
|
||||
}
|
||||
|
||||
#endif // STLDATAPLAYER_H
|
||||
|
||||
|
||||
@@ -49,23 +49,25 @@ template<unsigned int BUSWIDTH = 128>
|
||||
struct StlPlayer: public TracePlayer<BUSWIDTH>
|
||||
{
|
||||
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<BUSWIDTH>::StlPlayer(sc_module_name /*name*/, string pathToTrace, unsi
|
||||
}
|
||||
|
||||
#endif // STLPLAYER_H
|
||||
|
||||
|
||||
Reference in New Issue
Block a user