import sys import sqlite3 metrics = [] threadMetrics = [] def metric(function): metrics.append(function) return function def threadMetric(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 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] 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' """) result = cursor.fetchone() return round(result[0],1) @metric def memory_utilisation_percent(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 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) """ 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}) earliestReq = cursorMinREQ.fetchone() earliestResp = cursorMinRESP.fetchone() if(earliestReq[0] != 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 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.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 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.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] # @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] @metric def accesses_per_activate(connection): cursor = connection.cursor() cursor.execute("SELECT COUNT(*) FROM Phases WHERE PhaseName IN ('REQ')") result = cursor.fetchone() return round(result[0]*1.0/number_of_activates(connection),1) def timeInPowerStates(connection): totalTimeAllBanks = getTraceLength(connection)*getNumberOfBanks(connection) cursor = connection.cursor() result = [] cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = 'PDNA'") timeInPDNA = cursor.fetchone() totalTimeInPDNA = timeInPDNA[0] if(totalTimeInPDNA == None): totalTimeInPDNA = 0.0 fractionInPDNA = totalTimeInPDNA*1.0/totalTimeAllBanks result.append(("Time in PDNA (%)", fractionInPDNA*100)) print("{0} {1}".format(result[-1][0],result[-1][1])) cursor.execute("SELECT SUM(PhaseEnd-PhaseBegin) from Phases where PhaseName = '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])) return result 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 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 = [] print("================================") print("Calculating metrics for {0}".format(pathToTrace)) if(len(getThreads(connection))==1): for metric in metrics: res = (metric.__name__.replace("_"," "), metric(connection)) print("{0}: {1}".format(res[0],res[1])) calculatedMetrics.append(res) if(len(getThreads(connection))>1): # for thread in getThreads(connection): # for metric in threadMetrics: # res = ("Thread " + str(thread) + " " + metric.__name__.replace("_"," "), metric(connection, thread)) # print("{0}: {1}".format(res[0],res[1])) # calculatedMetrics.append(res) calculatedMetrics.extend(passRatio(connection)) #refreshMissDecision(connection, calculatedMetrics) #calculatedMetrics.extend(timeInPowerStates(connection)) #print(calculatedMetrics[-1]) #print(calculatedMetrics[-2]) #refreshMissDecision(connection, calculatedMetrics) print(calculatedMetrics[-1]) print(calculatedMetrics[-2]) connection.close() return calculatedMetrics if __name__ == "__main__": path = sys.argv[1] calculateMetrics(path)