version: 2.1

executors:
  default:
    machine:
      image: ubuntu-2004-cuda-11.2:202103-01
    working_directory: ~/gpuci
    resource_class: gpu.nvidia.medium

restore-workspace: &restore-workspace
  attach_workspace:
    at: ~/

restore-cache: &restore-cache
  restore_cache:
    keys:
      - cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
      - repo-source-{{ .Branch }}-{{ .Revision }}

commands:
  set-env-path:
    steps:
      - run:
          name: Set the PATH env variable
          command: |
            echo 'export PATH="$HOME:~/.cargo/bin:/usr/local/cuda-11.2/bin:$PATH"' | tee --append $BASH_ENV
            source $BASH_ENV

  install-gpu-deps:
    steps:
      - run:
          name: Install libraries for GPU tests
          command: |
            sudo apt update
            sudo apt install -y ocl-icd-opencl-dev

  test:
    parameters:
      cargo-args:
        description: Addtional arguments for the cargo command
        type: string
        default: ""
    steps:
      - *restore-workspace
      - *restore-cache
      - run:
          name: Test (<< parameters.cargo-args >>)
          command: cargo test --release << parameters.cargo-args >> -- --test-threads=1
          no_output_timeout: 30m

jobs:
  cargo_fetch:
    executor: default
    steps:
      - checkout
      - run: curl https://sh.rustup.rs -sSf | sh -s -- -y
      - set-env-path
      - run: echo $HOME
      - run: cargo --version
      - run: rustc --version
      - run:
          name: Update submodules
          command: git submodule update --init --recursive
      - run:
          name: Calculate dependencies
          command: cargo generate-lockfile
      - restore_cache:
          keys:
            - cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
      - run: cargo update
      - run: cargo fetch
      - run: rustup install $(cat rust-toolchain)
      - run: rustup default $(cat rust-toolchain)
      - run: rustc --version
      - run: rm -rf .git
      - persist_to_workspace:
          root: ~/
          paths:
            - gpuci
      - save_cache:
          key: cargo-v1-{{ checksum "rust-toolchain" }}-{{ checksum "Cargo.toml" }}-{{ checksum "Cargo.lock" }}-{{ arch }}
          paths:
            - "~/.cargo"
            - "~/.rustup"

  test_default_and_opencl:
    executor: default
    environment:
      RUST_LOG: debug
      # Build the kernel only for the single architecture that is used on CI. This should reduce
      # the overall compile-time significantly.
      EC_GPU_CUDA_NVCC_ARGS: --fatbin --gpu-architecture=sm_75 --generate-code=arch=compute_75,code=sm_75
    steps:
      - set-env-path
      - install-gpu-deps
      - test
      - test:
          cargo-args: "--features opencl,bls,pasta,arity2,arity4,arity8,arity11,arity16,arity24,arity36"

  test_darwin_default_and_opencl:
    macos:
      xcode: "13.4.1"
    working_directory: ~/crate
    resource_class: large
    steps:
      - checkout
      - run:
          name: Install Rust
          command: |
            curl https://sh.rustup.rs -sSf | sh -s -- -y
      - run: rustup install $(cat rust-toolchain)
      - run: rustup default $(cat rust-toolchain)
      - run: cargo update
      - run: cargo fetch
      - test
      - test:
          cargo-args: "--features opencl,bls,pasta,arity2,arity4,arity8,arity11,arity16,arity24,arity36"

  test_cuda:
    executor: default
    environment:
      RUST_LOG: debug
      # Build the kernel only for the single architecture that is used on CI. This should reduce
      # the overall compile-time significantly.
      EC_GPU_CUDA_NVCC_ARGS: --fatbin --gpu-architecture=sm_75 --generate-code=arch=compute_75,code=sm_75
    steps:
      - set-env-path
      - install-gpu-deps
      - test:
          cargo-args: "--features cuda,bls,pasta,arity2,arity4,arity8,arity11,arity16,arity24,arity36"


  test_cuda_opencl:
    executor: default
    environment:
      RUST_LOG: debug
      # Build the kernel only for the single architecture that is used on CI. This should reduce
      # the overall compile-time significantly.
      EC_GPU_CUDA_NVCC_ARGS: --fatbin --gpu-architecture=sm_75 --generate-code=arch=compute_75,code=sm_75
    steps:
      - set-env-path
      - install-gpu-deps
      - test:
          cargo-args: "--features cuda,opencl,bls,pasta,arity2,arity4,arity8,arity11,arity16,arity24,arity36"

  rustfmt:
    executor: default
    steps:
      - *restore-workspace
      - *restore-cache
      - set-env-path
      - run:
          name: Run cargo fmt
          command: cargo fmt --all -- --check

  clippy:
    executor: default
    steps:
      - *restore-workspace
      - *restore-cache
      - set-env-path
      - install-gpu-deps
      - run:
          # gbench doesn't support running without GPU support, hence don't run Clippy on the whole workspace
          name: Run cargo clippy, without gbench
          command: cargo clippy --all-targets -- -D warnings
      - run:
          name: Run cargo clippy (opencl)
          command: cargo clippy --workspace --all-targets --no-default-features --features opencl,bls,pasta,arity2 -- -D warnings
      - run:
          name: Run cargo clippy (cuda)
          command: cargo clippy --workspace --all-targets --no-default-features --features cuda,bls,pasta,arity2 -- -D warnings
      - run:
          name: Run cargo clippy (cuda,opencl)
          command: cargo clippy --workspace --all-targets --no-default-features --features cuda,bls,pasta,opencl,arity2 -- -D warnings

workflows:
  version: 2.1

  test:
    jobs:
      - cargo_fetch
      - rustfmt:
          requires:
            - cargo_fetch
      - clippy:
          requires:
            - cargo_fetch
      - test_default_and_opencl:
          requires:
            - cargo_fetch
      - test_darwin_default_and_opencl:
          requires:
            - cargo_fetch
      - test_cuda:
          requires:
            - cargo_fetch
      - test_cuda_opencl:
          requires:
            - cargo_fetch
