diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 2a1f37b74b15..ce3927fa9497 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -26,14 +26,14 @@ jobs: tag-prefix: lint clang-tidy: - name: Run clang-tidy + name: Run clang-tidy with CUDA 12.9 needs: ci-configure runs-on: - runs-on=${{ github.run_id }} - runner=linux-amd64-cpu - tag=lint-clang-tidy-clang-cuda container: - image: ${{ needs.ci-configure.outputs.docker_registry }}/xgb-ci.gpu_build_rockylinux8:${{ needs.ci-configure.outputs.image_tag }} + image: ${{ needs.ci-configure.outputs.docker_registry }}/xgb-ci.gpu_build_cuda12_rockylinux8:${{ needs.ci-configure.outputs.image_tag }} credentials: username: ${{ needs.ci-configure.outputs.docker_username }} password: ${{ needs.ci-configure.outputs.docker_password }} diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 36fe88dddf91..570164038067 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -70,17 +70,16 @@ jobs: - uses: dmlc/xgboost-devops/actions/sccache@main with: cache-key-prefix: ${{ github.job }}-${{ matrix.build_suite }} - - name: Build and test - run: bash ops/pipeline/build-cpu.sh ${{ matrix.build_suite }} - - name: Test federated learning on CPU + - name: Build run C++ tests on CPU if: matrix.variant == 'default' shell: bash -l {0} run: | source activate linux_cpu_test - conda install scikit-build-core -y - cd python-package && pip install -e . --no-deps --no-build-isolation && cd - - timeout 600s pytest -v -s -rxXs --durations=0 tests/test_distributed/test_federated + bash ops/pipeline/build-cpu.sh ${{ matrix.build_suite }} - run: sccache --show-stats + - name: Build and test with sanitizer + if: matrix.variant == 'sanitizer' + run: bash ops/pipeline/build-cpu.sh ${{ matrix.build_suite }} build-cuda: name: Build CUDA ${{ matrix.cuda_version }} (${{ matrix.arch }}) @@ -94,27 +93,27 @@ jobs: fail-fast: false matrix: include: - # CUDA 12 + # xgboost-cu12 - cuda_version: 12 arch: aarch64 runner: linux-arm64-cpu - image_repo: xgb-ci.gpu_build_rockylinux8_aarch64 + image_repo: xgb-ci.gpu_build_cuda12_rockylinux8_aarch64 use_rmm: 0 - cuda_version: 12 arch: x86_64 runner: linux-amd64-cpu - image_repo: xgb-ci.gpu_build_rockylinux8 + image_repo: xgb-ci.gpu_build_cuda12_rockylinux8 use_rmm: 0 - # CUDA 13 + # Default xgboost package (CUDA 13) - cuda_version: 13 arch: aarch64 runner: linux-arm64-cpu - image_repo: xgb-ci.gpu_build_cuda13_rockylinux8_aarch64 + image_repo: xgb-ci.gpu_build_rockylinux8_aarch64 use_rmm: 0 - cuda_version: 13 arch: x86_64 runner: linux-amd64-cpu - image_repo: xgb-ci.gpu_build_cuda13_rockylinux8 + image_repo: xgb-ci.gpu_build_rockylinux8 use_rmm: 0 container: image: ${{ needs.ci-configure.outputs.docker_registry }}/${{ matrix.image_repo }}:${{ needs.ci-configure.outputs.image_tag }} @@ -142,7 +141,7 @@ jobs: build/testxgboost python-package/dist/*.whl build-cuda-clang: - name: Build CUDA with clang 21.1.8 (x86_64) + name: Build CUDA 12.9 with clang 22.1.8 (x86_64) needs: ci-configure runs-on: - runs-on=${{ github.run_id }} @@ -150,7 +149,7 @@ jobs: - tag=main-build-cuda-clang - extras=s3-cache container: - image: ${{ needs.ci-configure.outputs.docker_registry }}/xgb-ci.gpu_build_rockylinux8:${{ needs.ci-configure.outputs.image_tag }} + image: ${{ needs.ci-configure.outputs.docker_registry }}/xgb-ci.gpu_build_cuda12_rockylinux8:${{ needs.ci-configure.outputs.image_tag }} credentials: username: ${{ needs.ci-configure.outputs.docker_username }} password: ${{ needs.ci-configure.outputs.docker_password }} @@ -161,8 +160,8 @@ jobs: submodules: "true" - uses: dmlc/xgboost-devops/actions/sccache@main with: - cache-key-prefix: ${{ github.job }}-clang21-cuda12 - - run: bash ops/pipeline/build-cuda-clang.sh --clang-version 21.1.8 + cache-key-prefix: ${{ github.job }}-clang22-1-8-cuda12 + - run: bash ops/pipeline/build-cuda-clang.sh --clang-version 22.1.8 - run: sccache --show-stats audit-cuda-wheel: @@ -176,22 +175,22 @@ jobs: fail-fast: false matrix: include: - # CUDA 12 + # xgboost-cu12 - cuda_version: 12 - cuda_variant_flag: "" + cuda_variant_flag: "--cuda-variant cuda12" arch: aarch64 runner: linux-arm64-cpu - cuda_version: 12 - cuda_variant_flag: "" + cuda_variant_flag: "--cuda-variant cuda12" arch: x86_64 runner: linux-amd64-cpu - # CUDA 13 + # Default xgboost package (CUDA 13) - cuda_version: 13 - cuda_variant_flag: "--cuda-variant cuda13" + cuda_variant_flag: "" arch: aarch64 runner: linux-arm64-cpu - cuda_version: 13 - cuda_variant_flag: "--cuda-variant cuda13" + cuda_variant_flag: "" arch: x86_64 runner: linux-amd64-cpu container: @@ -225,7 +224,7 @@ jobs: python-package/dist/*.whl build-cuda-with-rmm: - name: Build CUDA with RMM + name: Build CUDA 13 with RMM needs: ci-configure runs-on: - runs-on=${{ github.run_id }} @@ -243,9 +242,11 @@ jobs: with: submodules: "true" - uses: dmlc/xgboost-devops/actions/sccache@main + with: + cache-key-prefix: ${{ github.job }}-cuda13 - run: >- bash ops/pipeline/build-cuda.sh - --cuda-version 12 + --cuda-version 13 --use-rmm 1 - run: sccache --show-stats - name: Stash files @@ -331,13 +332,13 @@ jobs: fail-fast: false matrix: include: - # CUDA 12 tests + # CUDA 12 artifact tests using the native CUDA 12.9 runtime # Note: --gpus all provides GPU access; --privileged is not needed for basic GPU tests - cuda_version: 12 suite: gpu arch: x86_64 runner: linux-amd64-gpu - image_repo: xgb-ci.gpu + image_repo: xgb-ci.gpu_cuda12 artifact_from: build-cuda12-x86_64 container_options: "--gpus all --privileged" test_args: "" @@ -345,44 +346,44 @@ jobs: suite: gpu arch: aarch64 runner: linux-arm64-gpu - image_repo: xgb-ci.gpu_aarch64 + image_repo: xgb-ci.gpu_cuda12_aarch64 artifact_from: build-cuda12-aarch64 container_options: "--gpus all --privileged" test_args: "" - - cuda_version: 12 - suite: gpu-rmm + # Default CUDA 13 artifact tests + - cuda_version: 13 + suite: gpu arch: x86_64 runner: linux-amd64-gpu image_repo: xgb-ci.gpu - artifact_from: build-cuda-with-rmm + artifact_from: build-cuda13-x86_64 container_options: "--gpus all --privileged" - test_args: "--use-rmm-pool --gtest_filter=-*DeathTest*" - - cuda_version: 12 + test_args: "" + - cuda_version: 13 + suite: gpu + arch: aarch64 + runner: linux-arm64-gpu + image_repo: xgb-ci.gpu_aarch64 + artifact_from: build-cuda13-aarch64 + container_options: "--gpus all --privileged" + test_args: "" + - cuda_version: 13 suite: mgpu arch: x86_64 runner: linux-amd64-mgpu image_repo: xgb-ci.gpu - artifact_from: build-cuda12-x86_64 + artifact_from: build-cuda13-x86_64 # mgpu needs --shm-size for NCCL shared memory communication container_options: "--gpus all --shm-size=4g --privileged" test_args: "--gtest_filter=*MGPU*" - # CUDA 13 tests - cuda_version: 13 - suite: gpu + suite: gpu-rmm arch: x86_64 runner: linux-amd64-gpu - image_repo: xgb-ci.gpu_build_cuda13_rockylinux8 - artifact_from: build-cuda13-x86_64 - container_options: "--gpus all --privileged" - test_args: "" - - cuda_version: 13 - suite: gpu - arch: aarch64 - runner: linux-arm64-gpu - image_repo: xgb-ci.gpu_build_cuda13_rockylinux8_aarch64 - artifact_from: build-cuda13-aarch64 + image_repo: xgb-ci.gpu + artifact_from: build-cuda-with-rmm container_options: "--gpus all --privileged" - test_args: "" + test_args: "--use-rmm-pool --gtest_filter=-*DeathTest*" container: image: ${{ needs.ci-configure.outputs.docker_registry }}/${{ matrix.image_repo }}:${{ needs.ci-configure.outputs.image_tag }} credentials: @@ -416,41 +417,41 @@ jobs: fail-fast: false matrix: include: - # CUDA 12 tests + # xgboost-cu12 tests using the native CUDA 12.9 runtime - cuda_version: 12 description: GPU-x86_64-CUDA-12 - image_repo: xgb-ci.gpu + image_repo: xgb-ci.gpu_cuda12 suite: gpu runner: linux-amd64-gpu artifact_from: audit-cuda12-wheel-x86_64 container_options: "--gpus all --privileged" - - cuda_version: 12 - description: Multi-GPU-x86_64-CUDA-12 - image_repo: xgb-ci.gpu - suite: mgpu - runner: linux-amd64-mgpu - artifact_from: audit-cuda12-wheel-x86_64 - # mgpu needs --shm-size for NCCL shared memory communication - container_options: "--gpus all --shm-size=4g --privileged" - # CUDA 12 aarch64 tests + # xgboost-cu12 aarch64 test using the native CUDA 12.9 runtime - cuda_version: 12 description: GPU-arm64-CUDA-12 - image_repo: xgb-ci.gpu_aarch64 + image_repo: xgb-ci.gpu_cuda12_aarch64 suite: gpu-arm64 runner: linux-arm64-gpu artifact_from: audit-cuda12-wheel-aarch64 container_options: "--gpus all --privileged" - # CUDA 13 tests + # Default xgboost package tests (CUDA 13) - cuda_version: 13 description: GPU-x86_64-CUDA-13 - image_repo: xgb-ci.gpu_build_cuda13_rockylinux8 + image_repo: xgb-ci.gpu suite: gpu runner: linux-amd64-gpu artifact_from: audit-cuda13-wheel-x86_64 container_options: "--gpus all --privileged" + - cuda_version: 13 + description: Multi-GPU-x86_64-CUDA-13 + image_repo: xgb-ci.gpu + suite: mgpu + runner: linux-amd64-mgpu + artifact_from: audit-cuda13-wheel-x86_64 + # mgpu needs --shm-size for NCCL shared memory communication + container_options: "--gpus all --shm-size=4g --privileged" - cuda_version: 13 description: GPU-arm64-CUDA-13 - image_repo: xgb-ci.gpu_build_cuda13_rockylinux8_aarch64 + image_repo: xgb-ci.gpu_aarch64 suite: gpu-arm64 runner: linux-arm64-gpu artifact_from: audit-cuda13-wheel-aarch64 @@ -476,16 +477,16 @@ jobs: bash ops/pipeline/test-python-wheel.sh --suite ${{ matrix.suite }} --cuda-version ${{ matrix.cuda_version }} - # Train a model for cross-platform testing (only for CUDA 12 x86_64) + # Train a model for cross-platform testing (only for default CUDA 13 x86_64) - name: Train cross-platform test model - if: matrix.cuda_version == 12 && matrix.suite == 'gpu' + if: matrix.cuda_version == 13 && matrix.suite == 'gpu' shell: bash -l {0} run: | source activate gpu_test python tests/cross-platform/test_cross_platform_model.py \ --train --model-path cross_platform_model.ubj - name: Upload cross-platform model artifact - if: matrix.cuda_version == 12 && matrix.suite == 'gpu' + if: matrix.cuda_version == 13 && matrix.suite == 'gpu' uses: actions/upload-artifact@v7.0.1 with: name: cross-platform-model @@ -505,20 +506,20 @@ jobs: timeout-minutes: 60 strategy: fail-fast: false - # Uses the wheel from cuda12 for tests. + # Uses the default CUDA 13 wheel for tests. matrix: include: - description: CPU-amd64 image_repo: xgb-ci.cpu suite: cpu runner: linux-amd64-cpu - artifact_from: audit-cuda12-wheel-x86_64 + artifact_from: audit-cuda13-wheel-x86_64 container_options: "--init" - description: CPU-arm64 image_repo: xgb-ci.cpu_aarch64 suite: cpu-arm64 runner: linux-arm64-cpu - artifact_from: audit-cuda12-wheel-aarch64 + artifact_from: audit-cuda13-wheel-aarch64 container_options: "--init" container: image: ${{ needs.ci-configure.outputs.docker_registry }}/${{ matrix.image_repo }}:${{ needs.ci-configure.outputs.image_tag }} diff --git a/doc/build.rst b/doc/build.rst index 5ec1269c003c..20d6f21c059e 100644 --- a/doc/build.rst +++ b/doc/build.rst @@ -139,23 +139,6 @@ architectures can be found `in this page `_. Alternatively, one can use the -``libgrpc`` and the ``protobuf`` package from conda forge if conda is available. After -obtaining the required dependencies, enable the flag: ``-DPLUGIN_FEDERATED=ON`` when -running CMake. Please note that only Linux is supported for the federated plugin. - - -.. code-block:: bash - - cmake -B build -S . -DPLUGIN_FEDERATED=ON -GNinja - cd build && ninja - - .. _build_python: *********************************** @@ -206,8 +189,7 @@ There are several ways to build and install the package from source: --config-settings cmake.define.USE_CUDA=ON \ --config-settings cmake.define.USE_NCCL=ON - Common CMake options - (see :ref:`building-the-shared-library` for the full list): + Common CMake options (see :ref:`build_shared_lib` for the full list): - ``USE_CUDA`` — build with CUDA / GPU acceleration - ``USE_NCCL`` — build with NCCL for distributed GPU training diff --git a/doc/contrib/ci.rst b/doc/contrib/ci.rst index 1d96ea49adc7..6c18ad07ab9a 100644 --- a/doc/contrib/ci.rst +++ b/doc/contrib/ci.rst @@ -117,9 +117,10 @@ YAML file ``containers/ci_container.yml``. For example, when ``IMAGE_REPO`` is s xgb-ci.gpu: container_def: gpu build_args: - CUDA_VERSION_ARG: "12.4.1" - NCCL_VERSION_ARG: "2.23.4-1" - RAPIDS_VERSION_ARG: "24.10" + CUDA_VERSION: "13.3.0" + NCCL_VERSION: "2.30.7-1" + RAPIDS_VERSION: "26.04" + ARCH: x86_64 The ``container_def`` entry indicates where the Dockerfile is located. The container definition will be fetched from ``containers/dockerfile/Dockerfile.CONTAINER_DEF`` where @@ -131,8 +132,8 @@ the build arguments are: .. code-block:: - --build-arg CUDA_VERSION_ARG=12.4.1 --build-arg NCCL_VERSION_ARG=2.23.4-1 \ - --build-arg RAPIDS_VERSION_ARG=24.10 + --build-arg CUDA_VERSION=13.3.0 --build-arg NCCL_VERSION=2.30.7-1 \ + --build-arg RAPIDS_VERSION=26.04 --build-arg ARCH=x86_64 The build arguments provide inputs to the ``ARG`` instructions in the Dockerfile. @@ -152,7 +153,7 @@ Invoke ``ops/docker_run.py`` from the main ``dmlc/xgboost`` repo as follows: python3 ops/docker_run.py \ --image-uri 492475357299.dkr.ecr.us-west-2.amazonaws.com/[image_repo]:[image_tag] \ [--use-gpus] \ - -- "command to run inside the container" + -- command [arguments...] where ``--use-gpus`` should be specified to expose NVIDIA GPUs to the Docker container. @@ -163,13 +164,13 @@ For example: # Run without GPU python3 ops/docker_run.py \ --image-uri 492475357299.dkr.ecr.us-west-2.amazonaws.com/xgb-ci.cpu:main \ - -- bash ops/pipeline/build-cpu-impl.sh cpu + -- bash ops/pipeline/test-python-wheel.sh --suite cpu # Run with NVIDIA GPU python3 ops/docker_run.py \ --image-uri 492475357299.dkr.ecr.us-west-2.amazonaws.com/xgb-ci.gpu:main \ --use-gpus \ - -- bash ops/pipeline/test-python-wheel.sh gpu + -- bash ops/pipeline/test-python-wheel.sh --suite gpu --cuda-version 13 Optionally, you can specify ``--run-args`` to pass extra arguments to ``docker run``: @@ -181,7 +182,7 @@ Optionally, you can specify ``--run-args`` to pass extra arguments to ``docker r --image-uri 492475357299.dkr.ecr.us-west-2.amazonaws.com/xgb-ci.gpu:main \ --use-gpus \ --run-args='--shm-size=4g --privileged' \ - -- bash ops/pipeline/test-python-wheel.sh gpu + -- bash ops/pipeline/test-python-wheel.sh --suite mgpu --cuda-version 13 See :ref:`ci_container_infra` to read about how containers are built and managed in the CI pipelines. @@ -214,7 +215,7 @@ Examples: useful tasks for local development export DOCKER_REGISTRY=492475357299.dkr.ecr.us-west-2.amazonaws.com python3 ops/docker_run.py \ --image-uri ${DOCKER_REGISTRY}/xgb-ci.cpu:main \ - -- ops/pipeline/test-python-wheel.sh cpu + -- ops/pipeline/test-python-wheel.sh --suite cpu * Run Python tests with GPU algorithm @@ -224,7 +225,7 @@ Examples: useful tasks for local development python3 ops/docker_run.py \ --image-uri ${DOCKER_REGISTRY}/xgb-ci.gpu:main \ --use-gpus \ - -- ops/pipeline/test-python-wheel.sh gpu + -- ops/pipeline/test-python-wheel.sh --suite gpu --cuda-version 13 * Run Python tests with GPU algorithm on Linux ARM64 @@ -234,7 +235,7 @@ Examples: useful tasks for local development python3 ops/docker_run.py \ --image-uri ${DOCKER_REGISTRY}/xgb-ci.gpu_aarch64:main \ --use-gpus \ - -- ops/pipeline/test-python-wheel.sh gpu-arm64 + -- ops/pipeline/test-python-wheel.sh --suite gpu-arm64 --cuda-version 13 * Run Python tests with GPU algorithm, with multiple GPUs @@ -245,7 +246,7 @@ Examples: useful tasks for local development --image-uri ${DOCKER_REGISTRY}/xgb-ci.gpu:main \ --use-gpus \ --run-args='--shm-size=4g' \ - -- ops/pipeline/test-python-wheel.sh mgpu + -- ops/pipeline/test-python-wheel.sh --suite mgpu --cuda-version 13 # --shm-size=4g is needed for multi-GPU algorithms to function * Build and test JVM packages @@ -502,15 +503,16 @@ For example, when you run ``bash containers/docker_build.sh xgb-ci.gpu``, the lo # docker_build.sh calls docker_build.py... python3 containers/docker_build.py --container-def gpu \ --image-uri 492475357299.dkr.ecr.us-west-2.amazonaws.com/xgb-ci.gpu:main \ - --build-arg CUDA_VERSION_ARG=12.4.1 --build-arg NCCL_VERSION_ARG=2.23.4-1 \ - --build-arg RAPIDS_VERSION_ARG=24.10 + --build-arg CUDA_VERSION=13.3.0 --build-arg NCCL_VERSION=2.30.7-1 \ + --build-arg RAPIDS_VERSION=26.04 --build-arg ARCH=x86_64 ... # .. and docker_build.py in turn calls "docker build"... - docker build --build-arg CUDA_VERSION_ARG=12.4.1 \ - --build-arg NCCL_VERSION_ARG=2.23.4-1 \ - --build-arg RAPIDS_VERSION_ARG=24.10 \ + docker build --build-arg CUDA_VERSION=13.3.0 \ + --build-arg NCCL_VERSION=2.30.7-1 \ + --build-arg RAPIDS_VERSION=26.04 \ + --build-arg ARCH=x86_64 \ --load --progress=plain \ --ulimit nofile=1024000:1024000 \ -t 492475357299.dkr.ecr.us-west-2.amazonaws.com/xgb-ci.gpu:main \ @@ -526,7 +528,7 @@ Here is an example with ``docker_run.py``: # Run without GPU python3 ops/docker_run.py \ --image-uri 492475357299.dkr.ecr.us-west-2.amazonaws.com/xgb-ci.cpu:main \ - -- bash ops/pipeline/build-cpu-impl.sh cpu + -- bash ops/pipeline/test-python-wheel.sh --suite cpu # Run with NVIDIA GPU # Allocate extra space in /dev/shm to enable NCCL @@ -535,26 +537,26 @@ Here is an example with ``docker_run.py``: --image-uri 492475357299.dkr.ecr.us-west-2.amazonaws.com/xgb-ci.gpu:main \ --use-gpus \ --run-args='--shm-size=4g --privileged' \ - -- bash ops/pipeline/test-python-wheel.sh gpu + -- bash ops/pipeline/test-python-wheel.sh --suite mgpu --cuda-version 13 which are translated to the following ``docker run`` invocations: .. code-block:: bash docker run --rm --pid=host \ - -w /workspace -v /path/to/xgboost:/workspace \ + -v /path/to/xgboost:/workspace -w /workspace \ -e CI_BUILD_UID= -e CI_BUILD_USER= \ -e CI_BUILD_GID= -e CI_BUILD_GROUP= \ 492475357299.dkr.ecr.us-west-2.amazonaws.com/xgb-ci.cpu:main \ - bash ops/pipeline/build-cpu-impl.sh cpu + bash ops/pipeline/test-python-wheel.sh --suite cpu docker run --rm --pid=host --gpus all \ - -w /workspace -v /path/to/xgboost:/workspace \ + -v /path/to/xgboost:/workspace -w /workspace \ -e CI_BUILD_UID= -e CI_BUILD_USER= \ -e CI_BUILD_GID= -e CI_BUILD_GROUP= \ --shm-size=4g --privileged \ 492475357299.dkr.ecr.us-west-2.amazonaws.com/xgb-ci.gpu:main \ - bash ops/pipeline/test-python-wheel.sh gpu + bash ops/pipeline/test-python-wheel.sh --suite mgpu --cuda-version 13 .. _vm_images: diff --git a/doc/contrib/coding_guide.rst b/doc/contrib/coding_guide.rst index e3464d9e322c..8b0bec2b4a2a 100644 --- a/doc/contrib/coding_guide.rst +++ b/doc/contrib/coding_guide.rst @@ -146,7 +146,7 @@ Linter ====== We use a combination of linters to enforce style convention and find potential errors. Linting is especially useful for scripting languages like Python, as we can catch many errors that would have otherwise occurred at run-time. -For Python scripts, `pylint `_, `black `__ and `isort `__ are used for providing guidance on coding style, and `mypy `__ is required for type checking. The Python formatting and pylint checks are provided via the corresponding pre-commit hooks, which operate on changed files. For C++, `cpplint `_ is used along with ``clang-tidy``. For R, ``lintr`` is used. +For Python scripts, `pylint `_, `ruff `__ are used for providing guidance on coding style, and `mypy `__ is required for type checking. The Python formatting and pylint checks are provided via the corresponding pre-commit hooks, which operate on changed files. For C++, `cpplint `_ is used along with ``clang-tidy``. For R, ``lintr`` is used. To run Python checks locally, install the checkers mentioned previously and run the pre-commit hooks for the files you changed: @@ -186,35 +186,20 @@ To run this check locally, use the clang-CUDA helper from the top level source t bash ops/pipeline/run-clang-tidy-clang-cuda.sh This helper configures a clang-generated CUDA compilation database and then runs -``run-clang-tidy -p`` against it. The same path is used by CI. +``run-clang-tidy -p`` against files under ``src/`` using the repository's +``.clang-tidy`` configuration. The same path is used by CI. -By default it lints files under ``src/``. Use environment variables to narrow the -scope or adjust the checks: +Use ``--jobs`` to override the number of parallel clang-tidy processes: .. code-block:: bash cd /path/to/xgboost/ - XGBOOST_TIDY_FILES='src/common/timer.cc,src/predictor/interpretability/shap.cu' \ - XGBOOST_TIDY_CHECKS='-*,google-runtime-int' \ - bash ops/pipeline/run-clang-tidy-clang-cuda.sh - -The helper accepts command-line overrides for the build directory, job count, source -filter, checks, extra arguments, and ``warnings-as-errors`` filter. For example: - -.. code-block:: bash - - cd /path/to/xgboost/ - bash ops/pipeline/run-clang-tidy-clang-cuda.sh \ - --build-dir build-clang-tidy-cuda \ - --jobs 16 \ - --source-filter '.*/(src|include)/.*' \ - --checks '-*,google-runtime-int' + bash ops/pipeline/run-clang-tidy-clang-cuda.sh --jobs 16 The helper expects a clang toolchain with ``clang++``, ``clang-linker-wrapper``, and ``run-clang-tidy`` available either from the active conda base environment or from -``XGBOOST_CLANG_PREFIX``. When using conda, install both ``clangxx`` and -``clang-tools`` so the compiler resource directory and ``run-clang-tidy`` are both -present. +``XGBOOST_CLANG_PREFIX``. By default, it installs ``clang``, ``clangxx``, and +``clang-tools`` from the ``conda-forge`` channel. ********************************** Guide for handling user input data diff --git a/doc/gpu/index.rst b/doc/gpu/index.rst index d6c4fcde4a63..71d3ad36cf24 100644 --- a/doc/gpu/index.rst +++ b/doc/gpu/index.rst @@ -4,7 +4,7 @@ XGBoost GPU Support This page contains information about GPU algorithms supported in XGBoost. -.. note:: CUDA 12.0, Compute Capability 5.0 required (See `this list `_ to look up compute capability of your GPU card.) +.. note:: CUDA >= 12.9 is required. See :ref:`wheel-cuda`. ********************************************* CUDA Accelerated Tree Construction Algorithms diff --git a/doc/install.rst b/doc/install.rst index 1239e7c2e59c..acf524f7d506 100644 --- a/doc/install.rst +++ b/doc/install.rst @@ -16,36 +16,14 @@ Stable Release Python ------ -Pre-built binary wheels are uploaded to PyPI (Python Package Index) for each release. Supported platforms are Linux (x86_64, aarch64), Windows (x86_64) and MacOS (x86_64, Apple Silicon). +Pre-built binary wheels are uploaded to PyPI (Python Package Index) for each release. Supported platforms are Linux (x86_64, aarch64), Windows (x86_64) and MacOS (x86_64, Apple Silicon). In addition the ``xgboost-cpu`` windows package supports aarch64. .. code-block:: bash - # Pip 21.3+ is required pip install xgboost -You might need to run the command with ``--user`` flag or use ``virtualenv`` if you run -into permission errors. - -.. note:: Parts of the Python package now require glibc 2.28+ - - Starting from 2.1.0, XGBoost Python package will be distributed in two variants: - - * ``manylinux_2_28``: for recent Linux distros with glibc 2.28 or newer. This variant comes with all features enabled. - * ``manylinux2014``: for old Linux distros with glibc older than 2.28. This variant does not support GPU algorithms or federated learning. - - The ``pip`` package manager will automatically choose the correct variant depending on your system. - - Starting from **May 31, 2025**, we will stop distributing the ``manylinux2014`` variant and exclusively - distribute the ``manylinux_2_28`` variant. We made this decision so that our CI/CD pipeline won't have - depend on software components that reached end-of-life (such as CentOS 7). We strongly encourage - everyone to migrate to recent Linux distros in order to use future versions of XGBoost. - - Note. If you want to use GPU algorithms or federated learning on an older Linux distro, you have - two alternatives: - - 1. Upgrade to a recent Linux distro with glibc 2.28+. OR - 2. Build XGBoost from the source. +You might need to run the command with ``--user`` flag or use ``virtualenv`` if you run into permission errors. .. note:: Windows users need to install Visual C++ Redistributable @@ -56,7 +34,6 @@ into permission errors. necessary libraries and thus don't need to install Visual C++ Redistributable. - Capabilities of binary wheels for each platform: .. |tick| unicode:: U+2714 @@ -75,15 +52,37 @@ Capabilities of binary wheels for each platform: +---------------------+---------+----------------------+ | Windows | |tick| | |cross| | +---------------------+---------+----------------------+ +| Windows aarch64 | |cross| | |cross| | ++---------------------+---------+----------------------+ Linux aarch64 wheels now ship with CUDA support, so ``pip install xgboost`` on modern Jetson or Graviton machines provides the same GPU functionality as the Linux x86_64 wheel. Multi-node and multi-GPU training remain experimental on ARM64 at this time. +.. _wheel-cuda: + +CUDA toolkit variants (Linux) +***************************** +The default ``xgboost`` wheel for Linux x86_64 and aarch64 is built with CUDA Toolkit 13.x: + +.. code-block:: bash + + pip install xgboost + +Users with GPU whose NVIDIA driver supports CUDA 12 but not CUDA 13 can instead install the CUDA 12 package: + +.. code-block:: bash + + pip uninstall xgboost xgboost-cu12 + pip install xgboost-cu12 + +The CUDA 12 package is a driver-compatibility option. + + Minimal installation (CPU-only) ******************************* -The default installation with ``pip`` will install the full XGBoost package, including the support for the GPU algorithms and federated learning. +The default installation with ``pip`` will install the full XGBoost package, including support for GPU algorithms. You may choose to reduce the size of the installed package and save the disk space, by opting to install ``xgboost-cpu`` instead: @@ -91,8 +90,7 @@ You may choose to reduce the size of the installed package and save the disk spa pip install xgboost-cpu -The ``xgboost-cpu`` variant will have drastically smaller disk footprint, but does not provide some features, such as the GPU algorithms and -federated learning. +The ``xgboost-cpu`` variant has a drastically smaller disk footprint, but does not provide GPU algorithms. Conda ***** diff --git a/include/xgboost/json.h b/include/xgboost/json.h index 4abab6cf4f2a..bda358deae21 100644 --- a/include/xgboost/json.h +++ b/include/xgboost/json.h @@ -12,6 +12,7 @@ #include #include #include +#include #include // std::enable_if_t #include #include @@ -69,7 +70,7 @@ class Value { virtual bool operator==(Value const& rhs) const = 0; virtual Value& operator=(Value const& rhs) = delete; - std::string TypeStr() const; + std::string_view TypeStr() const; private: ValueKind kind_; @@ -85,7 +86,7 @@ T* Cast(U* value) { if (IsA(value)) { return dynamic_cast(value); } else { - LOG(FATAL) << "Invalid cast, from " + value->TypeStr() + " to " + T().TypeStr(); + LOG(FATAL) << "Invalid cast, from " << value->TypeStr() << " to " << T().TypeStr(); } return dynamic_cast(value); // suppress compiler warning. } diff --git a/jvm-packages/pom.xml b/jvm-packages/pom.xml index dd73873aa1fb..eb9a202071bd 100644 --- a/jvm-packages/pom.xml +++ b/jvm-packages/pom.xml @@ -60,9 +60,9 @@ OFF OFF OFF - 24.10.0 - 24.10.0 - cuda12 + 26.04.0 + 26.04.2 + cuda13 3.2.19 2.12.0 false diff --git a/jvm-packages/xgboost4j-spark-gpu/src/test/scala/ml/dmlc/xgboost4j/scala/spark/GpuTestSuite.scala b/jvm-packages/xgboost4j-spark-gpu/src/test/scala/ml/dmlc/xgboost4j/scala/spark/GpuTestSuite.scala index 1bda8f2b18da..407f565f7ed1 100644 --- a/jvm-packages/xgboost4j-spark-gpu/src/test/scala/ml/dmlc/xgboost4j/scala/spark/GpuTestSuite.scala +++ b/jvm-packages/xgboost4j-spark-gpu/src/test/scala/ml/dmlc/xgboost4j/scala/spark/GpuTestSuite.scala @@ -101,7 +101,7 @@ object SparkSessionHolder extends Logging { .config("spark.rapids.sql.test.enabled", "false") .config("spark.stage.maxConsecutiveAttempts", "1") .config("spark.plugins", "com.nvidia.spark.SQLPlugin") - .config("spark.rapids.memory.gpu.pooling.enabled", "false") // Disable RMM for unit tests. + .config("spark.rapids.memory.gpu.pool", "NONE") // Disable RMM for unit tests. .config("spark.sql.files.maxPartitionBytes", "1000") .appName("XGBoost4j-Spark-Gpu unit test") diff --git a/ops/conda_env/aarch64_test.yml b/ops/conda_env/aarch64_test.yml deleted file mode 100644 index fd26e3cd18c1..000000000000 --- a/ops/conda_env/aarch64_test.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: aarch64_test -channels: -- conda-forge -dependencies: -- python=3.12 -- pip -- wheel -- pytest -- pytest-cov -- numpy -- scipy -- scikit-learn -- pandas -- matplotlib -- dask -- distributed -- hypothesis -- graphviz -- python-graphviz -- codecov -- cmake -- ninja -- boto3 -- awscli -- numba -- llvmlite -- loky>=3.5.1 -- pyarrow -- pyspark>=4.0.0 -- cloudpickle -- pip: - - awscli - - auditwheel diff --git a/ops/conda_env/linux_cpu_test.yml b/ops/conda_env/linux_cpu_test.yml deleted file mode 100644 index 1d0b2f29d2b4..000000000000 --- a/ops/conda_env/linux_cpu_test.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: linux_cpu_test -channels: -- conda-forge -dependencies: -- python=3.12 -- cmake>=3.26.4 -- c-compiler -- cxx-compiler -- ninja -- pip -- wheel -- pyyaml -- cpplint -- pylint -- numpy -- scipy -- scikit-learn>=1.4.1 -- pandas -- polars -- matplotlib -- dask<=2024.10.0 -- distributed<=2024.10.0 -- python-graphviz -- hypothesis>=6.46 -- astroid -- sh -- mock -- pytest -- pytest-timeout -- pytest-cov -- python-kubernetes -- urllib3 -- boto3 -- awscli -- py-ubjson -- loky>=3.5.1 -- pyarrow -- cloudpickle -- modin -- pyspark>=4.0.0 diff --git a/ops/pipeline/audit-cuda-wheel.sh b/ops/pipeline/audit-cuda-wheel.sh index de5e396e6afd..644a5fe67cba 100755 --- a/ops/pipeline/audit-cuda-wheel.sh +++ b/ops/pipeline/audit-cuda-wheel.sh @@ -12,7 +12,7 @@ fi if [[ "$#" -lt 1 ]] then - echo "Usage: $0 {x86_64,aarch64} [--cuda-variant {cuda,cuda13}]" + echo "Usage: $0 {x86_64,aarch64} [--cuda-variant {cuda,cuda12}]" exit 2 fi arch="$1" @@ -33,6 +33,15 @@ while [[ $# -gt 0 ]]; do esac done +case "${cuda_variant}" in + cuda|cuda12) + ;; + *) + echo "Invalid CUDA variant: ${cuda_variant}. Expected cuda or cuda12." + exit 2 + ;; +esac + source ops/pipeline/classify-git-branch.sh WHEEL_TAG=manylinux_2_28_${arch} @@ -64,7 +73,7 @@ fi # Check size of wheel pydistcheck --config python-package/pyproject.toml "${final_wheel}" -# Generate meta.json only for the main CUDA variant (not cuda13) +# Generate meta.json only for the default CUDA variant (not cuda12) if [[ $cuda_variant == "cuda" && $arch == "x86_64" ]] then # Generate the meta info which includes xgboost version and the commit info diff --git a/ops/pipeline/build-cpu.sh b/ops/pipeline/build-cpu.sh index 24e9bb2b3ef3..50b520887b03 100755 --- a/ops/pipeline/build-cpu.sh +++ b/ops/pipeline/build-cpu.sh @@ -25,7 +25,6 @@ case "${suite}" in -DCMAKE_C_COMPILER_LAUNCHER=sccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=sccache \ -DCMAKE_COMPILE_WARNING_AS_ERROR=OFF \ - -DCMAKE_PREFIX_PATH='/opt/grpc' \ -DPLUGIN_FEDERATED=ON time ninja -v echo "--- Run Google Test" diff --git a/ops/pipeline/build-cuda-clang.sh b/ops/pipeline/build-cuda-clang.sh index f8cff9968f6a..79f11f642c1a 100755 --- a/ops/pipeline/build-cuda-clang.sh +++ b/ops/pipeline/build-cuda-clang.sh @@ -4,7 +4,7 @@ set -euo pipefail -clang_version="21.1.8" +clang_version="22.1.8" cmake_version="4.2.3" build_dir="build-clang-cuda" target="xgboost" @@ -53,12 +53,17 @@ if [[ "${build_dir}" != /* ]]; then fi if [[ "${XGBOOST_SKIP_CLANG_INSTALL:-0}" != 1 ]]; then + clang_packages=( + "conda-forge::clang==${clang_version}" + "conda-forge::clangxx==${clang_version}" + "conda-forge::clang-tools==${clang_version}" + ) if command -v mamba >/dev/null 2>&1; then - mamba install -y -n base -c conda-forge "clangxx=${clang_version}" "clang-tools=${clang_version}" "cmake=${cmake_version}" + mamba install -y -n base -c conda-forge "${clang_packages[@]}" "cmake=${cmake_version}" elif command -v conda >/dev/null 2>&1; then - conda install -y -n base -c conda-forge "clangxx=${clang_version}" "clang-tools=${clang_version}" "cmake=${cmake_version}" + conda install -y -n base -c conda-forge "${clang_packages[@]}" "cmake=${cmake_version}" else - echo "clangxx=${clang_version}, clang-tools=${clang_version}, and cmake=${cmake_version} are required, but neither mamba nor conda is available." + echo "${clang_packages[*]} and cmake=${cmake_version} are required, but neither mamba nor conda is available." exit 1 fi fi @@ -94,7 +99,7 @@ echo "--- Build with clang-CUDA using ${clang_cxx}" "${cmake_bin}" --version if ! command -v clang-linker-wrapper >/dev/null 2>&1; then - echo "clang-linker-wrapper is required for clang CUDA offload linking. Install clang-tools=${clang_version}." + echo "clang-linker-wrapper is required for clang CUDA offload linking. Install conda-forge::clang-tools==${clang_version}." exit 1 fi if [[ -f "${clang_bin_dir}/x86_64-conda-linux-gnu-clang++.cfg" ]] && diff --git a/ops/pipeline/build-cuda.sh b/ops/pipeline/build-cuda.sh index a71ab41694da..15a64664abee 100755 --- a/ops/pipeline/build-cuda.sh +++ b/ops/pipeline/build-cuda.sh @@ -8,14 +8,14 @@ ## All parameters are required (no defaults). ## ## Examples: -## # CUDA 12 standard build +## # CUDA 12 xgboost-cu12 package build ## build-cuda.sh --cuda-version 12 --use-rmm 0 ## -## # CUDA 12 with RMM -## build-cuda.sh --cuda-version 12 --use-rmm 1 -## -## # CUDA 13 +## # Default CUDA 13 build ## build-cuda.sh --cuda-version 13 --use-rmm 0 +## +## # CUDA 13 with RMM +## build-cuda.sh --cuda-version 13 --use-rmm 1 set -euo pipefail @@ -72,12 +72,9 @@ case "${use_rmm}" in ;; esac -# Validate CUDA 13 constraints -if [[ "${cuda_version}" == "13" ]]; then - if [[ "${use_rmm}" == "1" ]]; then - echo "Error: RMM is not supported for CUDA 13 (--use-rmm must be 0)" - exit 1 - fi +if [[ "${cuda_version}" == "12" && "${use_rmm}" == "1" ]]; then + echo "Error: CUDA 12 is reserved for the xgboost-cu12 package build and does not support RMM" + exit 1 fi # Export validated values @@ -95,9 +92,11 @@ fi set -x -# Configure PyPI variant for CUDA 13 -if [[ "${cuda_version}" == "13" ]]; then - python3 ops/script/pypi_variants.py --use-suffix=cu13 --require-nccl-dep=cu13 +# Configure the PyPI package variant +if [[ "${cuda_version}" == "12" ]]; then + python3 ops/script/pypi_variants.py --use-suffix=cu12 --require-nccl-dep=cu12 +else + python3 ops/script/pypi_variants.py --use-suffix=na --require-nccl-dep=cu13 fi # Run the build implementation directly (we're already inside the container) diff --git a/ops/pipeline/build-python-wheels-arm64-impl.sh b/ops/pipeline/build-python-wheels-arm64-impl.sh deleted file mode 100755 index 263df67f1bd2..000000000000 --- a/ops/pipeline/build-python-wheels-arm64-impl.sh +++ /dev/null @@ -1,32 +0,0 @@ -#!/bin/bash -## Build and test XGBoost with ARM64 CPU -## Companion script for ops/pipeline/build-cpu-arm64.sh - -set -euox pipefail - -source activate aarch64_test - -echo "--- Build libxgboost from the source" -mkdir -p build -pushd build - -cmake .. \ - -GNinja \ - -DCMAKE_PREFIX_PATH="${CONDA_PREFIX}" \ - -DUSE_OPENMP=ON \ - -DHIDE_CXX_SYMBOLS=ON \ - -DGOOGLE_TEST=ON \ - -DUSE_DMLC_GTEST=ON \ - -DENABLE_ALL_WARNINGS=ON \ - -DCMAKE_COMPILE_WARNING_AS_ERROR=OFF -time ninja -v - -echo "--- Run Google Test" -ctest --extra-verbose -popd - -echo "--- Build binary wheel" -pushd python-package -rm -rfv dist/* -pip wheel --no-deps -v . --wheel-dir dist/ -popd diff --git a/ops/pipeline/build-variant-wheels-impl.sh b/ops/pipeline/build-variant-wheels-impl.sh index b033fc2f8571..11b6237ae5a1 100755 --- a/ops/pipeline/build-variant-wheels-impl.sh +++ b/ops/pipeline/build-variant-wheels-impl.sh @@ -19,6 +19,6 @@ set -xu python -m pip install "variantlib[cli] @ git+https://github.com/wheelnext/variantlib.git@main" python -m pip install "nvidia-variant-provider @ git+https://github.com/wheelnext/nvidia-variant-provider.git@master" variantlib make-variant --no-isolation -f python-package/dist/xgboost-*.whl \ - -p "nvidia :: cuda_version_lower_bound :: 12.0" \ - -p "nvidia :: cuda_version_upper_bound :: 13" \ + -p "nvidia :: cuda_version_lower_bound :: 13.0" \ + -p "nvidia :: cuda_version_upper_bound :: 14" \ -o . --pyproject-toml python-package/pyproject.toml diff --git a/ops/pipeline/build-variant-wheels.sh b/ops/pipeline/build-variant-wheels.sh index 87817063d43c..f6b4a349d22b 100755 --- a/ops/pipeline/build-variant-wheels.sh +++ b/ops/pipeline/build-variant-wheels.sh @@ -2,14 +2,14 @@ ## Build Python wheels using Wheel Variant prototype (WheelNext) ## This script runs inside a container (via GitHub Actions container support) ## -## Uses CUDA 12 build settings with RMM disabled. +## Uses CUDA 13 build settings with RMM disabled. ## Does not modify the package name (keeps default 'xgboost'). set -euo pipefail # Use the unified build script with explicit parameters: -# - CUDA 12 +# - CUDA 13 # - RMM disabled exec bash ops/pipeline/build-cuda.sh \ - --cuda-version 12 \ + --cuda-version 13 \ --use-rmm 0 diff --git a/ops/pipeline/nightly-test-cccl-impl.sh b/ops/pipeline/nightly-test-cccl-impl.sh index 65e31e901e74..143feca92bad 100755 --- a/ops/pipeline/nightly-test-cccl-impl.sh +++ b/ops/pipeline/nightly-test-cccl-impl.sh @@ -12,10 +12,15 @@ fi cccl_version="$1" # Set up Conda env +cuda_version="$(nvcc --version | awk '/release/ {gsub(/,/, "", $5); print $5}')" +if [[ ! "${cuda_version}" =~ ^[0-9]+\.[0-9]+$ ]]; then + echo "Failed to determine the CUDA version from nvcc: '${cuda_version}'" + exit 1 +fi gosu root chown -R $(id -u):$(id -g) /opt/miniforge/envs /opt/miniforge/pkgs/cache gosu root chown $(id -u):$(id -g) /opt/miniforge/pkgs mamba create -y -n cccl_test -c conda-forge python=3.13 \ - cuda-version=13.0 cxx-compiler cuda-cudart-dev cuda-nvcc gcc_linux-64=14.* ninja \ + "cuda-version=${cuda_version}" cxx-compiler cuda-cudart-dev cuda-nvcc gcc_linux-64=14.* ninja \ gtest nccl source activate cccl_test diff --git a/ops/pipeline/nightly-test-cccl.sh b/ops/pipeline/nightly-test-cccl.sh index 4eadad262cca..4402b690d17f 100755 --- a/ops/pipeline/nightly-test-cccl.sh +++ b/ops/pipeline/nightly-test-cccl.sh @@ -14,7 +14,7 @@ source ops/pipeline/classify-git-branch.sh source ops/pipeline/get-docker-registry-details.sh source ops/pipeline/get-image-tag.sh -IMAGE_REPO="xgb-ci.gpu_build_cuda13_rockylinux8" +IMAGE_REPO="xgb-ci.gpu_build_rockylinux8" BUILD_IMAGE_URI="${DOCKER_REGISTRY_URL}/${IMAGE_REPO}:${IMAGE_TAG}" echo "--- Build XGBoost with CCCL ${cccl_version}" diff --git a/ops/pipeline/nightly-test-rmm-impl.sh b/ops/pipeline/nightly-test-rmm-impl.sh index e4a38b113a28..1a7dde09d545 100755 --- a/ops/pipeline/nightly-test-rmm-impl.sh +++ b/ops/pipeline/nightly-test-rmm-impl.sh @@ -12,10 +12,15 @@ fi rmm_version="$1" # Set up Conda env +cuda_version="$(nvcc --version | awk '/release/ {gsub(/,/, "", $5); print $5}')" +if [[ ! "${cuda_version}" =~ ^[0-9]+\.[0-9]+$ ]]; then + echo "Failed to determine the CUDA version from nvcc: '${cuda_version}'" + exit 1 +fi gosu root chown -R $(id -u):$(id -g) /opt/miniforge/envs /opt/miniforge/pkgs/cache gosu root chown $(id -u):$(id -g) /opt/miniforge/pkgs mamba create -y -n rmm_test -c conda-forge -c rapidsai-nightly python=3.13 \ - cuda-version=13.0 cxx-compiler cuda-cudart-dev cuda-nvcc gcc_linux-64=14.* ninja \ + "cuda-version=${cuda_version}" cxx-compiler cuda-cudart-dev cuda-nvcc gcc_linux-64=14.* ninja \ gtest nccl "rmm=${rmm_version%.*}.*,>=0.0.0a0" source activate rmm_test diff --git a/ops/pipeline/nightly-test-rmm.sh b/ops/pipeline/nightly-test-rmm.sh index 4f46f9bebba5..476632c0d2f2 100755 --- a/ops/pipeline/nightly-test-rmm.sh +++ b/ops/pipeline/nightly-test-rmm.sh @@ -14,7 +14,7 @@ source ops/pipeline/classify-git-branch.sh source ops/pipeline/get-docker-registry-details.sh source ops/pipeline/get-image-tag.sh -IMAGE_REPO="xgb-ci.gpu_build_cuda13_rockylinux8" +IMAGE_REPO="xgb-ci.gpu_build_rockylinux8" BUILD_IMAGE_URI="${DOCKER_REGISTRY_URL}/${IMAGE_REPO}:${IMAGE_TAG}" echo "--- Build XGBoost with RMM ${rmm_version}" diff --git a/ops/pipeline/run-clang-tidy-clang-cuda.sh b/ops/pipeline/run-clang-tidy-clang-cuda.sh index 0244763f817c..623130505abc 100755 --- a/ops/pipeline/run-clang-tidy-clang-cuda.sh +++ b/ops/pipeline/run-clang-tidy-clang-cuda.sh @@ -3,57 +3,18 @@ set -euo pipefail -clang_version="21.1.8" -cmake_version="4.2.3" build_dir="build-clang-tidy-cuda" -jobs="${XGBOOST_TIDY_JOBS:-}" -checks="${XGBOOST_TIDY_CHECKS:-}" -extra_args_csv="${XGBOOST_TIDY_EXTRA_ARGS:--Wno-everything}" -files_csv="${XGBOOST_TIDY_FILES:-}" -source_filter="${XGBOOST_TIDY_SOURCE_FILTER:-}" -warnings_as_errors="${XGBOOST_TIDY_WARNINGS_AS_ERRORS:-*,-clang-diagnostic-*,-clang-analyzer-*}" +jobs="" while [[ $# -gt 0 ]]; do case "$1" in - --clang-version) - clang_version="$2" - shift 2 - ;; - --cmake-version) - cmake_version="$2" - shift 2 - ;; - --build-dir) - build_dir="$2" - shift 2 - ;; --jobs) jobs="$2" shift 2 ;; - --checks) - checks="$2" - shift 2 - ;; - --extra-arg) - extra_args_csv="$2" - shift 2 - ;; - --files) - files_csv="$2" - shift 2 - ;; - --source-filter) - source_filter="$2" - shift 2 - ;; - --warnings-as-errors) - warnings_as_errors="$2" - shift 2 - ;; *) echo "Unrecognized argument: $1" - echo "Usage: $0 [--clang-version ] [--cmake-version ] [--build-dir ] [--jobs ] [--checks ] [--extra-arg ] [--files ] [--source-filter ] [--warnings-as-errors ]" + echo "Usage: $0 [--jobs ]" exit 1 ;; esac @@ -67,19 +28,11 @@ if [[ -z "${jobs}" ]]; then else jobs=4 fi - if (( jobs > 35 )); then - jobs=35 - fi fi repo_root="$(cd "$(dirname "$0")/../.." && pwd)" -if [[ -z "${source_filter}" ]]; then - source_filter="${repo_root}/src/.*" -fi "${repo_root}/ops/pipeline/build-cuda-clang.sh" \ - --clang-version "${clang_version}" \ - --cmake-version "${cmake_version}" \ --build-dir "${repo_root}/${build_dir}" \ --configure-only @@ -99,36 +52,20 @@ fi clang_run_tidy="${clang_prefix}/bin/run-clang-tidy" if [[ ! -x "${clang_run_tidy}" ]]; then if ! clang_run_tidy="$(command -v run-clang-tidy)"; then - echo "run-clang-tidy is required. Install clang-tools or set XGBOOST_CLANG_PREFIX to a clang prefix containing bin/run-clang-tidy." + echo "run-clang-tidy is required. Install conda-forge::clang-tools or set XGBOOST_CLANG_PREFIX to a clang prefix containing bin/run-clang-tidy." exit 1 fi fi -IFS=',' read -r -a extra_args <<< "${extra_args_csv}" -IFS=',' read -r -a tidy_files <<< "${files_csv}" - tidy_args=( -p "${repo_root}/${build_dir}" \ -j "${jobs}" \ -config-file "${repo_root}/.clang-tidy" \ -header-filter "${repo_root}/(include|src)/.*" \ - -source-filter "${source_filter}" \ + -source-filter "${repo_root}/src/.*" \ + -extra-arg=-Wno-everything \ + -warnings-as-errors="*,-clang-diagnostic-*,-clang-analyzer-*" \ -quiet ) -if [[ -n "${checks}" ]]; then - tidy_args+=(-checks="${checks}") -fi -if [[ -n "${extra_args_csv}" ]]; then - for extra_arg in "${extra_args[@]}"; do - tidy_args+=(-extra-arg="${extra_arg}") - done -fi -if [[ -n "${warnings_as_errors}" ]]; then - tidy_args+=(-warnings-as-errors="${warnings_as_errors}") -fi -if [[ -n "${files_csv}" ]]; then - tidy_args+=("${tidy_files[@]}") -fi - "${clang_run_tidy}" "${tidy_args[@]}" diff --git a/ops/pipeline/run-clang-tidy.sh b/ops/pipeline/run-clang-tidy.sh deleted file mode 100755 index 5daade9f2fd8..000000000000 --- a/ops/pipeline/run-clang-tidy.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -source ops/pipeline/get-docker-registry-details.sh -source ops/pipeline/get-image-tag.sh - -IMAGE_URI=${DOCKER_REGISTRY_URL}/xgb-ci.clang_tidy:${IMAGE_TAG} - -echo "--- Run clang-tidy" -set -x -python3 ops/docker_run.py \ - --image-uri ${IMAGE_URI} \ - -- python3 ops/script/run_clang_tidy.py --cuda-archs 75 diff --git a/ops/pipeline/test-python-wheel.sh b/ops/pipeline/test-python-wheel.sh index fd6163e1fb55..370ff8754fc3 100755 --- a/ops/pipeline/test-python-wheel.sh +++ b/ops/pipeline/test-python-wheel.sh @@ -68,17 +68,10 @@ if [[ -n "${cuda_version}" ]]; then esac fi -# Set up conda environment based on CUDA version and suite +# Set up the suite's pre-built conda environment # Cannot set -u before Conda env activation case "$suite" in gpu|mgpu|gpu-arm64) - if [[ "${cuda_version}" == "13" ]]; then - # CUDA 13: Create conda environment on-the-fly - # Fix permissions for conda directories - gosu root chown -R "$(id -u):$(id -g)" /opt/miniforge/envs /opt/miniforge/pkgs/cache - gosu root chown "$(id -u):$(id -g)" /opt/miniforge/pkgs - mamba create -y -n gpu_test python=3.12 pytest cupy scipy numpy pandas scikit-learn joblib hypothesis - fi source activate gpu_test ;; cpu|cpu-arm64) @@ -96,6 +89,23 @@ export SPARK_TESTING=1 pip install -v ./wheelhouse/*.whl +if [[ -n "${cuda_version}" ]]; then + python - "${cuda_version}" <<'PY' +import sys + +from xgboost import build_info + +expected_cuda_major = int(sys.argv[1]) +cuda_version = build_info()["CUDA_VERSION"] +if cuda_version[0] != expected_cuda_major: + raise RuntimeError( + f"Expected a CUDA {expected_cuda_major} wheel, but it was built with CUDA " + f"{cuda_version[0]}.{cuda_version[1]}" + ) +print(f"Wheel was built with CUDA {cuda_version[0]}.{cuda_version[1]}") +PY +fi + case "$suite" in gpu|gpu-arm64) echo "-- Run Python tests, using a single GPU" diff --git a/ops/script/change_version.py b/ops/script/change_version.py index ab6e3a1d5674..197ca70d1dc1 100644 --- a/ops/script/change_version.py +++ b/ops/script/change_version.py @@ -62,7 +62,7 @@ def pypkg( with open(pyprj_path, "w") as fd: fd.write(pyprj) - make_pyproject(use_suffix="na", require_nccl_dep="cu12") + make_pyproject(use_suffix="na", require_nccl_dep="cu13") @cd(R_PACKAGE) diff --git a/ops/script/release_artifacts.py b/ops/script/release_artifacts.py index 44ba589da6bf..0e0b8d1a20d7 100644 --- a/ops/script/release_artifacts.py +++ b/ops/script/release_artifacts.py @@ -130,16 +130,16 @@ def make_python_sdist( dest = dist_dir / sdist_name shutil.move(src, dest) - # Build stub package `xgboost-cu12`. + # Build stub package `xgboost-cu13`. with DirectoryExcursion(ROOT): - make_pyproject(use_suffix="cu12", require_nccl_dep="na", create_stub=True) + make_pyproject(use_suffix="cu13", require_nccl_dep="na", create_stub=True) with DirectoryExcursion(ROOT / "python-package"): subprocess.run(["python", "-m", "build", "--sdist"], check=True) sdist_name = ( - f"xgboost_cu12-{release}{rc}{rc_ver}.tar.gz" + f"xgboost_cu13-{release}{rc}{rc_ver}.tar.gz" if rc - else f"xgboost_cu12-{release}.tar.gz" + else f"xgboost_cu13-{release}.tar.gz" ) src = DIST / sdist_name subprocess.run(["twine", "check", str(src)], check=True) @@ -156,7 +156,7 @@ def download_python_wheels(branch: str, commit_hash: str, outdir: Path) -> None: "macosx_10_15_x86_64", "macosx_12_0_arm64", ] - cu13_platforms = [ + cu12_platforms = [ "manylinux_2_28_x86_64", "manylinux_2_28_aarch64", ] @@ -173,7 +173,7 @@ def download_python_wheels(branch: str, commit_hash: str, outdir: Path) -> None: for pkg_name, platforms in [ ("xgboost", full_platforms), ("xgboost_cpu", minimal_platforms), - ("xgboost_cu13", cu13_platforms), + ("xgboost_cu12", cu12_platforms), ]: src_filename_prefix = f"{pkg_name}-{args.release}-py3-none-" target_filename_prefix = f"{pkg_name}-{args.release}-py3-none-" diff --git a/ops/script/run_clang_tidy.py b/ops/script/run_clang_tidy.py deleted file mode 100755 index 5f9096ab5f9c..000000000000 --- a/ops/script/run_clang_tidy.py +++ /dev/null @@ -1,309 +0,0 @@ -#!/usr/bin/env python -from __future__ import annotations - -import argparse -import json -import os -import re -import shutil -import subprocess -import sys -from multiprocessing import Pool, cpu_count -from time import time - - -def call(args: list[str]) -> tuple[int, int, str, list[str]]: - """Subprocess run wrapper.""" - completed = subprocess.run(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE) - error_msg = completed.stdout.decode("utf-8") - # `workspace` is a name used in the CI container. Normally we should keep the dir - # as `xgboost`. - matched = re.search( - "(workspace|xgboost)/.*(ops|src|tests|include)/.*warning:", - error_msg, - re.MULTILINE, - ) - - if matched is None: - return_code = 0 - else: - return_code = 1 - return (completed.returncode, return_code, error_msg, args) - - -class ClangTidy: - """clang tidy wrapper. - Args: - args: Command line arguments. - cpp_lint: Run linter on C++ source code. - cuda_lint: Run linter on CUDA source code. - use_dmlc_gtest: Whether to use gtest bundled in dmlc-core. - """ - - def __init__(self, args: argparse.Namespace) -> None: - self.cpp_lint = args.cpp - self.cuda_lint = args.cuda - self.use_dmlc_gtest: bool = args.use_dmlc_gtest - self.cuda_archs = args.cuda_archs.copy() if args.cuda_archs else [] - - if args.tidy_version: - self.exe = "clang-tidy-" + str(args.tidy_version) - else: - self.exe = "clang-tidy" - - print("Run linter on CUDA: ", self.cuda_lint) - print("Run linter on C++:", self.cpp_lint) - print("Use dmlc gtest:", self.use_dmlc_gtest) - print("CUDA archs:", " ".join(self.cuda_archs)) - - if not self.cpp_lint and not self.cuda_lint: - raise ValueError("Both --cpp and --cuda are set to 0.") - self.root_path = os.path.abspath(os.path.curdir) - print("Project root:", self.root_path) - self.cdb_path = os.path.join(self.root_path, "cdb") - - def __enter__(self) -> "ClangTidy": - self.start = time() - if os.path.exists(self.cdb_path): - shutil.rmtree(self.cdb_path) - self._generate_cdb() - return self - - def __exit__(self, *args: list) -> None: - if os.path.exists(self.cdb_path): - shutil.rmtree(self.cdb_path) - self.end = time() - print("Finish running clang-tidy:", self.end - self.start) - - def _generate_cdb(self) -> None: - """Run CMake to generate compilation database.""" - os.mkdir(self.cdb_path) - os.chdir(self.cdb_path) - cmake_args = [ - "cmake", - self.root_path, - "-GNinja", # prevents cmake from using --option-files for include path. - "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON", - "-DGOOGLE_TEST=ON", - "-DCMAKE_CXX_FLAGS='-Wno-clang-diagnostic-deprecated-declarations'", - ] - if self.use_dmlc_gtest: - cmake_args.append("-DUSE_DMLC_GTEST=ON") - else: - cmake_args.append("-DUSE_DMLC_GTEST=OFF") - - if self.cuda_lint: - cmake_args.extend(["-DUSE_CUDA=ON", "-DUSE_NCCL=ON"]) - if self.cuda_archs: - arch_list = ";".join(self.cuda_archs) - cmake_args.append(f"-DCMAKE_CUDA_ARCHITECTURES={arch_list}") - subprocess.run(cmake_args) - os.chdir(self.root_path) - - def convert_nvcc_command_to_clang(self, command: str) -> str: - """Convert nvcc flags to corresponding clang flags.""" - components = command.split() - compiler: str = components[0] - if compiler.find("nvcc") != -1: - compiler = "clang++" - components[0] = compiler - # check each component in a command - converted_components = [compiler] - - for i in range(1, len(components)): - if components[i] == "-lineinfo": - continue - elif components[i] == "-fuse-ld=gold": - continue - elif components[i] == "-fuse-ld=lld": - continue - elif components[i].find("--default-stream") != -1: - continue - elif components[i] == "-rdynamic": - continue - elif components[i] == "-Xfatbin=-compress-all": - continue - elif components[i] == "-forward-unknown-to-host-compiler": - continue - elif components[i] == "-x" and components[i + 1] == "cu": - # -x cu -> -x cuda - converted_components.append("-x") - converted_components.append("cuda") - components[i + 1] = "" - continue - elif components[i].find("-Xcompiler") != -1: - continue - elif components[i].find("--expt-") != -1: - continue - elif components[i].find("-ccbin") != -1: - continue - elif components[i].find("--generate-code") != -1: - keyword = "code=sm" - pos = components[i].find(keyword) - capability = components[i][ - pos + len(keyword) + 1 : pos + len(keyword) + 3 - ] - if pos != -1: - converted_components.append("--cuda-gpu-arch=sm_" + capability) - elif components[i].find("--std=c++14") != -1: - converted_components.append("-std=c++14") - elif components[i].startswith("-isystem="): - converted_components.extend(components[i].split("=")) - else: - converted_components.append(components[i]) - - converted_components.append("-isystem /usr/local/cuda/include/") - - command = "" - for c in converted_components: - command = command + " " + c - command = command.strip() - return command - - def _configure_flags(self, path: str, command: str) -> list[list[str]]: - src = os.path.join(self.root_path, "src").replace("/", "\\/") - include = os.path.join(self.root_path, "include").replace("/", "\\/") - - header_filter = "(" + src + "|" + include + ")" - common_args = [ - self.exe, - path, - "--header-filter=" + header_filter, - "--config-file=" + self.tidy_file, - ] - common_args.append("--") - command = self.convert_nvcc_command_to_clang(command) - - command_split = command.split()[1:] # remove clang/c++/g++ - if "-c" in command_split: - index = command_split.index("-c") - del command_split[index + 1] - command_split.remove("-c") - if "-o" in command_split: - index = command_split.index("-o") - del command_split[index + 1] - command_split.remove("-o") - - common_args.extend(command_split) - - # Two passes, one for device code another for host code. - if path.endswith("cu"): - args = [common_args.copy(), common_args.copy()] - args[0].append("--cuda-host-only") - args[1].append("--cuda-device-only") - else: - args = [common_args.copy()] - for a in args: - a.append("-Wno-unused-command-line-argument") - return args - - def _configure(self) -> list[list[str]]: - """Load and configure compile_commands and clang_tidy.""" - - def should_lint(path: str) -> bool: - if not self.cpp_lint and path.endswith(".cc"): - return False - isxgb = path.find("dmlc-core") == -1 - isxgb = isxgb and (not path.startswith(self.cdb_path)) - if isxgb: - print(path) - return True - return False - - cdb_file = os.path.join(self.cdb_path, "compile_commands.json") - with open(cdb_file, "r") as fd: - self.compile_commands = json.load(fd) - - self.tidy_file = os.path.join(self.root_path, ".clang-tidy") - all_files = [] - for entry in self.compile_commands: - path = entry["file"] - if should_lint(path): - args = self._configure_flags(path, entry["command"]) - all_files.extend(args) - return all_files - - def run(self) -> bool: - """Run clang-tidy.""" - all_files = self._configure() - passed = True - BAR = "-" * 32 - with Pool(cpu_count()) as pool: - results = pool.map(call, all_files) - for i, (process_status, tidy_status, msg, args) in enumerate(results): - # Don't enforce clang-tidy to pass for now due to namespace - # for cub in thrust is not correct. - if tidy_status == 1: - passed = False - print( - BAR, - "\n" "Command args:", - " ".join(args), - ", ", - "Process return code:", - process_status, - ", ", - "Tidy result code:", - tidy_status, - ", ", - "Message:\n", - msg, - BAR, - "\n", - ) - if not passed: - print( - "Errors in `thrust` namespace can be safely ignored.", - "Please address rest of the clang-tidy warnings.", - ) - return passed - - -def test_tidy(args: argparse.Namespace) -> None: - """See if clang-tidy and our regex is working correctly. There are many subtleties - we need to be careful. Tests here are not thorough, at least we want to guarantee - tidy is not missing anything on the CI. - - """ - root_path = os.path.abspath(os.path.curdir) - tidy_file = os.path.join(root_path, ".clang-tidy") - test_file_path = os.path.join(root_path, "ops", "script", "test_tidy.cc") - - tidy_config = "--config-file=" + tidy_file - if not args.tidy_version: - tidy = "clang-tidy" - else: - tidy = "clang-tidy-" + str(args.tidy_version) - cmd = [tidy, tidy_config, test_file_path] - proc_code, tidy_status, error_msg, _ = call(cmd) - if proc_code != 0 or tidy_status != 1: - raise RuntimeError(error_msg) - print("clang-tidy is working.") - - -if __name__ == "__main__": - parser = argparse.ArgumentParser(description="Run clang-tidy.") - parser.add_argument("--cpp", type=int, default=1) - parser.add_argument( - "--tidy-version", - type=int, - default=None, - help="Specify the version of preferred clang-tidy.", - ) - parser.add_argument("--cuda", type=int, default=1) - parser.add_argument( - "--use-dmlc-gtest", - action="store_true", - help="Whether to use gtest bundled in dmlc-core.", - ) - parser.add_argument( - "--cuda-archs", action="append", help="List of CUDA archs to build" - ) - args = parser.parse_args() - - test_tidy(args) - - with ClangTidy(args) as linter: - passed = linter.run() - if not passed: - sys.exit(1) diff --git a/plugin/federated/README.md b/plugin/federated/README.md index 1040c933ef12..d048822ef18f 100644 --- a/plugin/federated/README.md +++ b/plugin/federated/README.md @@ -3,14 +3,22 @@ XGBoost Plugin for Federated Learning This folder contains the plugin for federated learning. -See [build instruction](../../doc/build.rst) for how to build the plugin. +Build +----- +The federated learning plugin requires `grpc` and `protobuf`. To install grpc, refer to the [installation guide from the gRPC website](https://grpc.io/docs/languages/cpp/quickstart/). Alternatively, one can use the `libgrpc` and the `protobuf` package from conda forge if conda is available. After obtaining the required dependencies, enable the flag: `-DPLUGIN_FEDERATED=ON` when running CMake. Please note that only Linux is supported for the federated plugin. + +``` shell + +cmake -B build -S . -DPLUGIN_FEDERATED=ON -GNinja +cd build && ninja + +``` Test Federated XGBoost ---------------------- -```shell + +``` shell # Under xgboost source tree. -cd tests/distributed/test_federated -# This tests both CPU training (`hist`) and GPU training (`gpu_hist`). -./runtests-federated.sh +pytest -sv tests/test_distributed/test_federated ``` diff --git a/python-package/pyproject.toml b/python-package/pyproject.toml index 2f2455b693dc..0a729af1508e 100644 --- a/python-package/pyproject.toml +++ b/python-package/pyproject.toml @@ -1,4 +1,4 @@ -# Generated by `pypi_variants.py`, don't edit: '--use-suffix=na --require-nccl-dep=cu12' +# Generated by `pypi_variants.py`, don't edit: '--use-suffix=na --require-nccl-dep=cu13' [build-system] requires = ["scikit-build-core>=0.11.0"] build-backend = "scikit_build_core.build" @@ -28,7 +28,7 @@ classifiers = [ dependencies = [ "numpy", "scipy", - "nvidia-nccl-cu12 ; platform_system == 'Linux'", + "nvidia-nccl-cu13 ; platform_system == 'Linux'", ] [project.urls] diff --git a/src/common/json.cc b/src/common/json.cc index 67e718f34e5c..1cc13a78fce4 100644 --- a/src/common/json.cc +++ b/src/common/json.cc @@ -147,7 +147,7 @@ void JsonWriter::Visit(JsonBoolean const* boolean) { } // Value -std::string Value::TypeStr() const { +std::string_view Value::TypeStr() const { switch (kind_) { case ValueKind::kString: return "String"; diff --git a/src/common/json_utils.h b/src/common/json_utils.h index a9e07c31e082..ff5f88bb28ca 100644 --- a/src/common/json_utils.h +++ b/src/common/json_utils.h @@ -27,12 +27,12 @@ std::enable_if_t TypeCheckImpl(Json const &value) { template std::string TypeCheckError() { - return "`" + Head{}.TypeStr() + "`"; + return "`" + std::string{Head{}.TypeStr()} + "`"; } template std::enable_if_t TypeCheckError() { - return "`" + Head{}.TypeStr() + "`, " + TypeCheckError(); + return "`" + std::string{Head{}.TypeStr()} + "`, " + TypeCheckError(); } } // namespace detail diff --git a/src/data/array_interface.cc b/src/data/array_interface.cc index 08d90199f457..25fc602a34f6 100644 --- a/src/data/array_interface.cc +++ b/src/data/array_interface.cc @@ -14,7 +14,7 @@ namespace xgboost { std::string ArrayInterfaceHandler::TypeStr(Type type) { auto name_fn = [](std::int32_t bits, char t) { - return std::to_string(bits) + "-bit " + ArrayInterfaceErrors::TypeStr(t); + return std::to_string(bits) + "-bit " + std::string{ArrayInterfaceErrors::TypeStr(t)}; }; switch (type) { case kF2: diff --git a/src/data/array_interface.h b/src/data/array_interface.h index ce393c0fffa4..45d509ae482a 100644 --- a/src/data/array_interface.h +++ b/src/data/array_interface.h @@ -1,5 +1,5 @@ /** - * Copyright 2019-2024, XGBoost Contributors + * Copyright 2019-2026, XGBoost Contributors * \file array_interface.h * \brief View of __array_interface__ */ @@ -12,6 +12,7 @@ #include // for numeric_limits #include // for map #include // for string +#include // for string_view #include // for alignment_of_v, remove_pointer_t, invoke_result_t #include // for vector @@ -55,7 +56,7 @@ struct ArrayInterfaceErrors { return str.c_str(); } - static std::string TypeStr(char c) { + static std::string_view TypeStr(char c) { switch (c) { case 't': return "Bit field"; @@ -91,8 +92,8 @@ struct ArrayInterfaceErrors { } } - static std::string UnSupportedType(StringView typestr) { - return TypeStr(typestr[1]) + "-" + typestr[2] + " is not supported."; + static std::string UnSupportedType(std::string_view typestr) { + return std::string{TypeStr(typestr[1])} + "-" + typestr[2] + " is not supported."; // NOLINT } }; @@ -253,8 +254,8 @@ class ArrayInterfaceHandler { * \brief Extracts the optiona `strides' field and returns whether the array is c-contiguous. */ template - static bool ExtractStride(Object::Map const &array, size_t itemsize, - size_t (&shape)[D], size_t (&stride)[D]) { + static bool ExtractStride(Object::Map const &array, size_t itemsize, size_t (&shape)[D], + size_t (&stride)[D]) { auto strides_it = array.find("strides"); // No stride is provided if (strides_it == array.cend() || IsA(strides_it->second)) { @@ -334,11 +335,13 @@ template <> struct ToDType { static constexpr ArrayInterfaceHandler::Type kType = ArrayInterfaceHandler::kF8; }; +// NumPy's 128-bit floating-point array interface maps to long double on supported hosts. +// NOLINTBEGIN(google-runtime-float) template -struct ToDType && sizeof(long double) == 16>> { +struct ToDType && sizeof(long double) == 16>> { static constexpr ArrayInterfaceHandler::Type kType = ArrayInterfaceHandler::kF16; }; +// NOLINTEND(google-runtime-float) // uint template <> struct ToDType { @@ -407,9 +410,14 @@ class ArrayInterface { ArrayInterfaceHandler::Validate(array); auto typestr = get(array.at("typestr")); - this->AssignType(StringView{typestr}); + this->AssignType(std::string_view{typestr}); ArrayInterfaceHandler::ExtractShape(array, shape); - std::size_t itemsize = typestr[2] - '0'; + std::size_t itemsize = 0; + if (this->type == ArrayInterfaceHandler::kF16) { + itemsize = 16; + } else { + itemsize = typestr[2] - '0'; + } is_contiguous = ArrayInterfaceHandler::ExtractStride(array, itemsize, shape, strides); n = linalg::detail::CalcSize(shape); @@ -466,7 +474,7 @@ class ArrayInterface { explicit ArrayInterface(StringView str) : ArrayInterface{Json::Load(str)} {} - void AssignType(StringView typestr) { + void AssignType(std::string_view typestr) { using T = ArrayInterfaceHandler::Type; if (typestr.size() == 4 && typestr[1] == 'f' && typestr[2] == '1' && typestr[3] == '6') { CHECK(sizeof(long double) == 16) << error::NoF128(); @@ -535,7 +543,7 @@ class ArrayInterface { } #else case T::kF16: - return func(reinterpret_cast(data)); + return func(reinterpret_cast(data)); // NOLINT #endif case T::kI1: return func(reinterpret_cast(data)); @@ -621,7 +629,7 @@ auto DispatchDType(ArrayInterfaceHandler::Type dtype, Fn dispatch) { return dispatch(double{}); } case ArrayInterfaceHandler::kF16: { - using T = long double; + using T = long double; // NOLINT CHECK(sizeof(T) == 16) << error::NoF128(); // Avoid invalid type. if constexpr (sizeof(T) == 16) { diff --git a/src/data/data.cc b/src/data/data.cc index 7868074ccbac..046acd2eb76d 100644 --- a/src/data/data.cc +++ b/src/data/data.cc @@ -1108,7 +1108,7 @@ bst_idx_t SparsePage::Push(AdapterBatchT const& batch, float missing, std::int32 auto& data_vec = data.HostVector(); size_t builder_base_row_offset = this->Size(); - common::ParallelGroupBuilder::type::value_type, + common::ParallelGroupBuilder::value_type, kIsRowMajor> builder(&offset_vec, &data_vec, builder_base_row_offset); // Estimate expected number of rows by using last element in batch diff --git a/src/tree/gpu_hist/histogram.cu b/src/tree/gpu_hist/histogram.cu index 654121ab3fe9..6c5cb8f7861e 100644 --- a/src/tree/gpu_hist/histogram.cu +++ b/src/tree/gpu_hist/histogram.cu @@ -599,7 +599,7 @@ void DeviceHistogramBuilder::AllReduceHist(Context const* ctx, bst_node_t nidx, std::size_t num_histograms) { this->monitor_.Start(__func__); auto d_node_hist = hist_.GetNodeHistogram(nidx); - using ReduceT = typename std::remove_pointer::type::ValueT; + using ReduceT = typename std::remove_pointer_t::ValueT; auto rc = collective::GlobalSum( ctx, linalg::MakeVec(reinterpret_cast(d_node_hist.data()), d_node_hist.size() * 2 * num_histograms, ctx->Device())); diff --git a/tests/cpp/common/test_span.cu b/tests/cpp/common/test_span.cu index 9c2bdc65cd34..6761645f7bfb 100644 --- a/tests/cpp/common/test_span.cu +++ b/tests/cpp/common/test_span.cu @@ -17,29 +17,23 @@ namespace common { struct TestStatus { private: - int *status_; + int* status_; public: - TestStatus () { + TestStatus() { dh::safe_cuda(cudaMalloc(&status_, sizeof(int))); int h_status = 1; - dh::safe_cuda(cudaMemcpy(status_, &h_status, - sizeof(int), cudaMemcpyHostToDevice)); - } - ~TestStatus() { - dh::safe_cuda(cudaFree(status_)); + dh::safe_cuda(cudaMemcpy(status_, &h_status, sizeof(int), cudaMemcpyHostToDevice)); } + ~TestStatus() { dh::safe_cuda(cudaFree(status_)); } int Get() { int h_status; - dh::safe_cuda(cudaMemcpy(&h_status, status_, - sizeof(int), cudaMemcpyDeviceToHost)); + dh::safe_cuda(cudaMemcpy(&h_status, status_, sizeof(int), cudaMemcpyDeviceToHost)); return h_status; } - int* Data() { - return status_; - } + int* Data() { return status_; } }; __global__ void TestFromOtherKernel(Span span) { @@ -64,18 +58,18 @@ __global__ void TestFromOtherKernelConst(Span span) { * \brief Here we just test whether the code compiles. */ TEST(GPUSpan, FromOther) { - thrust::host_vector h_vec (16); + thrust::host_vector h_vec(16); std::iota(h_vec.begin(), h_vec.end(), 0); - thrust::device_vector d_vec (h_vec.size()); + thrust::device_vector d_vec(h_vec.size()); thrust::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); // dynamic extent { - Span span (d_vec.data().get(), d_vec.size()); + Span span(d_vec.data().get(), d_vec.size()); TestFromOtherKernel<<<1, 16>>>(span); } { - Span span (d_vec.data().get(), d_vec.size()); + Span span(d_vec.data().get(), d_vec.size()); TestFromOtherKernelConst<<<1, 16>>>(span); } // static extent @@ -107,11 +101,10 @@ template struct TestEqual { private: T *lhs_, *rhs_; - int *status_; + int* status_; public: - TestEqual(T* _lhs, T* _rhs, int * _status) : - lhs_(_lhs), rhs_(_rhs), status_(_status) {} + TestEqual(T* _lhs, T* _rhs, int* _status) : lhs_(_lhs), rhs_(_rhs), status_(_status) {} XGBOOST_DEVICE void operator()(size_t _idx) { bool res = lhs_[_idx] == rhs_[_idx]; @@ -123,16 +116,16 @@ TEST(GPUSpan, WithTrust) { dh::safe_cuda(cudaSetDevice(0)); // Not adviced to initialize span with host_vector, since h_vec.data() is // a host function. - thrust::host_vector h_vec (16); + thrust::host_vector h_vec(16); std::iota(h_vec.begin(), h_vec.end(), 0); - thrust::device_vector d_vec (h_vec.size()); + thrust::device_vector d_vec(h_vec.size()); thrust::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); // Can't initialize span with device_vector, since d_vec.data() is not raw // pointer { - Span s (d_vec.data().get(), d_vec.size()); + Span s(d_vec.data().get(), d_vec.size()); ASSERT_EQ(d_vec.size(), s.size()); ASSERT_EQ(d_vec.data().get(), s.data()); @@ -140,13 +133,12 @@ TEST(GPUSpan, WithTrust) { { TestStatus status; - thrust::device_vector d_vec1 (d_vec.size()); + thrust::device_vector d_vec1(d_vec.size()); thrust::copy(thrust::device, d_vec.begin(), d_vec.end(), d_vec1.begin()); - Span s (d_vec1.data().get(), d_vec.size()); + Span s(d_vec1.data().get(), d_vec.size()); - dh::LaunchN(16, TestEqual{ - thrust::raw_pointer_cast(d_vec1.data()), - s.data(), status.Data()}); + dh::LaunchN(16, + TestEqual{thrust::raw_pointer_cast(d_vec1.data()), s.data(), status.Data()}); ASSERT_EQ(status.Get(), 1); // FIXME(trivialfis): memory error! @@ -180,13 +172,13 @@ __global__ void TestModifyKernel(Span span) { } TEST(GPUSpan, Modify) { - thrust::host_vector h_vec (16); + thrust::host_vector h_vec(16); InitializeRange(h_vec.begin(), h_vec.end()); - thrust::device_vector d_vec (h_vec.size()); + thrust::device_vector d_vec(h_vec.size()); thrust::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); - Span span (d_vec.data().get(), d_vec.size()); + Span span(d_vec.data().get(), d_vec.size()); TestModifyKernel<<<1, 16>>>(span); @@ -209,37 +201,6 @@ TEST(GPUSpan, Compare) { ASSERT_EQ(status.Get(), 1); } -struct TestElementAccess { - private: - Span span_; - - public: - XGBOOST_DEVICE explicit TestElementAccess (Span _span) : span_(_span) {} - - XGBOOST_DEVICE float operator()(size_t _idx) { - float tmp = span_[_idx]; - return tmp; - } -}; - -TEST(GPUSpanDeathTest, ElementAccess) { - dh::safe_cuda(cudaSetDevice(0)); - auto test_element_access = []() { - thrust::host_vector h_vec (16); - InitializeRange(h_vec.begin(), h_vec.end()); - - thrust::device_vector d_vec (h_vec.size()); - thrust::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); - - Span span (d_vec.data().get(), d_vec.size()); - dh::LaunchN(17, TestElementAccess{span}); - }; - - testing::internal::CaptureStdout(); - EXPECT_DEATH(test_element_access(), ""); - std::string output = testing::internal::GetCapturedStdout(); -} - __global__ void TestFirstDynamicKernel(Span _span) { _span.first::index_type>(-1)>(); } @@ -253,134 +214,8 @@ __global__ void TestLastStaticKernel(Span _span) { _span.last(static_cast::index_type>(-1)); } -TEST(GPUSpanDeathTest, FirstLast) { - // We construct vectors multiple times since thrust can not recover from - // death test. - auto lambda_first_dy = []() { - thrust::host_vector h_vec (4); - InitializeRange(h_vec.begin(), h_vec.end()); - - thrust::device_vector d_vec (h_vec.size()); - thrust::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); - - Span span (d_vec.data().get(), d_vec.size()); - TestFirstDynamicKernel<<<1, 1>>>(span); - }; - testing::internal::CaptureStdout(); - EXPECT_DEATH(lambda_first_dy(), ""); - std::string output = testing::internal::GetCapturedStdout(); - - auto lambda_first_static = []() { - thrust::host_vector h_vec (4); - InitializeRange(h_vec.begin(), h_vec.end()); - - thrust::device_vector d_vec (h_vec.size()); - thrust::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); - - Span span (d_vec.data().get(), d_vec.size()); - TestFirstStaticKernel<<<1, 1>>>(span); - }; - testing::internal::CaptureStdout(); - EXPECT_DEATH(lambda_first_static(), ""); - output = testing::internal::GetCapturedStdout(); - - auto lambda_last_dy = []() { - thrust::host_vector h_vec (4); - InitializeRange(h_vec.begin(), h_vec.end()); - - thrust::device_vector d_vec (h_vec.size()); - thrust::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); - - Span span (d_vec.data().get(), d_vec.size()); - TestLastDynamicKernel<<<1, 1>>>(span); - }; - testing::internal::CaptureStdout(); - EXPECT_DEATH(lambda_last_dy(), ""); - output = testing::internal::GetCapturedStdout(); - - auto lambda_last_static = []() { - thrust::host_vector h_vec (4); - InitializeRange(h_vec.begin(), h_vec.end()); - - thrust::device_vector d_vec (h_vec.size()); - thrust::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); - - Span span (d_vec.data().get(), d_vec.size()); - TestLastStaticKernel<<<1, 1>>>(span); - }; - testing::internal::CaptureStdout(); - EXPECT_DEATH(lambda_last_static(), ""); - output = testing::internal::GetCapturedStdout(); -} - -namespace { -void TestFrontBack() { - Span s; - EXPECT_DEATH( - { - // make sure the termination happens inside this test. - try { - dh::LaunchN(1, [=] __device__(size_t) { s.front(); }); - dh::safe_cuda(cudaDeviceSynchronize()); - dh::safe_cuda(cudaGetLastError()); - } catch (dmlc::Error const& e) { - std::terminate(); - } - }, - ""); - EXPECT_DEATH( - { - try { - dh::LaunchN(1, [=] __device__(size_t) { s.back(); }); - dh::safe_cuda(cudaDeviceSynchronize()); - dh::safe_cuda(cudaGetLastError()); - } catch (dmlc::Error const& e) { - std::terminate(); - } - }, - ""); -} -} // namespace - -TEST(GPUSpanDeathTest, FrontBack) { - TestFrontBack(); -} - -__global__ void TestSubspanDynamicKernel(Span _span) { - _span.subspan(16, 0); -} -__global__ void TestSubspanStaticKernel(Span _span) { - _span.subspan<16>(); -} -TEST(GPUSpanDeathTest, Subspan) { - auto lambda_subspan_dynamic = []() { - thrust::host_vector h_vec (4); - InitializeRange(h_vec.begin(), h_vec.end()); - - thrust::device_vector d_vec (h_vec.size()); - thrust::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); - - Span span (d_vec.data().get(), d_vec.size()); - TestSubspanDynamicKernel<<<1, 1>>>(span); - }; - testing::internal::CaptureStdout(); - EXPECT_DEATH(lambda_subspan_dynamic(), ""); - std::string output = testing::internal::GetCapturedStdout(); - - auto lambda_subspan_static = []() { - thrust::host_vector h_vec (4); - InitializeRange(h_vec.begin(), h_vec.end()); - - thrust::device_vector d_vec (h_vec.size()); - thrust::copy(h_vec.begin(), h_vec.end(), d_vec.begin()); - - Span span (d_vec.data().get(), d_vec.size()); - TestSubspanStaticKernel<<<1, 1>>>(span); - }; - testing::internal::CaptureStdout(); - EXPECT_DEATH(lambda_subspan_static(), ""); - output = testing::internal::GetCapturedStdout(); -} +__global__ void TestSubspanDynamicKernel(Span _span) { _span.subspan(16, 0); } +__global__ void TestSubspanStaticKernel(Span _span) { _span.subspan<16>(); } TEST(GPUSpanIter, Construct) { dh::safe_cuda(cudaSetDevice(0)); diff --git a/tests/python/test_dmatrix.py b/tests/python/test_dmatrix.py index cdfae960cf34..871b94bfb0b3 100644 --- a/tests/python/test_dmatrix.py +++ b/tests/python/test_dmatrix.py @@ -81,6 +81,20 @@ def test_np_view(self): assert from_view.shape == from_array.shape assert (from_view == from_array).all() + @pytest.mark.skipif( + np.dtype(np.longdouble).itemsize != 16, + reason="128-bit NumPy floating point is not supported on this platform", + ) + def test_np_float128_view(self): + base = np.arange(1, 401, dtype=np.longdouble).reshape(100, 4) + view = base[:2, ::2] + assert view.strides == (4 * view.itemsize, 2 * view.itemsize) + + dmat = xgb.DMatrix(view) + np.testing.assert_array_equal( + dmat.get_data().toarray(), view.astype(np.float32) + ) + def test_slice(self): X = rng.randn(100, 100) y = rng.randint(low=0, high=3, size=100).astype(np.float32) diff --git a/tests/python/test_with_polars.py b/tests/python/test_with_polars.py index b79cbafc545c..982c45169991 100644 --- a/tests/python/test_with_polars.py +++ b/tests/python/test_with_polars.py @@ -47,7 +47,9 @@ def test_polars_basic( df = pl.DataFrame({"a": [True, False, False], "b": [False, False, True]}) Xy = DMatrixT(df) - np.testing.assert_equal(Xy.get_data().data, np.array([1, m, m, m, m, 1])) + np.testing.assert_equal( + Xy.get_data().data, np.array([1.0, m, m, m, m, 1.0], dtype=np.float32) + ) def test_polars_missing() -> None: