Skip to content

Add BGL vecS/vecS eps=1e-6 curve to runtime benchmark & plots #10

Add BGL vecS/vecS eps=1e-6 curve to runtime benchmark & plots

Add BGL vecS/vecS eps=1e-6 curve to runtime benchmark & plots #10

Workflow file for this run

name: Louvain Benchmark
on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
workflow_dispatch:
concurrency:
group: benchmark-${{ github.ref }}
cancel-in-progress: true
permissions:
contents: write
# ─────────────────────────────────────────────────────────────────────────
# Job graph:
# build ──► correctness ─┐
# ├► runtime (×4) ─┤ (small, medium, 100k-lfr, 100k-scalefree)
# ├► incremental ─┤
# └► epsilon ─┴──► visualize (merge + plot + commit)
# ─────────────────────────────────────────────────────────────────────────
jobs:
# ══════════════════════════════════════════════════════════════════════
# 1. Build all C++ binaries and upload as artifact
# ══════════════════════════════════════════════════════════════════════
build:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: Clone Boost.Graph fork
run: |
git clone --depth 1 --branch feature/louvain-algorithm \
https://github.com/Becheler/graph.git \
${{ github.workspace }}/bgl-fork
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
cmake build-essential libboost-all-dev curl
- name: Prepare gen-louvain source
working-directory: louvain/vendor/gen-louvain
run: bash build.sh
continue-on-error: true
- name: Build all C++ binaries
working-directory: louvain
run: |
mkdir -p build
cd build
cmake ../src \
-DCMAKE_BUILD_TYPE=Release \
-DBGL_GRAPH_INCLUDE=${{ github.workspace }}/bgl-fork/include \
-Wno-dev
cmake --build . -j$(nproc)
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: louvain-build
path: louvain/build/
retention-days: 1
# ══════════════════════════════════════════════════════════════════════
# 2a. Non-runtime benchmarks in parallel
# ══════════════════════════════════════════════════════════════════════
benchmark:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 180
strategy:
fail-fast: false
matrix:
suite: [correctness, incremental, epsilon]
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Python dependencies
working-directory: louvain
run: |
python -m pip install --upgrade pip
pip install -r ../requirements-common.txt -r requirements.txt
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: louvain-build
path: louvain/build/
- name: Make binaries executable
run: chmod +x louvain/build/*
- name: Run ${{ matrix.suite }} benchmark
working-directory: louvain
run: |
mkdir -p results
python scripts/benchmark.py --only ${{ matrix.suite }}
- name: Upload ${{ matrix.suite }} results
uses: actions/upload-artifact@v4
if: always()
with:
name: results-${{ matrix.suite }}
path: louvain/results/*.csv
retention-days: 30
# ══════════════════════════════════════════════════════════════════════
# 2b. Runtime benchmark split by graph size
# ══════════════════════════════════════════════════════════════════════
runtime:
needs: build
runs-on: ubuntu-latest
timeout-minutes: 180
strategy:
fail-fast: false
matrix:
include:
- chunk: small
sizes: "1000,5000"
graph_types: ""
- chunk: medium
sizes: "10000,50000"
graph_types: ""
- chunk: 100k-lfr
sizes: "100000"
graph_types: "LFR"
- chunk: 100k-scalefree
sizes: "100000"
graph_types: "ScaleFree"
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Python dependencies
working-directory: louvain
run: |
python -m pip install --upgrade pip
pip install -r ../requirements-common.txt -r requirements.txt
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: louvain-build
path: louvain/build/
- name: Make binaries executable
run: chmod +x louvain/build/*
- name: Run runtime benchmark (${{ matrix.chunk }})
working-directory: louvain
run: |
mkdir -p results
python scripts/benchmark.py --only runtime \
--sizes ${{ matrix.sizes }} \
--output-suffix _${{ matrix.chunk }} \
${{ matrix.graph_types != '' && format('--graph-types {0}', matrix.graph_types) || '' }}
- name: Upload runtime ${{ matrix.chunk }} results
uses: actions/upload-artifact@v4
if: always()
with:
name: results-runtime-${{ matrix.chunk }}
path: louvain/results/*.csv
retention-days: 30
# ══════════════════════════════════════════════════════════════════════
# 3. Merge results, generate plots, and commit
# ══════════════════════════════════════════════════════════════════════
visualize:
needs: [benchmark, runtime]
if: always()
runs-on: ubuntu-latest
timeout-minutes: 30
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Python dependencies
working-directory: louvain
run: |
python -m pip install --upgrade pip
pip install -r ../requirements-common.txt -r requirements.txt
# Download all benchmark CSVs into results/
- name: Download correctness results
uses: actions/download-artifact@v4
with:
name: results-correctness
path: louvain/results/
continue-on-error: true
- name: Download runtime (small) results
uses: actions/download-artifact@v4
with:
name: results-runtime-small
path: louvain/results/
continue-on-error: true
- name: Download runtime (medium) results
uses: actions/download-artifact@v4
with:
name: results-runtime-medium
path: louvain/results/
continue-on-error: true
- name: Download runtime (100k-lfr) results
uses: actions/download-artifact@v4
with:
name: results-runtime-100k-lfr
path: louvain/results/
continue-on-error: true
- name: Download runtime (100k-scalefree) results
uses: actions/download-artifact@v4
with:
name: results-runtime-100k-scalefree
path: louvain/results/
continue-on-error: true
- name: Download incremental results
uses: actions/download-artifact@v4
with:
name: results-incremental
path: louvain/results/
continue-on-error: true
- name: Download epsilon results
uses: actions/download-artifact@v4
with:
name: results-epsilon
path: louvain/results/
continue-on-error: true
- name: Merge runtime CSV chunks
working-directory: louvain
run: |
python -c "
import pandas as pd, glob, os
parts = sorted(glob.glob('results/runtime_*.csv'))
if parts:
df = pd.concat([pd.read_csv(p) for p in parts], ignore_index=True)
df.to_csv('results/runtime.csv', index=False)
print(f'Merged {len(parts)} runtime chunks into runtime.csv ({len(df)} rows)')
for p in parts:
os.remove(p)
elif os.path.exists('results/runtime.csv'):
print('runtime.csv already present, skipping merge')
else:
print('WARNING: no runtime CSVs found')
"
- name: Generate visualizations
working-directory: louvain
run: python scripts/visualize.py
continue-on-error: true
# compare_passes needs C++ binaries + fork headers to patch & rebuild
- name: Clone Boost.Graph fork
run: |
git clone --depth 1 --branch feature/louvain-algorithm \
https://github.com/Becheler/graph.git \
${{ github.workspace }}/bgl-fork
- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends \
cmake build-essential libboost-all-dev
- name: Download build artifacts
uses: actions/download-artifact@v4
with:
name: louvain-build
path: louvain/build/
- name: Make binaries executable
run: chmod +x louvain/build/*
- name: Generate cumulative dQ comparison
working-directory: louvain
env:
BGL_GRAPH_INCLUDE: ${{ github.workspace }}/bgl-fork/include
run: python scripts/compare_passes.py --nodes 10000 --seed 42
continue-on-error: true
# Commit everything back
- name: Commit updated results
if: github.event_name == 'push'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add louvain/results/*.csv louvain/results/*.png
git diff --staged --quiet || \
git commit -m "ci: update benchmark results [skip ci]" && \
git push
- name: Upload final results
uses: actions/upload-artifact@v4
if: always()
with:
name: benchmark-results
path: |
louvain/results/*.csv
louvain/results/*.png
retention-days: 30