Skip to content

Commit d5c8ad4

Browse files
Allow endpoint to change the statistics calculation based on the replicates query param (#8678)
1 parent db27bed commit d5c8ad4

File tree

3 files changed

+60
-14
lines changed

3 files changed

+60
-14
lines changed

tests/webapp/api/test_perfcompare_api.py

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from django.urls import reverse
55

66
from treeherder.model.models import Job
7-
from treeherder.perf.models import PerformanceDatum
7+
from treeherder.perf.models import PerformanceDatum, PerformanceDatumReplicate
88
from treeherder.webapp.api import perfcompare_utils
99

1010
NOW = datetime.datetime.now()
@@ -224,6 +224,8 @@ def test_perfcompare_results_with_only_one_run_and_diff_repo(
224224

225225
base_perf_data_values = [32.4]
226226
new_perf_data_values = [40.2]
227+
base_perf_data_replicates = [20]
228+
new_perf_data_replicates = [15]
227229

228230
job = perf_jobs[0]
229231
job.push = test_perfcomp_push
@@ -238,6 +240,7 @@ def test_perfcompare_results_with_only_one_run_and_diff_repo(
238240
)
239241
perf_datum.push.time = job.push.time
240242
perf_datum.push.save()
243+
PerformanceDatumReplicate.objects.create(performance_datum=perf_datum, value=20)
241244

242245
new_sig = create_signature(
243246
signature_hash=(20 * "t2"),
@@ -264,6 +267,7 @@ def test_perfcompare_results_with_only_one_run_and_diff_repo(
264267
)
265268
perf_datum.push.time = job.push.time
266269
perf_datum.push.save()
270+
PerformanceDatumReplicate.objects.create(performance_datum=perf_datum, value=15)
267271

268272
response = get_expected(
269273
base_sig,
@@ -293,8 +297,8 @@ def test_perfcompare_results_with_only_one_run_and_diff_repo(
293297
"new_retriggerable_job_ids": [10],
294298
"base_runs": base_perf_data_values,
295299
"new_runs": new_perf_data_values,
296-
"base_runs_replicates": [],
297-
"new_runs_replicates": [],
300+
"base_runs_replicates": [20],
301+
"new_runs_replicates": [15],
298302
"base_avg_value": round(response["base_avg_value"], 2),
299303
"new_avg_value": round(response["new_avg_value"], 2),
300304
"base_median_value": round(response["base_median_value"], 2),
@@ -348,6 +352,38 @@ def test_perfcompare_results_with_only_one_run_and_diff_repo(
348352
assert response.status_code == 200
349353
assert expected[0] == response.json()[0]
350354

355+
# test the same comparison by setting the replicates values to true
356+
query_params = (
357+
"?base_repository={}&new_repository={}&base_revision={}&new_revision={}&framework={"
358+
"}&no_subtests=true&replicates=true".format(
359+
try_repository.name,
360+
test_repository.name,
361+
test_perfcomp_push.revision,
362+
test_perfcomp_push_2.revision,
363+
test_perf_signature.framework_id,
364+
)
365+
)
366+
367+
expected_response = get_expected(
368+
base_sig,
369+
new_sig,
370+
extra_options,
371+
test_option_collection,
372+
# get expected_response using the replicates values
373+
new_perf_data_replicates,
374+
base_perf_data_replicates,
375+
)
376+
response = client.get(reverse("perfcompare-results") + query_params)
377+
378+
# test to see how the response changed based on the replicates values
379+
assert response.status_code == 200
380+
response.json()[0]["base_avg_value"] = round(expected_response["base_avg_value"], 2)
381+
response.json()[0]["base_stddev"] = round(expected_response["base_stddev"], 2)
382+
response.json()[0]["base_median_value"] = round(expected_response["base_median_value"], 2)
383+
response.json()[0]["new_avg_value"] = round(expected_response["new_avg_value"], 2)
384+
response.json()[0]["new_stddev"] = round(expected_response["new_stddev"], 2)
385+
response.json()[0]["new_median_value"] = round(expected_response["new_median_value"], 2)
386+
351387

352388
def test_perfcompare_results_without_base_signature(
353389
client,

treeherder/webapp/api/performance_data.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,7 @@ def list(self, request):
919919
no_subtests = query_params.validated_data["no_subtests"]
920920
base_parent_signature = query_params.validated_data["base_parent_signature"]
921921
new_parent_signature = query_params.validated_data["new_parent_signature"]
922+
replicates = query_params.validated_data["replicates"]
922923

923924
try:
924925
new_push = models.Push.objects.get(revision=new_rev, repository__name=new_repo_name)
@@ -979,11 +980,17 @@ def list(self, request):
979980
new_grouped_replicates,
980981
) = self._get_grouped_perf_data(new_perf_data)
981982

983+
statistics_base_grouped_data = base_grouped_values
984+
statistics_new_grouped_data = new_grouped_values
985+
if replicates:
986+
statistics_base_grouped_data = base_grouped_replicates
987+
statistics_new_grouped_data = new_grouped_replicates
988+
982989
base_signatures_map, base_header_names, base_platforms = self._get_signatures_map(
983-
base_signatures, base_grouped_values, option_collection_map
990+
base_signatures, statistics_base_grouped_data, option_collection_map
984991
)
985992
new_signatures_map, new_header_names, new_platforms = self._get_signatures_map(
986-
new_signatures, new_grouped_values, option_collection_map
993+
new_signatures, statistics_new_grouped_data, option_collection_map
987994
)
988995

989996
header_names = list(set(base_header_names + new_header_names))
@@ -1020,22 +1027,24 @@ def list(self, request):
10201027
new_perf_data_values = new_grouped_values.get(new_sig_id, [])
10211028
base_perf_data_replicates = base_grouped_replicates.get(base_sig_id, [])
10221029
new_perf_data_replicates = new_grouped_replicates.get(new_sig_id, [])
1023-
base_runs_count = len(base_perf_data_values)
1024-
new_runs_count = len(new_perf_data_values)
1030+
statistics_base_perf_data = statistics_base_grouped_data.get(base_sig_id, [])
1031+
statistics_new_perf_data = statistics_new_grouped_data.get(new_sig_id, [])
1032+
base_runs_count = len(statistics_base_perf_data)
1033+
new_runs_count = len(statistics_new_perf_data)
10251034
is_complete = base_runs_count and new_runs_count
10261035
no_results_to_show = not base_runs_count and not new_runs_count
10271036
if no_results_to_show:
10281037
continue
1029-
base_avg_value = perfcompare_utils.get_avg(base_perf_data_values, header)
1030-
base_stddev = perfcompare_utils.get_stddev(base_perf_data_values, header)
1031-
base_median_value = perfcompare_utils.get_median(base_perf_data_values)
1032-
new_avg_value = perfcompare_utils.get_avg(new_perf_data_values, header)
1033-
new_stddev = perfcompare_utils.get_stddev(new_perf_data_values, header)
1034-
new_median_value = perfcompare_utils.get_median(new_perf_data_values)
1038+
base_avg_value = perfcompare_utils.get_avg(statistics_base_perf_data, header)
1039+
base_stddev = perfcompare_utils.get_stddev(statistics_base_perf_data, header)
1040+
base_median_value = perfcompare_utils.get_median(statistics_base_perf_data)
1041+
new_avg_value = perfcompare_utils.get_avg(statistics_new_perf_data, header)
1042+
new_stddev = perfcompare_utils.get_stddev(statistics_new_perf_data, header)
1043+
new_median_value = perfcompare_utils.get_median(statistics_new_perf_data)
10351044
base_stddev_pct = perfcompare_utils.get_stddev_pct(base_avg_value, base_stddev)
10361045
new_stddev_pct = perfcompare_utils.get_stddev_pct(new_avg_value, new_stddev)
10371046
confidence = perfcompare_utils.get_abs_ttest_value(
1038-
base_perf_data_values, new_perf_data_values
1047+
statistics_base_perf_data, statistics_new_perf_data
10391048
)
10401049
confidence_text = perfcompare_utils.get_confidence_text(confidence)
10411050
delta_value = perfcompare_utils.get_delta_value(new_avg_value, base_avg_value)

treeherder/webapp/api/performance_serializers.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -513,6 +513,7 @@ class PerfCompareResultsQueryParamsSerializer(serializers.Serializer):
513513
no_subtests = serializers.BooleanField(required=False)
514514
base_parent_signature = serializers.CharField(required=False, allow_null=True, default=None)
515515
new_parent_signature = serializers.CharField(required=False, allow_null=True, default=None)
516+
replicates = serializers.BooleanField(required=False)
516517

517518
def validate(self, data):
518519
if data["base_revision"] is None and data["interval"] is None:

0 commit comments

Comments
 (0)