blob: 6f49d019e6d67c57e8b51fa33fe98b9096202ee3 [file] [log] [blame]
# Copyright 2023 The Fuchsia Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""
Provides utilities for summarizing fuchsiaperf json files and writing files in
a concise and human-readable format.
"""
import json
import os
import statistics
from typing import Any, Iterable, TextIO
def write_fuchsiaperf_json(
destination_file: TextIO, json_list: list[Any]
) -> None:
"""Writes a human readable json file in a more concise way than pretty json."""
destination_file.write("[")
is_first: bool = True
for entry in json_list:
if not is_first:
destination_file.write(",\n")
json.dump(entry, destination_file)
is_first = False
destination_file.write("]\n")
def mean_excluding_warm_up(values: list[int | float]) -> float:
"""Returns the mean of the given list of values excluding the first one."""
if len(values) == 0:
raise ValueError("Cannot calculate mean of empty list")
if len(values) == 1:
return values[0]
return statistics.mean(values[1:])
def summarize_perf_files(
json_files: Iterable[str | os.PathLike[str]],
) -> list[dict[str, Any]]:
"""
This function takes a set of "raw data" fuchsiaperf files as input
and produces the contents of a "summary" fuchsiaperf file as output.
The output contains just the average values for each test case.
See `//docs/development/performance/metric_name_expectations.md` for a
description of how the summarization is done and what benefits it provides.
"""
output_by_name: dict[tuple[str, str], dict[str, Any]] = {}
result: list[dict[str, Any]] = []
for json_file in json_files:
with open(json_file, "r") as f:
json_data = json.load(f)
if not isinstance(json_data, list):
raise ValueError("Top level fuchsiaperf node must be a list")
for entry in json_data:
full_name = (entry["test_suite"], entry["label"])
output_entry = output_by_name.get(full_name)
if output_entry is None:
output_entry = {
"label": entry["label"],
"test_suite": entry["test_suite"],
"unit": entry["unit"],
"values": [],
}
output_by_name[full_name] = output_entry
result.append(output_entry)
elif entry["unit"] != output_entry["unit"]:
raise ValueError(
f"Inconsistent units in fuchsiaperf results: "
f'"{entry["unit"]}" and {output_entry["unit"]}'
f'for test "{entry["test_suite"]}", "{entry["label"]}"'
)
output_entry["values"].append(
mean_excluding_warm_up(entry["values"])
)
for entry in result:
entry["values"] = [statistics.mean(entry["values"])]
return result