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
3 changes: 3 additions & 0 deletions .devcontainer/launch.sh
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,9 @@ launch_docker() {
# Update run arguments and container environment variables
###

# Always clean up docker containers run via this script.
RUN_ARGS+=("--rm")

# Only pass `-it` if the shell is a tty
if ! ${CI:-'false'} && tty >/dev/null 2>&1 && (exec </dev/tty); then
RUN_ARGS+=("-it")
Expand Down
333 changes: 333 additions & 0 deletions .github/workflows/git-bisect.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
name: "Git Bisect"

defaults:
run:
shell: bash --noprofile --norc -euo pipefail {0}

on:
workflow_dispatch:
inputs:
runner:
description: "Runner label. Ex: 'linux-amd64-cpu16', 'linux-amd64-gpu-rtxa6000-latest-1'"
required: true
default: linux-amd64-cpu16
type: string
launch_args:
description: "'.devcontainer/launch.sh -d' add'l args. Ex: '--cuda 12.9 --host gcc13'"
required: false
default: "--cuda 13.0 --host gcc14"
type: string
preset:
description: "CMake preset. Ex: cub-cpp20"
required: true
default: "cub-cpp20"
type: string
cmake_options:
description: "Additional options passed to CMake preset configure (e.g. -DVAR=ON)"
required: false
default: "-DCMAKE_CUDA_ARCHITECTURES=80;90;100;120"
type: string
build_targets:
description: "Space separated ninja build targets to build."
required: false
default: ""
type: string
ctest_targets:
description: "Space separated CTest -R regexes to run."
required: false
default: ""
type: string
lit_precompile_tests:
description: "Space-separated libcudacxx lit test paths to compile without execution"
required: false
default: ""
type: string
lit_tests:
description: "Space-separated libcudacxx lit test paths to compile and execute"
required: false
default: ""
type: string
good_ref:
description: "Good ref/sha/tag/branch. Defaults to latest release tag. '-Nd' means 'N days ago on main'."
required: false
type: string
bad_ref:
description: "Bad ref/sha/tag/branch. Defaults to main. '-Nd' means 'N days ago on main'."
required: false
type: string
workflow_call:
inputs:
runner:
description: "Runner label. Ex: 'linux-amd64-cpu16', 'linux-amd64-gpu-rtxa6000-latest-1'"
required: true
default: linux-amd64-cpu16
type: string
launch_args:
description: "'.devcontainer/launch.sh -d' add'l args. Ex: '--ctk 12.9 --host gcc13'"
required: false
default: ""
type: string
preset:
description: "CMake preset. Ex: cub-cpp20"
required: true
default: ""
type: string
cmake_options:
description: "Additional options passed to CMake preset configure (e.g. -DVAR=ON)"
required: false
default: ""
type: string
build_targets:
description: "Space separated ninja build targets to build."
required: false
default: ""
type: string
ctest_targets:
description: "Space separated CTest -R regexes to run."
required: false
default: ""
type: string
lit_precompile_tests:
description: "Space-separated libcudacxx lit test paths to compile without execution"
required: false
default: ""
type: string
lit_tests:
description: "Space-separated libcudacxx lit test paths to compile and execute"
required: false
default: ""
type: string
good_ref:
description: "Good ref/sha/tag/branch. Defaults to latest release tag. '-Nd' means 'N days ago on main'."
required: false
type: string
bad_ref:
description: "Bad ref/sha/tag/branch. Defaults to main. '-Nd' means 'N days ago on main'."
required: false
type: string

jobs:
# Hash all of the inputs and generate a descriptive, but unique, name for the bisect job.
# This is necessary because GitHub Actions does not provide an easy way to get the numeric
# job id from within a running job, unless the name is unique across the entire run.
generate-job-name:
name: Generate Unique Job Name
runs-on: ubuntu-latest
outputs:
job-name: ${{ steps.set-name.outputs.unique-name }}
steps:
- name: Set unique name
id: set-name
run: |
# Hash the inputs to create a unique identifier
input_string=$(cat <<HASH
${{ inputs.runner }}
${{ inputs.launch_args }}
${{ inputs.preset }}
${{ inputs.cmake_options }}
${{ inputs.build_targets }}
${{ inputs.ctest_targets }}
${{ inputs.lit_precompile_tests }}
${{ inputs.lit_tests }}
${{ inputs.good_ref }}
${{ inputs.bad_ref }}
HASH
)
hash=$(echo -n "$input_string" | sha256sum | awk '{print $1}')
short_hash=${hash:0:8}

function sanitize() {
echo "$1" | tr -cd '[:alnum:]-'
}

function compress() {
input=$1
input_length=${#input}

# "begin.and.end" -> "begin_d.end"
delim="_"
keep_chars=5
compressed_str=${input:0:keep_chars}$delim${input: -keep_chars}
compressed_length=${#compressed_str}

if [[ $input_length -gt $compressed_length ]]; then
echo "$compressed_str"
else
echo "$input"
fi
}

preset=$(sanitize "${{ inputs.preset }}")
good_ref=$(sanitize "${{ inputs.good_ref }}")
bad_ref=$(sanitize "${{ inputs.bad_ref }}")
build_targets=$(sanitize "${{ inputs.build_targets }}")
ctest_targets=$(sanitize "${{ inputs.ctest_targets }}")
lit_precompile_tests=$(sanitize "${{ inputs.lit_precompile_tests }}")
lit_tests=$(sanitize "${{ inputs.lit_tests }}")

build_targets_part=$(compress "$build_targets")
ctest_targets_part=$(compress "$ctest_targets")
lit_precompile_tests_part=$(compress "$lit_precompile_tests")
lit_tests_part=$(compress "$lit_tests")

# Parse "--cuda XX.Y" / "-c XX.Y" and "--host <str>" / "-H <str>"
launch_args="${{ inputs.launch_args }}"
cuda_version="ctk$(grep -oP '(?:--cuda|-c)\s+\K\S+' <<< "$launch_args" || true)"
host_name=$(grep -oP '(?:--host|-H)\s+\K\S+' <<< "$launch_args" || true)

# Parse `amd64/arm64` and -gpu-<gpu_name> from runner name.
# Ex: 'linux-amd64-gpu-rtxa6000-latest-1'
runner=${{ inputs.runner }}
cpu_arch=$(echo "${runner}" | grep -oP '(?:^|-)\K(?:amd64|arm64)(?=-)' || true)
gpu_name=$(echo "${runner}" | grep -oP '(?:-gpu-)\K[^-]+' || true)

# Vars to include in unique name:
declare -a vars=(
"cuda_version"
"host_name"
"preset"
"build_targets_part"
"ctest_targets_part"
"lit_precompile_tests_part"
"lit_tests_part"
"gpu_name"
"cpu_arch"
"short_hash"
)
unique_name="bisect"
for var in "${vars[@]}"; do
val=${!var}
if [[ -n "$val" ]]; then
unique_name+="-$val"
fi
done

echo "Unique job name: $unique_name"
echo "unique-name=$unique_name" >> "$GITHUB_OUTPUT"

bisect:
needs: [generate-job-name]
name: ${{ needs.generate-job-name.outputs.job-name }}
runs-on: ${{ github.repository == 'NVIDIA/cccl' && inputs.runner || 'ubuntu-latest' }}
permissions:
id-token: write
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
persist-credentials: false
fetch-depth: 0 # FULL history
fetch-tags: true # Ensure tags are present

- name: Get AWS credentials for sccache bucket
if: ${{ github.repository == 'NVIDIA/cccl' }}
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::279114543810:role/gha-oidc-NVIDIA
aws-region: us-east-2
role-duration-seconds: 43200 # 12 hours

- name: Prepare AWS config for devcontainer
run: |
# The devcontainer will mount this path to the home directory
aws_dir="${{ github.workspace }}/.aws"
mkdir -p "${aws_dir}"
cat > "${aws_dir}/config" <<EOF
[default]
bucket=rapids-sccache-devs
region=us-east-2
EOF
cat > "${aws_dir}/credentials" <<EOF
[default]
aws_access_key_id=${AWS_ACCESS_KEY_ID:-}
aws_session_token=${AWS_SESSION_TOKEN:-}
aws_secret_access_key=${AWS_SECRET_ACCESS_KEY:-}
EOF
chmod 0600 "${aws_dir}/credentials"
chmod 0664 "${aws_dir}/config"

- name: Fetch full history
run: |
# Add the NVIDIA/cccl repo in case we're running on a fork without tags:
git remote add upstream https://github.com/NVIDIA/cccl.git || :
git fetch upstream || :

- name: Run git bisect
env:
GITHUB_TOKEN: ${{ github.token }}
LAUNCH_ARGS: ${{ inputs.launch_args }}
GITHUB_REPOSITORY: ${{ github.repository }}
# AWS credentials from the configure-aws-credentials action
AWS_ACCESS_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID }}
AWS_SESSION_TOKEN: ${{ env.AWS_SESSION_TOKEN }}
AWS_SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ env.AWS_REGION }}
run: |
echo -e "\e[1;34mLaunching devcontainer and running git bisect...\e[0m"

GPU_ARGS=""
if [[ "${{ inputs.runner }}" == *"-gpu-"* ]]; then
if [[ ! "${LAUNCH_ARGS}" =~ "--gpus" ]]; then
echo "GPU runner detected; enabling '--gpus all'"
GPU_ARGS="--gpus all"
else
echo "GPU runner detected, but '--gpus' already present in LAUNCH_ARGS"
fi
fi

# Grab the url for this step summary
run="$GITHUB_RUN_ID"
attempt="${GITHUB_RUN_ATTEMPT:-1}"
server="${GITHUB_SERVER_URL:-https://github.com}"
repo="$GITHUB_REPOSITORY"
job_name="${{ needs.generate-job-name.outputs.job-name }}"
job_id=$(
gh api --paginate \
repos/${GITHUB_REPOSITORY}/actions/runs/${GITHUB_RUN_ID}/jobs \
--jq ".jobs[] | select(.name | endswith(\"${job_name}\")) | .id"
) || :

GHA_LOG_URL="$server/$repo/actions/runs/$run/job/$job_id"
STEP_SUMMARY_URL="$server/$repo/actions/runs/$run/attempts/$attempt#summary-$job_id"

echo -e "\e[1;34mGHA Log URL: $GHA_LOG_URL\e[0m"
echo -e "\e[1;34mBisection Results: $STEP_SUMMARY_URL\e[0m"

mkdir -p /tmp/shared
rc=0
set -x
.devcontainer/launch.sh -d ${LAUNCH_ARGS} ${GPU_ARGS} \
--env "AWS_ROLE_ARN=" \
--env "AWS_REGION=${AWS_REGION}" \
--env "SCCACHE_REGION=${AWS_REGION}" \
--env "AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID}" \
--env "AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN}" \
--env "AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY}" \
--env "LAUNCH_ARGS=${LAUNCH_ARGS} ${GPU_ARGS}" \
--env "STEP_SUMMARY_URL=${STEP_SUMMARY_URL}" \
--env "GHA_LOG_URL=${GHA_LOG_URL}" \
--env "GITHUB_REPOSITORY=${GITHUB_REPOSITORY}" \
--volume "/tmp/shared:/tmp/shared" \
-- ./ci/util/git_bisect.sh \
--summary-file "/tmp/shared/summary.md" \
--good-ref "${{ inputs.good_ref }}" \
--bad-ref "${{ inputs.bad_ref }}" \
--preset "${{ inputs.preset }}" \
--cmake-options "${{ inputs.cmake_options }}" \
--build-targets "${{ inputs.build_targets }}" \
--ctest-targets "${{ inputs.ctest_targets }}" \
--lit-precompile-tests "${{ inputs.lit_precompile_tests }}" \
--lit-tests "${{ inputs.lit_tests }}" \
|| rc=$?
set +x

# Append the summary (if any) to the GitHub step summary
if [[ -d /tmp/shared ]]; then
find /tmp/shared -type f -exec cat {} \; >> "$GITHUB_STEP_SUMMARY" || :
fi

echo -e "\e[1;34mGHA Log URL: $GHA_LOG_URL\e[0m"
echo -e "\e[1;34mBisection Results: $STEP_SUMMARY_URL\e[0m"

exit $rc
Loading