Skip to content

Commit 4aae433

Browse files
kiritigowdaclaude
andcommitted
Run both benchmarks on same runner and fix comparison report
- Restructure CI from matrix strategy to single job so both Khronos and MIVisionX benchmarks run on identical hardware - Fix speedup direction: now shows how much faster AMD is vs sample (e.g., 154x instead of 0.01x) - Add system info section with hardware match verification - Add explanatory note for speedup column interpretation Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
1 parent aecb5d8 commit 4aae433

2 files changed

Lines changed: 133 additions & 75 deletions

File tree

.github/workflows/ci.yml

Lines changed: 70 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -7,33 +7,9 @@ on:
77
branches: [main]
88

99
jobs:
10-
build-and-test:
10+
benchmark:
1111
runs-on: ubuntu-latest
12-
13-
strategy:
14-
fail-fast: false
15-
matrix:
16-
include:
17-
- name: khronos-sample
18-
build_openvx: |
19-
git clone --recursive --depth 1 https://github.com/KhronosGroup/OpenVX-sample-impl.git /tmp/openvx
20-
cd /tmp/openvx
21-
python Build.py --os=Linux --arch=64 --conf=Release
22-
openvx_includes: /tmp/openvx/api-docs/include
23-
find_libs: true
24-
25-
- name: mivisionx-cpu
26-
build_openvx: |
27-
git clone --depth 1 https://github.com/ROCm/MIVisionX.git /tmp/openvx
28-
cd /tmp/openvx && mkdir build && cd build
29-
cmake -DBACKEND=CPU -DNEURAL_NET=OFF -DLOOM=OFF -DMIGRAPHX=OFF \
30-
-DCMAKE_INSTALL_PREFIX=/tmp/openvx/install ..
31-
make -j$(nproc)
32-
make install
33-
openvx_includes: /tmp/openvx/install/include/mivisionx
34-
find_libs: true
35-
36-
name: ${{ matrix.name }}
12+
name: Build, Benchmark & Compare
3713

3814
steps:
3915
- name: Checkout openvx-mark
@@ -42,76 +18,106 @@ jobs:
4218
- name: Install dependencies
4319
run: sudo apt-get update && sudo apt-get install -y cmake build-essential
4420

45-
- name: Build OpenVX implementation
46-
run: ${{ matrix.build_openvx }}
21+
# --- Khronos Sample Implementation ---
22+
- name: Build Khronos OpenVX sample
23+
run: |
24+
git clone --recursive --depth 1 https://github.com/KhronosGroup/OpenVX-sample-impl.git /tmp/openvx-khronos
25+
cd /tmp/openvx-khronos
26+
python Build.py --os=Linux --arch=64 --conf=Release
4727
48-
- name: Find OpenVX libraries
49-
id: openvx
28+
- name: Find Khronos libraries
29+
id: khronos
5030
run: |
51-
LIB_DIR=$(dirname $(find /tmp/openvx -name "libopenvx.so" -not -path "*/build/*" | head -1))
31+
LIB_DIR=$(dirname $(find /tmp/openvx-khronos -name "libopenvx.so" -not -path "*/build/*" | head -1))
5232
echo "lib_dir=$LIB_DIR" >> "$GITHUB_OUTPUT"
53-
echo "Found OpenVX libraries in: $LIB_DIR"
33+
echo "Found Khronos libraries in: $LIB_DIR"
5434
ls -la "$LIB_DIR"/libopenvx* "$LIB_DIR"/libvxu* 2>/dev/null || true
5535
56-
- name: Build openvx-mark
36+
- name: Build openvx-mark (Khronos)
5737
run: |
58-
mkdir build && cd build
59-
cmake -DOPENVX_INCLUDES=${{ matrix.openvx_includes }} \
60-
-DOPENVX_LIB_DIR=${{ steps.openvx.outputs.lib_dir }} ..
38+
mkdir build-khronos && cd build-khronos
39+
cmake -DOPENVX_INCLUDES=/tmp/openvx-khronos/api-docs/include \
40+
-DOPENVX_LIB_DIR=${{ steps.khronos.outputs.lib_dir }} ..
6141
cmake --build . -j$(nproc)
6242
63-
- name: Run openvx-mark
43+
- name: Run benchmark (Khronos)
6444
run: |
65-
cd build
66-
export LD_LIBRARY_PATH=${{ steps.openvx.outputs.lib_dir }}:$LD_LIBRARY_PATH
45+
cd build-khronos
46+
export LD_LIBRARY_PATH=${{ steps.khronos.outputs.lib_dir }}:$LD_LIBRARY_PATH
6747
./openvx-mark --resolution VGA --iterations 10 --warmup 3
6848
69-
- name: Upload benchmark results
70-
if: always()
71-
uses: actions/upload-artifact@v4
72-
with:
73-
name: benchmark-results-${{ matrix.name }}
74-
path: build/benchmark_results/
75-
if-no-files-found: ignore
76-
77-
compare:
78-
runs-on: ubuntu-latest
79-
needs: build-and-test
80-
if: always() && !cancelled()
49+
# --- MIVisionX (AMD OpenVX) ---
50+
- name: Build MIVisionX (CPU backend)
51+
run: |
52+
git clone --depth 1 https://github.com/ROCm/MIVisionX.git /tmp/openvx-mivisionx
53+
cd /tmp/openvx-mivisionx && mkdir build && cd build
54+
cmake -DBACKEND=CPU -DNEURAL_NET=OFF -DLOOM=OFF -DMIGRAPHX=OFF \
55+
-DCMAKE_INSTALL_PREFIX=/tmp/openvx-mivisionx/install ..
56+
make -j$(nproc)
57+
make install
58+
59+
- name: Find MIVisionX libraries
60+
id: mivisionx
61+
run: |
62+
LIB_DIR=$(dirname $(find /tmp/openvx-mivisionx -name "libopenvx.so" -not -path "*/build/*" | head -1))
63+
echo "lib_dir=$LIB_DIR" >> "$GITHUB_OUTPUT"
64+
echo "Found MIVisionX libraries in: $LIB_DIR"
65+
ls -la "$LIB_DIR"/libopenvx* "$LIB_DIR"/libvxu* 2>/dev/null || true
8166
82-
steps:
83-
- name: Checkout openvx-mark
84-
uses: actions/checkout@v4
67+
- name: Build openvx-mark (MIVisionX)
68+
run: |
69+
mkdir build-mivisionx && cd build-mivisionx
70+
cmake -DOPENVX_INCLUDES=/tmp/openvx-mivisionx/install/include/mivisionx \
71+
-DOPENVX_LIB_DIR=${{ steps.mivisionx.outputs.lib_dir }} ..
72+
cmake --build . -j$(nproc)
8573
86-
- name: Download all benchmark results
87-
uses: actions/download-artifact@v4
88-
with:
89-
path: artifacts/
74+
- name: Run benchmark (MIVisionX)
75+
run: |
76+
cd build-mivisionx
77+
export LD_LIBRARY_PATH=${{ steps.mivisionx.outputs.lib_dir }}:$LD_LIBRARY_PATH
78+
./openvx-mark --resolution VGA --iterations 10 --warmup 3
9079
80+
# --- Compare Results ---
9181
- name: Compare benchmark results
9282
run: |
93-
KHRONOS=artifacts/benchmark-results-khronos-sample/benchmark_results.json
94-
MIVISIONX=artifacts/benchmark-results-mivisionx-cpu/benchmark_results.json
83+
KHRONOS=build-khronos/benchmark_results/benchmark_results.json
84+
MIVISIONX=build-mivisionx/benchmark_results/benchmark_results.json
9585
9686
if [ ! -f "$KHRONOS" ] || [ ! -f "$MIVISIONX" ]; then
9787
echo "Skipping comparison — one or both benchmark results missing"
9888
exit 0
9989
fi
10090
10191
python3 scripts/compare_reports.py "$MIVISIONX" "$KHRONOS" \
102-
--output artifacts/comparison
92+
--output comparison
10393
10494
- name: Post comparison to job summary
10595
if: always()
10696
run: |
107-
if [ -f artifacts/comparison.md ]; then
108-
cat artifacts/comparison.md >> "$GITHUB_STEP_SUMMARY"
97+
if [ -f comparison.md ]; then
98+
cat comparison.md >> "$GITHUB_STEP_SUMMARY"
10999
fi
110100
101+
- name: Upload Khronos results
102+
if: always()
103+
uses: actions/upload-artifact@v4
104+
with:
105+
name: benchmark-results-khronos-sample
106+
path: build-khronos/benchmark_results/
107+
if-no-files-found: ignore
108+
109+
- name: Upload MIVisionX results
110+
if: always()
111+
uses: actions/upload-artifact@v4
112+
with:
113+
name: benchmark-results-mivisionx-cpu
114+
path: build-mivisionx/benchmark_results/
115+
if-no-files-found: ignore
116+
111117
- name: Upload comparison report
112118
if: always()
113119
uses: actions/upload-artifact@v4
114120
with:
115121
name: benchmark-comparison
116-
path: artifacts/comparison.*
122+
path: comparison.*
117123
if-no-files-found: ignore

scripts/compare_reports.py

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -57,14 +57,21 @@ def build_result_map(report):
5757
return result_map
5858

5959

60+
def get_system_info(report):
61+
"""Extract system info dict from a report."""
62+
return report.get('system', {})
63+
64+
6065
def compare(reports, paths):
6166
impl_names = []
6267
result_maps = []
68+
system_infos = []
6369

6470
for i, report in enumerate(reports):
6571
name = report.get('openvx', {}).get('implementation', os.path.basename(paths[i]))
6672
impl_names.append(name)
6773
result_maps.append(build_result_map(report))
74+
system_infos.append(get_system_info(report))
6875

6976
# Collect all unique benchmark keys
7077
all_keys = set()
@@ -73,21 +80,65 @@ def compare(reports, paths):
7380

7481
all_keys = sorted(all_keys)
7582

76-
return impl_names, result_maps, all_keys
83+
return impl_names, result_maps, all_keys, system_infos
84+
7785

86+
def format_ram(ram_value):
87+
"""Format RAM value from report (may be gb float or bytes int)."""
88+
if isinstance(ram_value, (int,)) and ram_value > 1e9:
89+
return f'{ram_value / (1024**3):.1f} GB'
90+
return f'{ram_value} GB'
7891

79-
def write_markdown(impl_names, result_maps, all_keys, output_path):
92+
93+
def write_markdown(impl_names, result_maps, all_keys, output_path, system_infos=None):
8094
with open(output_path + '.md', 'w') as f:
8195
f.write('# OpenVX Benchmark Comparison\n\n')
8296

83-
# System info table
97+
# Hardware / system info section
98+
if system_infos and len(system_infos) >= 2:
99+
hw_match = (system_infos[0].get('cpu_model') == system_infos[1].get('cpu_model')
100+
and system_infos[0].get('cpu_cores') == system_infos[1].get('cpu_cores'))
101+
102+
f.write('## System Info\n\n')
103+
if hw_match:
104+
si = system_infos[0]
105+
f.write(f'| Property | Value |\n')
106+
f.write(f'|:---|:---|\n')
107+
f.write(f'| CPU | {si.get("cpu_model", "N/A")} |\n')
108+
f.write(f'| Cores | {si.get("cpu_cores", "N/A")} |\n')
109+
f.write(f'| RAM | {format_ram(si.get("ram_gb", si.get("ram_bytes", "N/A")))} |\n')
110+
f.write(f'| OS | {si.get("os_name", "N/A")} {si.get("os_version", "")} |\n')
111+
f.write(f'\n> **Same hardware** — both benchmarks ran on identical hardware.\n\n')
112+
else:
113+
f.write(f'| Property |')
114+
for name in impl_names:
115+
f.write(f' {name} |')
116+
f.write('\n|:---|')
117+
for _ in impl_names:
118+
f.write(':---|')
119+
f.write('\n')
120+
for prop, key in [('CPU', 'cpu_model'), ('Cores', 'cpu_cores'),
121+
('OS', 'os_name')]:
122+
f.write(f'| {prop} |')
123+
for si in system_infos:
124+
f.write(f' {si.get(key, "N/A")} |')
125+
f.write('\n')
126+
f.write(f'\n> **Warning:** Benchmarks ran on different hardware — results may not be directly comparable.\n\n')
127+
128+
# Implementation table
84129
f.write('## Implementations\n\n')
85130
f.write('| # | Implementation |\n')
86131
f.write('|---|---|\n')
87132
for i, name in enumerate(impl_names):
88133
f.write(f'| {i+1} | {name} |\n')
89134
f.write('\n')
90135

136+
# Speedup label: first impl vs second
137+
if len(impl_names) >= 2:
138+
speedup_label = f'Speedup ({impl_names[0]} vs {impl_names[1]})'
139+
else:
140+
speedup_label = 'Speedup'
141+
91142
# Results table
92143
header = '| Benchmark | Mode | Resolution |'
93144
separator = '|:---|:---|:---|'
@@ -96,10 +147,11 @@ def write_markdown(impl_names, result_maps, all_keys, output_path):
96147
header += f' {short} (ms) | {short} (MP/s) |'
97148
separator += '---:|---:|'
98149

99-
header += ' Speedup |'
150+
header += f' Speedup |'
100151
separator += '---:|'
101152

102153
f.write('## Results\n\n')
154+
f.write(f'> Speedup = how much faster **{impl_names[0]}** is compared to **{impl_names[1]}** (higher is better)\n\n')
103155
f.write(header + '\n')
104156
f.write(separator + '\n')
105157

@@ -120,9 +172,9 @@ def write_markdown(impl_names, result_maps, all_keys, output_path):
120172
row += ' N/A | N/A |'
121173
medians.append(None)
122174

123-
# Speedup (first vs second, if both available)
124-
if len(medians) >= 2 and medians[0] and medians[1] and medians[1] > 0:
125-
speedup = medians[0] / medians[1]
175+
# Speedup: baseline (second) / candidate (first) — how much faster first is
176+
if len(medians) >= 2 and medians[0] and medians[1] and medians[0] > 0:
177+
speedup = medians[1] / medians[0]
126178
row += f' {speedup:.2f}x |'
127179
else:
128180
row += ' N/A |'
@@ -157,8 +209,8 @@ def write_csv(impl_names, result_maps, all_keys, output_path):
157209
row += ',,'
158210
medians.append(None)
159211

160-
if len(medians) >= 2 and medians[0] and medians[1] and medians[1] > 0:
161-
row += f',{medians[0]/medians[1]:.4f}'
212+
if len(medians) >= 2 and medians[0] and medians[1] and medians[0] > 0:
213+
row += f',{medians[1]/medians[0]:.4f}'
162214
else:
163215
row += ','
164216

@@ -184,9 +236,9 @@ def main():
184236
sys.exit(1)
185237
reports.append(load_report(path))
186238

187-
impl_names, result_maps, all_keys = compare(reports, args.reports)
239+
impl_names, result_maps, all_keys, system_infos = compare(reports, args.reports)
188240

189-
write_markdown(impl_names, result_maps, all_keys, args.output)
241+
write_markdown(impl_names, result_maps, all_keys, args.output, system_infos)
190242
write_csv(impl_names, result_maps, all_keys, args.output)
191243

192244
print(f'\nCompared {len(args.reports)} implementations across {len(all_keys)} benchmarks')

0 commit comments

Comments
 (0)