From d6bd86b94add30875a06003da868ce8e4aeb5975 Mon Sep 17 00:00:00 2001 From: Robert Cohn Date: Tue, 2 Jul 2024 13:09:13 -0400 Subject: [PATCH] selective test (#10) (#513) --- .github/scripts/domain-check.js | 137 ++++++++++++++++++++++++++++++++ .github/workflows/pr.yml | 41 ++++++---- 2 files changed, 162 insertions(+), 16 deletions(-) create mode 100644 .github/scripts/domain-check.js diff --git a/.github/scripts/domain-check.js b/.github/scripts/domain-check.js new file mode 100644 index 000000000..abf933f2f --- /dev/null +++ b/.github/scripts/domain-check.js @@ -0,0 +1,137 @@ +// +// This script is used by pr.yml to determine if a domain must be tested based +// on the files modified in the pull request. +// + +// Given a domain name and set of files, return true if the domain should be +// tested +function matchesPattern(domain, filePaths) { + // filter files that end in .md + filePaths = filePaths.filter( + (filePath) => + !filePath.endsWith(".md") && + !filePath.startsWith("docs/") && + !filePath.startsWith("third-party-programs/"), + ); + // These directories contain domain specific code + const dirs = "(tests/unit_tests|examples|src|include/oneapi/mkl)"; + const domains = "(blas|lapack|rng|dft)"; + // matches changes to the domain of interest or non domain-specific code + const re = new RegExp(`^(${dirs}/${domain}|(?!${dirs}/${domains}))`); + const match = filePaths.some((filePath) => re.test(filePath)); + return match; +} + +// Return the list of files modified in the pull request +async function prFiles(github, context) { + const response = await github.rest.pulls.listFiles({ + owner: context.repo.owner, + repo: context.repo.repo, + pull_number: context.payload.pull_request.number, + }); + const prFiles = response.data.map((file) => file.filename); + return prFiles; +} + +// Called by pr.yml. See: +// https://github.com/actions/github-script/blob/main/README.md for more +// information on the github and context parameters +module.exports = async ({ github, context, domain }) => { + if (!context.payload.pull_request) { + console.log("Not a pull request. Testing all domains."); + return true; + } + const files = await prFiles(github, context); + const match = matchesPattern(domain, files); + console.log("Domain: ", domain); + console.log("PR files: ", files); + console.log("Match: ", match); + return match; +}; + +// +// Test the matchesPattern function +// +// Run this script with `node domain-check.js` It should exit with code 0 if +// all tests pass. +// +// If you need to change the set of files that are ignored, add a test pattern +// below with positive and negative examples. It is also possible to test by +// setting up a fork and then submitting pull requests that modify files, but +// it requires a lot of manual work. +// +test_patterns = [ + { + domain: "blas", + files: ["tests/unit_tests/blas/test_blas.cpp"], + expected: true, + }, + { + domain: "rng", + files: ["examples/rng/example_rng.cpp"], + expected: true, + }, + { + domain: "lapack", + files: ["include/oneapi/mkl/lapack/lapack.hpp"], + expected: true, + }, + { + domain: "dft", + files: ["src/dft/lapack.hpp"], + expected: true, + }, + { + domain: "dft", + files: ["src/dft/lapack.md"], + expected: false, + }, + { + domain: "blas", + files: ["tests/unit_tests/dft/test_blas.cpp"], + expected: false, + }, + { + domain: "rng", + files: ["examples/blas/example_rng.cpp"], + expected: false, + }, + { + domain: "lapack", + files: ["include/oneapi/mkl/rng/lapack.hpp"], + expected: false, + }, + { + domain: "dft", + files: ["src/lapack/lapack.hpp"], + expected: false, + }, + { + domain: "dft", + files: ["docs/dft/dft.rst"], + expected: false, + }, + { + domain: "dft", + files: ["third-party-programs/dft/dft.rst"], + expected: false, + }, +]; + +function testPattern(test) { + const result = matchesPattern(test.domain, test.files); + if (result !== test.expected) { + console.log("Fail:"); + console.log(" domain:", test.domain); + console.log(" files:", test.files); + console.log(" expected:", test.expected); + console.log(" result:", result); + process.exit(1); + } +} + +if (require.main === module) { + // invoke test for each test pattern + test_patterns.forEach(testPattern); + console.log("All tests pass"); +} diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 5c4e3c08c..0da2153c6 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -1,7 +1,7 @@ name: "PR Tests" permissions: read-all -# Trigger for PR an merge to develop branch +# Trigger for PR and merge to develop branch on: push: branches: develop @@ -21,26 +21,32 @@ jobs: matrix: include: - config: portBLAS - options: -DTARGET_DOMAINS=blas -DREF_BLAS_ROOT=${PWD}/lapack/install -DENABLE_PORTBLAS_BACKEND=ON -DENABLE_MKLCPU_BACKEND=OFF -DPORTBLAS_TUNING_TARGET=INTEL_CPU - tests: '.*' + domain: blas + build_options: -DREF_BLAS_ROOT=${PWD}/lapack/install -DENABLE_PORTBLAS_BACKEND=ON -DENABLE_MKLCPU_BACKEND=OFF -DPORTBLAS_TUNING_TARGET=INTEL_CPU - config: portFFT - options: -DENABLE_PORTFFT_BACKEND=ON -DENABLE_MKLCPU_BACKEND=OFF -DTARGET_DOMAINS=dft - tests: 'DFT/CT/.*ComputeTests_in_place_COMPLEX.COMPLEX_SINGLE_in_place_buffer.sizes_8_batches_1*' + domain: dft + build_options: -DENABLE_PORTFFT_BACKEND=ON -DENABLE_MKLCPU_BACKEND=OFF + test_options: -R 'DFT/CT/.*ComputeTests_in_place_COMPLEX.COMPLEX_SINGLE_in_place_buffer.sizes_8_batches_1*' - config: MKL BLAS - options: -DTARGET_DOMAINS=blas -DREF_BLAS_ROOT=${PWD}/lapack/install - tests: '.*' + domain: blas + build_options: -DREF_BLAS_ROOT=${PWD}/lapack/install - config: MKL DFT - options: -DTARGET_DOMAINS=dft - tests: '.*' + domain: dft - config: MKL LAPACK - options: -DTARGET_DOMAINS=lapack -DREF_LAPACK_ROOT=${PWD}/lapack/install - tests: '.*' + domain: lapack + build_options: -DREF_LAPACK_ROOT=${PWD}/lapack/install - config: MKL RNG - options: -DTARGET_DOMAINS=rng - tests: '.*' + domain: rng name: unit tests ${{ matrix.config }} CPU steps: - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 + - name: Check if the changes affect this domain + id: domain_check + uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 + with: + script: | + const domainCheck = require('.github/scripts/domain-check.js') + return domainCheck({github, context, domain: "${{ matrix.domain }}"}) - name: Restore netlib from cache id: cache-lapack uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 @@ -48,7 +54,7 @@ jobs: path: lapack/install key: lapack-${{ env.LAPACK_VERSION }} - name: Install netlib - if: steps.cache-lapack.outputs.cache-hit != 'true' + if: steps.domain_check.outputs.result == 'true' && steps.cache-lapack.outputs.cache-hit != 'true' run: | curl -sL https://github.com/Reference-LAPACK/lapack/archive/refs/tags/v${LAPACK_VERSION}.tar.gz | tar zx SHARED_OPT="lapack-${LAPACK_VERSION} -DBUILD_SHARED_LIBS=on -DCBLAS=on -DLAPACKE=on -DCMAKE_INSTALL_PREFIX=${PWD}/lapack/install" @@ -59,17 +65,20 @@ jobs: cmake ${SHARED_OPT} -DBUILD_INDEX64=on -B lapack/build64 cmake --build lapack/build64 ${PARALLEL} --target install - name: Install oneapi + if: steps.domain_check.outputs.result == 'true' uses: rscohn2/setup-oneapi@2ad0cf6b74bc2426bdcee825cf88f9db719dd727 # v0.1.0 with: components: | icx@2024.1.0 mkl@2024.1.0 - name: Configure/Build for a domain + if: steps.domain_check.outputs.result == 'true' run: | source /opt/intel/oneapi/setvars.sh - cmake -DENABLE_MKLGPU_BACKEND=off -DCMAKE_VERBOSE_MAKEFILE=on ${{ matrix.options }} -B build + cmake -DTARGET_DOMAINS=${{ matrix.domain }} -DENABLE_MKLGPU_BACKEND=off -DCMAKE_VERBOSE_MAKEFILE=on ${{ matrix.build_options }} -B build cmake --build build ${PARALLEL} - name: Run tests + if: steps.domain_check.outputs.result == 'true' run: | source /opt/intel/oneapi/setvars.sh - ctest --test-dir build -R ${{ matrix.tests }} + ctest --test-dir build ${{ matrix.test_options }}