From 54acb3ec1fa51f6658f091e54f0615e56b5bf27d Mon Sep 17 00:00:00 2001 From: jasplin Date: Thu, 10 Feb 2011 12:27:02 +0100 Subject: Show trend as "delta from prev ranking pos". --- scripts/getrankings.py | 72 ++++++++++++++++++++++++++++++++++++++++-------- scripts/misc.py | 20 ++++++++++++++ web/getstats/rankings.js | 20 +++++++++----- 3 files changed, 93 insertions(+), 19 deletions(-) diff --git a/scripts/getrankings.py b/scripts/getrankings.py index 5b11453..d23cb38 100644 --- a/scripts/getrankings.py +++ b/scripts/getrankings.py @@ -3,7 +3,7 @@ import json from dbaccess import execQuery, database from misc import ( textToId, idToText, getContext, getTimestampFromContext, getSnapshots, - printJSONHeader) + getRankingContexts, printJSONHeader) class GetRankings: @@ -45,6 +45,15 @@ class GetRankings: print "error: invalid context" sys.exit(1) + # Find the previous context (if any) for which rankings exist: + ranking_contexts = getRankingContexts( + self.host_id, self.platform_id, self.branch_id) + curr_index = zip(*ranking_contexts)[0].index(self.context2_id) + if curr_index < (len(ranking_contexts) - 1): + context2_prev_id = ranking_contexts[curr_index + 1][0] + else: + context2_prev_id = -1 # No rankings before this context + rankings = {} context_ids = set([self.context2_id]) # Affected context IDs @@ -53,29 +62,68 @@ class GetRankings: for stat_id, stat_name in stat_infos: # Get the unsorted ranking information: - stat_ranking = execQuery( + ranking = execQuery( "SELECT benchmarkId, metricId, context1Id, pos, value" " FROM ranking" " WHERE context2Id = %d" " AND statId = %d;" % (self.context2_id, stat_id)) - for row in stat_ranking: + for row in ranking: context_ids.add(row[2]) # Sort the table in ascending order on the 'pos' column, but # so that negative positions are ranked below any other positions: - stat_ranking.sort(key=lambda row: row[3], cmp=self.cmp_rank_pos) + ranking.sort(key=lambda row: row[3], cmp=self.cmp_rank_pos) + + # Keep only the 'maxsize' highest ranked benchmarks: + ranking = ranking if (self.maxsize < 0) else ranking[:self.maxsize] + + if context2_prev_id >= 0: + # Compute deltas from previous ranking: + ranking_prev = execQuery( + "SELECT benchmarkId, metricId, pos" + " FROM ranking" + " WHERE context2Id = %d" + " AND statId = %d;" + % (context2_prev_id, stat_id)) + ranking_without_deltas = ranking + ranking = [] + for row in ranking_without_deltas: + benchmark_id = row[0] + metric_id = row[1] + context1_id = row[2] + pos = row[3] + value = row[4] + + new_row = [ + benchmark_id, metric_id, context1_id, pos, value] + + if pos >= 0: + + # ### Maybe optimize the search for row_prev by storing + # previous rankings in a dictionary with + # (benchmark_id, metric_id) as key? + row_prev = filter( + lambda row: row[0] == benchmark_id + and row[1] == metric_id, + ranking_prev) + + assert len(row_prev) == 1 + assert len(row_prev[0]) == 3 + pos_prev = row_prev[0][2] + + if pos_prev >= 0: + delta = pos_prev - pos + new_row.append(delta) + + + ranking.append(new_row) + - # For each benchmark in the table, compute the trend and append - # it to the row (each row now contains benchmark ID, pos, value, - # trend, and will still be sorted on pos): - # 2 B DONE! - # Add the 'maxsize' highest ranked benchmarks for this statistic: - rankings[stat_name.lower()] = ( - stat_ranking if (self.maxsize < 0) - else stat_ranking[:self.maxsize]) + # Add to main list: + rankings[stat_name.lower()] = ranking; # Extract affected SHA-1s: diff --git a/scripts/misc.py b/scripts/misc.py index 01864d0..a2e8ffd 100644 --- a/scripts/misc.py +++ b/scripts/misc.py @@ -174,6 +174,26 @@ def getLastRankingSnapshot(host_id, platform_id, branch_id): return -1, -1 +# For the given host/platform/branch combination, this function returns +# all contexts for which rankings exist. The return value is a list of +# (context ID, timestamp) pairs sorted in descending order on timestamp +# (latest timestamp first). +def getRankingContexts(host_id, platform_id, branch_id): + result = execQuery( + "SELECT DISTINCT matchingcontext.id," + " EXTRACT(EPOCH FROM timestamp)::INT AS etimestamp" + " FROM ranking," + " (SELECT id, sha1Id, timestamp" + " FROM context" + " WHERE hostId = %d" + " AND platformId = %d" + " AND branchId = %d) AS matchingContext" + " WHERE context2Id = matchingContext.id" + " ORDER BY etimestamp DESC;" + % (host_id, platform_id, branch_id)) + return result + + # Retrieves the time series of valid median results for the given # benchmark/metric combination. Only the part of the time series that # is within the selected snapshot interval is considered. diff --git a/web/getstats/rankings.js b/web/getstats/rankings.js index a7d2caa..136c746 100644 --- a/web/getstats/rankings.js +++ b/web/getstats/rankings.js @@ -27,12 +27,14 @@ function populateRankingTable( var html = ""; for (var i = 0; i < rankings.length; ++i) { - row = rankings[i]; - bmarkId = row[0]; - metricId = row[1]; - context1Id = row[2]; // unused? - pos = row[3]; - val = row[4]; + var row = rankings[i]; + var bmarkId = row[0]; + var metricId = row[1]; + var context1Id = row[2]; // unused? + var pos = row[3]; + var val = row[4]; + var hasPrevDelta = (row.length > 5); + var prevDelta = hasPrevDelta ? row[5] : null; benchmark = bmarkId2Name[bmarkId]; metric = metricId2Name[metricId]; @@ -51,7 +53,11 @@ function populateRankingTable( ")\""; html += "" + pos + ""; - html += "<trend>"; + if (hasPrevDelta) { + html += "" + prevDelta + ""; + } else { + html += "n/a"; + } html += "" + val + ""; html += "" + metric + ""; html += "" + benchmark + ""; -- cgit v1.2.3