version: 2.1

# -------------------------------------------------------------------------------------
# Environments to run the jobs in
# -------------------------------------------------------------------------------------
cpu: &cpu
  machine:
    image: ubuntu-2004:202107-02
  resource_class: medium

gpu: &gpu
  machine:
    # NOTE: use a cuda vesion that's supported by all our pytorch versions
    image: ubuntu-1604-cuda-11.1:202012-01
  resource_class: gpu.nvidia.small

windows-cpu: &windows_cpu
  machine:
    resource_class: windows.medium
    image: windows-server-2019-vs2019:stable
    shell: powershell.exe

# windows-gpu: &windows_gpu
#     machine:
#       resource_class: windows.gpu.nvidia.medium
#       image: windows-server-2019-nvidia:stable

version_parameters: &version_parameters
  parameters:
    pytorch_version:
      type: string
    torchvision_version:
      type: string
    pytorch_index:
      type: string
      # use test wheels index to have access to RC wheels
      # https://download.pytorch.org/whl/test/torch_test.html
      default: "https://download.pytorch.org/whl/torch_stable.html"
    python_version:  # NOTE: only affect linux
      type: string
      default: '3.6.8'

  environment:
    PYTORCH_VERSION: << parameters.pytorch_version >>
    TORCHVISION_VERSION: << parameters.torchvision_version >>
    PYTORCH_INDEX: << parameters.pytorch_index >>
    PYTHON_VERSION: << parameters.python_version>>
    # point datasets to ~/.torch so it's cached in CI
    DETECTRON2_DATASETS: ~/.torch/datasets

# -------------------------------------------------------------------------------------
# Re-usable commands
# -------------------------------------------------------------------------------------
# install_nvidia_driver: &install_nvidia_driver
#   - run:
#       name: Install nvidia driver
#       working_directory: ~/
#       command: |
#         wget -q 'https://s3.amazonaws.com/ossci-linux/nvidia_driver/NVIDIA-Linux-x86_64-430.40.run'
#         sudo /bin/bash ./NVIDIA-Linux-x86_64-430.40.run -s --no-drm
#         nvidia-smi

add_ssh_keys: &add_ssh_keys
  # https://circleci.com/docs/2.0/add-ssh-key/
  - add_ssh_keys:
      fingerprints:
        - "e4:13:f2:22:d4:49:e8:e4:57:5a:ac:20:2f:3f:1f:ca"

install_python: &install_python
  - run:
      name: Install Python
      working_directory: ~/
      command: |
        # upgrade pyenv
        cd /opt/circleci/.pyenv/plugins/python-build/../.. && git pull && cd -
        pyenv install -s $PYTHON_VERSION
        pyenv global $PYTHON_VERSION
        python --version
        which python
        pip install --upgrade pip

setup_venv: &setup_venv
  - run:
      name: Setup Virtual Env
      working_directory: ~/
      command: |
        python -m venv ~/venv
        echo ". ~/venv/bin/activate" >> $BASH_ENV
        . ~/venv/bin/activate
        python --version
        which python
        which pip
        pip install --upgrade pip

setup_venv_win: &setup_venv_win
  - run:
      name: Setup Virutal Env for Windows
      command: |
        pip install virtualenv
        python -m virtualenv env
        .\env\Scripts\activate
        python --version
        which python
        which pip

install_linux_dep: &install_linux_dep
  - run:
      name: Install Dependencies
      command: |
        # disable crash coredump, so unittests fail fast
        sudo systemctl stop apport.service
        # install from github to get latest; install iopath first since fvcore depends on it
        pip install --progress-bar off -U 'git+https://github.com/facebookresearch/iopath'
        pip install --progress-bar off -U 'git+https://github.com/facebookresearch/fvcore'
        # Don't use pytest-xdist: cuda tests are unstable under multi-process workers.
        pip install --progress-bar off ninja opencv-python-headless pytest tensorboard pycocotools
        pip install --progress-bar off torch==$PYTORCH_VERSION -f $PYTORCH_INDEX
        if [[ "$TORCHVISION_VERSION" == "master" ]]; then
          pip install git+https://github.com/pytorch/vision.git
        else
          pip install --progress-bar off torchvision==$TORCHVISION_VERSION -f $PYTORCH_INDEX
        fi

        python -c 'import torch; print("CUDA:", torch.cuda.is_available())'
        gcc --version

install_detectron2: &install_detectron2
  - run:
      name: Install Detectron2
      command: |
        # Remove first, in case it's in the CI cache
        pip uninstall -y detectron2
        pip install --progress-bar off -e .[all]
        python -m detectron2.utils.collect_env
        ./datasets/prepare_for_tests.sh

run_unittests: &run_unittests
  - run:
      name: Run Unit Tests
      command: |
        pytest -v --durations=15 tests  # parallel causes some random failures

# -------------------------------------------------------------------------------------
# Jobs to run
# -------------------------------------------------------------------------------------
jobs:
  linux_cpu_tests:
    <<: *cpu
    <<: *version_parameters

    working_directory: ~/detectron2

    steps:
      - checkout

      # Cache the venv directory that contains python, dependencies, and checkpoints
      # Refresh the key when dependencies should be updated (e.g. when pytorch releases)
      - restore_cache:
          keys:
            - cache-{{ arch }}-<< parameters.pytorch_version >>-{{ .Branch }}-20210827

      - <<: *install_python
      - <<: *install_linux_dep
      - <<: *install_detectron2
      - <<: *run_unittests

      - save_cache:
          paths:
            - /opt/circleci/.pyenv
            - ~/.torch
          key: cache-{{ arch }}-<< parameters.pytorch_version >>-{{ .Branch }}-20210827


  linux_gpu_tests:
    <<: *gpu
    <<: *version_parameters

    working_directory: ~/detectron2

    steps:
      - checkout

      - restore_cache:
          keys:
            - cache-{{ arch }}-<< parameters.pytorch_version >>-{{ .Branch }}-20210827

      - <<: *install_python
      - <<: *install_linux_dep
      - <<: *install_detectron2
      - <<: *run_unittests

      - save_cache:
          paths:
            - /opt/circleci/.pyenv
            - ~/.torch
          key: cache-{{ arch }}-<< parameters.pytorch_version >>-{{ .Branch }}-20210827

  windows_cpu_build:
    <<: *windows_cpu
    <<: *version_parameters
    steps:
      - <<: *add_ssh_keys
      - checkout
      - <<: *setup_venv_win

      # Cache the env directory that contains dependencies
      - restore_cache:
          keys:
            - cache-{{ arch }}-<< parameters.pytorch_version >>-{{ .Branch }}-20210404

      - run:
          name: Install Dependencies
          command: |
            pip install certifi --ignore-installed  # required on windows to workaround some cert issue
            pip install numpy cython  # required on windows before pycocotools
            pip install opencv-python-headless pytest-xdist pycocotools tensorboard
            pip install -U git+https://github.com/facebookresearch/iopath
            pip install -U git+https://github.com/facebookresearch/fvcore
            pip install torch==$env:PYTORCH_VERSION torchvision==$env:TORCHVISION_VERSION -f $env:PYTORCH_INDEX

      - save_cache:
          paths:
            - env
          key: cache-{{ arch }}-<< parameters.pytorch_version >>-{{ .Branch }}-20210404

      - <<: *install_detectron2
      # TODO: unittest fails for now

workflows:
  version: 2
  regular_test:
    jobs:
      - linux_cpu_tests:
          name: linux_cpu_tests_pytorch1.10
          pytorch_version: '1.10.0+cpu'
          torchvision_version: '0.11.1+cpu'
      - linux_gpu_tests:
          name: linux_gpu_tests_pytorch1.8
          pytorch_version: '1.8.1+cu111'
          torchvision_version: '0.9.1+cu111'
      - linux_gpu_tests:
          name: linux_gpu_tests_pytorch1.9
          pytorch_version: '1.9+cu111'
          torchvision_version: '0.10+cu111'
      - linux_gpu_tests:
          name: linux_gpu_tests_pytorch1.10
          pytorch_version: '1.10+cu111'
          torchvision_version: '0.11.1+cu111'
      - linux_gpu_tests:
          name: linux_gpu_tests_pytorch1.10_python39
          pytorch_version: '1.10+cu111'
          torchvision_version: '0.11.1+cu111'
          python_version: '3.9.6'
      - windows_cpu_build:
          pytorch_version: '1.10+cpu'
          torchvision_version: '0.11.1+cpu'
