Skip to content

benchmark_gpu_coprocessor #84

benchmark_gpu_coprocessor

benchmark_gpu_coprocessor #84

# Run all fhevm coprocessor benchmarks on a GPU instance on Hyperstack and return parsed results to Slab CI bot.
name: benchmark_gpu_coprocessor
on:
workflow_dispatch:
inputs:
profile:
description: "Instance type"
required: true
type: choice
options:
- "hyperstack::l40 (n3-L40x1)"
- "hyperstack::4-l40 (n3-L40x4)"
- "hyperstack::multi-a100-nvlink (n3-A100x8-NVLink)"
- "hyperstack::single-h100 (n3-H100x1)"
- "hyperstack::2-h100 (n3-H100x2)"
- "hyperstack::4-h100 (n3-H100x4)"
- "hyperstack::multi-h100 (n3-H100x8)"
- "hyperstack::multi-h100-nvlink (n3-H100x8-NVLink)"
- "hyperstack::multi-h100-sxm5 (n3-H100-SXM5x8)"
- "scaleway::multi-h100-sxm5 (H100-SXM-8-80G)"
- "scaleway::4-h100-sxm5 (H100-SXM-4-80G)"
- "scaleway::2-h100-sxm5 (H100-SXM-2-80G)"
- "scaleway::single-h100 (H100-1-80G)"
schedule:
# Weekly tests @ 1AM
- cron: "0 1 * * 6"
permissions:
contents: read
# zizmor: ignore[concurrency-limits] concurrency is managed after instance setup to ensure safe provisioning
env:
CARGO_TERM_COLOR: always
RESULTS_FILENAME: parsed_benchmark_results_${{ github.sha }}.json
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
RUST_BACKTRACE: "full"
RUST_MIN_STACK: "8388608"
CHECKOUT_TOKEN: ${{ secrets.REPO_CHECKOUT_TOKEN || secrets.GITHUB_TOKEN }}
PROFILE_SCHEDULED_RUN: "hyperstack::multi-h100-sxm5 (n3-H100-SXM5x8)"
PROFILE_MANUAL_RUN: ${{ inputs.profile }}
IS_MANUAL_RUN: ${{ github.event_name == 'workflow_dispatch' }}
BENCHMARK_TYPE: "ALL"
OPTIMIZATION_TARGET: "throughput"
BATCH_SIZE: "5000"
SCHEDULING_POLICY: "MAX_PARALLELISM"
BENCHMARKS: "erc20"
BRANCH_NAME: ${{ github.ref_name }}
COMMIT_SHA: ${{ github.sha }}
SLAB_SECRET: ${{ secrets.JOB_SECRET }}
jobs:
parse-inputs:
name: benchmark_gpu_coprocessor/parse-inputs
if: github.event_name == 'workflow_dispatch' ||
(github.event_name == 'schedule' && github.repository == 'zama-ai/tfhe-rs')
runs-on: ubuntu-latest
permissions:
contents: 'read'
outputs:
backend: ${{ steps.parse_profile.outputs.backend }}
profile: ${{ steps.parse_profile.outputs.profile }}
hardware_name: ${{ steps.parse_profile.outputs.hardware }}
cloud_provider: ${{ steps.parse_profile.outputs.cloud_provider }}
steps:
- name: Checkout tfhe-rs repo
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
persist-credentials: 'false'
token: ${{ env.CHECKOUT_TOKEN }}
- name: Parse profile and hardware name
id: parse_profile
run: |
if [[ ${IS_MANUAL_RUN} == true ]]; then
PROFILE_RAW="${PROFILE_MANUAL_RUN}"
else
PROFILE_RAW="${PROFILE_SCHEDULED_RUN}"
fi
python3 ci/parse_benchmark_profile.py "$PROFILE_RAW" "$GITHUB_OUTPUT"
setup-instance:
name: benchmark_gpu_coprocessor/setup-instance
needs: parse-inputs
runs-on: ubuntu-latest
permissions:
contents: 'read'
outputs:
runner-name: ${{ steps.start-remote-instance.outputs.label }}
steps:
- name: Start remote instance
id: start-remote-instance
uses: zama-ai/slab-github-runner@86c9d2378700ca356455e36ebb97b61e958ea47b # v1.6.2
with:
mode: start
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
backend: ${{ needs.parse-inputs.outputs.backend }}
profile: ${{ needs.parse-inputs.outputs.profile }}
benchmark-gpu:
name: benchmark_gpu_coprocessor/benchmark-gpu (bpr)
needs: [ parse-inputs, setup-instance ]
runs-on: ${{ needs.setup-instance.outputs.runner-name }}
continue-on-error: true
timeout-minutes: 720 # 12 hours
permissions:
contents: 'read' # Needed to read repositories contents
packages: 'read' # Needed to get fhevm packages
strategy:
fail-fast: false
# explicit include-based build matrix, of known valid options
matrix:
include:
- os: ubuntu-22.04
cuda: "12.8 12.2"
gcc: 12
env:
HW_NAME: "${{ needs.parse-inputs.outputs.hardware_name }}"
steps:
- name: Install git LFS
run: |
# Disable unattended-upgrades to avoid lock issues
sudo systemctl mask --now unattended-upgrades
sudo systemctl stop --now unattended-upgrades
sudo apt-get clean
sudo rm -rf /var/lib/apt/lists/*
sudo apt purge -y unattended-upgrades
sudo apt-get update
sudo apt-get install -y git-lfs protobuf-compiler
git lfs install
- name: Checkout tfhe-rs
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
persist-credentials: false
- name: Check fhEVM and TFHE-rs repos
run: |
pwd
ls
- name: Checkout fhevm
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
repository: zama-ai/fhevm
persist-credentials: 'false'
fetch-depth: 0
lfs: true
ref: antoniu/use-tfhe-main-benches
path: fhevm
- name: Get benchmark details
run: |
COMMIT_DATE_ENV=$(git --no-pager show -s --format=%cd --date=iso8601-strict "${COMMIT_SHA}")
{
echo "BENCH_DATE=$(date --iso-8601=seconds)";
echo "COMMIT_DATE=$COMMIT_DATE_ENV";
echo "COMMIT_HASH=$(git rev-parse HEAD)";
} >> "${GITHUB_ENV}"
- name: Setup cloud GPU machine dependencies
uses: ./.github/actions/gpu_setup
with:
cuda-version: ${{ matrix.cuda }}
gcc-version: ${{ matrix.gcc }}
cloud-provider: ${{ needs.parse-inputs.outputs.cloud_provider }}
# Disabled: this checked out a *fresh* tfhe-rs into the coprocessor. Instead we build
# the fhevm bench against the tfhe-rs already checked out at the workspace root (this
# CI branch), via a [patch.crates-io] applied later (see "Pin fhevm-engine to this
# branch's tfhe-rs"). tfhe-rs must stay at the root because the gpu_setup action
# resolves ci/*.sh relative to the workspace root. The patch is applied only after
# `init_db` so it does not leak into that step's Docker build (whose context does not
# contain the root tfhe-rs).
# - name: Checkout tfhe-rs in fhevm coprocessor
# uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
# with:
# path: fhevm/coprocessor/tfhe-rs
# persist-credentials: false
- name: Checkout LFS objects
run: git lfs checkout
working-directory: fhevm/
- name: Install rust
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # zizmor: ignore[stale-action-refs] this action doesn't create releases
with:
toolchain: nightly
- name: Install Safe-chain
run: |
make install_aikido_safe_chain_ci
- name: Install cargo dependencies
run: |
sudo apt-get install -y protobuf-compiler pkg-config libssl-dev \
libclang-dev acl
if ! command -v docker >/dev/null 2>&1; then
sudo apt-get install -y docker.io
fi
if ! docker compose version >/dev/null 2>&1; then
sudo apt-get install -y docker-compose-v2
fi
sudo usermod -aG docker "$USER"
newgrp docker
sudo setfacl --modify user:"$USER":rw /var/run/docker.sock
cargo install sqlx-cli --version=0.8.6 --locked
- name: Install foundry
uses: foundry-rs/foundry-toolchain@c7450ba673e133f5ee30098b3b54f444d3a2ca2d
- name: Cache cargo
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: ${{ runner.os }}-cargo-
- name: Login to GitHub Container Registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Login to Chainguard Registry
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4.2.0
with:
registry: cgr.dev
username: ${{ secrets.CGR_USERNAME }}
password: ${{ secrets.CGR_PASSWORD }}
- name: Init database
run: make init_db
working-directory: fhevm/coprocessor/fhevm-engine/tfhe-worker
- name: Use Node.js
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 20.x
- name: Build contracts
env:
HARDHAT_NETWORK: hardhat
run: |
ls
pwd
cp ./host-contracts/.env.example ./host-contracts/.env
cd ./host-contracts
npm ci --include=optional
npm install && npm run deploy:emptyProxies && npx hardhat compile
working-directory: fhevm/
- name: Pin fhevm-engine to this branch's tfhe-rs
run: |
# Applied here (after init_db) so it does not leak into init_db's Docker build,
# whose build context does not include the root tfhe-rs. Only the native
# `cargo bench` below needs to link this branch.
#
# fhevm pins `tfhe = "=1.6.2"` from crates.io, so a [patch.crates-io] only applies
# if the local crate reports that exact version. Make this checkout report it.
sed -i '0,/^version = "[^"]*"/ s//version = "1.6.2"/' tfhe/Cargo.toml
# Point fhevm-engine at this checked-out tfhe-rs (workspace root) so the bench
# builds this branch instead of the crates.io release.
{
printf '\n[patch.crates-io]\n'
printf 'tfhe = { path = "../../../tfhe" }\n'
} >> fhevm/coprocessor/fhevm-engine/Cargo.toml
- name: Profile erc20 no-cmux benchmark on GPU
run: |
export DATABASE_URL="postgres://postgres:postgres@127.0.0.1:5432/coprocessor"
export RUSTFLAGS="-C target-cpu=native"
export BENCHMARK_BATCH_SIZE="${BATCH_SIZE}"
export FHEVM_DF_SCHEDULE="${SCHEDULING_POLICY}"
export BENCHMARK_TYPE="THROUGHPUT_200"
export OPTIMIZATION_TARGET="${OPTIMIZATION_TARGET}"
#export FHEVM_TEST_NUM_SAMPLES=20
export RAYON_NUM_THREADS=32
export CUDA_DEVICE_MAX_CONNECTIONS=32
export CUDA_VISIBLE_DEVICES=0
cargo +nightly bench --no-run --bench erc20 --features=gpu-profile,bench,"${OPTIMIZATION_TARGET}" --
sudo -E env "PATH=$PATH" numactl --cpunodebind=0 --membind=0 \
nsys profile --trace=cuda,osrt,nvtx,openmp,oshmem --gpu-metrics-devices=all \
cargo +nightly bench --bench erc20 --features=gpu-profile,bench,"${OPTIMIZATION_TARGET}" -- 'throughput::whitepaper'
working-directory: fhevm/coprocessor/fhevm-engine/tfhe-worker
- name: Get nsys profile name
id: nsys_profile_name
run: echo "profile=coprocessor_profile_$(date +"%Y-%m-%d-%Hh").nsys-rep" >> "$GITHUB_OUTPUT"
- name: Timestamp nsys profile # zizmor: ignore[template-injection]
env:
REPORT_NAME: ${{ steps.nsys_profile_name.outputs.profile }}
run: |
mv report1.nsys-rep ${{ env.REPORT_NAME }}
working-directory: fhevm/coprocessor/fhevm-engine/tfhe-worker
- name: Upload profile artifact
env:
REPORT_NAME: ${{ steps.nsys_profile_name.outputs.profile }}
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ env.REPORT_NAME }}
path: fhevm/coprocessor/fhevm-engine/tfhe-worker/${{ env.REPORT_NAME }}
- name: Run latency benchmark on GPU
run: |
BENCHMARK_BATCH_SIZE="${BATCH_SIZE}" FHEVM_DF_SCHEDULE="${SCHEDULING_POLICY}" BENCHMARK_TYPE="LATENCY" OPTIMIZATION_TARGET="${OPTIMIZATION_TARGET}" make -e "benchmark_${BENCHMARKS}_gpu"
working-directory: fhevm/coprocessor/fhevm-engine/tfhe-worker
- name: Run throughput benchmarks on GPU
run: |
BENCHMARK_BATCH_SIZE="${BATCH_SIZE}" FHEVM_DF_SCHEDULE="${SCHEDULING_POLICY}" BENCHMARK_TYPE="THROUGHPUT_200" OPTIMIZATION_TARGET="${OPTIMIZATION_TARGET}" make -e "benchmark_${BENCHMARKS}_gpu"
working-directory: fhevm/coprocessor/fhevm-engine/tfhe-worker
- name: Parse results
run: |
cargo run --release -p tfhe-benchmark-parser -- -i "${GITHUB_WORKSPACE}/fhevm/coprocessor/fhevm-engine/target/criterion" -o "${RESULTS_FILENAME}" \
--database coprocessor \
--hardware "${HW_NAME}" \
--backend cuda \
--project-version "${COMMIT_HASH}" \
--branch "${BRANCH_NAME}" \
--commit-date "${COMMIT_DATE}" \
--bench-date "${BENCH_DATE}" \
--walk-subdirs \
--params-dir "${GITHUB_WORKSPACE}/fhevm/coprocessor/fhevm-engine/tfhe-worker" \
--name-suffix "operation_batch_size_${BATCH_SIZE}-schedule_${SCHEDULING_POLICY}-optimization_target_${OPTIMIZATION_TARGET}"
- name: Upload parsed results artifact
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a
with:
name: ${{ env.COMMIT_SHA }}_${{ env.BENCHMARKS }}_${{ needs.parse-inputs.outputs.profile }}
path: ${{ env.RESULTS_FILENAME }}
- name: Checkout Slab repo
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0
with:
repository: zama-ai/slab
path: slab
persist-credentials: 'false'
token: ${{ secrets.REPO_CHECKOUT_TOKEN }}
- name: Send data to Slab
shell: bash
env:
SLAB_URL: ${{ secrets.SLAB_URL }}
run: |
python3 slab/scripts/data_sender.py "${RESULTS_FILENAME}" "${SLAB_SECRET}" \
--slab-url "${SLAB_URL}"
teardown-instance:
name: benchmark_gpu_coprocessor/teardown-instance
if: ${{ always() && needs.setup-instance.result == 'success' }}
needs: [ setup-instance, benchmark-gpu ]
runs-on: ubuntu-latest
permissions:
contents: 'read'
steps:
- name: Stop remote instance
id: stop-instance
uses: zama-ai/slab-github-runner@86c9d2378700ca356455e36ebb97b61e958ea47b # v1.6.2
with:
mode: stop
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
label: ${{ needs.setup-instance.outputs.runner-name }}