diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 654afad97a..dccd02b48a 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -17,3 +17,9 @@ b37657e6ad9af16eaec2982d8e2397acd2af2881 # Add cython-lint to pre-commit config 0ce1aef210ffb88b7d2ea3a89e861486498f652f + +# Add new linters and rules to pre-commit +5cf074899f226726d07026db9899bb7632d8c1de + +# Transition from clang-format 18 to clang-format 22 +759dcdc80d0d99790205e87bdd7c5d4f2e93a1ff diff --git a/.github/workflows/conda-package.yml b/.github/workflows/conda-package.yml index 5ab4d9a835..55ae7241ae 100644 --- a/.github/workflows/conda-package.yml +++ b/.github/workflows/conda-package.yml @@ -50,24 +50,17 @@ jobs: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}-python-${{ matrix.python }}- ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Add conda to system path - run: echo $CONDA/bin >> $GITHUB_PATH + run: echo "$CONDA/bin" >> "$GITHUB_PATH" - name: Install conda-build run: conda install conda-build -c conda-forge --override-channels - name: Store conda paths as envs shell: bash -l {0} run: | - echo "WHEELS_OUTPUT_FOLDER=$GITHUB_WORKSPACE${{ runner.os == 'Linux' && '/' || '\\' }}" >> $GITHUB_ENV + echo "WHEELS_OUTPUT_FOLDER=$GITHUB_WORKSPACE${{ runner.os == 'Linux' && '/' || '\\' }}" >> "$GITHUB_ENV" - name: Build conda package run: | # use bootstrap channel to pull NumPy linked with OpenBLAS - CHANNELS="-c conda-forge --override-channels" - VERSIONS="--python ${{ matrix.python }} --numpy 2.0" - TEST="--no-test" - conda build \ - $TEST \ - $VERSIONS \ - $CHANNELS \ - conda-recipe + conda build --no-test --python ${{ matrix.python }} --numpy 2.0 -c conda-forge --override-channels conda-recipe - name: Upload artifact uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: @@ -126,8 +119,8 @@ jobs: - name: Store conda paths as envs shell: bash -l {0} run: | - echo "CONDA_BLD=$CONDA/conda-bld/win-64/" | tr "\\\\" '/' >> $GITHUB_ENV - echo "WHEELS_OUTPUT_FOLDER=$GITHUB_WORKSPACE${{ runner.os == 'Linux' && '/' || '\\' }}" >> $GITHUB_ENV + echo "CONDA_BLD=$CONDA/conda-bld/win-64/" | tr "\\\\" '/' >> "$GITHUB_ENV" + echo "WHEELS_OUTPUT_FOLDER=$GITHUB_WORKSPACE${{ runner.os == 'Linux' && '/' || '\\' }}" >> "$GITHUB_ENV" - name: Build conda package env: @@ -162,16 +155,16 @@ jobs: steps: - name: Construct channels line run: | - echo "CHANNELS=-c ${{ env.INTEL_CHANNEL }} -c conda-forge --override-channels" >> $GITHUB_ENV + echo "CHANNELS=-c ${{ env.INTEL_CHANNEL }} -c conda-forge --override-channels" >> "$GITHUB_ENV" - name: Display channels line run: | - echo ${{ env.CHANNELS }} + echo "${{ env.CHANNELS }}" - name: Download artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} - name: Add conda to system path - run: echo $CONDA/bin >> $GITHUB_PATH + run: echo "$CONDA/bin" >> "$GITHUB_PATH" - name: Install conda-index # Needed to be able to run conda index run: | @@ -179,18 +172,21 @@ jobs: conda install conda-index -c conda-forge --override-channels - name: Create conda channel run: | - mkdir -p $GITHUB_WORKSPACE/channel/linux-64 - conda index $GITHUB_WORKSPACE/channel || exit 1 - mv ${PACKAGE_NAME}-*.conda $GITHUB_WORKSPACE/channel/linux-64 || exit 1 - conda index $GITHUB_WORKSPACE/channel || exit 1 + mkdir -p "$GITHUB_WORKSPACE/channel/linux-64" + conda index "$GITHUB_WORKSPACE/channel" || exit 1 + mv "${PACKAGE_NAME}"-*.conda "$GITHUB_WORKSPACE/channel/linux-64" || exit 1 + conda index "$GITHUB_WORKSPACE/channel" || exit 1 # Test channel - conda search $PACKAGE_NAME -c $GITHUB_WORKSPACE/channel --override-channels --info --json > $GITHUB_WORKSPACE/ver.json + conda search "$PACKAGE_NAME" -c "$GITHUB_WORKSPACE/channel" --override-channels --info --json > "$GITHUB_WORKSPACE/ver.json" cat ver.json - name: Collect dependencies run: | CHANNELS="-c $GITHUB_WORKSPACE/channel ${{ env.CHANNELS }}" - export PACKAGE_VERSION=$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}") - conda create -n ${{ env.TEST_ENV_NAME }} $PACKAGE_NAME=${PACKAGE_VERSION} python=${{ matrix.python }} $CHANNELS --only-deps --dry-run > lockfile + export CHANNELS + PACKAGE_VERSION=$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}") + export PACKAGE_VERSION + # shellcheck disable=SC2086 + conda create -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=${PACKAGE_VERSION} python=${{ matrix.python }} $CHANNELS --only-deps --dry-run > lockfile cat lockfile - name: Set pkgs_dirs run: | @@ -208,38 +204,33 @@ jobs: ${{ runner.os }}-conda-${{ env.CACHE_NUMBER }}- - name: Install dpctl run: | - export CHANNELS="-c $GITHUB_WORKSPACE/channel ${{ env.CHANNELS }}" - export TEST_DEPENDENCIES="pytest pytest-cov cython setuptools" - export PACKAGE_VERSION=$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}") - conda create -n ${{ env.TEST_ENV_NAME }} $PACKAGE_NAME=${PACKAGE_VERSION} ${TEST_DEPENDENCIES} python=${{ matrix.python }} ${CHANNELS} + CHANNELS="-c $GITHUB_WORKSPACE/channel ${{ env.CHANNELS }}" + export CHANNELS + TEST_DEPENDENCIES="pytest pytest-cov cython setuptools" + export TEST_DEPENDENCIES + PACKAGE_VERSION=$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}") + export PACKAGE_VERSION + # shellcheck disable=SC2086 + conda create -n ${{ env.TEST_ENV_NAME }} ${{ env.PACKAGE_NAME }}=${PACKAGE_VERSION} $TEST_DEPENDENCIES python=${{ matrix.python }} $CHANNELS # Test installed packages - conda list -n ${{ env.TEST_ENV_NAME }} + conda list -n "${{ env.TEST_ENV_NAME }}" - name: Smoke test run: | - . $CONDA/etc/profile.d/conda.sh - conda activate ${{ env.TEST_ENV_NAME }} + . "$CONDA/etc/profile.d/conda.sh" + conda activate "${{ env.TEST_ENV_NAME }}" python -c "import dpctl; dpctl.lsplatform(verbosity=2)" - - name: Install gdb - run: | - sudo apt-get update --fix-missing - sudo apt-get install -y gdb - - name: Run test_elementwise under gdb - run: | - . $CONDA/etc/profile.d/conda.sh - conda activate ${{ env.TEST_ENV_NAME }} - gdb --batch -ex r -ex 'info sharedlibrary' -ex 'set print elements 1000' -ex bt --args ${CONDA_PREFIX}/bin/python -m pytest -q -ra --disable-warnings --pyargs dpctl.tests.elementwise.test_trigonometric::test_trig_order -vv || true - name: Create test temp dir # create temporary empty folder to runs tests from # https://github.com/pytest-dev/pytest/issues/11904 - run: mkdir -p ${GITHUB_WORKSPACE}/test_tmp + run: mkdir -p "${GITHUB_WORKSPACE}/test_tmp" - name: Run tests working-directory: ${{ github.workspace }}/test_tmp env: SYCL_CACHE_PERSISTENT: 1 run: | - . $CONDA/etc/profile.d/conda.sh - conda activate ${{ env.TEST_ENV_NAME }} - python -m pytest -v --pyargs $MODULE_NAME + . "$CONDA/etc/profile.d/conda.sh" + conda activate "${{ env.TEST_ENV_NAME }}" + python -m pytest -v --pyargs "${{ env.MODULE_NAME }}" test_windows: needs: build_windows @@ -265,7 +256,7 @@ jobs: - name: Display channels line run: | - echo ${{ env.CHANNELS }} + echo "${{ env.CHANNELS }}" - name: Download artifact uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 @@ -365,8 +356,8 @@ jobs: - name: Report content of test environment shell: cmd /C CALL {0} run: | - echo "Value of CONDA enviroment variable was: " %CONDA% - echo "Value of CONDA_PREFIX enviroment variable was: " %CONDA_PREFIX% + echo "Value of CONDA environment variable was: " %CONDA% + echo "Value of CONDA_PREFIX environment variable was: " %CONDA_PREFIX% conda info && conda list -n ${{ env.TEST_ENV_NAME }} - name: Configure Intel OpenCL CPU RT @@ -435,25 +426,21 @@ jobs: - name: Install anaconda-client run: conda install anaconda-client -c conda-forge --override-channels - name: Add conda to system path - run: echo $CONDA/bin >> $GITHUB_PATH + run: echo "$CONDA/bin" >> "$GITHUB_PATH" - name: Package version - run: echo "PACKAGE_VERSION=$(basename ${{ env.PACKAGE_NAME }}-*.conda | sed 's/^${{ env.PACKAGE_NAME }}-\([^-]*\).*/\1/')" >> $GITHUB_ENV + run: echo "PACKAGE_VERSION=$(basename ${{ env.PACKAGE_NAME }}-*.conda | sed 's/^${{ env.PACKAGE_NAME }}-\([^-]*\).*/\1/')" >> "$GITHUB_ENV" - name: Upload env: ANACONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} - # remove when anaconda-client 1.13.1 is available - ANACONDA_CLIENT_FORCE_STANDALONE: true if: ${{ env.ANACONDA_TOKEN != '' }} run: | - anaconda --token ${{ env.ANACONDA_TOKEN }} upload --user dppy --label dev ${PACKAGE_NAME}-*.conda + anaconda --token "${{ env.ANACONDA_TOKEN }}" upload --user dppy --label dev "${{ env.PACKAGE_NAME }}"-*.conda - name: Upload Wheels env: ANACONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} - # remove when anaconda-client 1.13.1 is available - ANACONDA_CLIENT_FORCE_STANDALONE: true - run: anaconda --token ${{ env.ANACONDA_TOKEN }} upload --user dppy --label dev ${{ env.PACKAGE_NAME }}-*.whl --version ${{ env.PACKAGE_VERSION }} + run: anaconda --token "${{ env.ANACONDA_TOKEN }}" upload --user dppy --label dev "${{ env.PACKAGE_NAME }}"-*.whl --version "${{ env.PACKAGE_VERSION }}" upload_windows: needs: test_windows @@ -490,18 +477,18 @@ jobs: - name: Package version shell: bash -el {0} - run: echo "PACKAGE_VERSION=$(basename ${{ env.PACKAGE_NAME }}-*.conda | sed 's/^${{ env.PACKAGE_NAME }}-\([^-]*\).*/\1/')" >> $GITHUB_ENV + run: echo "PACKAGE_VERSION=$(basename ${{ env.PACKAGE_NAME }}-*.conda | sed 's/^${{ env.PACKAGE_NAME }}-\([^-]*\).*/\1/')" >> "$GITHUB_ENV" - name: Upload env: ANACONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} run: | - anaconda --token ${{ env.ANACONDA_TOKEN }} upload --user dppy --label dev ${{ env.PACKAGE_NAME }}-*.conda + anaconda --token "${{ env.ANACONDA_TOKEN }}" upload --user dppy --label dev "${{ env.PACKAGE_NAME }}"-*.conda - name: Upload Wheels env: ANACONDA_TOKEN: ${{ secrets.ANACONDA_TOKEN }} - run: anaconda --token ${{ env.ANACONDA_TOKEN }} upload --user dppy --label dev ${{ env.PACKAGE_NAME }}-*.whl --version ${{ env.PACKAGE_VERSION }} + run: anaconda --token "${{ env.ANACONDA_TOKEN }}" upload --user dppy --label dev "${{ env.PACKAGE_NAME }}"-*.whl --version "${{ env.PACKAGE_VERSION }}" test_examples_linux: needs: build_linux @@ -520,7 +507,7 @@ jobs: steps: - name: Construct channels line run: | - echo "CHANNELS=-c ${{ env.INTEL_CHANNEL }} -c conda-forge --override-channels" >> $GITHUB_ENV + echo "CHANNELS=-c ${{ env.INTEL_CHANNEL }} -c conda-forge --override-channels" >> "$GITHUB_ENV" - name: Display channels line run: | echo ${{ env.CHANNELS }} @@ -538,21 +525,24 @@ jobs: with: name: ${{ env.PACKAGE_NAME }} ${{ runner.os }} Python ${{ matrix.python }} - name: Add conda to system path - run: echo $CONDA/bin >> $GITHUB_PATH + run: echo "$CONDA/bin" >> "$GITHUB_PATH" - name: Create conda channel run: | - mkdir -p $GITHUB_WORKSPACE/channel/linux-64 - conda index $GITHUB_WORKSPACE/channel || exit 1 - mv ${PACKAGE_NAME}-*.conda $GITHUB_WORKSPACE/channel/linux-64 || exit 1 - conda index $GITHUB_WORKSPACE/channel || exit 1 + mkdir -p "$GITHUB_WORKSPACE/channel/linux-64" + conda index "$GITHUB_WORKSPACE/channel" || exit 1 + mv "${{ env.PACKAGE_NAME }}"-*.conda "$GITHUB_WORKSPACE/channel/linux-64" || exit 1 + conda index "$GITHUB_WORKSPACE/channel" || exit 1 # Test channel - conda search $PACKAGE_NAME -c $GITHUB_WORKSPACE/channel --override-channels --info --json > $GITHUB_WORKSPACE/ver.json + conda search "$PACKAGE_NAME" -c "$GITHUB_WORKSPACE/channel" --override-channels --info --json > "$GITHUB_WORKSPACE/ver.json" cat ver.json - name: Collect dependencies run: | CHANNELS="-c $GITHUB_WORKSPACE/channel ${{ env.CHANNELS }}" - export PACKAGE_VERSION=$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}") - conda create -n ${{ env.EXAMPLES_ENV_NAME }} $PACKAGE_NAME=${PACKAGE_VERSION} python=${{ matrix.python }} $CHANNELS --only-deps --dry-run > lockfile + export CHANNELS + PACKAGE_VERSION=$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}") + export PACKAGE_VERSION + # shellcheck disable=SC2086 + conda create -n ${{ env.EXAMPLES_ENV_NAME }} ${{ env.PACKAGE_NAME }}=${PACKAGE_VERSION} python=${{ matrix.python }} $CHANNELS --only-deps --dry-run > lockfile cat lockfile - name: Set pkgs_dirs run: | @@ -574,96 +564,100 @@ jobs: # TODO: unpin when 2026.0 is available on conda-forge DPCPP_CMPLR: "dpcpp_linux-64>=2025.0,<2026.0" run: | - CHANNELS="${{ env.CHANNELS }}" - . $CONDA/etc/profile.d/conda.sh + export CHANNELS="${{ env.CHANNELS }}" + . "$CONDA/etc/profile.d/conda.sh" DPCTL_DEPENDS="$(python -c "${VER_SCRIPT1} ${VER_SCRIPT3}")" + export DPCTL_DEPENDS echo "Dpctl dependencies: ${DPCTL_DEPENDS}" + # shellcheck disable=SC2086 conda create -n ${{ env.EXAMPLES_ENV_NAME }} -y pytest python=${{ matrix.python }} "setuptools<72.2.0" $CHANNELS echo "Environment created" + # shellcheck disable=SC2086 conda install -n ${{ env.EXAMPLES_ENV_NAME }} -y cmake ninja $CHANNELS || exit 1 echo "Cmake and Ninja installed" + # shellcheck disable=SC2086 conda install -n ${{ env.EXAMPLES_ENV_NAME }} -y pybind11 cython scikit-build $CHANNELS || exit 1 echo "scikit-build installed" + # shellcheck disable=SC2086 conda install -n ${{ env.EXAMPLES_ENV_NAME }} -y mkl-dpcpp \ mkl-devel-dpcpp dpcpp_cpp_rt "${DPCTL_DEPENDS}" \ $CHANNELS || exit 1 echo "IPL installed" + # shellcheck disable=SC2086 conda create -y -n ${{ env.BUILD_ENV_NAME }} $CHANNELS gcc_linux-64 gxx_linux-64 \ "${{ env.DPCPP_CMPLR }}" "${DPCTL_DEPENDS}" \ "sysroot_linux-64>=2.28" echo "Compiler installed" - conda list -n ${{ env.BUILD_ENV_NAME }} + conda list -n "${{ env.BUILD_ENV_NAME }}" - name: Install dpctl shell: bash -l {0} run: | - source $CONDA/etc/profile.d/conda.sh + source "$CONDA/etc/profile.d/conda.sh" CHANNELS="-c $GITHUB_WORKSPACE/channel -c dppy/label/dev -c ${{ env.INTEL_CHANNEL }} -c conda-forge --override-channels" - export PACKAGE_VERSION=$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}") - conda install -n ${{ env.EXAMPLES_ENV_NAME }} -y ${CHANNELS} dpctl=${PACKAGE_VERSION} || exit 1 + export CHANNELS + PACKAGE_VERSION=$(python -c "${VER_SCRIPT1} ${VER_SCRIPT2}") + export PACKAGE_VERSION + # shellcheck disable=SC2086 + conda install -n ${{ env.EXAMPLES_ENV_NAME }} -y $CHANNELS ${{ env.PACKAGE_NAME }}=${PACKAGE_VERSION} || exit 1 - name: Build and run examples of pybind11 extensions shell: bash -l {0} run: | - source $CONDA/etc/profile.d/conda.sh - conda activate ${{ env.EXAMPLES_ENV_NAME }} + source "$CONDA/etc/profile.d/conda.sh" + conda activate "${{ env.EXAMPLES_ENV_NAME }}" conda list cd examples/pybind11 - for d in $(find . -maxdepth 1 -type d -not -path ".") - do - pushd $d + while IFS= read -r d; do + pushd "$d" > /dev/null conda activate --stack build_env CC=icx CXX=icpx python setup.py build_ext --inplace -G Ninja || exit 1 conda deactivate - if [ -e tests ] - then - LD_LIBRARY_PATH=${CONDA_PREFIX}/lib python -m pytest tests || exit 1 + if [ -e tests ]; then + LD_LIBRARY_PATH="${CONDA_PREFIX}/lib" python -m pytest tests || exit 1 else - LD_LIBRARY_PATH=${CONDA_PREFIX}/lib python example.py || exit 1 + LD_LIBRARY_PATH="${CONDA_PREFIX}/lib" python example.py || exit 1 fi - popd - done + popd > /dev/null + done < <(find . -maxdepth 1 -type d -not -path ".") - name: Build and run examples of Cython extensions shell: bash -l {0} run: | - source $CONDA/etc/profile.d/conda.sh - conda activate ${{ env.EXAMPLES_ENV_NAME }} + source "$CONDA/etc/profile.d/conda.sh" + conda activate "${{ env.EXAMPLES_ENV_NAME }}" conda list cd examples/cython - for d in $(find . -maxdepth 1 -type d -not -path ".") - do - pushd $d - conda activate --stack ${{ env.BUILD_ENV_NAME }} + while IFS= read -r d; do + pushd "$d" > /dev/null + conda activate --stack "${{ env.BUILD_ENV_NAME }}" CC=icx CXX=icpx python setup.py build_ext --inplace -G Ninja || exit 1 conda deactivate python -m pytest tests || exit 1 - popd - done + popd > /dev/null + done < <(find . -maxdepth 1 -type d -not -path ".") - name: Build and run examples of C-extensions shell: bash -l {0} run: | - source $CONDA/etc/profile.d/conda.sh - conda activate ${{ env.EXAMPLES_ENV_NAME }} + source "$CONDA/etc/profile.d/conda.sh" + conda activate "${{ env.EXAMPLES_ENV_NAME }}" conda list cd examples/c - for d in $(find . -maxdepth 1 -type d -not -path ".") - do - pushd $d - conda activate --stack ${{ env.BUILD_ENV_NAME }} + while IFS= read -r d; do + pushd "$d" > /dev/null + conda activate --stack "${{ env.BUILD_ENV_NAME }}" python setup.py build_ext --inplace || exit 1 conda deactivate python -m pytest tests || exit 1 - popd - done + popd > /dev/null + done < <(find . -maxdepth 1 -type d -not -path ".") - name: Run Python examples shell: bash -l {0} run: | cd examples/python - source $CONDA/etc/profile.d/conda.sh - conda activate ${{ env.EXAMPLES_ENV_NAME }} - for script in $(find . \( -not -name "_*" -and -name "*.py" \)) - do + source "$CONDA/etc/profile.d/conda.sh" + conda activate "${{ env.EXAMPLES_ENV_NAME }}" + while IFS= read -r script; do echo "Executing ${script}" - python ${script} || exit 1 - done + python "${script}" || exit 1 + done < <(find . \( -not -name "_*" -and -name "*.py" \)) cleanup_packages: name: Clean up anaconda packages diff --git a/.github/workflows/generate-coverage.yaml b/.github/workflows/generate-coverage.yaml index 08ecff8146..a955136361 100644 --- a/.github/workflows/generate-coverage.yaml +++ b/.github/workflows/generate-coverage.yaml @@ -26,10 +26,10 @@ jobs: - name: Add Intel repository run: | - wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB - cat GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null - rm GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB - echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list + wget -qO- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \ + | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null + echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" \ + | sudo tee /etc/apt/sources.list.d/oneAPI.list sudo apt update - name: Install latest Intel OneAPI @@ -112,15 +112,17 @@ jobs: shell: bash -l {0} run: | echo "Processing c-api-coverage" - export DPCTL_LCOV_FN=$(find _skbuild -name dpctl.lcov) - grep "/tmp" $DPCTL_LCOV_FN + DPCTL_LCOV_FN=$(find _skbuild -name dpctl.lcov) + export DPCTL_LCOV_FN + grep "/tmp" "$DPCTL_LCOV_FN" coveralls-lcov -v -n \ - $DPCTL_LCOV_FN > dpctl-c-api-coverage.json + "$DPCTL_LCOV_FN" > dpctl-c-api-coverage.json echo "Processing pytest-coverage" - export DPCTL_PYTEST_LCOV=$(find . -name dpctl_pytest.lcov) - grep "/tmp" $DPCTL_PYTEST_LCOV + DPCTL_PYTEST_LCOV=$(find . -name dpctl_pytest.lcov) + export DPCTL_PYTEST_LCOV + grep "/tmp" "$DPCTL_PYTEST_LCOV" coveralls-lcov -v -n \ - $DPCTL_PYTEST_LCOV > pytest-dpctl-c-api-coverage.json + "$DPCTL_PYTEST_LCOV" > pytest-dpctl-c-api-coverage.json echo "Merging JSON files" python -c "import json; \ fh1 = open('dpctl-c-api-coverage.json', 'r'); \ @@ -133,7 +135,7 @@ jobs: # merge combined file with coverage data and upload ls -lh dpctl-c-api-coverage.json pytest-dpctl-c-api-coverage.json \ combined-dpctl-c-api-coverage.json \ - $(find _skbuild -name dpctl.lcov) $(find . -name dpctl_pytest.lcov) + "$DPCTL_LCOV_FN" "$DPCTL_PYTEST_LCOV" echo "Merging combined files with coverage data" coveralls --service=github --merge=combined-dpctl-c-api-coverage.json env: diff --git a/.github/workflows/generate-docs.yml b/.github/workflows/generate-docs.yml index cbf784a7b2..149a2cda1e 100644 --- a/.github/workflows/generate-docs.yml +++ b/.github/workflows/generate-docs.yml @@ -24,10 +24,10 @@ jobs: - name: Add Intel repository if: ${{ !github.event.pull_request || github.event.action != 'closed' }} run: | - wget https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB - cat GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null - rm GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB - echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" | sudo tee /etc/apt/sources.list.d/oneAPI.list + wget -qO- https://apt.repos.intel.com/intel-gpg-keys/GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB \ + | gpg --dearmor | sudo tee /usr/share/keyrings/oneapi-archive-keyring.gpg > /dev/null + echo "deb [signed-by=/usr/share/keyrings/oneapi-archive-keyring.gpg] https://apt.repos.intel.com/oneapi all main" \ + | sudo tee /etc/apt/sources.list.d/oneAPI.list sudo apt update - name: Install Intel OneAPI if: ${{ !github.event.pull_request || github.event.action != 'closed' }} @@ -75,7 +75,7 @@ jobs: source /opt/intel/oneapi/setvars.sh wget https://github.com/vovkos/doxyrest/releases/download/doxyrest-2.1.2/doxyrest-2.1.2-linux-amd64.tar.xz tar xf doxyrest-2.1.2-linux-amd64.tar.xz - python scripts/gen_docs.py --doxyrest-root=`pwd`/doxyrest-2.1.2-linux-amd64 --verbose --multiversion --clean || exit 1 + python scripts/gen_docs.py --doxyrest-root="$(pwd)/doxyrest-2.1.2-linux-amd64" --verbose --multiversion --clean || exit 1 python -c "import dpctl; print(dpctl.__version__)" || exit 1 mv "$(find _skbuild -type d -path "*/cmake-install/docs/docs" | head -n 1)" ~/docs git clean -dfx @@ -87,9 +87,9 @@ jobs: git remote add tokened_docs https://IntelPython:${{ secrets.GITHUB_TOKEN }}@github.com/IntelPython/dpctl.git git fetch tokened_docs git checkout --track tokened_docs/gh-pages - echo `pwd` + pwd cd master - git rm -rf * + git rm -rf ./* mv ~/docs/* . || exit 1 git add . git config --global user.name 'github-actions[doc-deploy-bot]' @@ -112,10 +112,10 @@ jobs: git remote add tokened_docs https://IntelPython:${{ secrets.GITHUB_TOKEN }}@github.com/IntelPython/dpctl.git git fetch tokened_docs git checkout --track tokened_docs/gh-pages - echo `pwd` - [ -d pulls/${PR_NUM} ] && git rm -rf pulls/${PR_NUM} - mkdir -p pulls/${PR_NUM} - cd pulls/${PR_NUM} + pwd + [ -d "pulls/${PR_NUM}" ] && git rm -rf "pulls/${PR_NUM}" + mkdir -p "pulls/${PR_NUM}" + cd "pulls/${PR_NUM}" mv ~/docs/* . git add . git config --global user.name 'github-actions[doc-deploy-bot]' @@ -131,10 +131,10 @@ jobs: git remote add tokened_docs https://IntelPython:${{ secrets.GITHUB_TOKEN }}@github.com/IntelPython/dpctl.git git fetch tokened_docs git checkout --track tokened_docs/gh-pages - echo `pwd` + pwd ls [ -d pulls ] && ls pulls && echo "This is pull/${PR_NUM}" - [ -d pulls/${PR_NUM} ] && git rm -rf pulls/${PR_NUM} + [ -d "pulls/${PR_NUM}" ] && git rm -rf "pulls/${PR_NUM}" git config --global user.name 'github-actions[doc-deploy-bot]' git config --global user.email 'github-actions[doc-deploy-bot]@users.noreply.github.com' git commit -m "Removing docs for closed pull request ${PR_NUM}" diff --git a/.github/workflows/openssf-scorecard.yml b/.github/workflows/openssf-scorecard.yml index 5e6b9ec8b0..cc512f59be 100644 --- a/.github/workflows/openssf-scorecard.yml +++ b/.github/workflows/openssf-scorecard.yml @@ -69,6 +69,6 @@ jobs: # Upload the results to GitHub's code scanning dashboard. - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@95e58e9a2cdfd71adc6e0353d5c52f41a045d225 # v4.35.2 + uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3 with: sarif_file: results.sarif diff --git a/.github/workflows/os-llvm-sycl-build.yml b/.github/workflows/os-llvm-sycl-build.yml index 9c77f49b7e..53ebd382c4 100644 --- a/.github/workflows/os-llvm-sycl-build.yml +++ b/.github/workflows/os-llvm-sycl-build.yml @@ -59,28 +59,35 @@ jobs: cd sycl_bundle if [[ "${USE_LATEST_SYCLOS:-0}" -eq "1" ]]; then # get list of shas and tags from remote, filter nightly tags and reverse order - export LLVM_TAGS=$(git -c 'versionsort.suffix=-' ls-remote --tags --sort='v:refname' https://github.com/intel/llvm.git | \ + LLVM_TAGS=$(git -c 'versionsort.suffix=-' ls-remote --tags --sort='v:refname' https://github.com/intel/llvm.git | \ grep 'refs/tags/nightly-' | awk '{a[i++]=$0} END {for (j=i-1; j>=0;) print a[j--] }') + export LLVM_TAGS # initialize unset DEPLOY_NIGHTLY_TAG unset DEPLOY_NIGHTLY_TAG_SHA # go through tags and find the most recent one where nighly build binary is available while IFS= read -r NEXT_LLVM_TAG; do - export NEXT_LLVM_TAG_SHA=$(echo ${NEXT_LLVM_TAG} | awk '{print $1}') - export NEXT_NIGHTLY_TAG=$(python3 -c "import sys, urllib.parse as ul; print (ul.quote_plus(sys.argv[1]))" \ - $(echo ${NEXT_LLVM_TAG} | awk '{gsub(/^refs\/tags\//, "", $2)} {print $2}')) - if [[ `wget -S --spider ${DOWNLOAD_URL_PREFIX}/${NEXT_NIGHTLY_TAG}/${ARTIFACT_NAME}.tar.gz 2>&1 | grep 'HTTP/1.1 200 OK'` ]]; + NEXT_LLVM_TAG_SHA=$(echo "${NEXT_LLVM_TAG}" | awk '{print $1}') + export NEXT_LLVM_TAG_SHA + NEXT_NIGHTLY_TAG=$(python3 -c "import sys, urllib.parse as ul; print(ul.quote_plus(sys.argv[1]))" \ + "$(echo "${NEXT_LLVM_TAG}" | awk '{gsub(/^refs\/tags\//, "", $2)} {print $2}')") + export NEXT_NIGHTLY_TAG + if wget -S --spider "${DOWNLOAD_URL_PREFIX}/${NEXT_NIGHTLY_TAG}/${ARTIFACT_NAME}.tar.gz" 2>&1 | grep -q 'HTTP/1.1 200 OK'; then - export DEPLOY_NIGHTLY_TAG=${NEXT_NIGHTLY_TAG} - export DEPLOY_LLVM_TAG_SHA=${NEXT_LLVM_TAG_SHA} + DEPLOY_NIGHTLY_TAG="${NEXT_NIGHTLY_TAG}" + export DEPLOY_NIGHTLY_TAG + DEPLOY_LLVM_TAG_SHA="${NEXT_LLVM_TAG_SHA}" + export DEPLOY_LLVM_TAG_SHA break fi done <<< "${LLVM_TAGS}" else # Use latest known to work tag instead - export DEPLOY_NIGHTLY_TAG="sycl-nightly%2F20230606" - export DEPLOY_LLVM_TAG_SHA=f44d0133d4b0077298f034697a1f3818ff1d6134 + DEPLOY_NIGHTLY_TAG="sycl-nightly%2F20230606" + export DEPLOY_NIGHTLY_TAG + DEPLOY_LLVM_TAG_SHA=f44d0133d4b0077298f034697a1f3818ff1d6134 + export DEPLOY_LLVM_TAG_SHA fi [[ -n "${DEPLOY_NIGHTLY_TAG}" ]] || exit 1 @@ -90,16 +97,20 @@ jobs: if [[ -f bundle_id.txt && ( "$(cat bundle_id.txt)" == "${DEPLOY_LLVM_TAG_SHA}" ) ]]; then echo "Using cached download of ${DEPLOY_LLVM_TAG_SHA}" else - rm -rf ${ARTIFACT_NAME}.tar.gz - wget ${DOWNLOAD_URL_PREFIX}/${DEPLOY_NIGHTLY_TAG}/${ARTIFACT_NAME}.tar.gz && echo ${DEPLOY_LLVM_TAG_SHA} > bundle_id.txt || rm -rf bundle_id.txt - [ -f ${OCLCPUEXP_FN} ] || wget ${DOWNLOAD_URL_PREFIX}/${DRIVER_PATH}/${OCLCPUEXP_FN} || rm -rf bundle_id.txt - [ -f ${TBB_FN} ] || wget ${TBB_URL}/${TBB_FN} || rm -rf bundle_id.txt + rm -rf "${ARTIFACT_NAME}.tar.gz" + if wget "${DOWNLOAD_URL_PREFIX}/${DEPLOY_NIGHTLY_TAG}/${ARTIFACT_NAME}.tar.gz"; then + echo "${DEPLOY_LLVM_TAG_SHA}" > bundle_id.txt + else + rm -rf bundle_id.txt + fi + [ -f "${OCLCPUEXP_FN}" ] || wget "${DOWNLOAD_URL_PREFIX}/${DRIVER_PATH}/${OCLCPUEXP_FN}" || rm -rf bundle_id.txt + [ -f "${TBB_FN}" ] || wget "${TBB_URL}/${TBB_FN}" || rm -rf bundle_id.txt rm -rf dpcpp_compiler mkdir -p dpcpp_compiler - tar xf ${ARTIFACT_NAME}.tar.gz -C dpcpp_compiler + tar xf "${ARTIFACT_NAME}.tar.gz" -C dpcpp_compiler mkdir -p oclcpuexp - [ -d oclcpuexp/x64 ] || tar xf ${OCLCPUEXP_FN} -C oclcpuexp - [ -d ${TBB_INSTALL_DIR}/lib ] || tar xf ${TBB_FN} + [ -d oclcpuexp/x64 ] || tar xf "${OCLCPUEXP_FN}" -C oclcpuexp + [ -d "${TBB_INSTALL_DIR}/lib" ] || tar xf "${TBB_FN}" cp oclcpuexp/x64/libOpenCL.so* dpcpp_compiler/lib/ fi @@ -152,7 +163,7 @@ jobs: run: | source set_allvars.sh python scripts/build_locally.py --c-compiler=clang --cxx-compiler=clang++ \ - --compiler-root=${SYCL_BUNDLE_FOLDER}/dpcpp_compiler/bin || exit 1 + --compiler-root="${SYCL_BUNDLE_FOLDER}/dpcpp_compiler/bin" || exit 1 - name: Run lsplatforms shell: bash -l {0} diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 7a136e5903..8c8f6fc9a9 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -9,13 +9,20 @@ permissions: read-all jobs: pre-commit: + name: pre-commit + runs-on: ubuntu-24.04 timeout-minutes: 30 + steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0 with: - python-version: '3.12' + python-version: '3.14' + - name: Install from PyPI + shell: bash -l {0} + run: | + pip install codespell pylint - name: Version of clang-format run: | clang-format --version diff --git a/.github/workflows/run-tests-from-dppy-bits.yaml b/.github/workflows/run-tests-from-dppy-bits.yaml index 4add1ff769..b40baf7252 100644 --- a/.github/workflows/run-tests-from-dppy-bits.yaml +++ b/.github/workflows/run-tests-from-dppy-bits.yaml @@ -35,11 +35,11 @@ jobs: steps: - name: Construct channels line run: | - echo "CHANNELS=-c ${{ env.INTEL_CHANNEL }} -c conda-forge --override-channels" >> $GITHUB_ENV + echo "CHANNELS=-c ${{ env.INTEL_CHANNEL }} -c conda-forge --override-channels" >> "$GITHUB_ENV" - name: Display channels line run: | - echo ${{ env.CHANNELS }} + echo "${{ env.CHANNELS }}" - name: Set pkgs_dirs run: | @@ -47,27 +47,27 @@ jobs: - name: Install dpctl run: | - conda create -n ${{ env.TEST_ENV_NAME }} -c dppy/label/dev ${{ env.CHANNELS }} dpctl pytest pytest-cov cython setuptools c-compiler cxx-compiler + conda create -n "${{ env.TEST_ENV_NAME }}" -c dppy/label/dev "${{ env.CHANNELS }}" dpctl pytest pytest-cov cython setuptools c-compiler cxx-compiler - name: Smoke test run: | - . $CONDA/etc/profile.d/conda.sh - conda activate ${{ env.TEST_ENV_NAME }} + . "$CONDA/etc/profile.d/conda.sh" + conda activate "${{ env.TEST_ENV_NAME }}" python -m dpctl -f - name: Create test temp dir # create temporary empty folder to runs tests from # https://github.com/pytest-dev/pytest/issues/11904 - run: mkdir -p ${GITHUB_WORKSPACE}/test_tmp + run: mkdir -p "${GITHUB_WORKSPACE}/test_tmp" - name: Run tests working-directory: ${{ github.workspace }}/test_tmp env: SYCL_CACHE_PERSISTENT: 1 run: | - . $CONDA/etc/profile.d/conda.sh - conda activate ${{ env.TEST_ENV_NAME }} - python -m pytest -v --pyargs $MODULE_NAME + . "$CONDA/etc/profile.d/conda.sh" + conda activate "${{ env.TEST_ENV_NAME }}" + python -m pytest -v --pyargs "${{ env.MODULE_NAME }}" test_windows: @@ -94,7 +94,7 @@ jobs: - name: Display channels line run: | - echo ${{ env.CHANNELS }} + echo "${{ env.CHANNELS }}" - uses: conda-incubator/setup-miniconda@8ee1f361103df19b6f8c8655fd3967a8ecb162d5 # v4.0.1 with: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 672b8300a7..a961d47d09 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,5 +1,6 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks +exclude: "docs/_legacy/" repos: - repo: https://github.com/PyCQA/bandit rev: '1.9.4' @@ -10,8 +11,48 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v6.0.0 hooks: + # Git + - id: check-added-large-files + - id: no-commit-to-branch + name: "ensure no direct commit to master/maintenance branches" + args: [--branch, "master", --pattern, "maintenance/.*"] + - id: check-case-conflict + - id: check-illegal-windows-names + - id: check-ast + - id: check-builtin-literals + - id: check-case-conflict + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-symlinks + - id: check-toml + - id: debug-statements + - id: destroyed-symlinks - id: end-of-file-fixer + - id: fix-byte-order-marker + - id: mixed-line-ending - id: trailing-whitespace +- repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: python-check-blanket-noqa + - id: python-check-blanket-type-ignore + - id: python-check-mock-methods + - id: python-no-eval + - id: python-no-log-warn + - id: python-use-type-annotations + - id: rst-backticks + - id: rst-directive-colons + - id: rst-inline-touching-normal + - id: text-unicode-replacement-char +- repo: https://github.com/codespell-project/codespell + rev: v2.4.1 + hooks: + - id: codespell + args: ["-L", "ba,som,xWindows"] # ignore some variable names + additional_dependencies: + - tomli + exclude: "docs/doxyrest-config.lua.in" - repo: https://github.com/psf/black rev: 26.3.1 hooks: @@ -32,8 +73,8 @@ repos: rev: 7.3.0 hooks: - id: flake8 -- repo: https://github.com/pocc/pre-commit-hooks - rev: v1.3.5 +- repo: https://github.com/pre-commit/mirrors-clang-format + rev: v22.1.3 hooks: - id: clang-format args: ["-i"] @@ -47,3 +88,19 @@ repos: hooks: - id: cython-lint - id: double-quote-cython-strings + +- repo: https://github.com/jumanjihouse/pre-commit-hooks + rev: 3.0.0 + hooks: + - id: shellcheck + +- repo: https://github.com/gitleaks/gitleaks + rev: v8.30.0 + hooks: + - id: gitleaks + +- repo: https://github.com/rhysd/actionlint + rev: v1.7.11 + hooks: + - id: actionlint + args: ["-ignore", "SC2317"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d16c02dbc..0a9e67c252 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,11 +12,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +## [0.22.1] - Apr. 24, 2026 + +This is a bug-fix release which fixes a memory leak in `dpctl.RawKernelArg`. + +### Fixed +* Fixed a memory leak in `dpctl.RawKernelArg` [gh-2294](https://github.com/IntelPython/dpctl/pull/2294) + ## [0.22.0] - Apr. 14, 2026 The highlight of this release is the full migration of `dpctl.tensor` submodule to sister project [`dpnp`](https://github.com/IntelPython/dpnp), shrinking the size of the package tremendously, by between 93% and 96%. The `__sycl_usm_array_interface__` is still supported, with `dpctl` serving as curator of the protocol. - Additionally, `dpctl` build scripts were updated, removing use of `python setup.py develop` and `python setup.py install`, and `dpctl` [documentation page](https://intelpython.github.io/dpctl/latest/index.html) now supports a version dropdown. **NOTE**: Changes below which reference `tensor` were added to the `tensor` submodule prior to release, and therefore are included in the migrated `tensor` submodule in [`dpnp`](https://github.com/IntelPython/dpnp). They are included here for transparency and continuity of the submodule's history in the changelog. diff --git a/README.md b/README.md index 428fd0410f..04507fe063 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ To get the library from the latest oneAPI release, follow the instructions from Intel(R) [oneAPI installation guide](https://www.intel.com/content/www/us/en/developer/articles/guide/installation-guide-for-oneapi-toolkits.html). -> **NOTE:** You need to install the Intel(R) oneAPI AI Analytics Tookit to get +> **NOTE:** You need to install the Intel(R) oneAPI AI Analytics Toolkit to get >IDP and `dpctl`. diff --git a/cmake/IntelSYCLConfig.cmake b/cmake/IntelSYCLConfig.cmake old mode 100755 new mode 100644 index c51e47290c..7a4721dd6a --- a/cmake/IntelSYCLConfig.cmake +++ b/cmake/IntelSYCLConfig.cmake @@ -18,7 +18,7 @@ IntelSYCLConfig ------- -Library to verify SYCL compatability of CMAKE_CXX_COMPILER +Library to verify SYCL compatibility of CMAKE_CXX_COMPILER and passes relevant compiler flags. Result Variables @@ -290,7 +290,7 @@ if(nosycllang) set(IntelSYCL_NOT_FOUND_MESSAGE "${SYCL_REASON_FAILURE}") endif() -# Placeholder for identifying various implemenations of SYCL compilers. +# Placeholder for identifying various implementations of SYCL compilers. # for now, set to the CMAKE_CXX_COMPILER_ID set(SYCL_IMPLEMENTATION_ID "${CMAKE_CXX_COMPILER_ID}") diff --git a/conda-recipe/build.sh b/conda-recipe/build.sh index 1ca6329e3a..e892602ede 100755 --- a/conda-recipe/build.sh +++ b/conda-recipe/build.sh @@ -5,8 +5,10 @@ export LIBRARY_PATH="$LIBRARY_PATH:${BUILD_PREFIX}/lib" # Intel LLVM must cooperate with compiler and sysroot from conda echo "--gcc-toolchain=${BUILD_PREFIX} --sysroot=${BUILD_PREFIX}/${HOST}/sysroot -target ${HOST}" > icpx_for_conda.cfg -export ICPXCFG="$(pwd)/icpx_for_conda.cfg" -export ICXCFG="$(pwd)/icpx_for_conda.cfg" +ICPXCFG="$(pwd)/icpx_for_conda.cfg" +export ICPXCFG +ICXCFG="$(pwd)/icpx_for_conda.cfg" +export ICXCFG read -r GLIBC_MAJOR GLIBC_MINOR <<<"$(conda list '^sysroot_linux-64$' \ | tail -n 1 | awk '{print $2}' | grep -oP '\d+' | head -n 2 | tr '\n' ' ')" diff --git a/conda-recipe/run_test.sh b/conda-recipe/run_test.sh old mode 100644 new mode 100755 diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index d2053d106c..0bd31e059c 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -4,10 +4,10 @@ option(DPCTL_ENABLE_DOXYREST OFF ) -# Option to add verion links to the side bar. This option is primarily +# Option to add version links to the side bar. This option is primarily # intended to generate dpctl's docs for our github.io page. option(DPCTL_USE_MULTIVERSION_TEMPLATE - "Enable adding verion links to side bar" + "Enable adding version links to side bar" OFF ) diff --git a/docs/_legacy/docfiles/user_guides/QuickStart.rst b/docs/_legacy/docfiles/user_guides/QuickStart.rst index 57c443e543..382528cc98 100644 --- a/docs/_legacy/docfiles/user_guides/QuickStart.rst +++ b/docs/_legacy/docfiles/user_guides/QuickStart.rst @@ -262,7 +262,7 @@ library. pushd build || exit 1 INSTALL_PREFIX=$(pwd)/../install - rm -rf ${INSTALL_PREFIX} + rm -rf "${INSTALL_PREFIX}" export ONEAPI_ROOT=/opt/intel/oneapi DPCPP_ROOT=${ONEAPI_ROOT}/compiler/latest/linux diff --git a/docs/doc_sources/_static/dpctl.svg b/docs/doc_sources/_static/dpctl.svg old mode 100755 new mode 100644 diff --git a/docs/doc_sources/api_reference/dpctl/filter_selector_string.rst b/docs/doc_sources/api_reference/dpctl/filter_selector_string.rst index b31edbf789..f96a8764df 100644 --- a/docs/doc_sources/api_reference/dpctl/filter_selector_string.rst +++ b/docs/doc_sources/api_reference/dpctl/filter_selector_string.rst @@ -24,7 +24,7 @@ least one component. ``Backend`` specifies the desired backend of targeted devices, while ``DeviceType`` specifies the type of targeted devices. ``RelativeDeviceNumber`` refers to the number of the device that matches -any other given requirements, starting from `0` to marking the +any other given requirements, starting from 0 to marking the "first device that matches the requirements". Attempting to use a non-conforming string in places where filter selector diff --git a/docs/doc_sources/api_reference/dpctl_cmake.rst b/docs/doc_sources/api_reference/dpctl_cmake.rst index 62a9135e5f..e72b5dc23c 100644 --- a/docs/doc_sources/api_reference/dpctl_cmake.rst +++ b/docs/doc_sources/api_reference/dpctl_cmake.rst @@ -3,7 +3,7 @@ CMake support ============= -:py:mod:`dpctl` comes with the configuration file `dpctl-config.cmake` which is installed +:py:mod:`dpctl` comes with the configuration file :file:`dpctl-config.cmake` which is installed on the `standard search path CMake uses to search for packages `_. To build your extension that leverages :py:mod:`dpctl`, include the following line in your CMake script: diff --git a/docs/doc_sources/beginners_guides/installation.rst b/docs/doc_sources/beginners_guides/installation.rst index 75fab31e02..c3d41bf658 100644 --- a/docs/doc_sources/beginners_guides/installation.rst +++ b/docs/doc_sources/beginners_guides/installation.rst @@ -211,7 +211,7 @@ AMD build python scripts/build_locally.py --verbose --target-hip= -Note that the `oneAPI for AMD GPUs` plugin requires the architecture be specified and only +Note that the oneAPI for AMD GPUs plugin requires the architecture be specified and only one architecture can be specified at a time. To determine the architecture code (````) for your AMD GPU, run: diff --git a/docs/doc_sources/beginners_guides/managing_devices.rst b/docs/doc_sources/beginners_guides/managing_devices.rst index 4e7ec12cca..9389f47fc3 100644 --- a/docs/doc_sources/beginners_guides/managing_devices.rst +++ b/docs/doc_sources/beginners_guides/managing_devices.rst @@ -310,7 +310,7 @@ For Intel GPU devices, additional architectural information can be access with : In [2]: d_gpu = dpctl.SyclDevice() - # Output for Iris Xe integerate GPU, with PCI ID 0x9a49 + # Output for Iris Xe integrate GPU, with PCI ID 0x9a49 # (corresponding decimal value: 39497) In [3]: dpctl.utils.intel_device_info(d_gpu) Out[3]: diff --git a/docs/doc_sources/contributor_guides/building.rst b/docs/doc_sources/contributor_guides/building.rst index f1681c6c6a..df2a8c35b2 100644 --- a/docs/doc_sources/contributor_guides/building.rst +++ b/docs/doc_sources/contributor_guides/building.rst @@ -209,7 +209,7 @@ library. pushd build || exit 1 INSTALL_PREFIX=$(pwd)/../install - rm -rf ${INSTALL_PREFIX} + rm -rf "${INSTALL_PREFIX}" export ONEAPI_ROOT=/opt/intel/oneapi # Values are set as appropriate for oneAPI DPC++ 2024.0 # or later. diff --git a/docs/doc_sources/extlinks_gen.py b/docs/doc_sources/extlinks_gen.py index 6e61624cda..789e3a433a 100644 --- a/docs/doc_sources/extlinks_gen.py +++ b/docs/doc_sources/extlinks_gen.py @@ -19,7 +19,7 @@ def create_extlinks(): """Reads a JSON file to create a dictionary of urls in the format supported - by the sphinx.ect.extlinks extension. + by the sphinx.ext.extlinks extension. Returns: dict: A dictionary that is understood by the extlinks Sphinx extension. diff --git a/docs/doc_sources/index.rst b/docs/doc_sources/index.rst index e69559f7f6..3923b716b5 100644 --- a/docs/doc_sources/index.rst +++ b/docs/doc_sources/index.rst @@ -56,7 +56,7 @@ Intel(R) oneAPI :dpcpp_compiler:`DPC++ compiler <>`. Access API Reference - .. grid-item-card:: Contibutor Guides + .. grid-item-card:: Contributor Guides The contributing guidelines will suggest a process of contributing to :mod:`dpctl`. diff --git a/docs/doc_sources/user_guides/basic_concepts.rst b/docs/doc_sources/user_guides/basic_concepts.rst index d2438e4a38..ebec1d6377 100644 --- a/docs/doc_sources/user_guides/basic_concepts.rst +++ b/docs/doc_sources/user_guides/basic_concepts.rst @@ -111,7 +111,7 @@ backend. The context is required to map unified address space pointer to the dev where it was allocated unambiguously. In order for two DPC++-based Python extensions to share USM allocations, they each -must use the `same` SYCL context when submitting for execution programs that would +must use the *same* SYCL context when submitting for execution programs that would access this allocation. Since ``sycl::context`` is dynamically constructed by each extension sharing a USM allocation, diff --git a/dpctl/_backend.pxd b/dpctl/_backend.pxd index 93d9b5ef97..d23edaf506 100644 --- a/dpctl/_backend.pxd +++ b/dpctl/_backend.pxd @@ -431,12 +431,18 @@ cdef extern from "syclinterface/dpctl_sycl_context_interface.h": cdef extern from "syclinterface/dpctl_sycl_kernel_bundle_interface.h": + ctypedef struct _spec_const "DPCTLSpecConst": + uint32_t id + size_t size + const void *value cdef DPCTLSyclKernelBundleRef DPCTLKernelBundle_CreateFromSpirv( const DPCTLSyclContextRef Ctx, const DPCTLSyclDeviceRef Dev, const void *IL, size_t Length, - const char *CompileOpts) + const char *CompileOpts, + size_t NumSpecConsts, + const _spec_const *SpecConsts) cdef DPCTLSyclKernelBundleRef DPCTLKernelBundle_CreateFromOCLSource( const DPCTLSyclContextRef Ctx, const DPCTLSyclDeviceRef Dev, diff --git a/dpctl/_host_task_util.hpp b/dpctl/_host_task_util.hpp index 4db07e1cb1..5a2ea19645 100644 --- a/dpctl/_host_task_util.hpp +++ b/dpctl/_host_task_util.hpp @@ -65,7 +65,7 @@ DPCTLSyclEventRef async_dec_ref(DPCTLSyclQueueRef QRef, #else const bool finalizing = Py_IsFinalizing(); #endif - // if the main thread has not finilized the interpreter yet + // if the main thread has not finalized the interpreter yet if (initialized && !finalizing) { PyGILState_STATE gstate; gstate = PyGILState_Ensure(); diff --git a/dpctl/_sycl_device.pyx b/dpctl/_sycl_device.pyx index bad21ee91f..6c6638e2e3 100644 --- a/dpctl/_sycl_device.pyx +++ b/dpctl/_sycl_device.pyx @@ -1691,7 +1691,7 @@ cdef class SyclDevice(_SyclDevice): return _get_devices(DVRef) def create_sub_devices(self, **kwargs): - """create_sub_devices(partition=parition_spec) + """create_sub_devices(partition=partition_spec) Creates a list of sub-devices by partitioning a root device based on the provided partition specifier. @@ -1755,12 +1755,12 @@ cdef class SyclDevice(_SyclDevice): """ if "partition" not in kwargs: raise TypeError( - "create_sub_devices(partition=parition_spec) is expected." + "create_sub_devices(partition=partition_spec) is expected." ) partition = kwargs.pop("partition") if kwargs: raise TypeError( - "create_sub_devices(partition=parition_spec) is expected." + "create_sub_devices(partition=partition_spec) is expected." ) if isinstance(partition, int) and partition >= 0: return self.create_sub_devices_equally(partition) diff --git a/dpctl/_sycl_platform.pyx b/dpctl/_sycl_platform.pyx index 41eff7b5d3..ba78226e50 100644 --- a/dpctl/_sycl_platform.pyx +++ b/dpctl/_sycl_platform.pyx @@ -236,7 +236,7 @@ cdef class SyclPlatform(_SyclPlatform): and filter string for each device is printed. Args: - verbosity (Literal[0, 1, 2], optional):. + verbosity (Literal[0, 1, 2], optional): The verbosity controls how much information is printed by the function. Value ``0`` is the lowest level set by default and ``2`` is the highest level to print the most verbose output. diff --git a/dpctl/_sycl_queue.pyx b/dpctl/_sycl_queue.pyx index 766f385a8f..a9d0a2c71c 100644 --- a/dpctl/_sycl_queue.pyx +++ b/dpctl/_sycl_queue.pyx @@ -1788,7 +1788,7 @@ cdef class RawKernelArg: Variadic argument, see class documentation. Raises: - TypeError: In case of incorrect arguments given to constructurs, + TypeError: In case of incorrect arguments given to constructors, unexpected types of input arguments. """ def __cinit__(self, *args): diff --git a/dpctl/apis/include/dpctl4pybind11.hpp b/dpctl/apis/include/dpctl4pybind11.hpp index 577b88cd6d..b1c17e8e90 100644 --- a/dpctl/apis/include/dpctl4pybind11.hpp +++ b/dpctl/apis/include/dpctl4pybind11.hpp @@ -143,11 +143,11 @@ class dpctl_capi { const bool initialized = Py_IsInitialized(); #if PY_VERSION_HEX < 0x30d0000 - const bool finilizing = _Py_IsFinalizing(); + const bool finalizing = _Py_IsFinalizing(); #else - const bool finilizing = Py_IsFinalizing(); + const bool finalizing = Py_IsFinalizing(); #endif - const bool guard = initialized && !finilizing; + const bool guard = initialized && !finalizing; if (guard) { delete p; diff --git a/dpctl/program/__init__.py b/dpctl/program/__init__.py index 71302e4186..e1e625ff7a 100644 --- a/dpctl/program/__init__.py +++ b/dpctl/program/__init__.py @@ -22,6 +22,7 @@ """ from ._program import ( + SpecializationConstant, SyclKernel, SyclKernelBundle, SyclKernelBundleCompilationError, @@ -41,6 +42,12 @@ "SyclKernelBundleCompilationError", "SyclProgram", "SyclProgramCompilationError", + "SpecializationConstant", +] + +# add submodules +__all__ += [ + "utils", ] diff --git a/dpctl/program/_program.pxd b/dpctl/program/_program.pxd index 435ef68521..41f781cecd 100644 --- a/dpctl/program/_program.pxd +++ b/dpctl/program/_program.pxd @@ -63,7 +63,10 @@ cpdef create_kernel_bundle_from_source ( SyclQueue q, unicode source, unicode copts=* ) cpdef create_kernel_bundle_from_spirv ( - SyclQueue q, const unsigned char[:] IL, unicode copts=* + SyclQueue q, + const unsigned char[:] IL, + unicode copts=*, + list specializations=*, ) cpdef create_program_from_source (SyclQueue q, unicode source, unicode copts=*) cpdef create_program_from_spirv ( diff --git a/dpctl/program/_program.pyx b/dpctl/program/_program.pyx index 8737be4762..166d46a3e3 100644 --- a/dpctl/program/_program.pyx +++ b/dpctl/program/_program.pyx @@ -26,7 +26,18 @@ an OpenCL source string or a SPIR-V binary file. """ +from cpython.buffer cimport ( + Py_buffer, + PyBUF_ANY_CONTIGUOUS, + PyBUF_SIMPLE, + PyBuffer_Release, + PyObject_CheckBuffer, + PyObject_GetBuffer, +) +from cpython.bytes cimport PyBytes_FromStringAndSize from libc.stdint cimport uint32_t +from libc.stdlib cimport free, malloc +from libc.string cimport memcmp import warnings @@ -51,14 +62,20 @@ from dpctl._backend cimport ( # noqa: E211, E402; DPCTLSyclDeviceRef, DPCTLSyclKernelBundleRef, DPCTLSyclKernelRef, + _spec_const, ) +import numbers + +import numpy as np + __all__ = [ "create_kernel_bundle_from_source", "create_kernel_bundle_from_spirv", "SyclKernel", "SyclKernelBundle", "SyclKernelBundleCompilationError", + "SpecializationConstant", ] cdef class SyclKernelBundleCompilationError(Exception): @@ -252,6 +269,160 @@ cdef api SyclKernelBundle SyclKernelBundle_Make(DPCTLSyclKernelBundleRef KBRef): return SyclKernelBundle._create(copied_KBRef) +cdef class SpecializationConstant: + """ + SpecializationConstant(spec_id, *args) + + Python class representing SYCL specialization constants that can be used + when creating a :class:`dpctl.program.SyclKernelBundle` from SPIR-V. + + There are multiple ways to create a :class:`.SpecializationConstant`: + + - ``SpecializationConstant(spec_id, obj)`` + If the constructor is invoked with a single variadic argument, the + argument is expected to either expose the Python buffer protocol or be + coercible to a NumPy array. If the argument is coercible to a NumPy array + or is one, it must have a supported data type (bool, integral, or + floating point). The specialization constant will be constructed from the + data in the buffer + + - ``SpecializationConstant(spec_id, dtype, obj)`` + If the constructor is invoked with two variadic arguments, and the first + argument is a string, it is interpreted as a NumPy ``dtype`` string and the + second argument will be coerced to a NumPy array with that data type. + The data type specified by the first argument must be a supported data + type (bool, integral, or floating point). + + - ``SpecializationConstant(spec_id, nbytes, raw_ptr)`` + If the constructor is invoked with two variadic arguments where both are + integers, the first argument is interpreted as the number of bytes and + the second argument is interpreted as a pointer to the data. + + Note that when constructing from a buffer, the + :class:`.SpecializationConstant`, shares memory with the original object. + Modifications to the original object's data after construction will be + reflected when the :class:`.SpecializationConstant` is used to create a + :class:`.SyclKernelBundle`. This is not the case when constructing from a + raw pointer, as the data is copied. + + Args: + spec_id (int): + The SPIR-V specialization ID. + args: + Variadic argument, see class documentation. + + Raises: + TypeError: In case of incorrect arguments given to constructor, + failure to coerce to a buffer, or unsupported data type when + coercing to a buffer. + ValueError: If the provided object fails to construct a buffer. + """ + + cdef _spec_const _spec_const + cdef Py_buffer _buffer + + def __cinit__(self, spec_id, *args): + cdef int ret_code = 0 + cdef object target_obj = None + + if not isinstance(spec_id, numbers.Integral): + raise TypeError( + "Specialization constant ID must be of type `int`, got " + f"{type(spec_id)}" + ) + + if len(args) == 0 or len(args) > 2: + raise TypeError( + f"Constructor takes 2 or 3 arguments, got {len(args)}." + ) + + self._spec_const.id = spec_id + + if len(args) == 2: + if ( + isinstance(args[0], numbers.Integral) and + isinstance(args[1], numbers.Integral) + ): + target_obj = PyBytes_FromStringAndSize( + args[1], args[0] + ) + elif isinstance(args[0], str): + target_obj = np.ascontiguousarray(args[1], dtype=args[0]) + + elif len(args) == 1: + target_obj = args[0] + if not PyObject_CheckBuffer(target_obj): + # attempt to coerce to a numpy array + target_obj = np.ascontiguousarray(target_obj) + else: + raise TypeError( + "Invalid arguments." + ) + + if isinstance(target_obj, np.ndarray): + if target_obj.dtype.kind not in ("b", "i", "u", "f", "c"): + raise TypeError( + "Coercion of input to buffer resulted in an unsupported " + f"data type '{target_obj.dtype}'. When coercing objects, " + "`SpecializationConstant` expects the data to coerce to a " + "supported type: bool, integral, or real or complex " + "floating point. To pass arbitrary data, use a " + "`memoryview` or `bytes` object, or pass the pointer and " + "size directly." + ) + + ret_code = PyObject_GetBuffer( + target_obj, &(self._buffer), PyBUF_SIMPLE | PyBUF_ANY_CONTIGUOUS + ) + if ret_code != 0: + raise ValueError( + "Failed to get buffer view for the provided object." + ) + self._spec_const.value = self._buffer.buf + self._spec_const.size = self._buffer.len + + def __dealloc__(self): + PyBuffer_Release(&(self._buffer)) + + def __repr__(self): + return f"SpecializationConstant({self._spec_const.id})" + + def __eq__(self, other): + if not isinstance(other, SpecializationConstant): + return False + cdef SpecializationConstant _other = other + if ( + self._spec_const.id != _other._spec_const.id or + self._spec_const.size != _other._spec_const.size or + self._spec_const.value != _other._spec_const.value + ): + return False + return memcmp( + self._spec_const.value, + _other._spec_const.value, + self._spec_const.size + ) == 0 + + @property + def id(self): + """Returns the specialization ID for this specialization constant.""" + return self._spec_const.id + + @property + def size(self): + """ + Returns the size in bytes of the data for this specialization constant. + """ + return self._spec_const.size + + cdef size_t addressof(self): + """ + Returns the address of the _spec_const for this + :class:`.SpecializationConstant` cast to ``size_t``. + """ + return &(self._spec_const) + + cpdef create_kernel_bundle_from_source(SyclQueue q, str src, str copts=""): """ Creates a Sycl interoperability kernel bundle from an OpenCL source @@ -299,7 +470,10 @@ cpdef create_kernel_bundle_from_source(SyclQueue q, str src, str copts=""): cpdef create_kernel_bundle_from_spirv( - SyclQueue q, const unsigned char[:] IL, str copts="" + SyclQueue q, + const unsigned char[:] IL, + str copts="", + list specializations=None, ): """ Creates a Sycl interoperability kernel bundle from an SPIR-V binary. @@ -317,7 +491,9 @@ cpdef create_kernel_bundle_from_spirv( copts (str, optional) Optional compilation flags that will be used when compiling the kernel bundle. Default: ``""``. - + specializations (list, optional) + A list of :class:`.SpecializationConstant` objects to be used + when creating the kernel bundle. Default: ``None``. Returns: kernel_bundle (:class:`.SyclKernelBundle`) A :class:`.SyclKernelBundle` object wrapping the @@ -336,11 +512,44 @@ cpdef create_kernel_bundle_from_spirv( cdef size_t length = IL.shape[0] cdef bytes bCOpts = copts.encode("utf8") cdef const char *COpts = bCOpts - KBref = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, dIL, length, COpts - ) - if KBref is NULL: - raise SyclKernelBundleCompilationError() + cdef size_t num_spconsts + cdef _spec_const *spconsts + cdef SpecializationConstant spconst + + if specializations is not None: + num_spconsts = len(specializations) + spconsts = <_spec_const *>( + malloc(num_spconsts * sizeof(_spec_const)) + ) + if spconsts == NULL: + raise MemoryError( + "Failed to allocate memory for specialization constants." + ) + for i, spconst in enumerate(specializations): + if not isinstance(spconst, SpecializationConstant): + free(spconsts) + raise TypeError( + "All items in specializations must be of type " + f"`SpecializationConstant`, got {type(spconst)}" + ) + spconsts[i] = spconst._spec_const + else: + num_spconsts = 0 + spconsts = NULL + try: + KBref = DPCTLKernelBundle_CreateFromSpirv( + CRef, + DRef, + dIL, + length, COpts, + num_spconsts, + spconsts, + ) + if KBref is NULL: + raise SyclKernelBundleCompilationError() + finally: + if spconsts != NULL: + free(spconsts) return SyclKernelBundle._create(KBref) diff --git a/dpctl/program/utils/__init__.py b/dpctl/program/utils/__init__.py new file mode 100644 index 0000000000..474f154f95 --- /dev/null +++ b/dpctl/program/utils/__init__.py @@ -0,0 +1,25 @@ +# Data Parallel Control (dpctl) +# +# Copyright 2020-2025 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +""" +A collection of utility functions for dpctl.program module. +""" + +from ._utils import parse_spirv_specializations + +__all__ = [ + "parse_spirv_specializations", +] diff --git a/dpctl/program/utils/_utils.py b/dpctl/program/utils/_utils.py new file mode 100644 index 0000000000..86df0855ad --- /dev/null +++ b/dpctl/program/utils/_utils.py @@ -0,0 +1,192 @@ +# Data Parallel Control (dpctl) +# +# Copyright 2020-2025 Intel Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Implements various utilities for the dpctl.program module.""" + +from dataclasses import dataclass +from enum import IntEnum + +import numpy as np + + +class SpirvOpCode(IntEnum): + OpName = 5 + OpTypeBool = 20 + OpTypeInt = 21 + OpTypeFloat = 22 + OpSpecConstantTrue = 48 + OpSpecConstantFalse = 49 + OpSpecConstant = 50 + OpFunction = 54 + OpDecorate = 71 + + +class SpirvDecoration(IntEnum): + SpecId = 1 + + +@dataclass(frozen=True) +class SpecializationConstantInfo: + """Data class representing specialization constant information.""" + + spec_id: int + dtype: str + name: str + itemsize: int + default_value: int | float | bool | None + + +def parse_spirv_specializations( + spv_bytes: bytes | bytearray | memoryview, +) -> tuple[SpecializationConstantInfo]: + """ + Parses SPIR-V byte stream to extract information about specializations, + including the specialization IDs, types, names, and default values. + + Note that the dtype information may be imprecise, as the compiler may + choose to, for example, represent a bool as char, or may represent both + signed and unsigned integers as unsigned integer bit buckets of the same + length. + + Args: + spv_bytes (bytes | bytearray | memoryview): + the SPIR-V byte stream. + + Returns: + tuple[SpecializationConstantInfo]: + a tuple of parsed constants and their information represented by + `SpecializationConstantInfo` objects, sorted by their + specialization IDs. The length of the tuple is equal to the number + of specialization constants found. Each + `SpecializationConstantInfo` object contains the following + attributes: + + - `spec_id` (int): The specialization ID. + - `dtype` (str): A NumPy style string representing the data type. + - `itemsize` (int): The size of the specialization constant in + bytes. + - `name` (str): The variable name. If not preserved in the binary, + a default name in the format `unnamed_spec_const_{spec_id}` is + used. + - `default_value` (int | float | bool | None): The default value of + the specialization constant. If not specified, `None` is used. + """ + words = np.frombuffer(spv_bytes, dtype=np.uint32) + + # verify magic number + if len(words) < 5 or words[0] != 0x07230203: + raise ValueError("Invalid SPIR-V binary") + + types = {} + ids = {} + names = {} + constants = {} + defaults = {} + + i = 5 # skip 5 word header + while i < len(words): + word = words[i] + opcode = word & 0xFFFF + word_count = word >> 16 + + if word_count == 0: + raise ValueError(f"Invalid SPIR-V instruction at word index {i}") + + if opcode == SpirvOpCode.OpFunction: + # everything following is not relevant to specialization constant + # parsing, so we can stop parsing at this point + break + elif opcode == SpirvOpCode.OpTypeBool: + result_id = int(words[i + 1]) + types[result_id] = {"dtype": "?", "itemsize": 1} + elif opcode == SpirvOpCode.OpTypeInt: + result_id = int(words[i + 1]) + width = int(words[i + 2]) + signed = int(words[i + 3]) + prefix = "i" if signed else "u" + types[result_id] = { + "dtype": f"{prefix}{width // 8}", + "itemsize": width // 8, + } + elif opcode == SpirvOpCode.OpTypeFloat: + result_id = int(words[i + 1]) + width = int(words[i + 2]) + types[result_id] = { + "dtype": f"f{width // 8}", + "itemsize": width // 8, + } + elif opcode == SpirvOpCode.OpSpecConstant: + type_id = int(words[i + 1]) + result_id = int(words[i + 2]) + constants[result_id] = type_id + literal_words = words[i + 3 : i + word_count] + defaults[result_id] = literal_words.tobytes() + elif opcode == SpirvOpCode.OpSpecConstantTrue: + type_id = int(words[i + 1]) + result_id = int(words[i + 2]) + constants[result_id] = type_id + defaults[result_id] = True + elif opcode == SpirvOpCode.OpSpecConstantFalse: + type_id = int(words[i + 1]) + result_id = int(words[i + 2]) + constants[result_id] = type_id + defaults[result_id] = False + elif opcode == SpirvOpCode.OpDecorate: + target_id = int(words[i + 1]) + decoration = int(words[i + 2]) + if decoration == SpirvDecoration.SpecId: + ids[target_id] = int(words[i + 3]) + elif opcode == SpirvOpCode.OpName: + target_id = int(words[i + 1]) + name_bytes = words[i + 2 : i + word_count].tobytes() + names[target_id] = name_bytes.split(b"\x00", 1)[0].decode("utf-8") + + i += word_count + + # a spec ID may appear multiple times in the same binary with different + # target IDs. We only need to keep one, so skip duplicates + unique_ids = set() + result = [] + for target_id, spec_id in ids.items(): + if spec_id in unique_ids: + continue + unique_ids.add(spec_id) + type_id = constants.get(target_id) + type_info = types.get(type_id, {"dtype": "unknown_type", "itemsize": 0}) + name = names.get(target_id, f"unnamed_spec_const_{spec_id}") + + dtype_str = type_info["dtype"] + raw_default = defaults.get(target_id) + default_value = None + if isinstance(raw_default, bytes): + try: + default_value = np.frombuffer(raw_default, dtype=dtype_str)[ + 0 + ].item() + except Exception: + default_value = None + + result.append( + SpecializationConstantInfo( + spec_id=spec_id, + dtype=dtype_str, + name=name, + itemsize=type_info["itemsize"], + default_value=default_value, + ) + ) + + return tuple(sorted(result, key=lambda x: x.spec_id)) diff --git a/dpctl/tests/input_files/specialization_constant_composite.spv b/dpctl/tests/input_files/specialization_constant_composite.spv new file mode 100644 index 0000000000..c262f97ff6 Binary files /dev/null and b/dpctl/tests/input_files/specialization_constant_composite.spv differ diff --git a/dpctl/tests/input_files/specialization_constant_kernel.spv b/dpctl/tests/input_files/specialization_constant_kernel.spv new file mode 100644 index 0000000000..d696fa755f Binary files /dev/null and b/dpctl/tests/input_files/specialization_constant_kernel.spv differ diff --git a/dpctl/tests/test_sycl_device.py b/dpctl/tests/test_sycl_device.py index e5767113d6..e9eee7e223 100644 --- a/dpctl/tests/test_sycl_device.py +++ b/dpctl/tests/test_sycl_device.py @@ -192,7 +192,7 @@ def test_supported_aspect(supported_aspect): assert getattr(d_wa, "has_aspect_" + supported_aspect) except dpctl.SyclDeviceCreationError: # ValueError may be raised if no device with - # requested aspect charateristics is available + # requested aspect characteristics is available assert not has_it diff --git a/dpctl/tests/test_sycl_program.py b/dpctl/tests/test_sycl_program.py index 1c09adc28e..564f40bed9 100644 --- a/dpctl/tests/test_sycl_program.py +++ b/dpctl/tests/test_sycl_program.py @@ -18,10 +18,12 @@ import os +import numpy as np import pytest import dpctl import dpctl.program as dpctl_prog +from dpctl.program.utils import parse_spirv_specializations def get_spirv_abspath(fn): @@ -262,3 +264,127 @@ def test_create_kernel_bundle_from_invalid_src_ocl(): }" with pytest.raises(dpctl_prog.SyclKernelBundleCompilationError): dpctl_prog.create_kernel_bundle_from_source(q, invalid_oclSrc) + + +def test_create_kernel_bundle_with_spec_const(): + try: + q = dpctl.SyclQueue() + except dpctl.SyclQueueCreationError: + pytest.skip("Could not create default queue") + + spec_id = 0 + sp = dpctl_prog.SpecializationConstant(spec_id, "i4", 42) + + spirv_file = get_spirv_abspath("specialization_constant_kernel.spv") + with open(spirv_file, "br") as spv: + spv_bytes = spv.read() + + kb = dpctl_prog.create_kernel_bundle_from_spirv( + q, spv_bytes, specializations=[sp] + ) + kernel = kb.get_sycl_kernel("_ZTS20BasicSpecConstKernel") + + n = 128 + x = np.ones(n, dtype="i4") + y = np.zeros_like(x) + + x_usm = dpctl.memory.MemoryUSMDevice(x.nbytes, queue=q) + y_usm = dpctl.memory.MemoryUSMDevice(y.nbytes, queue=q) + + e1 = q.memcpy_async(x_usm, x, x.nbytes) + e2 = q.submit(kernel, [x_usm, y_usm], [n], dEvents=[e1]) + e3 = q.memcpy_async(y, y_usm, y.nbytes, [e2]) + + ht_e = q._submit_keep_args_alive([x_usm], [e3]) + + e3.wait() + ht_e.wait() + + assert np.all(y == 43) + + +def test_create_kernel_bundle_with_composite_spec_const(): + try: + q = dpctl.SyclQueue() + except dpctl.SyclQueueCreationError: + pytest.skip("Could not create default queue") + + # composite specialization constants are separated into individual + # specialization constants with unique spec_ids + sp1 = dpctl_prog.SpecializationConstant(0, "i4", 10) + sp2 = dpctl_prog.SpecializationConstant(1, "f4", 2.5) + sp3 = dpctl_prog.SpecializationConstant(2, "?", 1) + + spirv_file = get_spirv_abspath("specialization_constant_composite.spv") + with open(spirv_file, "br") as spv: + spv_bytes = spv.read() + + kb = dpctl_prog.create_kernel_bundle_from_spirv( + q, spv_bytes, specializations=[sp1, sp2, sp3] + ) + kernel = kb.get_sycl_kernel("_ZTS21StructSpecConstKernel") + + n = 128 + x = np.ones(n, dtype="f4") + y = np.zeros_like(x) + + x_usm = dpctl.memory.MemoryUSMDevice(x.nbytes, queue=q) + y_usm = dpctl.memory.MemoryUSMDevice(y.nbytes, queue=q) + + e1 = q.memcpy_async(x_usm, x, x.nbytes) + e2 = q.submit(kernel, [x_usm, y_usm], [n], dEvents=[e1]) + e3 = q.memcpy_async(y, y_usm, y.nbytes, [e2]) + + ht_e = q._submit_keep_args_alive([x_usm], [e3]) + + e3.wait() + ht_e.wait() + + # 1.0 * 10 + 2.5 = 12.5 + assert np.all(y == 12.5) + + +def test_spirv_specializations_parser(): + spirv_file = get_spirv_abspath("specialization_constant_kernel.spv") + with open(spirv_file, "rb") as spv: + spv_bytes = spv.read() + spec_consts = parse_spirv_specializations(spv_bytes) + assert len(spec_consts) == 1 + assert spec_consts[0].dtype == "u4" + + spirv_file = get_spirv_abspath("specialization_constant_composite.spv") + with open(spirv_file, "rb") as spv: + spv_bytes = spv.read() + + spec_consts = parse_spirv_specializations(spv_bytes) + assert len(spec_consts) == 3 + spec_const0, spec_const1, spec_const2 = spec_consts + assert spec_const0.dtype == "u4" + assert spec_const0.itemsize == 4 + assert spec_const0.name == "unnamed_spec_const_0" + assert spec_const0.default_value == 1 + + assert spec_const1.dtype == "f4" + assert spec_const1.itemsize == 4 + assert spec_const1.name == "unnamed_spec_const_1" + assert spec_const1.default_value == 0 + + # compiler translates bool to char + assert spec_const2.dtype == "u1" + assert spec_const2.itemsize == 1 + assert spec_const2.name == "unnamed_spec_const_2" + assert spec_const2.default_value == 0 + + +def test_spirv_specializations_parser_no_spec_consts(): + spirv_file = get_spirv_abspath("multi_kernel.spv") + with open(spirv_file, "rb") as spv: + spv_bytes = spv.read() + spec_consts = parse_spirv_specializations(spv_bytes) + assert not spec_consts + + +def test_spirv_specializations_parser_invalid_spirv(): + invalid_spv = b"\x00\x01\x02\x03\x04\x05" + with pytest.raises(ValueError): + parse_spirv_specializations(invalid_spv) diff --git a/dpctl/tests/test_sycl_usm.py b/dpctl/tests/test_sycl_usm.py index 40fee9a0b3..b1aefa325c 100644 --- a/dpctl/tests/test_sycl_usm.py +++ b/dpctl/tests/test_sycl_usm.py @@ -101,7 +101,7 @@ def test_memory_without_context(): def test_memory_cpu_context(): mobj = _create_memory() - # type respective to the context in which + # USM type respective to the context in which # memory was created usm_type = mobj.get_usm_type() assert usm_type == "shared" @@ -110,9 +110,9 @@ def test_memory_cpu_context(): cpu_queue = dpctl.SyclQueue("cpu") except dpctl.SyclQueueCreationError: pytest.skip("SyclQueue('cpu') failed, skip further testing") - # type as view from CPU queue + # USM type as view from CPU queue usm_type = mobj.get_usm_type(cpu_queue) - # type can be unknown if current queue is + # USM type can be unknown if current queue is # not in the same SYCL context assert usm_type in ["unknown", "shared"] @@ -439,7 +439,7 @@ def invalid_data(suai_iface): with pytest.raises(ValueError): MemoryUSMShared(v) - # typestr validation + # validate typestring def invalid_typestr(suai_iface): suai_iface["typestr"] = "invalid" return suai_iface diff --git a/dpctl/utils/CMakeLists.txt b/dpctl/utils/CMakeLists.txt index 40569da8a4..8f27fb0566 100644 --- a/dpctl/utils/CMakeLists.txt +++ b/dpctl/utils/CMakeLists.txt @@ -57,7 +57,7 @@ foreach(python_module_name ${_pybind11_targets}) ${_dpctl_sycl_target_link_options} ) endif() - # TODO: update source so they refernece individual libraries instead of + # TODO: update source so they reference individual libraries instead of # dpctl4pybind11.hpp. It will allow to simplify dependency tree target_link_libraries(${python_module_name} PRIVATE DpctlCAPI) if (DPCTL_WITH_REDIST) diff --git a/examples/cython/README.md b/examples/cython/README.md index 010e871867..e2daa39be6 100644 --- a/examples/cython/README.md +++ b/examples/cython/README.md @@ -4,5 +4,5 @@ The `dpctl` package provides Cython definition files for types it defines. Use `cimport dpctl as c_dpctl` or `cimport dpctl.memory as c_dpm` to use these definitions. -Cython definition fille `dpctl.sycl` provides incomplete definitions of core SYCL runtime classes as +Cython definition file `dpctl.sycl` provides incomplete definitions of core SYCL runtime classes as well as conversion routine between `SyclInterface` reference types and SYCL runtime classes. diff --git a/examples/cython/sycl_buffer/README.md b/examples/cython/sycl_buffer/README.md index 89d57f0d40..6cda697dcf 100644 --- a/examples/cython/sycl_buffer/README.md +++ b/examples/cython/sycl_buffer/README.md @@ -1,6 +1,6 @@ # SYCL Extension Working NumPy Array Input via SYCL Buffers -## Decription +## Description Cython function expecting a 2D array in a C-contiguous layout that computes column-wise total by using SYCL oneMKL (as GEMV call with diff --git a/examples/cython/sycl_buffer/scripts/bench.py b/examples/cython/sycl_buffer/scripts/bench.py index 0589c7ad36..60be049e65 100644 --- a/examples/cython/sycl_buffer/scripts/bench.py +++ b/examples/cython/sycl_buffer/scripts/bench.py @@ -79,7 +79,7 @@ def run_offload(selector_string, X): for ss in ["opencl:cpu", "opencl:gpu", "level_zero:gpu"]: print(f"Result for '{ss}': {run_offload(ss, X)}") -print("=" * 10 + " Running bechmarks " + "=" * 10) +print("=" * 10 + " Running benchmarks " + "=" * 10) for ss in ["opencl:cpu", "opencl:gpu", "level_zero:gpu"]: print(f"Timing offload to '{ss}': {bench_offload(ss, X)}") diff --git a/examples/pybind11/external_usm_allocation/external_usm_allocation/_usm_alloc_example.cpp b/examples/pybind11/external_usm_allocation/external_usm_allocation/_usm_alloc_example.cpp index b982fcaa20..f92a99026e 100644 --- a/examples/pybind11/external_usm_allocation/external_usm_allocation/_usm_alloc_example.cpp +++ b/examples/pybind11/external_usm_allocation/external_usm_allocation/_usm_alloc_example.cpp @@ -49,7 +49,7 @@ struct DMatrix : n_(rows), m_(columns), q_(q), alloc_(q), vec_(n_ * m_, alloc_) { } - ~DMatrix(){}; + ~DMatrix() {}; DMatrix(const DMatrix &) = default; DMatrix(DMatrix &&) = default; diff --git a/examples/pybind11/onemkl_gemv/sycl_gemm/build.sh b/examples/pybind11/onemkl_gemv/sycl_gemm/build.sh index 221f484ae1..7e3a770d3b 100755 --- a/examples/pybind11/onemkl_gemv/sycl_gemm/build.sh +++ b/examples/pybind11/onemkl_gemv/sycl_gemm/build.sh @@ -1,15 +1,20 @@ #!/bin/bash -x -export PYBIND11_INCLUDES=$(python3 -m pybind11 --includes) -export DPCTL_INCLUDE_DIR=$(python -c "import dpctl; print(dpctl.get_include())") -export DPCTL_LIB_DIR=${DPCTL_INCLUDE_DIR}/.. -export PY_EXT_SUFFIX=$(python3-config --extension-suffix) -export HOST_COMPILER_FLAGS="-g -std=c++2a -O3 -Wno-return-type -Wno-deprecated-declarations -fPIC ${PYBIND11_INCLUDES} -I${DPCTL_INCLUDE_DIR}" +PYBIND11_INCLUDES=$(python3 -m pybind11 --includes) +export PYBIND11_INCLUDES +DPCTL_INCLUDE_DIR=$(python -c "import dpctl; print(dpctl.get_include())") +export DPCTL_INCLUDE_DIR +DPCTL_LIB_DIR=${DPCTL_INCLUDE_DIR}/.. +export DPCTL_LIB_DIR +PY_EXT_SUFFIX=$(python3-config --extension-suffix) +export PY_EXT_SUFFIX +HOST_COMPILER_FLAGS="-g -std=c++2a -O3 -Wno-return-type -Wno-deprecated-declarations -fPIC ${PYBIND11_INCLUDES} -I${DPCTL_INCLUDE_DIR}" +export HOST_COMPILER_FLAGS # -fsycl-host-compiler=g++ \ # -fsycl-host-compiler-options="${HOST_COMPILER_FLAGS}" \ dpcpp -O3 -fsycl -Wno-deprecated-declarations \ -fpic -fPIC -shared \ - ${PYBIND11_INCLUDES} -I${DPCTL_INCLUDE_DIR} \ - sycl_gemm.cpp -o _sycl_gemm${PY_EXT_SUFFIX} + "${PYBIND11_INCLUDES}" -I"${DPCTL_INCLUDE_DIR}" \ + sycl_gemm.cpp -o _sycl_gemm"${PY_EXT_SUFFIX}" diff --git a/examples/python/_runner.py b/examples/python/_runner.py index 94ab6b4077..452f0207b9 100644 --- a/examples/python/_runner.py +++ b/examples/python/_runner.py @@ -75,7 +75,7 @@ def run_examples(example_description, glbls_dict): if has_nondefault_params(sgn): if not args.quiet: print( - f"INFO: Skip exectution of {fn} as it " + f"INFO: Skip execution of {fn} as it " "requires arguments" ) else: diff --git a/examples/python/subdevices.py b/examples/python/subdevices.py index e5e69373b8..282674f297 100644 --- a/examples/python/subdevices.py +++ b/examples/python/subdevices.py @@ -35,7 +35,7 @@ def subdivide_root_cpu_device(): """ Create root CPU device, and equally partition it into smaller CPU devices 4 execution units each, - and then further parition those subdevice into + and then further partition those sub-devices into smaller sub-devices """ cpu_d = dpctl.SyclDevice("cpu") @@ -84,7 +84,7 @@ def create_subdevice_queue(): cpu_count = cpu_d.max_compute_units sub_devs = cpu_d.create_sub_devices(partition=cpu_count // 2) multidevice_ctx = dpctl.SyclContext(sub_devs) - # create a SyclQueue for each sub-device, using commont + # create a SyclQueue for each sub-device, using common # multi-device context q0, q1 = [dpctl.SyclQueue(multidevice_ctx, d) for d in sub_devs] # for each sub-device allocate 26 bytes diff --git a/examples/python/usm_memory_host_access.py b/examples/python/usm_memory_host_access.py index 21092a01a5..f6af9c4305 100644 --- a/examples/python/usm_memory_host_access.py +++ b/examples/python/usm_memory_host_access.py @@ -23,7 +23,7 @@ # USM-shared and USM-host pointers are host-accessible, # meaning they are accessible from Python, therefore -# they implement Pyton buffer protocol +# they implement Python buffer protocol # allocate 1K of USM-shared buffer ms = dpmem.MemoryUSMShared(1024) diff --git a/libsyclinterface/cmake/modules/GetProjectVersion.cmake b/libsyclinterface/cmake/modules/GetProjectVersion.cmake index 8968eec729..a45ad0ee96 100644 --- a/libsyclinterface/cmake/modules/GetProjectVersion.cmake +++ b/libsyclinterface/cmake/modules/GetProjectVersion.cmake @@ -45,7 +45,7 @@ function(get_version) if(NOT result EQUAL 0) message(WARNING "Something went wrong when executing \"git describe\". " - "Seting all version values to 0." + "Setting all version values to 0." ) set(VERSION_MAJOR 0 PARENT_SCOPE) set(VERSION_MINOR 0 PARENT_SCOPE) @@ -63,7 +63,7 @@ function(get_version) else() message(WARNING "The last git tag does not use proper semantic versioning. " - "Seting all version values to 0." + "Setting all version values to 0." ) set(VERSION_MAJOR 0 PARENT_SCOPE) set(VERSION_MINOR 0 PARENT_SCOPE) @@ -86,7 +86,7 @@ function(get_version) if(NOT result EQUAL 0) message(WARNING "Something went wrong when executing \"git describe\". " - "Seting all version values to 0." + "Setting all version values to 0." ) set(VERSION_MAJOR 0 PARENT_SCOPE) set(VERSION_MINOR 0 PARENT_SCOPE) diff --git a/libsyclinterface/dbg_build.bat b/libsyclinterface/dbg_build.bat index fd591d9399..6101f41471 100644 --- a/libsyclinterface/dbg_build.bat +++ b/libsyclinterface/dbg_build.bat @@ -5,7 +5,7 @@ if errorlevel 1 ( call "%ONEAPI_ROOT%\compiler\latest\env\vars.bat" if %ERRORLEVEL% neq 0 exit 1 ) -@REM conda uses %ERRORLEVEL% but FPGA scripts can set it. So it should be reseted. +@REM conda uses %ERRORLEVEL% but FPGA scripts can set it. So it should be reset. set ERRORLEVEL= rmdir /S /Q build diff --git a/libsyclinterface/dbg_build.sh b/libsyclinterface/dbg_build.sh index cba4e71d71..c090bc700c 100755 --- a/libsyclinterface/dbg_build.sh +++ b/libsyclinterface/dbg_build.sh @@ -5,10 +5,11 @@ mkdir build pushd build || exit 1 INSTALL_PREFIX=$(pwd)/../install -rm -rf ${INSTALL_PREFIX} +rm -rf "${INSTALL_PREFIX}" -# With DPC++ 2024.0 adn newer set these to ensure that +# With DPC++ 2024.0 and newer set these to ensure that # cmake can find llvm-cov and other utilities +# shellcheck disable=SC2034 LLVM_TOOLS_HOME=${CMPLR_ROOT}/bin/compiler PATH=$PATH:${CMPLR_ROOT}/bin/compiler @@ -17,8 +18,8 @@ cmake \ -DCMAKE_C_COMPILER=icx \ -DCMAKE_CXX_COMPILER=icpx \ -DCMAKE_CXX_FLAGS=-fsycl \ - -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \ - -DCMAKE_PREFIX_PATH=${INSTALL_PREFIX} \ + -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \ + -DCMAKE_PREFIX_PATH="${INSTALL_PREFIX}" \ -DDPCTL_ENABLE_L0_PROGRAM_CREATION=ON \ -DDPCTL_BUILD_CAPI_TESTS=ON \ -DDPCTL_GENERATE_COVERAGE=OFF \ diff --git a/libsyclinterface/dbg_build_custom.sh b/libsyclinterface/dbg_build_custom.sh index ad738a0c8a..4c30cca1ce 100755 --- a/libsyclinterface/dbg_build_custom.sh +++ b/libsyclinterface/dbg_build_custom.sh @@ -2,10 +2,10 @@ set +xe rm -rf build mkdir build -pushd build +pushd build || exit 1 -INSTALL_PREFIX=`pwd`/../install -rm -rf ${INSTALL_PREFIX} +INSTALL_PREFIX=$(pwd)/../install +rm -rf "${INSTALL_PREFIX}" if [[ -z "${DPCPP_HOME}" ]]; then echo "Set the DPCPP_HOME environment variable to root directory." @@ -13,11 +13,11 @@ fi cmake \ -DCMAKE_BUILD_TYPE=Debug \ - -DCMAKE_INSTALL_PREFIX=${INSTALL_PREFIX} \ - -DCMAKE_PREFIX_PATH=${INSTALL_PREFIX} \ - -DDPCTL_CUSTOM_DPCPP_INSTALL_DIR=${DPCPP_HOME} \ - -DCMAKE_LINKER:PATH=${DPCPP_HOME}/bin/lld \ - -DDPCTL_ENABLE_L0_PROGRAM_CREATION=${USE_LO_HEADERS} \ + -DCMAKE_INSTALL_PREFIX="${INSTALL_PREFIX}" \ + -DCMAKE_PREFIX_PATH="${INSTALL_PREFIX}" \ + -DDPCTL_CUSTOM_DPCPP_INSTALL_DIR="${DPCPP_HOME}" \ + -DCMAKE_LINKER:PATH="${DPCPP_HOME}/bin/lld" \ + -DDPCTL_ENABLE_L0_PROGRAM_CREATION="${USE_LO_HEADERS}" \ -DDPCTL_BUILD_CAPI_TESTS=ON \ -DDPCTL_GENERATE_COVERAGE=ON \ .. @@ -32,4 +32,4 @@ make lcov-genhtml # ctest -V --progress --output-on-failure -j 4 # cd .. -popd +popd || exit 1 diff --git a/libsyclinterface/helper/source/dpctl_error_handlers.cpp b/libsyclinterface/helper/source/dpctl_error_handlers.cpp index 149eb26692..8ee9626f00 100644 --- a/libsyclinterface/helper/source/dpctl_error_handlers.cpp +++ b/libsyclinterface/helper/source/dpctl_error_handlers.cpp @@ -20,7 +20,7 @@ /// /// \file /// A functor to use for passing an error handler callback function to sycl -/// context and queue contructors. +/// context and queue constructors. //===----------------------------------------------------------------------===// #include "dpctl_error_handlers.h" diff --git a/libsyclinterface/include/syclinterface/Support/DllExport.h b/libsyclinterface/include/syclinterface/Support/DllExport.h index 0578387145..f2eb627bc7 100644 --- a/libsyclinterface/include/syclinterface/Support/DllExport.h +++ b/libsyclinterface/include/syclinterface/Support/DllExport.h @@ -1,4 +1,4 @@ -//===--------- DllExport.h - Decalres dllexport for Windows -*-C++-*- ===// +//===--------- DllExport.h - Declares dllexport for Windows -*-C++-*- ===// // // Data Parallel Control (dpctl) // diff --git a/libsyclinterface/include/syclinterface/dpctl_sycl_device_manager.h b/libsyclinterface/include/syclinterface/dpctl_sycl_device_manager.h index cec8ec076c..3f4f08e18f 100644 --- a/libsyclinterface/include/syclinterface/dpctl_sycl_device_manager.h +++ b/libsyclinterface/include/syclinterface/dpctl_sycl_device_manager.h @@ -41,7 +41,7 @@ DPCTL_C_EXTERN_C_BEGIN * @{ */ -// Declares a set of types abd functions to deal with vectors of +// Declares a set of types and functions to deal with vectors of // DPCTLSyclDeviceRef. Refer dpctl_vector_macros.h DPCTL_DECLARE_VECTOR(Device) diff --git a/libsyclinterface/include/syclinterface/dpctl_sycl_kernel_bundle_interface.h b/libsyclinterface/include/syclinterface/dpctl_sycl_kernel_bundle_interface.h index 07a76c3fd8..3909a1c3d1 100644 --- a/libsyclinterface/include/syclinterface/dpctl_sycl_kernel_bundle_interface.h +++ b/libsyclinterface/include/syclinterface/dpctl_sycl_kernel_bundle_interface.h @@ -35,6 +35,13 @@ DPCTL_C_EXTERN_C_BEGIN +typedef struct DPCTLSpecConstTy +{ + uint32_t id; + size_t size; + const void *value; +} DPCTLSpecConst; + /** * @defgroup KernelBundleInterface Kernel_bundle class C wrapper */ @@ -51,6 +58,8 @@ DPCTL_C_EXTERN_C_BEGIN * @param Length The size of the IL binary in bytes. * @param CompileOpts Optional compiler flags used when compiling the * SPIR-V binary. + * @param NumSpecConsts The number of specialization constants. + * @param SpecConsts An array of specialization constants. * @return A new SyclKernelBundleRef pointer if the kernel_bundle creation * succeeded, else returns NULL. * @ingroup KernelBundleInterface @@ -61,7 +70,9 @@ DPCTLKernelBundle_CreateFromSpirv(__dpctl_keep const DPCTLSyclContextRef Ctx, __dpctl_keep const DPCTLSyclDeviceRef Dev, __dpctl_keep const void *IL, size_t Length, - const char *CompileOpts); + const char *CompileOpts, + size_t NumSpecConsts, + const DPCTLSpecConst *SpecConsts); /*! * @brief Create a Sycl kernel bundle from an OpenCL kernel source string. diff --git a/libsyclinterface/include/syclinterface/dpctl_sycl_platform_manager.h b/libsyclinterface/include/syclinterface/dpctl_sycl_platform_manager.h index 99ff224317..5fce58bd19 100644 --- a/libsyclinterface/include/syclinterface/dpctl_sycl_platform_manager.h +++ b/libsyclinterface/include/syclinterface/dpctl_sycl_platform_manager.h @@ -39,7 +39,7 @@ DPCTL_C_EXTERN_C_BEGIN * @{ */ -// Declares a set of types abd functions to deal with vectors of +// Declares a set of types and functions to deal with vectors of // DPCTLSyclPlatformRef. Refer dpctl_vector_macros.h DPCTL_DECLARE_VECTOR(Platform) diff --git a/libsyclinterface/source/dpctl_sycl_kernel_bundle_interface.cpp b/libsyclinterface/source/dpctl_sycl_kernel_bundle_interface.cpp index 78c714ecbb..73e5d9ef87 100644 --- a/libsyclinterface/source/dpctl_sycl_kernel_bundle_interface.cpp +++ b/libsyclinterface/source/dpctl_sycl_kernel_bundle_interface.cpp @@ -31,6 +31,7 @@ #include "dpctl_error_handlers.h" #include "dpctl_sycl_type_casters.hpp" #include /* OpenCL headers */ +#include #include #include #include @@ -170,6 +171,21 @@ std::string _GetErrorCode_ocl_impl(cl_int code) } } +typedef cl_int (*clSetProgramSpecializationConstantFT)(cl_program, + cl_uint, + size_t, + const void *); +const char *clSetProgramSpecializationConstant_Name = + "clSetProgramSpecializationConstant"; +clSetProgramSpecializationConstantFT get_clSetProgramSpecializationConstant() +{ + static auto st_clSetProgramSpecializationConstantF = + cl_loader::get().getSymbol( + clSetProgramSpecializationConstant_Name); + + return st_clSetProgramSpecializationConstantF; +} + DPCTLSyclKernelBundleRef _CreateKernelBundle_common_ocl_impl(cl_program clProgram, const context &ctx, @@ -235,7 +251,9 @@ _CreateKernelBundleWithIL_ocl_impl(const context &ctx, const device &dev, const void *IL, size_t il_length, - const char *CompileOpts) + const char *CompileOpts, + size_t NumSpecConsts, + const DPCTLSpecConst *SpecConsts) { auto clCreateProgramWithILF = get_clCreateProgramWithIL(); if (clCreateProgramWithILF == nullptr) { @@ -257,6 +275,22 @@ _CreateKernelBundleWithIL_ocl_impl(const context &ctx, return nullptr; } + if (SpecConsts != nullptr && NumSpecConsts > 0) { + auto clSetProgramSpecConstF = get_clSetProgramSpecializationConstant(); + if (clSetProgramSpecConstF) { + for (size_t i = 0; i < NumSpecConsts; ++i) { + clSetProgramSpecConstF(clProgram, SpecConsts[i].id, + SpecConsts[i].size, SpecConsts[i].value); + } + } + else { + error_handler("clSetProgramSpecializationConstant is not available " + "in the OpenCL implementation.", + __FILE__, __func__, __LINE__); + return nullptr; + } + } + return _CreateKernelBundle_common_ocl_impl(clProgram, ctx, dev, CompileOpts); } @@ -428,7 +462,9 @@ _CreateKernelBundleWithIL_ze_impl(const context &SyclCtx, const device &SyclDev, const void *IL, size_t il_length, - const char *CompileOpts) + const char *CompileOpts, + size_t NumSpecConsts, + const DPCTLSpecConst *SpecConsts) { auto zeModuleCreateFn = get_zeModuleCreate(); if (zeModuleCreateFn == nullptr) { @@ -444,8 +480,22 @@ _CreateKernelBundleWithIL_ze_impl(const context &SyclCtx, ZeDevice = get_native(SyclDev); // Specialization constants are not supported by DPCTL at the moment + std::vector spec_ids; + std::vector spec_values; + + if (SpecConsts != nullptr && NumSpecConsts > 0) { + spec_ids.reserve(NumSpecConsts); + spec_values.reserve(NumSpecConsts); + for (size_t i = 0; i < NumSpecConsts; ++i) { + spec_ids.push_back(SpecConsts[i].id); + spec_values.push_back(SpecConsts[i].value); + } + } ze_module_constants_t ZeSpecConstants = {}; - ZeSpecConstants.numConstants = 0; + ZeSpecConstants.numConstants = static_cast(NumSpecConsts); + ZeSpecConstants.pConstantIds = spec_ids.empty() ? nullptr : spec_ids.data(); + ZeSpecConstants.pConstantValues = + spec_values.empty() ? nullptr : spec_values.data(); // Populate the Level Zero module descriptions ze_module_desc_t ZeModuleDesc = {}; @@ -583,7 +633,9 @@ DPCTLKernelBundle_CreateFromSpirv(__dpctl_keep const DPCTLSyclContextRef CtxRef, __dpctl_keep const DPCTLSyclDeviceRef DevRef, __dpctl_keep const void *IL, size_t length, - const char *CompileOpts) + const char *CompileOpts, + size_t NumSpecConsts, + const DPCTLSpecConst *SpecConsts) { DPCTLSyclKernelBundleRef KBRef = nullptr; if (!CtxRef) { @@ -611,12 +663,14 @@ DPCTLKernelBundle_CreateFromSpirv(__dpctl_keep const DPCTLSyclContextRef CtxRef, switch (BE) { case backend::opencl: KBRef = _CreateKernelBundleWithIL_ocl_impl(*SyclCtx, *SyclDev, IL, - length, CompileOpts); + length, CompileOpts, + NumSpecConsts, SpecConsts); break; case backend::ext_oneapi_level_zero: #ifdef DPCTL_ENABLE_L0_PROGRAM_CREATION KBRef = _CreateKernelBundleWithIL_ze_impl(*SyclCtx, *SyclDev, IL, - length, CompileOpts); + length, CompileOpts, + NumSpecConsts, SpecConsts); break; #endif default: diff --git a/libsyclinterface/tests/test_service.cpp b/libsyclinterface/tests/test_service.cpp index b8581092d5..4b75b34e4c 100644 --- a/libsyclinterface/tests/test_service.cpp +++ b/libsyclinterface/tests/test_service.cpp @@ -1,4 +1,4 @@ -//===--- test_service.cpp - Test cases for sevice functions ===// +//===--- test_service.cpp - Test cases for service functions ===// // // Data Parallel Control (dpctl) // diff --git a/libsyclinterface/tests/test_sycl_kernel_bundle_interface.cpp b/libsyclinterface/tests/test_sycl_kernel_bundle_interface.cpp index a835c277b9..5793e983d9 100644 --- a/libsyclinterface/tests/test_sycl_kernel_bundle_interface.cpp +++ b/libsyclinterface/tests/test_sycl_kernel_bundle_interface.cpp @@ -69,7 +69,8 @@ struct TestDPCTLSyclKernelBundleInterface spirvFile.seekg(0, std::ios::beg); spirvFile.read(spirvBuffer.data(), spirvFileSize); KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, spirvBuffer.data(), spirvFileSize, nullptr); + CRef, DRef, spirvBuffer.data(), spirvFileSize, nullptr, 0, + nullptr); } } @@ -132,18 +133,21 @@ TEST_P(TestDPCTLSyclKernelBundleInterface, ChkCreateFromSpirvNull) const void *null_spirv = nullptr; DPCTLSyclKernelBundleRef KBRef = nullptr; // Null context - EXPECT_NO_FATAL_FAILURE(KBRef = DPCTLKernelBundle_CreateFromSpirv( - Null_CRef, Null_DRef, null_spirv, 0, nullptr)); + EXPECT_NO_FATAL_FAILURE( + KBRef = DPCTLKernelBundle_CreateFromSpirv( + Null_CRef, Null_DRef, null_spirv, 0, nullptr, 0, nullptr)); ASSERT_TRUE(KBRef == nullptr); // Null device - EXPECT_NO_FATAL_FAILURE(KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, Null_DRef, null_spirv, 0, nullptr)); + EXPECT_NO_FATAL_FAILURE( + KBRef = DPCTLKernelBundle_CreateFromSpirv(CRef, Null_DRef, null_spirv, + 0, nullptr, 0, nullptr)); ASSERT_TRUE(KBRef == nullptr); // Null IL - EXPECT_NO_FATAL_FAILURE(KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, null_spirv, 0, nullptr)); + EXPECT_NO_FATAL_FAILURE( + KBRef = DPCTLKernelBundle_CreateFromSpirv(CRef, DRef, null_spirv, 0, + nullptr, 0, nullptr)); ASSERT_TRUE(KBRef == nullptr); } @@ -350,8 +354,8 @@ TEST_F(TestKernelBundleUnsupportedBackend, CheckCreateFromSpirv) spirvFile.close(); DPCTLSyclKernelBundleRef KBRef = nullptr; - EXPECT_NO_FATAL_FAILURE( - KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, spirvBuffer.data(), spirvFileSize, nullptr)); + EXPECT_NO_FATAL_FAILURE(KBRef = DPCTLKernelBundle_CreateFromSpirv( + CRef, DRef, spirvBuffer.data(), spirvFileSize, + nullptr, 0, nullptr)); ASSERT_TRUE(KBRef == nullptr); } diff --git a/libsyclinterface/tests/test_sycl_queue_submit.cpp b/libsyclinterface/tests/test_sycl_queue_submit.cpp index ab5b6bef82..f2fc2b2140 100644 --- a/libsyclinterface/tests/test_sycl_queue_submit.cpp +++ b/libsyclinterface/tests/test_sycl_queue_submit.cpp @@ -242,7 +242,8 @@ struct TestQueueSubmit : public ::testing::Test auto CRef = DPCTLQueue_GetContext(QRef); KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr); + CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr, 0, + nullptr); DPCTLDevice_Delete(DRef); DPCTLDeviceSelector_Delete(DSRef); } @@ -282,7 +283,8 @@ struct TestQueueSubmitFP64 : public ::testing::Test auto CRef = DPCTLQueue_GetContext(QRef); KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr); + CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr, 0, + nullptr); DPCTLDeviceSelector_Delete(DSRef); } diff --git a/libsyclinterface/tests/test_sycl_queue_submit_local_accessor_arg.cpp b/libsyclinterface/tests/test_sycl_queue_submit_local_accessor_arg.cpp index f6110375bb..8f1b97d1d4 100644 --- a/libsyclinterface/tests/test_sycl_queue_submit_local_accessor_arg.cpp +++ b/libsyclinterface/tests/test_sycl_queue_submit_local_accessor_arg.cpp @@ -237,7 +237,8 @@ struct TestQueueSubmitWithLocalAccessor : public ::testing::Test auto CRef = DPCTLQueue_GetContext(QRef); KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr); + CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr, 0, + nullptr); DPCTLDevice_Delete(DRef); DPCTLDeviceSelector_Delete(DSRef); } @@ -276,7 +277,8 @@ struct TestQueueSubmitWithLocalAccessorFP64 : public ::testing::Test auto CRef = DPCTLQueue_GetContext(QRef); KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr); + CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr, 0, + nullptr); DPCTLDeviceSelector_Delete(DSRef); } diff --git a/libsyclinterface/tests/test_sycl_queue_submit_raw_kernel_arg.cpp b/libsyclinterface/tests/test_sycl_queue_submit_raw_kernel_arg.cpp index f40bc20066..04d3958d8d 100644 --- a/libsyclinterface/tests/test_sycl_queue_submit_raw_kernel_arg.cpp +++ b/libsyclinterface/tests/test_sycl_queue_submit_raw_kernel_arg.cpp @@ -262,7 +262,8 @@ struct TestQueueSubmitWithRawKernelArg : public ::testing::Test auto CRef = DPCTLQueue_GetContext(QRef); KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr); + CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr, 0, + nullptr); DPCTLDevice_Delete(DRef); DPCTLDeviceSelector_Delete(DSRef); } @@ -301,7 +302,8 @@ struct TestQueueSubmitWithRawKernelArgFP64 : public ::testing::Test auto CRef = DPCTLQueue_GetContext(QRef); KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr); + CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr, 0, + nullptr); DPCTLDeviceSelector_Delete(DSRef); } diff --git a/libsyclinterface/tests/test_sycl_queue_submit_work_group_memory_arg.cpp b/libsyclinterface/tests/test_sycl_queue_submit_work_group_memory_arg.cpp index d0f44b7275..d1d1f69bfa 100644 --- a/libsyclinterface/tests/test_sycl_queue_submit_work_group_memory_arg.cpp +++ b/libsyclinterface/tests/test_sycl_queue_submit_work_group_memory_arg.cpp @@ -262,7 +262,8 @@ struct TestQueueSubmitWithWorkGroupMemory : public ::testing::Test auto CRef = DPCTLQueue_GetContext(QRef); KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr); + CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr, 0, + nullptr); DPCTLDevice_Delete(DRef); DPCTLDeviceSelector_Delete(DSRef); } @@ -301,7 +302,8 @@ struct TestQueueSubmitWithWorkGroupMemoryFP64 : public ::testing::Test auto CRef = DPCTLQueue_GetContext(QRef); KBRef = DPCTLKernelBundle_CreateFromSpirv( - CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr); + CRef, DRef, spirvBuffer_.data(), spirvFileSize_, nullptr, 0, + nullptr); DPCTLDeviceSelector_Delete(DSRef); } diff --git a/pyproject.toml b/pyproject.toml index 92be4c0771..019dd178c6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,12 @@ Repository = "https://github.com/IntelPython/dpctl.git" exclude = "dpctl/_version.py" line-length = 80 +[tool.codespell] +builtin = "clear,rare,informal,names" +check-filenames = true +ignore-words-list = "nd" +quiet-level = 3 + [tool.coverage.report] omit = [ "dpctl/tests/*", diff --git a/setup.py b/setup.py index 1b10322ef8..2c44bd4a11 100644 --- a/setup.py +++ b/setup.py @@ -27,6 +27,7 @@ "dpctl", "dpctl.memory", "dpctl.program", + "dpctl.program.utils", "dpctl.utils", ], package_data={