Skip to content

Commit 397f410

Browse files
LifengWangiupaikov-amd
authored andcommitted
add JSON output support for operator benchmark (pytorch#154410)
To better support the integration of operator benchmark performance data into the OSS benchmark database for the dashboard, I’ve added a JSON output format that meets the required specifications: https://github.com/pytorch/pytorch/wiki/How-to-integrate-with-PyTorch-OSS-benchmark-database#output-format Since the current operator benchmark already has a flag `--output-json` to support saving the results into a JSON file, I add a new flag `--output-json-for-dashboard` for this feature. At the same time, I renamed the `--output-dir` to `--output-csv` for a clearer and more intuitive expression. An example of the JSON output of the operator benchmark. ``` [ { "benchmark": { "name": "PyTorch operator benchmark - add_M1_N1_K1_cpu", "mode": "inference", "dtype": "float32", "extra_info": { "input_config": "M: 1, N: 1, K: 1, device: cpu" } }, "model": { "name": "add_M1_N1_K1_cpu", "type": "micro-benchmark", "origins": [ "pytorch" ] }, "metric": { "name": "latency", "unit": "us", "benchmark_values": [ 2.074 ], "target_value": null } }, { "benchmark": { "name": "PyTorch operator benchmark - add_M64_N64_K64_cpu", "mode": "inference", "dtype": "float32", "extra_info": { "input_config": "M: 64, N: 64, K: 64, device: cpu" } }, "model": { "name": "add_M64_N64_K64_cpu", "type": "micro-benchmark", "origins": [ "pytorch" ] }, "metric": { "name": "latency", "unit": "us", "benchmark_values": [ 9.973 ], "target_value": null } }, ] ``` Pull Request resolved: pytorch#154410 Approved by: https://github.com/huydhn
1 parent b82d351 commit 397f410

File tree

3 files changed

+101
-13
lines changed

3 files changed

+101
-13
lines changed

.ci/pytorch/test.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1562,7 +1562,8 @@ test_operator_benchmark() {
15621562

15631563
cd "${TEST_DIR}"/benchmarks/operator_benchmark
15641564
$TASKSET python -m benchmark_all_test --device "$1" --tag-filter "$2" \
1565-
--output-dir "${TEST_REPORTS_DIR}/operator_benchmark_eager_float32_cpu.csv"
1565+
--output-csv "${TEST_REPORTS_DIR}/operator_benchmark_eager_float32_cpu.csv" \
1566+
--output-json-for-dashboard "${TEST_REPORTS_DIR}/operator_benchmark_eager_float32_cpu.json" \
15661567

15671568
pip_install pandas
15681569
python check_perf_csv.py \

benchmarks/operator_benchmark/benchmark_core.py

Lines changed: 92 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
import os
77
import timeit
88
from collections import namedtuple
9+
from dataclasses import asdict, dataclass
10+
from typing import Any, Optional
911

1012
import benchmark_utils
1113

@@ -191,9 +193,8 @@ def __init__(self, args):
191193
self.use_jit = args.use_jit
192194
self.num_runs = args.num_runs
193195
self.print_per_iter = False
194-
self.output_dir = args.output_dir
196+
self.output_csv = args.output_csv
195197
self.operator_range = benchmark_utils.get_operator_range(args.operator_range)
196-
self.disable_output = args.disable_output
197198
# 100 is the default warmup iterations
198199
if self.args.warmup_iterations == -1:
199200
self.args.warmup_iterations = 100
@@ -457,8 +458,6 @@ def _print_test_case_info(self, test_case):
457458
return False
458459

459460
def _output_csv(self, filename, headers, row):
460-
if self.args.disable_output is True:
461-
return
462461
if os.path.exists(filename):
463462
with open(filename) as fd:
464463
lines = list(csv.reader(fd)) or [[]]
@@ -475,9 +474,91 @@ def _output_csv(self, filename, headers, row):
475474
for line in lines:
476475
writer.writerow(list(line) + ["0"] * (len(headers) - len(line)))
477476

477+
def _output_json(
478+
self,
479+
perf_list,
480+
output_file,
481+
):
482+
"""
483+
Write the result into JSON format, so that it can be uploaded to the benchmark database
484+
to be displayed on OSS dashboard. The JSON format is defined at
485+
https://github.com/pytorch/pytorch/wiki/How-to-integrate-with-PyTorch-OSS-benchmark-database
486+
"""
487+
if not perf_list:
488+
return
489+
490+
# Prepare headers and records for JSON output
491+
records = []
492+
for perf_item in perf_list:
493+
# Extract data from perf_item
494+
test_name = perf_item.get("test_name", "unknown")
495+
input_config = perf_item.get("input_config", "")
496+
run_type = perf_item.get("run")
497+
latency = perf_item.get("latency", 0)
498+
499+
dtype = "float32" # default
500+
501+
# Extract mode based on run_type
502+
mode = None
503+
if run_type == "Forward":
504+
mode = "inference"
505+
elif run_type == "Backward":
506+
mode = "training"
507+
508+
# Create the record
509+
@dataclass
510+
class BenchmarkInfo:
511+
name: str
512+
mode: Optional[str]
513+
dtype: str
514+
extra_info: dict[str, Any]
515+
516+
@dataclass
517+
class ModelInfo:
518+
name: str
519+
type: str
520+
origins: list[str]
521+
522+
@dataclass
523+
class MetricInfo:
524+
name: str
525+
unit: str
526+
benchmark_values: list[float]
527+
target_value: Optional[float]
528+
529+
@dataclass
530+
class BenchmarkRecord:
531+
benchmark: BenchmarkInfo
532+
model: ModelInfo
533+
metric: MetricInfo
534+
535+
record = BenchmarkRecord(
536+
benchmark=BenchmarkInfo(
537+
name="PyTorch operator benchmark",
538+
mode=mode,
539+
dtype=dtype,
540+
extra_info={"input_config": input_config},
541+
),
542+
model=ModelInfo(
543+
name=test_name, type="micro-benchmark", origins=["pytorch"]
544+
),
545+
metric=MetricInfo(
546+
name="latency",
547+
unit="us",
548+
benchmark_values=[latency],
549+
target_value=None,
550+
),
551+
)
552+
553+
records.append(asdict(record))
554+
555+
# Write all records to the output file
556+
with open(output_file, "w", encoding="utf-8") as f:
557+
json.dump(records, f, indent=2)
558+
478559
def run(self):
479560
self._print_header()
480-
output_filename = self.args.output_dir
561+
output_csv_filename = self.args.output_csv
481562
headers = [
482563
"Benchmarking Framework",
483564
"Benchamrking Module Name",
@@ -487,7 +568,7 @@ def run(self):
487568
"Execution Time",
488569
]
489570

490-
if self.args.output_json:
571+
if self.args.output_json or self.args.output_json_for_dashboard:
491572
perf_list = []
492573

493574
for test_metainfo in BENCHMARK_TESTER:
@@ -532,7 +613,7 @@ def run(self):
532613

533614
# output results to csv
534615
self._output_csv(
535-
output_filename,
616+
output_csv_filename,
536617
headers,
537618
[
538619
test_case.framework,
@@ -547,11 +628,14 @@ def run(self):
547628
reported_time[0],
548629
],
549630
)
550-
if self.args.output_json:
631+
if self.args.output_json or self.args.output_json_for_dashboard:
551632
perf_list.append(
552633
self._perf_result_to_dict(reported_time, test_case)
553634
)
554635

636+
if self.args.output_json_for_dashboard:
637+
self._output_json(perf_list, self.args.output_json_for_dashboard)
638+
555639
if self.args.output_json:
556640
with open(self.args.output_json, "w") as f:
557641
json.dump(perf_list, f)

benchmarks/operator_benchmark/benchmark_runner.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,16 @@ def parse_args():
152152
)
153153

154154
parser.add_argument(
155-
"--output-dir",
156-
help="Choose the output directory to save the logs",
155+
"--output-csv",
156+
"--output_csv",
157+
help="CSV file path to store the results",
157158
default="benchmark_logs",
158159
)
160+
159161
parser.add_argument(
160-
"--disable-output",
161-
help="Disable log output to csv file",
162+
"--output-json-for-dashboard",
163+
"--output_json_for_dashboard",
164+
help="Save results in JSON format for display on the OSS dashboard",
162165
default="False",
163166
)
164167

0 commit comments

Comments
 (0)