Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 45 additions & 11 deletions .github/workflows/gpu-zluda.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
# which no hosted runner has. It is therefore the only workflow that answers "are the HSPs still
# identical to the C++ reference", and it is free and unlimited.
#
# Machine paths (CUDA toolkit root, ZLUDA, shim, oracle, test data) are not in this file either:
# they live in the self-hosted runner host's per-user test.env and are read by the first step.
#
# SECURITY, non-negotiable. A self-hosted runner that executes pull-request code from a fork is
# arbitrary code execution on the workstation. The job-level `if` below is the control -- not the
# repository's "require approval" setting, because an approved fork PR would still run here.
Expand Down Expand Up @@ -37,22 +40,53 @@ jobs:
github.event.pull_request.head.repo.full_name == github.repository
runs-on: [self-hosted, linux, x64, zluda]
timeout-minutes: 120
env:
CUDACONDA: /home/alejandro/opt/cudaconda
ZLUDA: /home/alejandro/opt/zluda
HIPFIX: /home/alejandro/opt/zluda-guide/hipfix.so
KEGALIGN: /tmp/kegalign/build/kegalign
TESTDATA: /tmp/kegalign/test-data
# Outside the workspace on purpose: actions/checkout runs `git clean -ffdx`, which would
# throw away the incremental build on every run.
CARGO_TARGET_DIR: /home/alejandro/.cache/hspZ-ci-target
steps:
- uses: actions/checkout@v4
- run: echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"

# Machine paths are not in the tree: they live in this runner host's per-user file
# (plain KEY=value lines, never committed), read before anything else needs them.
# CARGO_TARGET_DIR also stays outside the workspace on purpose: actions/checkout runs
# `git clean -ffdx`, which would throw away the incremental build on every run.
- name: machine environment (runner host file, not the tree)
run: |
f=${HSPZ_TEST_ENV:-${XDG_CONFIG_HOME:-$HOME/.config}/hspz/test.env}
if [ ! -f "$f" ]; then
echo "::error::missing machine path file $f (CUDA_HOME, ZLUDA, HIPFIX, KEGALIGN, TESTDATA)"
exit 1
fi
set -a; . "$f"; set +a
for v in CUDA_HOME ZLUDA KEGALIGN TESTDATA; do
if ! eval "[ -n \"\${$v:-}\" ]"; then
echo "::error::$v not set in $f"
exit 1
fi
eval "printf '%s=%s\n' '$v' \"\${$v}\"" >> "$GITHUB_ENV"
done
if [ -n "${HIPFIX:-}" ]; then
printf 'HIPFIX=%s\n' "$HIPFIX" >> "$GITHUB_ENV"
fi
echo "CARGO_TARGET_DIR=${CARGO_TARGET_DIR:-$HOME/.cache/hspZ-ci-target}" >> "$GITHUB_ENV"
echo "$HOME/.cargo/bin" >> "$GITHUB_PATH"

# The codegen backend must come from the cuda-oxide revision pinned in Cargo.lock: when
# the runner's backend cache is missing or invalidated, cargo-oxide would otherwise clone
# upstream HEAD, which tracks newer nightlies (see assets/container/Dockerfile).
- name: pin the cuda-oxide backend source
run: |
pin=$(grep -m1 -o 'cuda-oxide\.git#[0-9a-f]\{40\}' Cargo.lock | cut -d'#' -f2)
test -n "$pin"
src="${CARGO_HOME:-$HOME/.cargo}/cuda-oxide/src"
if [ "$(git -C "$src" rev-parse HEAD 2>/dev/null)" != "$pin" ]; then
git init -q "$src"
git -C "$src" fetch -q --depth 1 https://github.com/NVlabs/cuda-oxide.git "$pin"
git -C "$src" checkout -q --detach FETCH_HEAD
rm -f "$(dirname "$src")/librustc_codegen_cuda.so"
fi
test "$(git -C "$src" rev-parse HEAD)" = "$pin"

- name: build
run: |
export CUDA_HOME="$CUDACONDA" LD_LIBRARY_PATH="$ZLUDA:$CUDACONDA/lib"
export LD_LIBRARY_PATH="$ZLUDA:$CUDA_HOME/lib"
cargo oxide build -- --release --locked
strings -n 6 "$CARGO_TARGET_DIR/release/hspZ" | grep -qx '.target sm_80' \
|| { echo "::error::expected sm_80 PTX -- is .cargo/cuda-oxide.toml present?"; exit 1; }
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

25 changes: 23 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "hspz"
authors = ["Alejandro Gonzales-Irribarren <alejandrxgzi@gmail.com>"]
version = "0.0.3"
version = "0.0.4"
edition = "2024"
license = "GPL-3.0"
description = "GPU-accelerated high-scoring ungapped alignment pair backend"
Expand All @@ -27,7 +27,7 @@ twobit = "0.2.2"
tar = "0.4.46"

[features]
default = ["simd-prelude", "find-hits-warp"]
default = ["simd-prelude", "find-hits-warp", "ref-loc-buckets", "gate-int-keep", "gate-payload-ballot"]

# Benchmark-only find_hsps counters. Never time a build with this
# on — per-hit stores and per-tile increments shift register pressure.
Expand Down Expand Up @@ -63,13 +63,34 @@ dense-anchors = ["warp-score-gate"]
# 16 hits/seed; sparse launches keep thread-per-seed. Default.
find-hits-warp = ["dense-anchors"]

# Round 83-87: between find_hits and the score gate, stably reorder a chunk's anchors
# into reference-address buckets so consecutive warps of the gate gather from an
# L2-resident reference window. Output stays byte-identical. Default; at runtime
# `HSPZ_REF_BUCKETS=auto` (unset) measures both paths per engine and keeps the faster.
ref-loc-buckets = ["dense-anchors"]

# Score the first 64 left bases as 32 adjacent pairs.
left-pair-tile = ["dense-anchors"]

# Score 32 right + 64 left as packed 4-base groups in one warp
# (lanes 0-7 / 8-23), width-8 and width-16 scans.
simd-prelude = ["left-pair-tile"]

# Score-gate instruction diet. Both are byte-identical and default. L4, unit 0
# of hg38 x mm39 at W=1, reversed arms, output digest unchanged: with the
# reference-bucketed gate kernel gate-int-keep alone takes the score gate -6.5%
# and both together -30.1% (wall -25.3%); with the plain kernel both together
# take it -25.9% (wall -23.4%).
#
# Lane 0's keep compares `total >= t_min` in integers instead of rounding
# through f32 and f64; the host computes t_min = keep_threshold(hspthresh) once
# per engine. find_hsps keeps its own f32 threshold.
gate-int-keep = []
# The SIMD prelude's first-drop recovery from one payload ballot (each lane
# offers its maximum before its own first drop) instead of four ballots, the
# first-of decodes, the min cascades and the recover branches.
gate-payload-ballot = ["simd-prelude"]

[profile.release]
# `debug = 1` used to live here; `strip = true` discards it immediately, so it only cost
# build time (70 s -> 43 s once removed). The two container integrity gates do not need it:
Expand Down
Loading
Loading