diff --git a/DRAMSys/traceAnalyzer/scripts/metrics.py b/DRAMSys/traceAnalyzer/scripts/metrics.py index 6e451867..92f1ad3d 100644 --- a/DRAMSys/traceAnalyzer/scripts/metrics.py +++ b/DRAMSys/traceAnalyzer/scripts/metrics.py @@ -59,7 +59,6 @@ def trans_with_max_response_latency(connection): result = cursor.fetchone() return result[0] - @metric def memory_active(connection): cursor = connection.cursor() @@ -68,7 +67,6 @@ def memory_active(connection): clk, unit = getClock(connection) return (active[0]/clk) - @metric def memory_total(connection): cursor = connection.cursor() @@ -81,41 +79,56 @@ def memory_total(connection): def memory_idle(connection): # This complex query identifies idle times where the DRAM is not used. # The code works also if schedulers are used. - subquery = """ -- The subquery selects all TLM phases and sorts them according to BEGIN_RESP - SELECT - ROW_NUMBER () OVER ( - ORDER BY q.PhaseBegin - ) RowNum, - p.PhaseBegin AS BeginRequest, - p.PhaseEnd AS EndRequest, - q.PhaseBegin AS BeginResponse, - q.PhaseEnd AS EndResponse - - FROM - Phases p, - Phases q - - WHERE - p.PhaseName = "REQ" - AND q.PhaseName = "RESP" - AND p.Transact = q.Transact - """ - - query = """ - SELECT sum(b.BeginRequest - a.EndResponse) as idle FROM - ( - {} - ) AS a, - ( - {} - ) AS b - WHERE - (a.RowNum)=(b.RowNum-1) -- In the list of ordered transactions always compare two adjacent - AND b.BeginRequest > a.EndResponse; -- This makes sure that no negative summands exists - """.format(subquery, subquery) - + cursor = connection.cursor() + + # Create a table with transactions sorted by BeginRequest: + # (RowNum, BeginRequest) + query = """ DROP TABLE IF EXISTS transactionsInRequestOrder; """ cursor.execute(query) + + query = """ + CREATE TEMPORARY TABLE transactionsInRequestOrder AS + SELECT + ROW_NUMBER () OVER (ORDER BY p.PhaseBegin) RowNum, + p.PhaseBegin AS BeginRequest + FROM + Phases p + WHERE + p.PhaseName = "REQ"; + """ + cursor.execute(query) + + # Create a table with transactions sorted by BeginResponse: + # (RowNum, ID, EndResponse) + query = """ DROP TABLE IF EXISTS transactionsInResponseOrder; """ + cursor.execute(query) + + query = """ + CREATE TEMPORARY TABLE transactionsInResponseOrder AS + SELECT + ROW_NUMBER () OVER (ORDER BY q.PhaseBegin) RowNum, + q.Transact AS ID, + q.PhaseEnd AS EndResponse + FROM + Phases q + WHERE + q.PhaseName = "RESP"; + """ + cursor.execute(query) + + # Sum up the idle times: + query = """ + SELECT + sum(c.BeginRequest - b.EndResponse) AS idle + FROM + transactionsInRequestOrder AS a, transactionsInResponseOrder AS b, transactionsInRequestOrder AS c + WHERE + a.RowNum=b.RowNum AND + c.RowNum=(a.RowNum+1) AND + c.BeginRequest>b.EndResponse; + """ + cursor.execute(query) idle = cursor.fetchone() cursor.execute(""" SELECT min(PhaseBegin) FROM Phases WHERE PhaseName = 'REQ' """) @@ -134,6 +147,193 @@ def memory_delayed(connection): idle = memory_idle(connection) return total - active - idle +@metric +def delayed_reasons(connection): + cursor = connection.cursor() + + # Create a table with sorted Datastrobes: + # (RowNum, ID, Begin, End) + query = """ DROP TABLE IF EXISTS dataStrobesInOrder; """ + cursor.execute(query) + + query = """ + CREATE TEMPORARY TABLE dataStrobesInOrder AS + SELECT + ROW_NUMBER () OVER (ORDER BY t.DataStrobeBegin) RowNum, + t.ID as ID, + t.DataStrobeBegin as Begin, + t.DataStrobeEnd as End, + t.TRow as Row, + t.TBank as Bank, + t.Command as Command + FROM + Transactions t + WHERE + t.DataStrobeBegin <> 0 AND + t.DataStrobeEnd <> 0; + """ + cursor.execute(query) + + # Create a table with transactions sorted by BeginRequest: + # (RowNum, BeginRequest) + query = """ DROP TABLE IF EXISTS transactionsInRequestOrder; """ + cursor.execute(query) + + query = """ + CREATE TEMPORARY TABLE transactionsInRequestOrder AS + SELECT + ROW_NUMBER () OVER (ORDER BY p.PhaseBegin) RowNum, + p.PhaseBegin AS BeginRequest + FROM + Phases p + WHERE + p.PhaseName = "REQ"; + """ + cursor.execute(query) + + # Create a table with transactions sorted by BeginResponse: + # (RowNum, ID, EndResponse) + query = """ DROP TABLE IF EXISTS transactionsInResponseOrder; """ + cursor.execute(query) + + query = """ + CREATE TEMPORARY TABLE transactionsInResponseOrder AS + SELECT + ROW_NUMBER () OVER (ORDER BY q.PhaseBegin) RowNum, + q.Transact AS ID, + q.PhaseEnd AS EndResponse + FROM + Phases q + WHERE + q.PhaseName = "RESP"; + """ + cursor.execute(query) + + # Create a table with transaction IDs that start a idle time: + # (ID) + query = """ DROP TABLE IF EXISTS idleGaps; """ + cursor.execute(query) + + query = """ + CREATE TEMPORARY TABLE idleGaps AS + SELECT + b.ID AS ID + FROM + transactionsInRequestOrder AS a, transactionsInResponseOrder AS b, transactionsInRequestOrder AS c + WHERE + a.RowNum=b.RowNum AND + c.RowNum=(a.RowNum+1) AND + c.BeginRequest>b.EndResponse; + """ + cursor.execute(query) + + # Create a table which features IDs that form gaps on the databus: + # (gapBeginID, gapEndID) + query = """ DROP TABLE IF EXISTS delayedDataBusGaps; """ + cursor.execute(query) + + query = """ + CREATE TEMPORARY TABLE delayedDataBusGaps AS + SELECT + a.ID AS gapBeginID, + b.ID AS gapEndID, + a.Command AS gapBeginCommand, + b.Command AS gapEndCommand + FROM + dataStrobesInOrder a, + dataStrobesInOrder b + WHERE + (a.RowNum) = (b.RowNum-1) AND + b.Begin > a.End AND + a.ID not in (SELECT ID FROM idleGaps); + """ + cursor.execute(query) + + # Count RW + query = """ + SELECT + COUNT(*) + FROM delayedDataBusGaps + WHERE + gapBeginCommand = "R" AND + gapEndCommand = "W"; + """; + cursor.execute(query) + RW = cursor.fetchone()[0] + + # Count WR + query = """ + SELECT + COUNT(*) + FROM + delayedDataBusGaps + WHERE + gapBeginCommand = "W" AND + gapEndCommand = "R"; + """; + cursor.execute(query) + WR = cursor.fetchone()[0] + + # Count RR Miss + query = """ + SELECT COUNT(*) FROM + ( + SELECT + COUNT(*) + FROM + delayedDataBusGaps d, Phases p + WHERE + d.gapBeginCommand = "R" AND + d.gapEndCommand = "R" AND + p.Transact = d.gapEndID AND + p.PhaseName = "ACT" + GROUP BY + d.gapBeginID + ) + """; + cursor.execute(query) + RRM = cursor.fetchone()[0] + + # Count WW Miss + query = """ + SELECT COUNT(*) FROM + ( + SELECT + COUNT(*) + FROM + delayedDataBusGaps d, Phases p + WHERE + d.gapBeginCommand = "W" AND + d.gapEndCommand = "W" AND + p.Transact = d.gapEndID AND + p.PhaseName = "ACT" + GROUP BY + d.gapBeginID + ) + """; + cursor.execute(query) + WWM = cursor.fetchone()[0] + + # Count All Gaps + query = """ + SELECT + COUNT(*) + FROM delayedDataBusGaps; + """; + cursor.execute(query) + total = cursor.fetchone()[0] + + other = total - RW - WR - RRM - WWM + + RW /= total / 100.0 + WR /= total / 100.0 + RRM /= total / 100.0 + WWM /= total / 100.0 + other /= total / 100.0 + + result = "RW: {}, WR: {}, RRM: {}, WWM: {}, Other: {}".format(RW, WR, RRM, WWM, other); + return result + @metric def memory_idle_in_percent(connection): total = memory_total(connection)