Skip to content

Commit df2ef70

Browse files
authored
optimize groupsummary/ api, also reduce intermediate datastructure size. (#8904)
1 parent 50ce058 commit df2ef70

File tree

1 file changed

+63
-50
lines changed

1 file changed

+63
-50
lines changed

treeherder/webapp/api/groups.py

Lines changed: 63 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -42,62 +42,75 @@ def list(self, request):
4242
if (enddate - startdate).days > 1:
4343
enddate = startdate + datetime.timedelta(days=1)
4444

45-
q = (
46-
Job.objects.filter(push__time__range=(startdate.date(), enddate.date()))
47-
.filter(repository_id__in=(1, 77))
48-
.values(
49-
"job_log__groups__name",
50-
"job_type__name",
51-
"job_log__group_result__status",
52-
"failure_classification_id",
53-
)
54-
.annotate(job_count=Count("id"))
55-
.order_by("job_log__groups__name")
56-
)
57-
self.queryset = q
58-
serializer = self.get_serializer(self.queryset, many=True)
5945
summary = {}
60-
job_type_names = []
61-
for item in serializer.data:
62-
if not item["group_name"] or not item["job_type_name"]:
63-
continue
64-
65-
if not item["job_type_name"].startswith("test-"):
66-
continue
67-
68-
if int(item["group_status"]) == 1: # ok
69-
result = "passed"
70-
elif int(item["group_status"]) == 2: # testfailed
71-
result = "testfailed"
72-
else:
73-
# other: 3 (skipped), 10 (unsupported (i.e. crashed))
74-
# we don't want to count this at all
75-
continue
76-
77-
# TODO: consider stripping out some types; mostly care about FBC vs Intermittent
78-
classification = item["failure_classification"]
79-
80-
if item["job_type_name"] not in job_type_names:
81-
job_type_names.append(item["job_type_name"])
82-
if item["group_name"] not in summary:
83-
summary[item["group_name"]] = {}
84-
if item["job_type_name"] not in summary[item["group_name"]]:
85-
summary[item["group_name"]][item["job_type_name"]] = {}
86-
if result not in summary[item["group_name"]][item["job_type_name"]]:
87-
summary[item["group_name"]][item["job_type_name"]][result] = {}
88-
if classification not in summary[item["group_name"]][item["job_type_name"]][result]:
89-
summary[item["group_name"]][item["job_type_name"]][result][classification] = 0
90-
summary[item["group_name"]][item["job_type_name"]][result][classification] += item[
91-
"job_count"
92-
]
93-
94-
data = {"job_type_names": job_type_names, "manifests": []}
46+
job_type_names = {}
47+
job_type_counter = 0
48+
49+
for platform in ["windows", "linux", "macosx", "android"]:
50+
q = (
51+
Job.objects.filter(
52+
push__time__range=(startdate.date(), enddate.date()),
53+
repository_id__in=(1, 77),
54+
job_type__name__startswith=f"test-{platform}", # Filter at DB level
55+
job_log__group_result__status__in=(1, 2), # Only OK and ERROR statuses
56+
)
57+
.select_related("job_type", "job_log") # Reduce queries
58+
.values(
59+
"job_log__groups__name",
60+
"job_type__name",
61+
"job_log__group_result__status",
62+
"failure_classification_id",
63+
)
64+
.annotate(job_count=Count("id"))
65+
.order_by("job_log__groups__name")
66+
)
67+
68+
self.queryset = q
69+
serializer = self.get_serializer(self.queryset, many=True)
70+
for item in serializer.data:
71+
group_name = item["group_name"]
72+
job_type_name = item["job_type_name"]
73+
group_status = int(item["group_status"])
74+
classification = item["failure_classification"]
75+
job_count = item["job_count"]
76+
77+
if not group_name or not job_type_name:
78+
continue
79+
80+
# serialize job_type_name (remove chunk number)
81+
parts = job_type_name.split("-")
82+
try:
83+
_ = int(parts[-1])
84+
job_type_name = "-".join(parts[:-1])
85+
except ValueError:
86+
pass
87+
88+
result = "passed" if group_status == 1 else "testfailed"
89+
90+
if job_type_name not in job_type_names:
91+
job_type_names[job_type_name] = job_type_counter
92+
jt_index = job_type_counter
93+
job_type_counter += 1
94+
else:
95+
jt_index = job_type_names[job_type_name]
96+
97+
if group_name not in summary:
98+
summary[group_name] = {}
99+
if jt_index not in summary[group_name]:
100+
summary[group_name][jt_index] = {}
101+
if result not in summary[group_name][jt_index]:
102+
summary[group_name][jt_index][result] = {}
103+
if classification not in summary[group_name][jt_index][result]:
104+
summary[group_name][jt_index][result][classification] = 0
105+
summary[group_name][jt_index][result][classification] += job_count
106+
107+
data = {"job_type_names": job_type_names.keys(), "manifests": []}
95108
for m in summary.keys():
96109
mdata = []
97110
for d in summary[m]:
98111
for r in summary[m][d]:
99112
for c in summary[m][d][r]:
100-
mdata.append([job_type_names.index(d), r, int(c), summary[m][d][r][c]])
113+
mdata.append([d, r, int(c), summary[m][d][r][c]])
101114
data["manifests"].append({m: mdata})
102115

103116
return Response(data=data)

0 commit comments

Comments
 (0)