feat(gpu): add fast op-sequence tests in makefile and the CI

This commit is contained in:
Andrei Stoian
2025-06-30 16:08:51 +02:00
parent 42112c53c2
commit 734f930a6e
10 changed files with 199 additions and 7 deletions

View File

@@ -0,0 +1,118 @@
name: Cuda - Short Op-sequence Tests on GPU
env:
CARGO_TERM_COLOR: always
ACTION_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
RUSTFLAGS: "-C target-cpu=native"
RUST_BACKTRACE: "full"
RUST_MIN_STACK: "8388608"
SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }}
SLACK_ICON: https://pbs.twimg.com/profile_images/1274014582265298945/OjBKP9kn_400x400.png
SLACK_USERNAME: ${{ secrets.BOT_USERNAME }}
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }}
CHECKOUT_TOKEN: ${{ secrets.REPO_CHECKOUT_TOKEN || secrets.GITHUB_TOKEN }}
on:
# Allows you to run this workflow manually from the Actions tab as an alternative.
workflow_dispatch:
schedule:
# Nightly tests will be triggered each evening 8p.m.
- cron: "0 20 * * *"
permissions:
contents: read
jobs:
setup-instance:
name: Setup instance (gpu-tests)
if: github.event_name != 'schedule' ||
(github.event_name == 'schedule' && github.repository == 'zama-ai/tfhe-rs')
runs-on: ubuntu-latest
outputs:
runner-name: ${{ steps.start-instance.outputs.label }}
steps:
- name: Start instance
id: start-instance
uses: zama-ai/slab-github-runner@79939325c3c429837c10d6041e4fd8589d328bac
with:
mode: start
github-token: ${{ secrets.SLAB_ACTION_TOKEN }}
slab-url: ${{ secrets.SLAB_BASE_URL }}
job-secret: ${{ secrets.JOB_SECRET }}
backend: hyperstack
profile: multi-gpu-test
cuda-tests:
name: Short op-sequence GPU tests
needs: [ setup-instance ]
concurrency:
group: ${{ github.workflow_ref }}_${{github.event_name}}
cancel-in-progress: true
runs-on: ${{ needs.setup-instance.outputs.runner-name }}
strategy:
fail-fast: false
# explicit include-based build matrix, of known valid options
matrix:
include:
- os: ubuntu-22.04
cuda: "12.2"
gcc: 11
timeout-minutes: 4320 # 72 hours
steps:
- name: Checkout tfhe-rs
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
persist-credentials: 'false'
token: ${{ env.CHECKOUT_TOKEN }}
- name: Setup Hyperstack dependencies
uses: ./.github/actions/gpu_setup
with:
cuda-version: ${{ matrix.cuda }}
gcc-version: ${{ matrix.gcc }}
- name: Install latest stable
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # zizmor: ignore[stale-action-refs] this action doesn't create releases
with:
toolchain: stable
- name: Run tests
run: |
make test_integer_short_op_sequence_gpu
slack-notify:
name: Slack Notification
needs: [ setup-instance, cuda-tests ]
runs-on: ubuntu-latest
if: ${{ always() && needs.cuda-tests.result != 'skipped' && failure() }}
continue-on-error: true
steps:
- name: Send message
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661
env:
SLACK_COLOR: ${{ needs.cuda-tests.result }}
SLACK_MESSAGE: "Integer GPU fast op-sequence tests finished with status: ${{ needs.cuda-tests.result }}. (${{ env.ACTION_RUN_URL }})"
teardown-instance:
name: Teardown instance (gpu-tests)
if: ${{ always() && needs.setup-instance.result == 'success' }}
needs: [ setup-instance, cuda-tests ]
runs-on: ubuntu-latest
steps:
- name: Stop instance
id: stop-instance
uses: zama-ai/slab-github-runner@79939325c3c429837c10d6041e4fd8589d328bac
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 }}
- name: Slack Notification
if: ${{ failure() }}
continue-on-error: true
uses: rtCamp/action-slack-notify@e31e87e03dd19038e411e38ae27cbad084a90661
env:
SLACK_COLOR: ${{ job.status }}
SLACK_MESSAGE: "Instance teardown (gpu-short-op-sequence-tests) finished with status: ${{ job.status }}. (${{ env.ACTION_RUN_URL }})"

View File

@@ -666,6 +666,15 @@ test_integer_long_run_gpu: install_rs_check_toolchain install_cargo_nextest
--cargo-profile "$(CARGO_PROFILE)" --avx512-support "$(AVX512_SUPPORT)" \
--tfhe-package "$(TFHE_SPEC)" --backend "gpu"
.PHONY: test_integer_short_op_sequence_gpu # Run the long run integer tests on the gpu backend
test_integer_short_op_sequence_gpu: install_rs_check_toolchain install_cargo_nextest
BIG_TESTS_INSTANCE="$(BIG_TESTS_INSTANCE)" \
SHORT_TESTS=TRUE \
./scripts/integer-tests.sh --rust-toolchain $(CARGO_RS_BUILD_TOOLCHAIN) \
--cargo-profile "$(CARGO_PROFILE)" --avx512-support "$(AVX512_SUPPORT)" \
--tfhe-package "$(TFHE_SPEC)" --backend "gpu"
.PHONY: test_integer_compression
test_integer_compression: install_rs_build_toolchain
RUSTFLAGS="$(RUSTFLAGS)" cargo $(CARGO_RS_BUILD_TOOLCHAIN) test --profile $(CARGO_PROFILE) \

View File

@@ -24,7 +24,7 @@ RUST_TOOLCHAIN="+stable"
multi_bit_argument=
sign_argument=
fast_tests_argument=
long_tests_argument=
op_sequence_tests_argument=
nightly_tests_argument=
no_big_params_argument=
cargo_profile="release"
@@ -96,7 +96,11 @@ if [[ "${FAST_TESTS}" == TRUE ]]; then
fi
if [[ "${LONG_TESTS}" == TRUE ]]; then
long_tests_argument=--long-tests
op_sequence_tests_argument=--long-tests
fi
if [[ "${SHORT_TESTS}" == TRUE ]]; then
op_sequence_tests_argument=--short-tests
fi
if [[ "${NIGHTLY_TESTS}" == TRUE ]]; then
@@ -145,7 +149,7 @@ if [[ "${backend}" == "gpu" ]]; then
fi
fi
filter_expression=$(/usr/bin/python3 scripts/test_filtering.py --layer integer --backend "${backend}" ${fast_tests_argument} ${long_tests_argument} ${nightly_tests_argument} ${multi_bit_argument} ${sign_argument} ${no_big_params_argument})
filter_expression=$(/usr/bin/python3 scripts/test_filtering.py --layer integer --backend "${backend}" ${fast_tests_argument} ${op_sequence_tests_argument} ${nightly_tests_argument} ${multi_bit_argument} ${sign_argument} ${no_big_params_argument})
if [[ "${FAST_TESTS}" == "TRUE" ]]; then
echo "Running 'fast' test set"
@@ -157,6 +161,10 @@ if [[ "${LONG_TESTS}" == "TRUE" ]]; then
echo "Running 'long run' test set"
fi
if [[ "${SHORT_TESTS}" == "TRUE" ]]; then
echo "Running 'short op-sequence' test set"
fi
if [[ "${NIGHTLY_TESTS}" == "TRUE" ]]; then
echo "Running 'nightly' test set"
fi
@@ -172,7 +180,7 @@ cargo "${RUST_TOOLCHAIN}" nextest run \
--test-threads "${test_threads}" \
-E "$filter_expression"
if [[ -z ${multi_bit_argument} && -z ${long_tests_argument} ]]; then
if [[ -z ${multi_bit_argument} && -z ${op_sequence_tests_argument} ]]; then
cargo "${RUST_TOOLCHAIN}" test \
--profile "${cargo_profile}" \
--package "${tfhe_package}" \

View File

@@ -32,6 +32,12 @@ parser.add_argument(
action="store_true",
help="Run only the long tests suite",
)
parser.add_argument(
"--short-tests",
dest="short_tests",
action="store_true",
help="Run only the short tests suite",
)
parser.add_argument(
"--nightly-tests",
dest="nightly_tests",
@@ -107,7 +113,10 @@ def filter_integer_tests(input_args):
("_multi_bit", "_group_[0-9]") if input_args.multi_bit else ("", "")
)
backend_filter = ""
if not input_args.long_tests:
# Regular tests are mostly unit-tests
regular_test_suite = not input_args.long_tests and not input_args.short_tests
filter_expression = []
if regular_test_suite:
if input_args.backend == "gpu":
backend_filter = "gpu::"
if multi_bit_filter:
@@ -153,7 +162,10 @@ def filter_integer_tests(input_args):
for pattern in excluded_tests:
filter_expression.append(f"not test({pattern})")
else:
# Long and short op-sequence tests are more complex
# tests that run random operations in sequence
elif input_args.long_tests :
# Long tests run many operations (e.g. 20 000)
if input_args.backend == "gpu":
filter_expression = [
"test(/^integer::gpu::server_key::radix::tests_long_run.*/)"
@@ -162,6 +174,19 @@ def filter_integer_tests(input_args):
filter_expression = [
"test(/^integer::server_key::radix_parallel::tests_long_run.*/)"
]
elif input_args.short_tests:
# Short op-sequence tests run few iterations (tens or hundreds)
if input_args.backend == "gpu":
filter_expression = [
"test(/^integer::gpu::server_key::radix::tests_short_run.*/)"
]
elif input_args.backend == "cpu":
filter_expression = [
"test(/^integer::server_key::radix_parallel::tests_short_run/)"
]
assert False, "Short tests not yet implemented for cpu backend"
else:
assert False, "Invalid test suite selection"
return " and ".join(filter_expression)

View File

@@ -64,6 +64,9 @@ mod tests_signed;
#[cfg(test)]
mod tests_unsigned;
#[cfg(test)]
mod tests_short_run;
impl CudaServerKey {
/// Create a trivial ciphertext filled with zeros on the GPU.
///

View File

@@ -8,6 +8,7 @@ use crate::integer::server_key::radix_parallel::tests_long_run::test_signed_rand
SignedScalarOverflowingOpExecutor, SignedScalarShiftRotateExecutor, SignedSelectOpExecutor,
SignedShiftRotateExecutor, SignedUnaryOpExecutor,
};
use crate::integer::server_key::radix_parallel::tests_long_run::NB_TESTS_LONG_RUN;
use crate::shortint::parameters::*;
use std::cmp::{max, min};
@@ -15,6 +16,13 @@ create_gpu_parameterized_test!(signed_random_op_sequence {
PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
});
fn signed_random_op_sequence<P>(param: P)
where
P: Into<TestParameters> + Clone,
{
signed_random_op_sequence_generic(param, NB_TESTS_LONG_RUN);
}
pub(crate) fn signed_random_op_sequence_generic<P>(param: P, num_iterations: usize)
where
P: Into<TestParameters> + Clone,
{
@@ -416,6 +424,7 @@ where
signed_random_op_sequence_test(
param,
num_iterations,
&mut binary_ops,
&mut unary_ops,
&mut scalar_binary_ops,

View File

@@ -0,0 +1 @@
pub(crate) mod test_op_sequence;

View File

@@ -0,0 +1,16 @@
use crate::integer::gpu::server_key::radix::tests_long_run::test_signed_random_op_sequence::signed_random_op_sequence_generic;
use crate::integer::gpu::server_key::radix::tests_unsigned::create_gpu_parameterized_test;
use crate::integer::server_key::radix_parallel::tests_long_run::NB_TESTS_SHORT_RUN;
use crate::shortint::parameters::{
TestParameters, PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128,
};
create_gpu_parameterized_test!(signed_random_op_sequence {
PARAM_GPU_MULTI_BIT_GROUP_4_MESSAGE_2_CARRY_2_KS_PBS_TUNIFORM_2M128
});
fn signed_random_op_sequence<P>(param: P)
where
P: Into<TestParameters> + Clone,
{
signed_random_op_sequence_generic(param, NB_TESTS_SHORT_RUN);
}

View File

@@ -4,3 +4,4 @@ pub(crate) mod test_signed_erc20;
pub(crate) mod test_signed_random_op_sequence;
pub(crate) const NB_CTXT_LONG_RUN: usize = 32;
pub(crate) const NB_TESTS_LONG_RUN: usize = 20000;
pub(crate) const NB_TESTS_SHORT_RUN: usize = 20;

View File

@@ -479,6 +479,7 @@ where
signed_random_op_sequence_test(
param,
NB_TESTS_LONG_RUN,
&mut binary_ops,
&mut unary_ops,
&mut scalar_binary_ops,
@@ -498,6 +499,7 @@ where
#[allow(clippy::too_many_arguments)]
pub(crate) fn signed_random_op_sequence_test<P>(
param: P,
num_iterations: usize,
binary_ops: &mut [(SignedBinaryOpExecutor, impl Fn(i64, i64) -> i64, String)],
unary_ops: &mut [(SignedUnaryOpExecutor, impl Fn(i64) -> i64, String)],
scalar_binary_ops: &mut [(
@@ -646,7 +648,7 @@ pub(crate) fn signed_random_op_sequence_test<P>(
.iter()
.map(|&m| cks.encrypt_signed(m)) // Generate random i64 values
.collect();
for fn_index in 0..NB_TESTS_LONG_RUN {
for fn_index in 0..num_iterations {
let i = rng.gen_range(0..total_num_ops);
let j = rng.gen_range(0..total_num_ops);