in treeherder/webapp/api/performance_data.py [0:0]
def list(self, request):
query_params = PerformanceQueryParamsSerializer(data=request.query_params)
if not query_params.is_valid():
return Response(data=query_params.errors, status=HTTP_400_BAD_REQUEST)
startday = query_params.validated_data["startday"]
endday = query_params.validated_data["endday"]
revision = query_params.validated_data["revision"]
repository_name = query_params.validated_data["repository"]
interval = query_params.validated_data["interval"]
frameworks = query_params.validated_data["framework"]
parent_signature = query_params.validated_data["parent_signature"]
signature = query_params.validated_data["signature"]
no_subtests = query_params.validated_data["no_subtests"]
all_data = query_params.validated_data["all_data"]
no_retriggers = query_params.validated_data["no_retriggers"]
replicates = query_params.validated_data["replicates"]
signature_data = PerformanceSignature.objects.select_related(
"framework", "repository", "platform", "push", "job"
).filter(repository__name=repository_name)
# TODO deprecate signature hash support
if signature and len(signature) == 40:
signature_data = signature_data.filter(signature_hash=signature)
elif signature:
signature_data = signature_data.filter(id=signature)
else:
signature_data = signature_data.filter(parent_signature__isnull=no_subtests)
if frameworks:
signature_data = signature_data.filter(framework__in=frameworks)
if parent_signature:
signature_data = signature_data.filter(parent_signature_id=parent_signature)
# we do this so all relevant signature data is returned even if there isn't performance data
# and it's also not needed since this param is used to filter directly on signature_id
if interval and not all_data:
signature_data = signature_data.filter(
last_updated__gte=datetime.datetime.utcfromtimestamp(
int(time.time() - int(interval))
)
)
# TODO signature_hash is being returned for legacy support - should be removed at some point
self.queryset = signature_data.values(
"framework_id",
"id",
"lower_is_better",
"has_subtests",
"extra_options",
"suite",
"signature_hash",
"platform__platform",
"test",
"option_collection_id",
"parent_signature_id",
"repository_id",
"tags",
"measurement_unit",
"application",
"should_alert",
"alert_change_type",
"alert_threshold",
"parent_signature__should_alert",
)
self.check_and_update_should_alert()
signature_ids = [item["id"] for item in list(self.queryset)]
data = (
PerformanceDatum.objects.select_related("push", "repository", "job")
.filter(signature_id__in=signature_ids, repository__name=repository_name)
.order_by("job_id", "id")
)
if revision:
data = data.filter(push__revision=revision)
elif interval and not startday and not endday:
data = data.filter(
push_timestamp__gt=datetime.datetime.utcfromtimestamp(
int(time.time() - int(interval))
)
)
else:
data = data.filter(push_timestamp__gt=startday, push_timestamp__lt=endday)
# more efficient than creating a join on option_collection and option
option_collection = OptionCollection.objects.select_related("option").values(
"id", "option__name"
)
option_collection_map = {
item["id"]: item["option__name"] for item in list(option_collection)
}
if signature and all_data:
for item in self.queryset:
if replicates:
item["data"] = list()
for (
value,
job_id,
datum_id,
push_id,
push_timestamp,
push_revision,
replicate_value,
submit_time,
) in data.values_list(
"value",
"job_id",
"id",
"push_id",
"push_timestamp",
"push__revision",
"performancedatumreplicate__value",
"job__submit_time",
).order_by("push_timestamp", "push_id", "job_id"):
if replicate_value is not None:
item["data"].append(
{
"value": replicate_value,
"job_id": job_id,
"id": datum_id,
"push_id": push_id,
"push_timestamp": push_timestamp,
"push__revision": push_revision,
"submit_time": submit_time,
}
)
elif value is not None:
item["data"].append(
{
"value": value,
"job_id": job_id,
"id": datum_id,
"push_id": push_id,
"push_timestamp": push_timestamp,
"push__revision": push_revision,
"submit_time": submit_time,
}
)
else:
item["data"] = data.values(
"value",
"job_id",
"id",
"push_id",
"push_timestamp",
"push__revision",
"job__submit_time",
).order_by("push_timestamp", "push_id", "job_id")
item["option_name"] = option_collection_map[item["option_collection_id"]]
item["repository_name"] = repository_name
else:
grouped_values = defaultdict(list)
grouped_job_ids = defaultdict(list)
grouped_submit_times = defaultdict(list)
if replicates:
for signature_id, value, job_id, replicate_value, submit_time in data.values_list(
"signature_id",
"value",
"job_id",
"performancedatumreplicate__value",
"job__submit_time",
):
if replicate_value is not None:
grouped_values[signature_id].append(replicate_value)
grouped_job_ids[signature_id].append(job_id)
grouped_submit_times[signature_id].append(submit_time)
elif value is not None:
grouped_values[signature_id].append(value)
grouped_job_ids[signature_id].append(job_id)
grouped_submit_times[signature_id].append(submit_time)
else:
for signature_id, value, job_id, submit_time in data.values_list(
"signature_id", "value", "job_id", "job__submit_time"
):
if value is not None:
grouped_values[signature_id].append(value)
grouped_job_ids[signature_id].append(job_id)
grouped_submit_times[signature_id].append(submit_time)
# name field is created in the serializer
for item in self.queryset:
item["values"] = grouped_values.get(item["id"], [])
item["job_ids"] = grouped_job_ids.get(item["id"], [])
item["submit_times"] = grouped_submit_times.get(item["id"], [])
item["option_name"] = option_collection_map[item["option_collection_id"]]
item["repository_name"] = repository_name
serializer = self.get_serializer(self.queryset, many=True)
serialized_data = serializer.data
if no_retriggers:
serialized_data = self._filter_out_retriggers(serialized_data)
return Response(data=serialized_data)