1
+ # Copyright 2025 The OpenXLA Authors. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ # ============================================================================
15
+ # .github/workflows/benchmarks/prepare_artifact.sh
16
+ # TODO(juliagmt): convert this to a python script.
17
+ #! /bin/bash
18
+ set -u # Treat unset variables as an error when substituting.
19
+ # IMPORTANT: pipefail is handled specifically around the runner command.
20
+ set -e # Exit on errors, EXCEPT where explicitly handled.
21
+
22
+ echo " --- Running Benchmark ---"
23
+
24
+ # Reads ENVs from the Step:
25
+ # RUNNER_BINARY, STATS_BINARY, DEVICE_TYPE_FLAG, LOCAL_ARTIFACT_PATH
26
+ # Reads ENVs from the Job:
27
+ # BENCHMARK_NAME, CONFIG_ID, HARDWARE_CATEGORY, OUTPUT_DIR,
28
+ # XLA_FLAGS_JSON, RUNTIME_FLAGS_JSON,
29
+ # COMMIT_SHA, WORKFLOW_RUN_ID
30
+
31
+ # --- Validate Inputs ---
32
+ if [ -z " $LOCAL_ARTIFACT_PATH " ] || [ ! -f " $LOCAL_ARTIFACT_PATH " ]; then echo " ::error::LOCAL_ARTIFACT_PATH path is invalid or file not found: '$LOCAL_ARTIFACT_PATH '" ; exit 1; fi
33
+ if [ -z " $RUNNER_BINARY " ] || [ ! -x " $RUNNER_BINARY " ]; then echo " ::error::RUNNER_BINARY path is invalid or file not executable: '$RUNNER_BINARY '" ; exit 1; fi
34
+ if [ -z " $DEVICE_TYPE_FLAG " ]; then echo " ::error::DEVICE_TYPE_FLAG is empty" ; exit 1; fi
35
+ if [ -z " $STATS_BINARY " ] || [ ! -x " $STATS_BINARY " ]; then echo " ::error::STATS_BINARY path is invalid or file not executable: '$STATS_BINARY '" ; exit 1; fi
36
+ if ! command -v jq & > /dev/null; then echo " ::error::jq command not found." ; exit 1; fi
37
+
38
+ RUNNER_STDOUT_FILE=" $OUTPUT_DIR /runner_stdout.txt"
39
+ XSPACE_FILE_PATH=" $OUTPUT_DIR /xspace.pb"
40
+ RESULTS_JSON_FILE=" $OUTPUT_DIR /results.json"
41
+
42
+ # --- Prepare flags ---
43
+ declare -a xla_flags_array=()
44
+ declare -a runtime_flags_array=()
45
+
46
+ # Use JQ to safely parse JSON and populate bash arrays
47
+ if echo " $XLA_FLAGS_JSON " | jq -e ' . | arrays and length > 0' > /dev/null; then
48
+ mapfile -t xla_flags_array < <( echo " $XLA_FLAGS_JSON " | jq -r ' .[]' )
49
+ fi
50
+ if echo " $RUNTIME_FLAGS_JSON " | jq -e ' . | arrays and length > 0' > /dev/null; then
51
+ mapfile -t runtime_flags_array < <( echo " $RUNTIME_FLAGS_JSON " | jq -r ' .[]' )
52
+ fi
53
+
54
+ # Conditionally add profile flag if needed for stats
55
+ needs_profile_flag=true
56
+ for flag in " ${runtime_flags_array[@]} " ; do
57
+ if [[ " $flag " == " --profile_execution" * ]]; then
58
+ needs_profile_flag=false; break
59
+ fi
60
+ done
61
+ needs_xspace_dump_flag=true # Assume we always want stats if possible
62
+ if $needs_profile_flag && $needs_xspace_dump_flag ; then
63
+ runtime_flags_array+=(" --profile_execution=True" )
64
+ echo " INFO: Added --profile_execution=True for stats generation."
65
+ fi
66
+
67
+ # --- Build Runner Command ---
68
+ declare -a runner_command_array=(" $RUNNER_BINARY " " --device_type=$DEVICE_TYPE_FLAG " )
69
+ if [ ${# runtime_flags_array[@]} -gt 0 ]; then runner_command_array+=(" ${runtime_flags_array[@]} " ); fi
70
+ if [ ${# xla_flags_array[@]} -gt 0 ]; then runner_command_array+=(" ${xla_flags_array[@]} " ); fi
71
+ if $needs_xspace_dump_flag ; then
72
+ runner_command_array+=(" --xla_gpu_dump_xspace_to=$XSPACE_FILE_PATH " )
73
+ fi
74
+ runner_command_array+=(" $LOCAL_ARTIFACT_PATH " )
75
+
76
+ # --- Execute Runner ---
77
+ echo " Executing HLO Runner command:"
78
+ printf " %q " " ${runner_command_array[@]} " ; echo # Print quoted command
79
+
80
+ set +e # Disable exit-on-error temporarily to capture exit code
81
+ set -o pipefail # Ensure tee doesn't mask the runner's exit code
82
+ " ${runner_command_array[@]} " 2>&1 | tee " $RUNNER_STDOUT_FILE "
83
+ RUNNER_EXIT_CODE=${PIPESTATUS[0]}
84
+ set +o pipefail
85
+ set -e # Re-enable exit-on-error
86
+
87
+ echo " Runner stdout/stderr saved to $RUNNER_STDOUT_FILE "
88
+ echo " Runner exited with code: $RUNNER_EXIT_CODE "
89
+
90
+ # --- Execute Stats or Generate Fallback JSON ---
91
+ STATS_EXIT_CODE=0
92
+ if [ -f " $XSPACE_FILE_PATH " ] && [ $RUNNER_EXIT_CODE -eq 0 ]; then
93
+ echo " Running compute_xspace_stats_main..."
94
+ STATS_PLATFORM_TYPE=$( [[ " $HARDWARE_CATEGORY " == GPU* ]] && echo " GPU" || echo " CPU" )
95
+ declare -a stats_command_array=(" $STATS_BINARY " " --input=$XSPACE_FILE_PATH " " --device_type=$STATS_PLATFORM_TYPE " " --output_json=$RESULTS_JSON_FILE " )
96
+
97
+ echo " Executing Stats command:" ; printf " %q " " ${stats_command_array[@]} " ; echo
98
+
99
+ set +e # Disable exit-on-error temporarily
100
+ " ${stats_command_array[@]} " >> " $RUNNER_STDOUT_FILE " # Append stats stdout to runner log
101
+ STATS_EXIT_CODE=$?
102
+ set -e # Re-enable
103
+
104
+ if [ $STATS_EXIT_CODE -ne 0 ]; then
105
+ echo " ::warning::compute_xspace_stats_main failed with code $STATS_EXIT_CODE ."
106
+ # Fallback to creating JSON with run status and error message for stats failure
107
+ jq -n \
108
+ --arg bn " $BENCHMARK_NAME " --arg cid " $CONFIG_ID " --arg hc " $HARDWARE_CATEGORY " \
109
+ --arg rs " STATS_FAILURE" \
110
+ --arg em " compute_xspace_stats_main failed with code $STATS_EXIT_CODE . Runner was successful." \
111
+ --arg cs " $COMMIT_SHA " --arg wrid " $WORKFLOW_RUN_ID " \
112
+ ' { benchmark_name: $bn, config_id: $cid, hardware_category: $hc, run_status: $rs, error_message: $em, commit_sha: $cs, workflow_run_id: $wrid }' \
113
+ > " $RESULTS_JSON_FILE "
114
+ echo " Fallback results JSON created at $RESULTS_JSON_FILE due to stats failure."
115
+ else
116
+ echo " Stats computed and saved to $RESULTS_JSON_FILE "
117
+ fi
118
+ else
119
+ # Create fallback JSON if Runner failed OR if Runner succeeded but produced no XSpace file
120
+ if [ $RUNNER_EXIT_CODE -ne 0 ]; then
121
+ echo " ::warning::Runner failed (Exit Code: $RUNNER_EXIT_CODE ), skipping stats."
122
+ else
123
+ echo " ::warning::XSpace file missing at $XSPACE_FILE_PATH , skipping stats."
124
+ fi
125
+
126
+ RUN_STATUS=$( [ $RUNNER_EXIT_CODE -eq 0 ] && echo " SUCCESS_NO_PROFILE" || echo " FAILURE" )
127
+ ERROR_MSG=$( [ $RUNNER_EXIT_CODE -ne 0 ] && echo " Runner failed with code $RUNNER_EXIT_CODE " || echo " XSpace file not generated by successful run." )
128
+
129
+ jq -n \
130
+ --arg bn " $BENCHMARK_NAME " --arg cid " $CONFIG_ID " --arg hc " $HARDWARE_CATEGORY " \
131
+ --arg rs " $RUN_STATUS " --arg em " $ERROR_MSG " \
132
+ --arg cs " $COMMIT_SHA " --arg wrid " $WORKFLOW_RUN_ID " \
133
+ ' { benchmark_name: $bn, config_id: $cid, hardware_category: $hc, run_status: $rs, error_message: $em, commit_sha: $cs, workflow_run_id: $wrid }' \
134
+ > " $RESULTS_JSON_FILE "
135
+
136
+ if [ $? -eq 0 ]; then
137
+ echo " Basic results JSON created at $RESULTS_JSON_FILE ."
138
+ else
139
+ # Should not happen if jq is present, but a safety-net
140
+ echo " ::error::FATAL: Failed to create basic results JSON using jq."
141
+ echo " Fallback error: Benchmark Name: $BENCHMARK_NAME , Run Status: $RUN_STATUS , Error: $ERROR_MSG " > " $RESULTS_JSON_FILE .txt"
142
+ exit 1 # Make sure this failure is noted
143
+ fi
144
+ fi
145
+
146
+ # --- Final Exit Status ---
147
+ if [ $RUNNER_EXIT_CODE -ne 0 ]; then
148
+ echo " ::error::Benchmark run failed (Runner Exit Code: $RUNNER_EXIT_CODE )."
149
+ exit $RUNNER_EXIT_CODE # Propagate the runner's failure code
150
+ fi
151
+
152
+ echo " --- Run Benchmark Script Finished Successfully ---"
0 commit comments