Skip to content
Open
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
172 changes: 172 additions & 0 deletions .github/workflows/adaptivecpp-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
name: Build with AdaptiveCpp

on:
push:
branches:
- master
pull_request:

permissions:
contents: read

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true

env:
CHANNELS: "-c conda-forge --override-channels"
# examples that AdaptiveCpp can build
SYCL_EXAMPLES: "cython/sycl_buffer cython/use_dpctl_sycl pybind11/external_usm_allocation pybind11/use_dpctl_sycl_queue"
C_EXAMPLES: "c/py_sycl_ls"

jobs:
test_linux:
name: Build and test with AdaptiveCpp, Python ${{ matrix.python }}
runs-on: ubuntu-latest
timeout-minutes: 120
defaults:
run:
shell: bash -el {0}

strategy:
fail-fast: false
matrix:
include:
- python: '3.14'
python_spec: '3.14.*=*_cp314'
- python: '3.14t'
python_spec: '3.14.*=*_cp314t'

steps:
- name: Checkout dpctl repo
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
# the package version comes from git describe
fetch-depth: 0

- name: Cache conda packages
uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
env:
CACHE_NUMBER: 0 # Increase to reset cache
with:
# the package directory that setup-miniconda configures
path: ~/conda_pkgs_dir
key:
${{ runner.os }}-conda-acpp-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-${{ hashFiles('.github/workflows/adaptivecpp-build.yml') }}
restore-keys: |
${{ runner.os }}-conda-acpp-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}-
${{ runner.os }}-conda-acpp-${{ env.CACHE_NUMBER }}-

- uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1
with:
auto-update-conda: true
miniforge-version: latest
activate-environment: acpp
channels: conda-forge
conda-remove-defaults: true

- name: Install AdaptiveCpp and build dependencies
run: |
# the Python build string selects the GIL or the free-threaded variant,
# clang must come from the LLVM that adaptivecpp was built against, and
# intel-opencl-rt provides the OpenCL CPU device to run on; the HIP
# backend plugin links libamdhip64.so.6, which ROCm 7 does not provide
conda install -y ${{ env.CHANNELS }} \
"python=${{ matrix.python_spec }}" \
"adaptivecpp=*=cpu_llvm19*" "clang=19.*" "clangxx=19.*" \
"hip-runtime-amd=6.*" \
intel-opencl-rt \
cmake cython ninja numpy pybind11 pytest scikit-build "setuptools<80" versioneer

- name: Report the environment
run: |
conda list
python -VV
acpp-info -l

- name: Build dpctl
run: |
python scripts/build_locally.py --sycl-provider=AdaptiveCpp

- name: List platforms
run: |
python -m dpctl -f
python -c "from dpctl._diagnostics import sycl_provider; assert sycl_provider() == 'AdaptiveCpp'"

- name: Run dpctl/tests on the OpenMP device
env:
ACPP_VISIBILITY_MASK: omp
run: |
python -m pytest -q --capture=sys dpctl/tests

- name: Run dpctl/tests on the OpenCL CPU device
env:
ACPP_VISIBILITY_MASK: ocl
run: |
python -m pytest -q --capture=sys dpctl/tests

- name: Build examples of extensions
env:
PYTHONPATH: ${{ github.workspace }}
run: |
for d in ${SYCL_EXAMPLES}; do
pushd "examples/${d}" > /dev/null
CC="${CONDA_PREFIX}/bin/clang" CXX="${CONDA_PREFIX}/bin/acpp" \
python setup.py build_ext --inplace -G Ninja -- \
-DDPCTL_SYCL_PROVIDER=AdaptiveCpp \
-DDpctl_DIR="${GITHUB_WORKSPACE}/cmake"
popd > /dev/null
done
for d in ${C_EXAMPLES}; do
pushd "examples/${d}" > /dev/null
python setup.py build_ext --inplace
popd > /dev/null
done

- name: Run examples of extensions on the OpenMP device
env:
ACPP_VISIBILITY_MASK: omp
PYTHONPATH: ${{ github.workspace }}
run: |
for d in ${SYCL_EXAMPLES} ${C_EXAMPLES}; do
# the OpenMP backend allocates plain host memory, so every USM kind
# reports usm_type "host" and this example's checks cannot hold
if [ "${d}" = "pybind11/external_usm_allocation" ]; then
continue
fi
pushd "examples/${d}" > /dev/null
python -m pytest -q tests
popd > /dev/null
done

- name: Run examples of extensions on the OpenCL CPU device
env:
ACPP_VISIBILITY_MASK: ocl
PYTHONPATH: ${{ github.workspace }}
run: |
for d in ${SYCL_EXAMPLES} ${C_EXAMPLES}; do
pushd "examples/${d}" > /dev/null
python -m pytest -q tests
popd > /dev/null
done

- name: Run Python examples on the OpenMP device
working-directory: examples/python
env:
ACPP_VISIBILITY_MASK: omp
run: |
while IFS= read -r script; do
echo "Executing ${script}"
python "${script}" --run all
done < <(find . \( -not -name "_*" -and -name "*.py" \))

- name: Run Python examples on the OpenCL CPU device
working-directory: examples/python
env:
ACPP_VISIBILITY_MASK: ocl
run: |
while IFS= read -r script; do
echo "Executing ${script}"
python "${script}" --run all
done < <(find . \( -not -name "_*" -and -name "*.py" \))
79 changes: 53 additions & 26 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,13 @@ option(DPCTL_GENERATE_COVERAGE_FOR_PYBIND11_EXTENSIONS
OFF
)

# SYCL provider selection
set(DPCTL_SYCL_PROVIDER "Intel" CACHE STRING "SYCL compiler provider (Intel or AdaptiveCpp)")
set_property(CACHE DPCTL_SYCL_PROVIDER PROPERTY STRINGS Intel AdaptiveCpp)

set(DPCTL_TARGET_CUDA
""
CACHE STRING
""
CACHE STRING
"Build DPCTL to target CUDA device. \
Set to a truthy value (e.g., ON, TRUE) to use default architecture (sm_50), \
or to a specific architecture like sm_80."
Expand All @@ -38,24 +42,11 @@ set(DPCTL_TARGET_HIP
CACHE STRING
"Build DPCTL to target a HIP device architecture"
)
option(
DPCTL_WITH_REDIST
"Build DPCTL assuming DPC++ redistributable is installed into Python prefix"
OFF)
option(
DPCTL_OFFLOAD_COMPRESS
"Build using offload section compression feature of DPC++ to reduce \
size of shared object with offloading sections"
OFF
)

find_package(IntelSYCL REQUIRED PATHS ${CMAKE_SOURCE_DIR}/cmake NO_DEFAULT_PATH)

set(_dpctl_sycl_target_compile_options)
set(_dpctl_sycl_target_link_options)

# architecture mapping
set(_dpctl_sycl_targets)
set(_dpctl_cuda_arch)
set(_acpp_targets_list) # Used strictly for AdaptiveCpp

if ("x${DPCTL_SYCL_TARGETS}" STREQUAL "x")
if (DPCTL_TARGET_CUDA)
Expand All @@ -69,15 +60,25 @@ if ("x${DPCTL_SYCL_TARGETS}" STREQUAL "x")
"Expected 'ON', 'TRUE', 'YES', 'Y', '1', or a CUDA architecture like 'sm_80'."
)
endif()
set(_dpctl_sycl_targets "nvidia_gpu_${_dpctl_cuda_arch},spir64-unknown-unknown")

# Map to Provider Formats
if(DPCTL_SYCL_PROVIDER STREQUAL "Intel")
set(_dpctl_sycl_targets "nvidia_gpu_${_dpctl_cuda_arch},spir64-unknown-unknown")
elseif(DPCTL_SYCL_PROVIDER STREQUAL "AdaptiveCpp")
list(APPEND _acpp_targets_list "cuda:${_dpctl_cuda_arch}")
endif()
endif()

if (DPCTL_TARGET_HIP)
if(DPCTL_TARGET_HIP MATCHES "^gfx")
if(_dpctl_sycl_targets)
set(_dpctl_sycl_targets "amd_gpu_${DPCTL_TARGET_HIP},${_dpctl_sycl_targets}")
else()
set(_dpctl_sycl_targets "amd_gpu_${DPCTL_TARGET_HIP},spir64-unknown-unknown")
if(DPCTL_SYCL_PROVIDER STREQUAL "Intel")
if(_dpctl_sycl_targets)
set(_dpctl_sycl_targets "amd_gpu_${DPCTL_TARGET_HIP},${_dpctl_sycl_targets}")
else()
set(_dpctl_sycl_targets "amd_gpu_${DPCTL_TARGET_HIP},spir64-unknown-unknown")
endif()
elseif(DPCTL_SYCL_PROVIDER STREQUAL "AdaptiveCpp")
list(APPEND _acpp_targets_list "hip:${DPCTL_TARGET_HIP}")
endif()
else()
message(FATAL_ERROR
Expand All @@ -94,12 +95,38 @@ else()
)
endif()
set(_dpctl_sycl_targets ${DPCTL_SYCL_TARGETS})
if(DPCTL_SYCL_PROVIDER STREQUAL "AdaptiveCpp")
set(_acpp_targets_list ${DPCTL_SYCL_TARGETS})
endif()
endif()

if (_dpctl_sycl_targets)
message(STATUS "Compiling for -fsycl-targets=${_dpctl_sycl_targets}")
list(APPEND _dpctl_sycl_target_compile_options -fsycl-targets=${_dpctl_sycl_targets})
list(APPEND _dpctl_sycl_target_link_options -fsycl-targets=${_dpctl_sycl_targets})
# Load the SYCL env
set(_dpctl_sycl_target_compile_options)
set(_dpctl_sycl_target_link_options)

if(DPCTL_SYCL_PROVIDER STREQUAL "Intel")
message(STATUS "Using Intel DPC++ SYCL Provider")
find_package(IntelSYCL REQUIRED PATHS ${CMAKE_SOURCE_DIR}/cmake NO_DEFAULT_PATH)

if (_dpctl_sycl_targets)
message(STATUS "Compiling for -fsycl-targets=${_dpctl_sycl_targets}")
list(APPEND _dpctl_sycl_target_compile_options -fsycl-targets=${_dpctl_sycl_targets})
list(APPEND _dpctl_sycl_target_link_options -fsycl-targets=${_dpctl_sycl_targets})
endif()

elseif(DPCTL_SYCL_PROVIDER STREQUAL "AdaptiveCpp")
message(STATUS "Using AdaptiveCpp SYCL Provider")

# AdaptiveCpp reads the ACPP_TARGETS variable directly during find_package
if(_acpp_targets_list)
string(REPLACE ";" ";" ACPP_TARGETS "${_acpp_targets_list}")
set(ACPP_TARGETS "${ACPP_TARGETS}" CACHE STRING "AdaptiveCpp Targets" FORCE)
message(STATUS "Compiling for ACPP_TARGETS=${ACPP_TARGETS}")
endif()

# This automatically provides the add_sycl_to_target macro
find_package(AdaptiveCpp CONFIG REQUIRED)

endif()

add_subdirectory(libsyclinterface)
Expand Down
86 changes: 85 additions & 1 deletion docs/doc_sources/contributor_guides/building.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ To run examples and test suite you would need GPU drivers and/or CPU
OpenCL drivers. It is preferable to use the Intel(R) oneAPI DPC++ compiler
available as part of oneAPI Base-Kit. However, it is possible to use a custom
build of DPC++ to build :py:mod:`dpctl`, especially if you want to enable
CUDA support or try latest features.
CUDA support or try latest features. On Linux OS, AdaptiveCpp can be used
instead of DPC++, see `Building Using AdaptiveCpp`_.

Building using oneAPI DPC++
---------------------------
Expand Down Expand Up @@ -210,6 +211,89 @@ Should a loader be installed under a different file name, override the name that
``LIBZE_SET_LOADER_FILENAME`` CMake variables.


Building Using AdaptiveCpp
--------------------------

:py:mod:`dpctl` can also be built with `AdaptiveCpp <https://adaptivecpp.github.io/>`_
as the SYCL implementation, on Linux OS. The build was tested with AdaptiveCpp
25.10.

Prerequisites for AdaptiveCpp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Install AdaptiveCpp, the ``clang`` that it was built against, and a runtime for
the devices you intend to use. The conda packages, for example:

.. code-block:: bash

conda install -c conda-forge "adaptivecpp=*=cpu_llvm19*" "clang=19.*" \
"clangxx=19.*" intel-opencl-rt tbb

The ``clang`` version must match the LLVM version AdaptiveCpp was built with,
which the build string of the ``adaptivecpp`` package states, as in
``cpu_llvm19_h8255587_10``, hence the pins above. The ``intel-opencl-rt``
package provides an OpenCL CPU device; AdaptiveCpp always provides its own
OpenMP host device, which needs no runtime.

Run ``acpp-info -l`` to list the backends of the installed AdaptiveCpp, and set
the ``ACPP_VISIBILITY_MASK`` environment variable to select among them, for
example ``ACPP_VISIBILITY_MASK=omp`` for the OpenMP host device, or
``ACPP_VISIBILITY_MASK=ocl`` for the OpenCL devices.

Build and Install Using AdaptiveCpp
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Use the driver script with the provider option:

.. code-block:: bash

python scripts/build_locally.py --sycl-provider=AdaptiveCpp

The option defaults the compilers to ``clang`` and ``acpp``, which are taken
from the ``PATH`` unless ``--c-compiler`` and ``--cxx-compiler`` are given, and
it disables Level Zero kernel bundle creation, which only DPC++ implements.
Leaving it on would only check out the Level Zero headers for code that an
AdaptiveCpp build excludes; it does not affect whether a Level Zero device is
available, which depends on the backends AdaptiveCpp itself was built with.

Building with ``setuptools`` directly takes the equivalent CMake variables:

.. code-block:: bash

python setup.py build_ext --inplace -G Ninja -- \
-DCMAKE_C_COMPILER:PATH=clang -DCMAKE_CXX_COMPILER:PATH=acpp \
-DDPCTL_SYCL_PROVIDER=AdaptiveCpp \
-DDPCTL_ENABLE_L0_KERNEL_BUNDLE_CREATION=OFF
python -m pip install -e .

Differences from a DPC++ build
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

An AdaptiveCpp build reports its SYCL implementation through
``dpctl._diagnostics.sycl_provider()``. The following is unavailable in such a
build:

- kernel bundle creation from OpenCL source and from SPIR-V, hence the
:py:mod:`dpctl.compiler` functions and kernel submission through them, both
through the OpenCL and the Level Zero backend
- the raw kernel argument extension
- the atomic memory order, fence order and scope capability descriptors of
devices and of contexts
- the DPC++ version, the backend version and the default selector score

A few behaviors differ as well: a context can span platforms, and a platform is
reported for every backend AdaptiveCpp was built with, including backends with
no device.

Tests covering the above carry the ``unsupported_on_acpp`` pytest marker and are
skipped automatically.

The extension examples under ``examples/`` that build SYCL kernels take
``-DDPCTL_SYCL_PROVIDER=AdaptiveCpp`` as well, with the exception of
``pybind11/onemkl_gemv`` and ``pybind11/use_dpctl_sycl_kernel``, which are
DPC++ only.


Building the libsyclinterface Library
=======================================

Expand Down
Loading
Loading