Skip to content

perf(stft): optimize FFT with table-based transforms and memory pooling #44

perf(stft): optimize FFT with table-based transforms and memory pooling

perf(stft): optimize FFT with table-based transforms and memory pooling #44

Workflow file for this run

name: CI
on:
push:
branches: [main, master]
paths:
- '**/*.cpp'
- '**/*.h'
- '**/*.hpp'
- '**/CMakeLists.txt'
- '.github/workflows/**'
pull_request:
types: [opened, synchronize, reopened]
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
cancel-in-progress: true
env:
# HuggingFace model info (Mel-Band)
HF_MB_REPO: GaboxR67/MelBandRoformers
HF_MB_CHECKPOINT: melbandroformers/vocals/voc_fv6.ckpt
HF_MB_CONFIG: melbandroformers/vocals/voc_gabox.yaml
# BS Roformer model info
HF_BS_REPO: anvuew/BS-RoFormer
HF_BS_CHECKPOINT: bs_roformer_anvuew_sdr_12.45.ckpt
HF_BS_CONFIG: config.yaml
# Music-Source-Separation-Training repo
MSST_REPO: https://github.com/ZFTurbo/Music-Source-Separation-Training.git
# Enable sccache GitHub Actions cache
SCCACHE_GHA_ENABLED: "true"
jobs:
# ===========================================================================
# Prepare: Generate test data (runs once, shared via artifacts)
# ===========================================================================
prepare-test-data:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Clone MSST Repository
run: git clone --depth 1 ${{ env.MSST_REPO }} msst
- name: Install Dependencies
run: |
pip install torch torchaudio --index-url https://download.pytorch.org/whl/cpu
pip install huggingface_hub scipy soundfile gguf librosa ml_collections einops pyyaml numpy tqdm beartype rotary_embedding_torch
- name: Download Model from HuggingFace
env:
HF_TOKEN: ${{ secrets.HF_TOKEN }}
run: |
python -c "
from huggingface_hub import hf_hub_download
import os
token = os.environ.get('HF_TOKEN') or None
# Download Mel-Band Roformer
hf_hub_download('${{ env.HF_MB_REPO }}', '${{ env.HF_MB_CHECKPOINT }}',
local_dir='./model', token=token)
hf_hub_download('${{ env.HF_MB_REPO }}', '${{ env.HF_MB_CONFIG }}',
local_dir='./model', token=token)
# Download BS Roformer
hf_hub_download('${{ env.HF_BS_REPO }}', '${{ env.HF_BS_CHECKPOINT }}',
local_dir='./model_bs', token=token)
hf_hub_download('${{ env.HF_BS_REPO }}', '${{ env.HF_BS_CONFIG }}',
local_dir='./model_bs', token=token)
"
- name: Generate Test Audio
run: |
python scripts/generate_test_audio.py --output test_audio.wav --duration 5.0 --sample-rate 44100
- name: Generate Test Data
run: |
python scripts/generate_test_data.py \
--model-repo msst \
--audio test_audio.wav \
--checkpoint model/${{ env.HF_MB_CHECKPOINT }} \
--config model/${{ env.HF_MB_CONFIG }} \
--output test_data
- name: Convert Model to GGUF (Mel-Band)
run: |
python scripts/convert_to_gguf.py \
--ckpt model/${{ env.HF_MB_CHECKPOINT }} \
--config model/${{ env.HF_MB_CONFIG }} \
--out model.gguf \
--dtype fp32
# ----- BS Roformer Setup -----
- name: Generate Test Data (BS)
run: |
# Need to make sure msst is in python path
export PYTHONPATH=$PYTHONPATH:$(pwd)/msst
# Use real BS model
python scripts/generate_test_data.py \
--model-repo msst \
--audio test_audio.wav \
--checkpoint model_bs/${{ env.HF_BS_CHECKPOINT }} \
--config model_bs/${{ env.HF_BS_CONFIG }} \
--output test_data_bs
- name: Convert Model to GGUF (BS)
run: |
python scripts/convert_to_gguf.py \
--ckpt model_bs/${{ env.HF_BS_CHECKPOINT }} \
--config model_bs/${{ env.HF_BS_CONFIG }} \
--out model_bs.gguf \
--dtype fp32 \
--arch bs
- name: Upload Test Data Artifact
uses: actions/upload-artifact@v4
with:
name: test-data
path: |
test_data/
model.gguf
test_audio.wav
test_data_bs/
model_bs.gguf
retention-days: 1
# ===========================================================================
# Build Matrix: Core Platforms + Vulkan
# ===========================================================================
build:
needs: prepare-test-data
strategy:
fail-fast: false
matrix:
include:
# Tier 1: Core Platforms (CPU)
- { name: linux-x64-cpu, os: ubuntu-22.04, backend: cpu, test: true }
- { name: linux-arm64-cpu, os: ubuntu-22.04-arm, backend: cpu, test: true }
- { name: macos-arm64, os: macos-latest, backend: cpu, test: true }
- { name: macos-x64, os: macos-15-intel, backend: cpu, test: true }
- { name: windows-x64-msvc, os: windows-2025, backend: cpu, test: true }
# Tier 2: Vulkan Backend
- { name: linux-vulkan, os: ubuntu-24.04, backend: vulkan, test: true }
- { name: windows-vulkan, os: windows-2025, backend: vulkan, test: true }
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Clone GGML
run: git clone --depth 1 https://github.com/ggerganov/ggml.git ggml
- name: Download Test Data
uses: actions/download-artifact@v4
with:
name: test-data
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Setup MSVC
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1
- name: Install Python Dependencies
run: pip install numpy scipy
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.9
with:
version: "v0.12.0"
# ----- Linux Dependencies -----
- name: Install Dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake
- name: Install Vulkan SDK (Linux)
if: matrix.backend == 'vulkan' && runner.os == 'Linux'
run: |
sudo apt-get install -y libvulkan-dev glslc mesa-vulkan-drivers
# ----- macOS Dependencies -----
- name: Install Dependencies (macOS)
if: runner.os == 'macOS'
run: brew install cmake
# ----- Windows Dependencies -----
- name: Install Dependencies (Windows)
if: runner.os == 'Windows'
run: choco install ninja -y
- name: Install Vulkan SDK (Windows)
if: matrix.backend == 'vulkan' && runner.os == 'Windows'
run: |
$VK_VERSION = "1.4.313.2"
curl.exe -o VulkanSDK.exe -L "https://sdk.lunarg.com/sdk/download/${VK_VERSION}/windows/vulkansdk-windows-X64-${VK_VERSION}.exe"
Start-Process -FilePath .\VulkanSDK.exe -ArgumentList "--accept-licenses --default-answer --confirm-command install" -Wait
Add-Content $env:GITHUB_ENV "VULKAN_SDK=C:\VulkanSDK\${VK_VERSION}"
Add-Content $env:GITHUB_PATH "C:\VulkanSDK\${VK_VERSION}\bin"
# ----- Configure -----
- name: Configure (Unix)
if: runner.os != 'Windows'
run: |
cmake -B build \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_DIR=ggml \
-DGGML_CUDA=OFF \
-DGGML_VULKAN=${{ matrix.backend == 'vulkan' && 'ON' || 'OFF' }} \
-DCMAKE_C_COMPILER_LAUNCHER=sccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache \
-DMBR_BUILD_TESTS=ON \
-DMBR_BUILD_CLI=ON
- name: Configure (Windows)
if: runner.os == 'Windows'
run: |
cmake -B build -G "Ninja Multi-Config" `
-DGGML_DIR=ggml `
-DGGML_CUDA=OFF `
-DGGML_VULKAN=${{ matrix.backend == 'vulkan' && 'ON' || 'OFF' }} `
-DCMAKE_C_COMPILER_LAUNCHER=sccache `
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache `
-DMBR_BUILD_TESTS=ON `
-DMBR_BUILD_CLI=ON
# ----- Build -----
- name: Build (Unix)
if: runner.os != 'Windows'
run: cmake --build build --config Release -j $(nproc 2>/dev/null || sysctl -n hw.logicalcpu)
- name: Build (Windows)
if: runner.os == 'Windows'
run: cmake --build build --config Release -j $env:NUMBER_OF_PROCESSORS
# ----- Unit Tests -----
- name: Run Unit Tests
if: matrix.test
env:
MBR_MODEL_PATH: ${{ github.workspace }}/model.gguf
MBR_TEST_DATA_DIR: ${{ github.workspace }}/test_data
MBR_FORCE_CPU: ${{ runner.os == 'macOS' && '1' || '' }}
run: ctest --test-dir build -C Release -V --output-on-failure --timeout 300
- name: Run Unit Tests (BS Roformer)
if: matrix.test
env:
MBR_MODEL_PATH: ${{ github.workspace }}/model_bs.gguf
MBR_TEST_DATA_DIR: ${{ github.workspace }}/test_data_bs
MBR_ARCHITECTURE: bs
MBR_FORCE_CPU: ${{ runner.os == 'macOS' && '1' || '' }}
run: ctest --test-dir build -C Release -V --output-on-failure --timeout 300
# ----- CLI Tests -----
- name: Test CLI
if: matrix.test
shell: bash
env:
MBR_MODEL_PATH: ${{ github.workspace }}/model.gguf
MBR_FORCE_CPU: ${{ runner.os == 'macOS' && '1' || '' }}
run: |
echo "=== CLI Test Suite ==="
# Dynamically find CLI executable
CLI_NAME="bs_roformer-cli"
if [[ "$RUNNER_OS" == "Windows" ]]; then CLI_NAME="bs_roformer-cli.exe"; fi
echo "Searching for $CLI_NAME..."
CLI_PATH=$(find build -name "$CLI_NAME" | head -n 1)
if [[ -z "$CLI_PATH" ]]; then
echo "Error: CLI executable not found!"
find build
exit 1
fi
echo "Found CLI at: $CLI_PATH"
chmod +x "$CLI_PATH"
# Setup execution variables
CLI_DIR=$(dirname "$CLI_PATH")
CLI_EXE="./$CLI_NAME"
# Debug Info
echo "Debug: Listing directory $CLI_DIR"
ls -l "$CLI_DIR"
echo "Debug: Checking dependencies"
if command -v ldd >/dev/null; then
ldd "$CLI_PATH" || echo "ldd returned error"
fi
# Define runner helper
run_cli() {
echo "Executing: ./$CLI_NAME $@"
(cd "$CLI_DIR" && ./$CLI_NAME "$@")
}
# Debug PATH
echo "PATH: $PATH"
# 1. Test --help
echo "[1/4] Testing --help..."
run_cli --help
# 2. Test with missing arguments (should fail)
echo "[2/4] Testing error handling..."
if run_cli 2>/dev/null; then
echo "ERROR: CLI should fail without arguments"
exit 1
fi
# 3. Use existing test audio
echo "[3/4] Using generated test audio..."
cp test_audio.wav cli_test_input.wav
# 4. Run full inference
echo "[4/4] Running inference..."
# Use absolute paths for input/output to avoid directory issues
ABS_MODEL=$(readlink -f "$MBR_MODEL_PATH" || echo "$(pwd)/model.gguf")
ABS_INPUT=$(readlink -f cli_test_input.wav || echo "$(pwd)/cli_test_input.wav")
ABS_OUTPUT=$(readlink -f cli_test_output.wav || echo "$(pwd)/cli_test_output.wav")
# Convert paths for Windows MSVC executables
if [[ "$RUNNER_OS" == "Windows" ]]; then
ABS_MODEL=$(cygpath -w "$ABS_MODEL")
ABS_INPUT=$(cygpath -w "$ABS_INPUT")
ABS_OUTPUT=$(cygpath -w "$ABS_OUTPUT")
fi
echo "Running with model: $ABS_MODEL"
run_cli "$ABS_MODEL" "$ABS_INPUT" "$ABS_OUTPUT" --chunk-size 88200 --overlap 2
# Verify output exists and has reasonable size
if [[ ! -f cli_test_output.wav ]]; then
echo "ERROR: Output file not created"
exit 1
fi
OUTPUT_SIZE=$(stat -c%s cli_test_output.wav 2>/dev/null || stat -f%z cli_test_output.wav)
if [[ $OUTPUT_SIZE -lt 1000 ]]; then
echo "ERROR: Output file too small: $OUTPUT_SIZE bytes"
exit 1
fi
echo "=== CLI Tests Passed ==="
# ----- Upload Artifacts -----
- name: Upload Build Artifacts
uses: actions/upload-artifact@v4
with:
name: build-${{ matrix.name }}
path: |
build/bin/
build/lib*/
build/*.dll
build/*.so
build/*.dylib
build/bs_roformer-cli*
build/Release/
retention-days: 7
# ----- Prepare Release Artifact -----
- name: Prepare Release Artifact (Unix)
if: runner.os != 'Windows'
shell: bash
run: |
# Create release directory
mkdir -p release/mel-band-roformer
# Find and copy CLI executable
CLI_PATH=$(find build -name "bs_roformer-cli" -type f | head -n 1)
if [[ -n "$CLI_PATH" ]]; then
cp "$CLI_PATH" release/mel-band-roformer/
chmod +x release/mel-band-roformer/bs_roformer-cli
fi
# Copy shared libraries if exist (only real files, not symlinks)
find build \( -name "*.so*" -o -name "*.dylib" \) -type f ! -type l | while read lib; do
cp "$lib" release/mel-band-roformer/ 2>/dev/null || true
done
# List contents
echo "Release artifact contents:"
ls -lh release/mel-band-roformer/
- name: Prepare Release Artifact (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
# Create release directory
New-Item -ItemType Directory -Force -Path "release\mel-band-roformer"
# Find and copy CLI executable
$CliPath = Get-ChildItem -Path build -Filter "bs_roformer-cli.exe" -Recurse -File | Select-Object -First 1
if ($CliPath) {
Copy-Item $CliPath.FullName "release\mel-band-roformer\"
}
# Copy DLL files
Get-ChildItem -Path build -Filter "*.dll" -Recurse -File | ForEach-Object {
Copy-Item $_.FullName "release\mel-band-roformer\" -ErrorAction SilentlyContinue
}
# List contents
Write-Host "Release artifact contents:"
Get-ChildItem "release\mel-band-roformer" | Format-Table Name, Length
- name: Upload Release Artifact
uses: actions/upload-artifact@v4
with:
name: BSRoformer-${{ matrix.name }}
path: release/mel-band-roformer/
retention-days: 30
# ===========================================================================
# CUDA Build: Linux (Compile Verification Only)
# ===========================================================================
build-cuda-linux:
name: build-cuda-linux-${{ matrix.cuda_version }}
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- { cuda_version: "11.8.0", os: ubuntu-22.04 }
- { cuda_version: "12.9.1", os: ubuntu-latest }
- { cuda_version: "13.1.0", os: ubuntu-latest }
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Clone GGML
run: git clone --depth 1 https://github.com/ggerganov/ggml.git ggml
- name: Install CUDA Toolkit
uses: Jimver/cuda-toolkit@master
with:
cuda: ${{ matrix.cuda_version }}
method: network
sub-packages: '["nvcc", "cudart", "thrust"]'
non-cuda-sub-packages: '["libcublas", "libcublas-dev"]'
- name: Install Dependencies
run: |
sudo apt-get install -y cmake build-essential ninja-build
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.9
- name: Configure
run: |
ls -ld ggml
# Minimal architectures for compile verification
# Just verify compilation works, not for distribution
CUDA_ARCHS="75;86"
echo "Verifying build for CUDA architectures: $CUDA_ARCHS"
cmake -B build -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
-DGGML_DIR=ggml \
-DGGML_CUDA=ON \
-DGGML_CUDA_FORCE_MMQ=ON \
-DCMAKE_CUDA_ARCHITECTURES="$CUDA_ARCHS" \
-DCMAKE_C_COMPILER_LAUNCHER=sccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache \
-DCMAKE_CUDA_COMPILER_LAUNCHER=sccache \
-DMBR_BUILD_TESTS=OFF \
-DMBR_BUILD_CLI=ON
- name: Build
run: cmake --build build --config Release -j $(nproc)
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: build-linux-cuda-${{ matrix.cuda_version }}
path: |
build/bin/
build/lib*/
build/*.so
retention-days: 7
# ----- Prepare Release Artifact -----
- name: Prepare Release Artifact
run: |
# Create release directory
mkdir -p release/mel-band-roformer
# Find and copy CLI executable
CLI_PATH=$(find build -name "bs_roformer-cli" -type f | head -n 1)
if [[ -n "$CLI_PATH" ]]; then
cp "$CLI_PATH" release/mel-band-roformer/
chmod +x release/mel-band-roformer/bs_roformer-cli
fi
# Copy shared libraries
find build -name "*.so*" | while read lib; do
cp "$lib" release/mel-band-roformer/ 2>/dev/null || true
done
# List contents
echo "Release artifact contents:"
ls -lh release/mel-band-roformer/
- name: Upload Release Artifact
uses: actions/upload-artifact@v4
with:
name: BSRoformer-linux-cuda-${{ matrix.cuda_version }}
path: release/mel-band-roformer/
retention-days: 30
# ===========================================================================
# CUDA Build: Windows (Compile Only - No GPU for testing)
# ===========================================================================
build-cuda-windows:
name: build-cuda-windows-${{ matrix.cuda_version }}
runs-on: windows-2022
strategy:
fail-fast: false
matrix:
cuda_version: ["11.8.0", "12.9.1", "13.1.0"]
env:
CUDA_VERSION: ${{ matrix.cuda_version }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup MSVC
if: runner.os == 'Windows'
uses: ilammy/msvc-dev-cmd@v1
- name: Clone GGML
run: git clone --depth 1 https://github.com/ggerganov/ggml.git ggml
- name: Install CUDA Toolkit
if: ${{ matrix.cuda_version != '13.1.0' }}
uses: Jimver/cuda-toolkit@master
with:
cuda: ${{ matrix.cuda_version }}
method: network
sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "thrust", "visual_studio_integration"]'
- name: Install CUDA Toolkit(13.1.0)
if: ${{ matrix.cuda_version == '13.1.0' }}
uses: Jimver/cuda-toolkit@master
with:
cuda: ${{ matrix.cuda_version }}
method: network
sub-packages: '["nvcc", "cudart", "cublas", "cublas_dev", "nvrtc", "nvrtc_dev", "crt", "nvvm", "visual_studio_integration"]'
- name: Install Ninja
run: choco install ninja -y
- name: Setup sccache
uses: mozilla-actions/sccache-action@v0.0.9
- name: Configure and Build
shell: pwsh
run: |
# Consumer GPU architectures:
# 61=Pascal (GTX 10), 75=Turing (RTX 20/GTX 16), 86=Ampere (RTX 30), 89=Ada (RTX 40), 120=Blackwell (RTX 50)
$cudaVersion = "${{ matrix.cuda_version }}"
if ($cudaVersion -match "^11\.") {
# CUDA 11.x: Support Pascal (61) to Ada (89)
$cudaArchs = "61;75;86;89"
$env:CUDAFLAGS = "-allow-unsupported-compiler -D_ALLOW_COMPILER_AND_STL_VERSION_MISMATCH -D_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR"
} elseif ($cudaVersion -match "^12\.") {
# CUDA 12.x: Support Pascal (61) to Blackwell (120) (technically 120 needs 12.8+, keeping unified for now or simple)
# Actually 12.x still supports Pascal.
$cudaArchs = "61;75;86;89"
$env:CUDAFLAGS = ""
} else {
# CUDA 13+: Drop Pascal (61). Support Turing (75) to Blackwell (120)
$cudaArchs = "75;86;89;120"
$env:CUDAFLAGS = ""
}
Write-Host "Building for CUDA architectures: $cudaArchs"
cmake -B build -G "Ninja Multi-Config" `
-DGGML_DIR=ggml `
-DGGML_CUDA=ON `
-DGGML_CUDA_FORCE_MMQ=ON `
"-DCMAKE_CUDA_ARCHITECTURES=$cudaArchs" `
-DCMAKE_C_COMPILER_LAUNCHER=sccache `
-DCMAKE_CXX_COMPILER_LAUNCHER=sccache `
-DMBR_BUILD_TESTS=OFF `
-DMBR_BUILD_CLI=ON
cmake --build build --config Release -j $env:NUMBER_OF_PROCESSORS
- name: Upload Artifacts
uses: actions/upload-artifact@v4
with:
name: build-windows-cuda-${{ matrix.cuda_version }}
path: |
build/bin/
build/Release/
build/*.dll
retention-days: 7
# ----- Prepare Release Artifact -----
- name: Prepare Release Artifact
shell: pwsh
run: |
# Create release directory
New-Item -ItemType Directory -Force -Path "release\mel-band-roformer"
# Find and copy CLI executable
$CliPath = Get-ChildItem -Path build -Filter "bs_roformer-cli.exe" -Recurse -File | Select-Object -First 1
if ($CliPath) {
Copy-Item $CliPath.FullName "release\mel-band-roformer\"
}
# Copy DLL files
Get-ChildItem -Path build -Filter "*.dll" -Recurse -File | ForEach-Object {
Copy-Item $_.FullName "release\mel-band-roformer\" -ErrorAction SilentlyContinue
}
# List contents
Write-Host "Release artifact contents:"
Get-ChildItem "release\mel-band-roformer" | Format-Table Name, Length
- name: Upload Release Artifact
uses: actions/upload-artifact@v4
with:
name: BSRoformer-windows-cuda-${{ matrix.cuda_version }}
path: release\mel-band-roformer\
retention-days: 30