Skip to content

Commit 9eb1f6c

Browse files
authored
Merge pull request #66 from mattip/changes-per-environment
Changes per environment
2 parents 7843093 + 29b6015 commit 9eb1f6c

4 files changed

Lines changed: 77 additions & 51 deletions

File tree

codespeed/models.py

Lines changed: 41 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -401,49 +401,55 @@ def get_changes_table(self, trend_depth=10, force_save=False):
401401
return self._get_tablecache()
402402
# Otherwise generate a new changes table
403403
# Get latest revisions for this branch (which also sets the project)
404-
lastrevisions = self.get_last_revisions(trend_depth)
404+
lastrevisions = list(self.get_last_revisions(trend_depth))
405405
if not lastrevisions:
406406
return []
407407

408-
change_list = []
408+
changerevision = None
409409
pastrevisions = []
410410
if len(lastrevisions) > 1:
411411
changerevision = lastrevisions[1]
412-
change_list = Result.objects.filter(
413-
revision=changerevision
414-
).filter(
415-
environment=self.environment
416-
).filter(
417-
executable=self.executable
418-
)
419412
pastrevisions = lastrevisions[trend_depth - 2:trend_depth + 1]
420413

421-
result_list = Result.objects.filter(
422-
revision=lastrevisions[0]
423-
).filter(
424-
environment=self.environment
425-
).filter(
426-
executable=self.executable
427-
)
414+
# Bulk fetch all results needed across current, change, and past revisions
415+
relevant_revs = [lastrevisions[0]]
416+
if changerevision:
417+
relevant_revs.append(changerevision)
418+
relevant_revs.extend(pastrevisions)
419+
results_map = {
420+
(r.revision_id, r.benchmark_id): r
421+
for r in Result.objects.filter(
422+
revision__in=relevant_revs,
423+
environment=self.environment,
424+
executable=self.executable,
425+
)
426+
}
427+
428+
# Fetch and group all benchmarks in one query, preserving DB order
429+
benchmarks_by_units = {}
430+
for bench in Benchmark.objects.all():
431+
benchmarks_by_units.setdefault(bench.units_title, []).append(bench)
432+
433+
current_rev_id = lastrevisions[0].pk
434+
change_rev_id = changerevision.pk if changerevision else None
435+
past_rev_ids = [rev.pk for rev in pastrevisions]
428436

429437
tablelist = []
430-
for units_title in Benchmark.objects.all().values_list(
431-
'units_title', flat=True).distinct():
438+
for units_title, bench_group in benchmarks_by_units.items():
432439
currentlist = []
433440
units = ""
434441
hasmin = False
435442
hasmax = False
436443
has_stddev = False
437444
smallest = 1000
438445
totals = {'change': [], 'trend': []}
439-
for bench in Benchmark.objects.filter(units_title=units_title):
446+
for bench in bench_group:
440447
units = bench.units
441448
lessisbetter = bench.lessisbetter
442-
resultquery = result_list.filter(benchmark=bench)
443-
if not len(resultquery):
444-
continue
445449

446-
resobj = resultquery.filter(benchmark=bench)[0]
450+
resobj = results_map.get((current_rev_id, bench.pk))
451+
if resobj is None:
452+
continue
447453

448454
std_dev = resobj.std_dev
449455
if std_dev is not None:
@@ -466,13 +472,13 @@ def get_changes_table(self, trend_depth=10, force_save=False):
466472
# Calculate percentage change relative to previous result
467473
result = max(resobj.value, 0)
468474
change = "-"
469-
if len(change_list):
470-
c = change_list.filter(benchmark=bench)
471-
if c.count() and result is not None:
472-
if c[0].value != 0:
473-
change = (result - c[0].value) * 100 / c[0].value
474-
totals['change'].append(result / c[0].value)
475-
elif c[0].value == 0:
475+
if change_rev_id is not None:
476+
c = results_map.get((change_rev_id, bench.pk))
477+
if c is not None:
478+
if c.value != 0:
479+
change = (result - c.value) * 100 / c.value
480+
totals['change'].append(result / c.value)
481+
elif c.value == 0:
476482
if result == 0:
477483
# 0/0 = 1, in our world
478484
change = 0
@@ -481,27 +487,16 @@ def get_changes_table(self, trend_depth=10, force_save=False):
481487
# n/0 = ∞
482488
change = float("inf")
483489
totals['change'].append(float("inf"))
484-
else:
485-
# no previous result, no change available
486-
pass
487490

488491
# Calculate trend:
489492
# percentage change relative to average of 3 previous results
490-
# Calculate past average
491493
result_sum = 0
492494
num_past_results = 0
493-
if len(pastrevisions):
494-
for rev in pastrevisions:
495-
past_result = Result.objects.filter(
496-
revision=rev
497-
).filter(
498-
environment=self.environment
499-
).filter(
500-
executable=self.executable
501-
).filter(benchmark=bench)
502-
if past_result.count():
503-
result_sum += past_result[0].value
504-
num_past_results += 1
495+
for rev_id in past_rev_ids:
496+
past_r = results_map.get((rev_id, bench.pk))
497+
if past_r is not None:
498+
result_sum += past_r.value
499+
num_past_results += 1
505500
trend = "-"
506501
if result_sum:
507502
average = result_sum / num_past_results

codespeed/static/js/changes.js

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ var Changes = (function(window){
33
// Localize globals
44
var TIMELINE_URL = window.TIMELINE_URL, getLoadText = window.getLoadText;
55

6-
var currentproject, changethres, trendthres, projectmatrix, revisionboxes = {};
6+
var currentproject, changethres, trendthres, projectmatrix, revisionboxes = {}, revisiondata = {}, envhasresults = {};
77

88
function getConfiguration(revision) {
99
return {
@@ -82,6 +82,19 @@ function updateTable() {
8282
});
8383
}
8484

85+
function updateRevisionMarkers(env_id) {
86+
var has = {};
87+
$.each(envhasresults[env_id] || [], function(_, commitid) { has[commitid] = true; });
88+
var current = $("#revision").val();
89+
var options = "";
90+
$.each(revisiondata[currentproject] || [], function(_, r) {
91+
var marker = has[r[1]] ? '● ' : '○ ';
92+
options += "<option value='" + r[1] + "'>" + marker + r[0] + "</option>";
93+
});
94+
$("#revision").html(options);
95+
$("#revision").val(current);
96+
}
97+
8598
function refreshContent() {
8699
refreshContentTable($("#revision option:selected").val());
87100
}
@@ -110,8 +123,8 @@ function changeRevisions() {
110123
selected_project = projectmatrix[executable];
111124

112125
if (selected_project !== currentproject) {
113-
$("#revision").html(revisionboxes[selected_project]);
114126
currentproject = selected_project;
127+
updateRevisionMarkers($("input[name='environment']:checked").val());
115128

116129
//Give visual cue that the select box has changed
117130
var bgc = $("#revision").parent().parent().css("backgroundColor");
@@ -132,8 +145,10 @@ function config(c) {
132145
function init(defaults) {
133146
currentproject = defaults.project;
134147
projectmatrix = defaults.projectmatrix;
148+
envhasresults = defaults.envhasresults || {};
135149

136150
$.each(defaults.revisionlists, function(project, revs) {
151+
revisiondata[project] = revs;
137152
var options = "";
138153
$.each(revs, function(index, r) {
139154
options += "<option value='" + r[1] + "'>" + r[0] + "</option>";
@@ -148,10 +163,14 @@ function init(defaults) {
148163
$("input[name='executable']").change(changeRevisions);
149164

150165
$("#env" + defaults.environment).prop('checked', true);
151-
$("input[name='environment']").change(refreshContent);
166+
$("input[name='environment']").change(function() {
167+
updateRevisionMarkers($("input[name='environment']:checked").val());
168+
refreshContent();
169+
});
152170

153171
$("#revision").html(revisionboxes[defaults.project]);
154172
$("#revision").val(defaults.revision);
173+
updateRevisionMarkers(defaults.environment);
155174
$("#revision").change(refreshContent);
156175

157176
$("#permalink").click(function() {

codespeed/templates/codespeed/changes.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,12 @@
8181
Changes.init({
8282
project: "{{ defaultexecutable.project }}",
8383
executable: "{{ defaultexecutable.id }}",
84-
environment: "{{ defaultenvironment.id }}",
84+
environment: "{{ defaultenvironment.0.id }}",
8585
revision: "{{ selectedrevision.commitid }}",
8686
trend: "{{ defaulttrend }}",
8787
projectmatrix: eval({{ projectmatrix|safe }}),
88-
revisionlists: eval({{ revisionlists|safe }})
88+
revisionlists: eval({{ revisionlists|safe }}),
89+
envhasresults: eval({{ env_has_results|safe }})
8990
});
9091
});
9192
</script>

codespeed/views.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -908,6 +908,16 @@ def changes(request):
908908
projectmatrix[e.id] = e.project.name
909909
projectmatrix = json.dumps(projectmatrix)
910910

911+
all_commitids = [rev.commitid for revisions in revisionlists.values() for rev in revisions]
912+
env_has_results = {}
913+
for env in enviros:
914+
has = set(Result.objects.filter(
915+
environment=env,
916+
revision__commitid__in=all_commitids,
917+
).values_list('revision__commitid', flat=True).distinct())
918+
env_has_results[str(env.id)] = list(has)
919+
env_has_results = json.dumps(env_has_results)
920+
911921
for project, revisions in revisionlists.items():
912922
revisionlists[project] = [
913923
(str(rev), rev.commitid) for rev in revisions
@@ -928,6 +938,7 @@ def changes(request):
928938
'executables': executables,
929939
'projectmatrix': projectmatrix,
930940
'revisionlists': revisionlists,
941+
'env_has_results': env_has_results,
931942
'trends': trends,
932943
})
933944

0 commit comments

Comments
 (0)