Skip to content
Snippets Groups Projects
Commit 2e8486bb authored by Frederik Hennig's avatar Frederik Hennig
Browse files

Upgrade noxfile to pass params through to pytest. Add testing section to...

Upgrade noxfile to pass params through to pytest. Add testing section to contrib guide. Fix a weird error in the legacy jit.
parent 48be020a
1 merge request!445Object-Oriented CPU JIT API and Prototype Implementation
Pipeline #73138 canceled with stages
in 6 minutes and 41 seconds
...@@ -127,18 +127,16 @@ If you think a new module is ready to be type-checked, add an exception clause t ...@@ -127,18 +127,16 @@ If you think a new module is ready to be type-checked, add an exception clause t
## Running the Test Suite ## Running the Test Suite
Pystencils comes with an extensive and steadily growing suite of unit tests. Pystencils comes with an extensive and steadily growing suite of unit tests.
To run the testsuite, you may invoke a variant of the Nox `testsuite` session. To run the full testsuite, invoke the Nox `testsuite` session:
There are multiple different versions of the `testsuite` session, depending on whether you are testing with our
without CUDA, or which version of Python you wish to test with. ```bash
You can list the available sessions using `nox -l`. nox -s testsuite
Select one of the `testsuite` variants and run it via `nox -s "testsuite(<variant>)"`, e.g.
```
nox -s "testsuite(cpu)"
``` ```
for the CPU-only suite.
During the testsuite run, coverage information is collected and displayed using [coverage.py](https://coverage.readthedocs.io/en/7.6.10/). :::{seealso}
You can display a detailed overview of code coverage by opening the generated `htmlcov/index.html` page. [](#testing_pystencils)
:::
## Building the Documentation ## Building the Documentation
......
...@@ -7,6 +7,7 @@ Pystencils is an open-source package licensed under the [AGPL v3](https://www.gn ...@@ -7,6 +7,7 @@ Pystencils is an open-source package licensed under the [AGPL v3](https://www.gn
As such, the act of contributing to pystencils by submitting a merge request is taken as agreement to the terms of the licence. As such, the act of contributing to pystencils by submitting a merge request is taken as agreement to the terms of the licence.
:::{toctree} :::{toctree}
:maxdepth: 2 :maxdepth: 2
dev-workflow dev-workflow
testing
::: :::
(testing_pystencils)=
# Testing pystencils
The pystencils testsuite is located at the `tests` directory,
constructed using [pytest](https://pytest.org),
and automated through [Nox](https://nox.thea.codes).
On this page, you will find instructions on how to execute and extend it.
## Running the Testsuite
The fastest way to execute the pystencils test suite is through the `testsuite` Nox session:
```bash
nox -s testsuite
```
There exist several configurations of the testsuite session, from which the above command will
select and execute only those that are available on your machine.
- *Python Versions:* The testsuite session can be run against all major Python versions between 3.10 and 3.13 (inclusive).
To only use a specific Python version, add the `-p 3.XX` argument to your Nox invocation; e.g. `nox -s testsuite -p 3.11`.
- *CuPy:* There exist three variants of `testsuite`, including or excluding tests for the CUDA GPU target: `cpu`, `cupy12` and `cupy13`.
To select one, append `(<variant>)` to the session name; e.g. `nox -s "testsuite(cupy12)"`.
You may also pass options through to pytest via positional arguments after a pair of dashes, e.g.:
```bash
nox -s testsuite -- -k "kernelcreation"
```
During the testsuite run, coverage information is collected using [coverage.py](https://coverage.readthedocs.io/en/7.6.10/),
and the results are exported to HTML.
You can display a detailed overview of code coverage by opening the generated `htmlcov/index.html` page.
## Extending the Test Suite
### Codegen Configurations via Fixtures
In the pystencils test suite, it is often necessary to test code generation features against multiple targets.
To simplify this process, we provide a number of [pytest fixtures](https://docs.pytest.org/en/stable/how-to/fixtures.html)
you can and should use in your tests:
- `target`: Provides code generation targets for your test.
Using this fixture will make pytest create a copy of your test for each target
available on the current machine (see {any}`Target.available_targets`).
- `gen_config`: Provides default code generation configurations for your test.
This fixture depends on `target` and provides a {any}`CreateKernelConfig` instance
with target-specific optimization options (in particular vectorization) enabled.
- `xp`: The `xp` fixture gives you either the *NumPy* (`np`) or the *CuPy* (`cp`) module,
depending on whether `target` is a CPU or GPU target.
These fixtures are defined in `tests/fixtures.py`.
### Overriding Fixtures
Pytest allows you to locally override fixtures, which can be especially practical when you wish
to restrict the target selection of a test.
For example, the following test overrides `target` using a parametrization mark,
and uses this in combination with the `gen_config` fixture, which now
receives the overridden `target` parameter as input:
```Python
@pytest.mark.parametrize("target", [Target.X86_SSE, Target.X86_AVX])
def test_bogus(gen_config):
assert gen_config.target.is_vector_cpu()
```
## Testing with the Experimental CPU JIT
Currently, the testsuite by default still uses the {any}`legacy CPU JIT compiler <LegacyCpuJit>`,
since the new CPU JIT compiler is still in an experimental stage.
To test your code against the new JIT compiler, pass the `--experimental-cpu-jit` option to pytest:
```bash
nox -s testsuite -- --experimental-cpu-jit
```
This will alter the `gen_config` fixture, activating the experimental CPU JIT for CPU targets.
...@@ -86,9 +86,15 @@ def typecheck(session: nox.Session): ...@@ -86,9 +86,15 @@ def typecheck(session: nox.Session):
session.run("mypy", "src/pystencils") session.run("mypy", "src/pystencils")
@nox.session(python=["3.10", "3.12", "3.13"], tags=["test"]) @nox.session(python=["3.10", "3.11", "3.12", "3.13"], tags=["test"])
@nox.parametrize("cupy_version", [None, "12", "13"], ids=["cpu", "cupy12", "cupy13"]) @nox.parametrize("cupy_version", [None, "12", "13"], ids=["cpu", "cupy12", "cupy13"])
def testsuite(session: nox.Session, cupy_version: str | None): def testsuite(session: nox.Session, cupy_version: str | None):
"""Run the pystencils test suite.
**Positional Arguments:** Any positional arguments passed to nox after `--`
are propagated to pytest.
"""
if cupy_version is not None: if cupy_version is not None:
install_cupy(session, cupy_version, skip_if_no_cuda=True) install_cupy(session, cupy_version, skip_if_no_cuda=True)
...@@ -108,6 +114,7 @@ def testsuite(session: nox.Session, cupy_version: str | None): ...@@ -108,6 +114,7 @@ def testsuite(session: nox.Session, cupy_version: str | None):
"--html", "--html",
"test-report/index.html", "test-report/index.html",
"--junitxml=report.xml", "--junitxml=report.xml",
*session.posargs
) )
session.run("coverage", "html") session.run("coverage", "html")
session.run("coverage", "xml") session.run("coverage", "xml")
......
...@@ -51,7 +51,7 @@ class Pybind11KernelModuleBuilder(ExtensionModuleBuilderBase): ...@@ -51,7 +51,7 @@ class Pybind11KernelModuleBuilder(ExtensionModuleBuilderBase):
kernel_def = self._get_kernel_definition(kernel) kernel_def = self._get_kernel_definition(kernel)
kernel_args = [param.name for param in kernel.parameters] kernel_args = [param.name for param in kernel.parameters]
includes = [f"#include {h}" for h in kernel.required_headers] includes = [f"#include {h}" for h in sorted(kernel.required_headers)]
from string import Template from string import Template
...@@ -76,7 +76,7 @@ class Pybind11KernelModuleBuilder(ExtensionModuleBuilderBase): ...@@ -76,7 +76,7 @@ class Pybind11KernelModuleBuilder(ExtensionModuleBuilderBase):
def _get_kernel_definition(self, kernel: Kernel) -> str: def _get_kernel_definition(self, kernel: Kernel) -> str:
from ...backend.emission import CAstPrinter from ...backend.emission import CAstPrinter
printer = CAstPrinter(func_prefix="inline") printer = CAstPrinter()
return printer(kernel) return printer(kernel)
......
...@@ -91,12 +91,14 @@ class PsKernelExtensioNModule: ...@@ -91,12 +91,14 @@ class PsKernelExtensioNModule:
code += "\n" code += "\n"
# Kernels and call wrappers # Kernels and call wrappers
from ..backend.emission import CAstPrinter
printer = CAstPrinter(func_prefix="FUNC_PREFIX")
for name, kernel in self._kernels.items(): for name, kernel in self._kernels.items():
old_name = kernel.name old_name = kernel.name
kernel.name = f"kernel_{name}" kernel.name = f"kernel_{name}"
code += kernel.get_c_code() code += printer(kernel)
code += "\n" code += "\n"
code += emit_call_wrapper(name, kernel) code += emit_call_wrapper(name, kernel)
code += "\n" code += "\n"
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment