Skip to content

Commit 2519495

Browse files
authored
[Feat] Handle execution_failure (#250)
* CONTRIBUTE_TUTORIAL_cn.md * Handle big int tensors by converting to sparse COO * Update utils * Update utils * Update utils * Update utils * Update utils * Update paddle test compiler * Add compilation_duration display * resolve conflict * Feat: generate violin figure (benchmark) * revert file * cn->en * Update Analysis * Update * Update * Update * Update * Update * Update * Update * Update * Update * add annotation * Optimized structure, add e2e time * Record 2 types of speedup * update analysis * Update * Update * Update CI * Feat: Record model name & Update config * Update graph_net.json of transformers models * Update * Update * Update * Handle execution_failure、correctness_failure * Update * Update * Update * Del panelty * Del panelty * Separate log and log2Json process * Remove /work/GraphNet/graph_net/benchmark_demo.sh
1 parent 4feebaa commit 2519495

File tree

4 files changed

+365
-190
lines changed

4 files changed

+365
-190
lines changed

README.md

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -84,24 +84,20 @@ All the **construction constraints** will be examined automatically. After passi
8484

8585
**Step 1: Benchmark**
8686

87-
We use `graph_net/benchmark_demo.sh` to benchmark GraphNet computation graph samples:
87+
We use `graph_net.torch.test_compiler` to benchmark GraphNet samples with specific batch and log configurations:
8888

8989
```bash
90-
bash graph_net/benchmark_demo.sh &
91-
```
92-
93-
The script runs `graph_net.torch.test_compiler` with specific batch and log configurations.
94-
95-
Or you can customize and use `graph_net.torch.test_compiler` yourself:
90+
# Set your benchmark directory
91+
export GRAPH_NET_BENCHMARK_PATH=/home/yourname/graphnet_benchmark/
9692

97-
```bash
93+
# Run benchmark
9894
python -m graph_net.torch.test_compiler \
9995
--model-path $GRAPH_NET_EXTRACT_WORKSPACE/model_name/ \
10096
--compiler /custom/or/builtin/compiler/ \
97+
--device /device/to/execute/ \
10198
--warmup /times/to/warmup/ \
10299
--trials /times/to/test/ \
103-
--device /device/to/execute/ \
104-
--output-dir /path/to/save/JSON/result/file/
100+
> $GRAPH_NET_BENCHMARK_PATH/log.log 2>&1
105101

106102
# Note: if --compiler is omitted, PyTorch’s built-in compiler is used by default
107103
```
@@ -110,9 +106,20 @@ After executing, `graph_net.torch.test_compiler` will:
110106
1. Running the original model in eager mode to record a baseline.
111107
2. Compiling the model with the specified backend (e.g., CINN, TVM, Inductor, TensorRT, XLA, BladeDISC).
112108
3. Executing the compiled model and collecting its runtime and outputs.
113-
4. Conduct speedup by comparing the compiled results against the baseline.
109+
4. Conduct speedup by comparing the compiled results against the baseline (if no execution failure occurs).
110+
111+
**Step 2: Generate JSON Record**
112+
113+
This step is to extract information (including failure) from logs in benchmark.
114+
All the information will be saved to multiple `model_compiler.json` files via:
115+
116+
```bash
117+
python -m graph_net.torch.log2json \
118+
--log-file $GRAPH_NET_BENCHMARK_PATH/log.log \
119+
--output-dir $GRAPH_NET_BENCHMARK_PATH
120+
```
114121

115-
**Step 2: Analysis**
122+
**Step 3: Analysis**
116123

117124
After processing, we provide `graph_net/analysis.py` to generate [violin plot](https://en.m.wikipedia.org/wiki/Violin_plot) based on the JSON results.
118125

graph_net/benchmark_demo.sh

Lines changed: 0 additions & 40 deletions
This file was deleted.

graph_net/torch/log2json.py

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import argparse
2+
import json
3+
import os
4+
import re
5+
from collections import defaultdict
6+
7+
8+
def parse_logs_to_json(log_file: str, output_dir: str):
9+
"""
10+
Parses a structured log file generated by the benchmark script and
11+
creates a separate JSON report for each model-compiler run.
12+
"""
13+
try:
14+
with open(log_file, "r", encoding="utf-8") as f:
15+
lines = f.readlines()
16+
except FileNotFoundError:
17+
print(f"Error: Log file not found at '{log_file}'")
18+
return
19+
except Exception as e:
20+
print(f"Error reading log file: {e}")
21+
return
22+
23+
# This dictionary will hold the parsed data for all runs found in the log file.
24+
# Key: The model path from the '[Processing]' line, which is unique per run.
25+
# Value: The dictionary that will be converted to JSON.
26+
all_runs_data = {}
27+
current_run_key = None
28+
29+
# Define regex patterns for each type of log line we need to parse.
30+
patterns = {
31+
"processing": re.compile(r"\[Processing\] (.+)"),
32+
"config": re.compile(r"\[Config\] (\S+): (.+)"),
33+
"performance": re.compile(r"\[Performance\]\[(\w+)\]: (.+)"),
34+
"datatype": re.compile(r"\[Datatype\]\[(\w+)\]: (.+)"),
35+
"correctness": re.compile(r"\[Correctness\](\[.+\]): (.+)"),
36+
"result_status": re.compile(r"\[Result\] status: (.+)"),
37+
"speedup": re.compile(r"\[Speedup\]\[(\w+)\]: (.+)"),
38+
}
39+
40+
for line in lines:
41+
# Check for the start of a new model run
42+
processing_match = patterns["processing"].search(line)
43+
if processing_match:
44+
current_run_key = processing_match.group(1).strip()
45+
# Initialize a nested dictionary structure for this new run
46+
all_runs_data[current_run_key] = {
47+
"configuration": {},
48+
"correctness": {},
49+
"performance": {
50+
"eager": {},
51+
"compiled": {},
52+
"datatype": {},
53+
"speedup": {},
54+
},
55+
}
56+
continue
57+
58+
# If we haven't identified a run yet, skip the line
59+
if not current_run_key:
60+
continue
61+
62+
# Get the data dictionary for the current run
63+
data = all_runs_data[current_run_key]
64+
65+
# Try to match other patterns
66+
config_match = patterns["config"].search(line)
67+
if config_match:
68+
key, value = config_match.groups()
69+
data["configuration"][key.strip()] = value.strip()
70+
continue
71+
72+
performance_match = patterns["performance"].search(line)
73+
if performance_match:
74+
key, value_str = performance_match.groups()
75+
# The performance value is a JSON string, so we load it
76+
data["performance"][key.strip()] = json.loads(value_str)
77+
continue
78+
79+
datatype_match = patterns["datatype"].search(line)
80+
if datatype_match:
81+
key, value_str = datatype_match.groups()
82+
# The datatype value is a space-separated string
83+
data["performance"]["datatype"][key.strip()] = value_str.strip().split()
84+
continue
85+
86+
correctness_match = patterns["correctness"].search(line)
87+
if correctness_match:
88+
key, value_str = correctness_match.groups()
89+
values = []
90+
for v in value_str.strip().split():
91+
try:
92+
# Try to convert to int if it's a whole number, else float
93+
values.append(int(v) if "." not in v else float(v))
94+
except ValueError:
95+
# Handle non-numeric values like 'nan'
96+
values.append(float(v))
97+
data["correctness"][key.strip()] = values
98+
continue
99+
100+
result_status_match = patterns["result_status"].search(line)
101+
if result_status_match:
102+
status = result_status_match.group(1).strip()
103+
if status == "failed":
104+
data["performance"]["failure"] = "True"
105+
continue
106+
107+
speedup_match = patterns["speedup"].search(line)
108+
if speedup_match:
109+
key, value_str = speedup_match.groups()
110+
data["performance"]["speedup"][key.strip()] = float(value_str)
111+
continue
112+
113+
# After parsing all lines, write the results to JSON files
114+
if not all_runs_data:
115+
print("No processable log entries found in the file.")
116+
return
117+
118+
os.makedirs(output_dir, exist_ok=True)
119+
120+
for run_key, data in all_runs_data.items():
121+
try:
122+
model_name = data["configuration"]["model"]
123+
compiler_name = data["configuration"]["compiler"]
124+
filename = f"{model_name}_{compiler_name}.json"
125+
filepath = os.path.join(output_dir, filename)
126+
127+
with open(filepath, "w", encoding="utf-8") as f:
128+
json.dump(data, f, indent=4)
129+
130+
print(f"Successfully generated report: {filepath}")
131+
132+
except KeyError as e:
133+
print(
134+
f"Warning: Could not generate report for '{run_key}' due to missing key: {e}"
135+
)
136+
except Exception as e:
137+
print(
138+
f"Warning: An unexpected error occurred while writing report for '{run_key}': {e}"
139+
)
140+
141+
142+
def main():
143+
parser = argparse.ArgumentParser(
144+
description="Convert benchmark logs to JSON reports.",
145+
formatter_class=argparse.RawTextHelpFormatter,
146+
)
147+
parser.add_argument(
148+
"--log-file",
149+
type=str,
150+
required=True,
151+
help="Path to the benchmark log file generated by test_compiler.py.",
152+
)
153+
parser.add_argument(
154+
"--output-dir",
155+
type=str,
156+
required=True,
157+
help="Directory to save the structured JSON result files.",
158+
)
159+
args = parser.parse_args()
160+
parse_logs_to_json(args.log_file, args.output_dir)
161+
162+
163+
if __name__ == "__main__":
164+
main()

0 commit comments

Comments
 (0)