Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
cd45b22
test VivadoAccelerator synth
marco66colombo Mar 12, 2026
e915de1
add VivadoAccelerator test baseline
marco66colombo Mar 12, 2026
72d3414
add: export vivado command in CI
marco66colombo Mar 12, 2026
1bf3236
assign vivadoaccelerator test to a signle job
marco66colombo Mar 12, 2026
9e35fff
add board and part in test_keras_api_vivadoacc
marco66colombo Mar 12, 2026
dee7f60
fix: update vivado board and part
marco66colombo Mar 13, 2026
791d062
update baselines
marco66colombo Mar 13, 2026
0048498
move VivadoAccelerator baselines files
marco66colombo Mar 16, 2026
e630187
add new CI for implementation tests
marco66colombo Apr 14, 2026
dd8912a
update ci scripts to handle different tools installation
marco66colombo Apr 14, 2026
26512c1
Add implementation CI dataset collection
marco66colombo Apr 30, 2026
67c0efe
Merge branch 'main' of https://github.com/fastmachinelearning/hls4ml …
marco66colombo Apr 30, 2026
3837bbe
update conftest.py
marco66colombo May 7, 2026
5cf3b89
update implementaion tests reports and example models usage
marco66colombo May 8, 2026
ad45034
update the ci templates hirerarchy
marco66colombo May 8, 2026
1c56ae3
update commits related metadata
marco66colombo May 8, 2026
c979c5a
add zip file artifact of project folder
marco66colombo May 8, 2026
1b88291
remove accuracy tests
marco66colombo May 8, 2026
c2b42df
add onnx models support
marco66colombo May 11, 2026
1fcbdd1
fix tool versions in report
marco66colombo May 11, 2026
14b8ea5
remove onnx tests
marco66colombo May 11, 2026
a68edf2
update vivadoacc keras test cases
marco66colombo May 11, 2026
880212c
update implementation pytest.yml
marco66colombo May 11, 2026
10729f0
move implementation helpers into implementation tests
marco66colombo May 12, 2026
4585990
update implementation README
marco66colombo May 12, 2026
305906c
update vivadoaccelerator report expected keys
marco66colombo May 14, 2026
1449de0
remove complile step from vivado impl test
marco66colombo May 14, 2026
f8e23ac
add stream implementation logs while preserving artifatc
marco66colombo May 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@ stages:
- trigger
- test

# Pipeline mode:
# - default (CI_PIPELINE_MODE unset): normal pytest CI
# - implementation (CI_PIPELINE_MODE=implementation): dedicated implementation pipeline

generator:
stage: generate
image: python:3.8-alpine
variables:
N_TESTS_PER_YAML: 4
rules:
- if: '$CI_PIPELINE_MODE == "implementation"'
when: never
- when: on_success
tags:
- k8s-default
before_script:
Expand All @@ -21,9 +29,25 @@ generator:

pytests:
stage: trigger
rules:
- if: '$CI_PIPELINE_MODE == "implementation"'
when: never
- when: on_success
trigger:
include:
- local: test/pytest/ci-template.yml
- artifact: test/pytest/pytests.yml
job: generator
strategy: depend

implementation-pytests:
stage: trigger
rules:
- if: '$CI_PIPELINE_MODE == "implementation"'
when: on_success
- when: never
trigger:
include:
- local: test/pytest/implementation/ci-template.yml
- local: test/pytest/implementation/pytests.yml
strategy: depend
15 changes: 15 additions & 0 deletions test/pytest/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ def synthesis_config():
'run_synthesis': str_to_bool(os.getenv('RUN_SYNTHESIS', 'false')),
'tools_version': {
'Vivado': os.getenv('VIVADO_VERSION', '2020.1'),
'VivadoAccelerator': os.getenv('VIVADO_VERSION', '2020.1'),
'Vitis': os.getenv('VITIS_VERSION', '2024.1'),
'Quartus': os.getenv('QUARTUS_VERSION', 'latest'),
'oneAPI': os.getenv('ONEAPI_VERSION', '2025.0.1'),
Expand All @@ -66,4 +67,18 @@ def synthesis_config():
'Quartus': {'synth': True, 'fpgasynth': False},
'oneAPI': {'build_type': 'report', 'run': False},
},
'implementation_build_args': {
# Full accelerator flow for implementation dataset collection:
# run HLS synth, downstream Vivado synth, and bitfile generation.
'VivadoAccelerator': {
'reset': True,
'csim': False,
'synth': True,
'cosim': True,
'validation': False,
'export': True,
'vsynth': True,
'bitfile': True,
}
},
}
19 changes: 15 additions & 4 deletions test/pytest/generate_ci_yaml.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

# Blacklisted tests will be skipped
BLACKLIST = {'test_reduction'}
EXCLUDED_DIRS = {'implementation'}

# Long-running tests will not be bundled with other tests
LONGLIST = {'test_hgq_layers', 'test_hgq_players', 'test_qkeras', 'test_pytorch_api'}
Expand All @@ -44,6 +45,11 @@
}


def include_in_default_ci(path: Path) -> bool:
"""Exclude dedicated suites (e.g. implementation-only jobs) from the default CI matrix."""
return not any(part in EXCLUDED_DIRS for part in path.parts)


def collect_test_functions_from_ast(test_file):
"""Collect all test function names using AST parsing (no imports)."""
with open(test_file, encoding='utf-8') as f:
Expand Down Expand Up @@ -79,7 +85,8 @@ def generate_test_yaml(test_root='.'):
test_paths = [
path
for path in test_root.glob('**/test_*.py')
if path.stem not in (BLACKLIST | LONGLIST | set(SPLIT_BY_TEST_CASE.keys()) | KERAS3_LIST)
if include_in_default_ci(path)
and path.stem not in (BLACKLIST | LONGLIST | set(SPLIT_BY_TEST_CASE.keys()) | KERAS3_LIST)
]
need_example_models = [uses_example_model(path) for path in test_paths]

Expand All @@ -99,15 +106,17 @@ def generate_test_yaml(test_root='.'):
else:
yml.update(diff_yml)

test_paths = [path for path in test_root.glob('**/test_*.py') if path.stem in LONGLIST]
test_paths = [path for path in test_root.glob('**/test_*.py') if include_in_default_ci(path) and path.stem in LONGLIST]
for path in test_paths:
name = path.stem.replace('test_', '')
test_file = str(path.relative_to(test_root))
needs_examples = uses_example_model(path)
diff_yml = yaml.safe_load(template.format(name, '.pytest', test_file, int(needs_examples)))
yml.update(diff_yml)

test_paths = [path for path in test_root.glob('**/test_*.py') if path.stem in SPLIT_BY_TEST_CASE]
test_paths = [
path for path in test_root.glob('**/test_*.py') if include_in_default_ci(path) and path.stem in SPLIT_BY_TEST_CASE
]
for path in test_paths:
stem = path.stem
name_base = stem.replace('test_', '')
Expand All @@ -125,7 +134,9 @@ def generate_test_yaml(test_root='.'):
else:
yml.update(diff_yml)

keras3_paths = [path for path in test_root.glob('**/test_*.py') if path.stem in KERAS3_LIST]
keras3_paths = [
path for path in test_root.glob('**/test_*.py') if include_in_default_ci(path) and path.stem in KERAS3_LIST
]
keras3_need_examples = [uses_example_model(path) for path in keras3_paths]

k3_idxs = list(range(len(keras3_need_examples)))
Expand Down
67 changes: 67 additions & 0 deletions test/pytest/implementation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Implementation CI Suite

This directory contains manually listed implementation tests. These jobs run full backend implementation flows and collect dataset artifacts with actual tool reports and generated project files.

The normal pytest CI should stay separate from this suite. Implementation tests are intended for manually triggered dataset collection, not for the regular fast test matrix.

## Pipeline Layout

Implementation CI uses:

- `test/pytest/implementation/pytests.yml`: static job list
- `test/pytest/implementation/ci-template.yml`: implementation-specific GitLab templates
- `test/pytest/implementation/implementation_helpers.py`: dataset artifact helpers used by implementation tests

Jobs in `pytests.yml` extend backend-specific runtime templates from `ci-template.yml`, for example:

- `.pytest-implementation-vivadoaccelerator`
- `.pytest-implementation-vivado-runtime`

Each concrete job sets `PYTESTFILE` to one specific test function, so each model/backend run becomes a separate CI job and artifact set.

## Dataset Artifacts

Implementation tests should use `run_implementation_collection_test()` from `implementation_helpers.py`. The helper:

- runs `hls_model.build(...)` with backend-specific implementation build args
- captures full terminal output to `*_build.log`
- writes the hls4ml report returned by the backend to `*_hls4ml_report.json`
- writes one compact dataset record to `*_dataset.json`
- compresses the generated project directory to `*_project.zip`
- records the project archive path, size, and SHA256 in the dataset record

The dataset record includes:

- hls4ml source commit and repository URL
- example-models source commit and model file names
- backend, project name, board/part metadata, and build args
- backend-specific toolchain versions
- CI metadata for finding the run later
- build timing and the hls4ml report
- pointers to the log, hls4ml report JSON, bitstream files, and project archive

`IMPLEMENTATION_DATASET_DIR` controls where artifacts are written. In CI it is set to:

```bash
test/pytest/implementation
```

## Test Policy

Implementation tests should load models from the `example-models` submodule instead of defining models inline. This keeps dataset records tied to a model name, model file, and exact `example-models` commit.

Keep test code focused on:

- loading the example model
- converting it with the backend under test
- passing clear metadata to `run_implementation_collection_test()`

Avoid duplicating dataset/report parsing in individual tests. Add backend-specific dataset behavior in `implementation_helpers.py` when needed.

## Adding A Test

1. Add or update a `test_*.py` file in this directory.
2. Load a model from `example-models`.
3. Add model metadata including name, source, source commit, and model file paths.
4. Add a static job in `pytests.yml` with `PYTESTFILE` pointing to the specific test function.
5. Set tool versions and backend runtime template through the job/template variables.
64 changes: 64 additions & 0 deletions test/pytest/implementation/ci-template.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
.pytest-implementation:
stage: test
image: gitlab-registry.cern.ch/fastmachinelearning/hls4ml-testing:0.6.3.base
tags:
- k8s-default
variables:
CONDA_ENV: "hls4ml-testing"
EXTRA_DEPS: "[da,testing,testing-keras2,sr,optimization]"
IMPLEMENTATION_DATASET_DIR: "test/pytest/implementation"
before_script:
- eval "$(conda shell.bash hook)"
- conda activate "$CONDA_ENV"
- git config --global --add safe.directory /builds/fastmachinelearning/hls4ml
- git submodule update --init --recursive hls4ml/templates/catapult/
- if [ $EXAMPLEMODEL == 1 ]; then git submodule update --init example-models; fi
- pip install .${EXTRA_DEPS}
artifacts:
when: always
reports:
junit:
- test/pytest/report.xml
paths:
- test/pytest/*.tar.gz
- test/pytest/implementation/*_dataset.json
- test/pytest/implementation/*_hls4ml_report.json
- test/pytest/implementation/*_build.log
- test/pytest/implementation/*_project.zip

.pytest-implementation-vivado-runtime:
extends: .pytest-implementation
script:
- mkdir -p cmd_vivado_${VIVADO_VERSION}
- echo '#!/bin/bash' > cmd_vivado_${VIVADO_VERSION}/vivado_hls
- echo "apptainer exec --cleanenv --env LANG=C,LC_ALL=C /cvmfs/projects.cern.ch/hls4ml/vivado/${VIVADO_VERSION} vivado_hls \"\$@\"" >> cmd_vivado_${VIVADO_VERSION}/vivado_hls
- chmod +x cmd_vivado_${VIVADO_VERSION}/vivado_hls
- echo '#!/bin/bash' > cmd_vivado_${VIVADO_VERSION}/vivado
- echo "apptainer exec --cleanenv --env LANG=C,LC_ALL=C /cvmfs/projects.cern.ch/hls4ml/vivado/${VIVADO_VERSION} vivado \"\$@\"" >> cmd_vivado_${VIVADO_VERSION}/vivado
- chmod +x cmd_vivado_${VIVADO_VERSION}/vivado
- export PATH=$PWD/cmd_vivado_${VIVADO_VERSION}:$PATH
- export IMPLEMENTATION_DATASET_DIR=$PWD/test/pytest/implementation
- cd test/pytest
- pytest $PYTESTFILE -s -rA --junitxml=report.xml --randomly-seed=42 --randomly-dont-reorganize --randomly-dont-reset-seed

.pytest-implementation-vitis-runtime:
extends: .pytest-implementation
script:
- mkdir -p cmd_vivado_${VIVADO_VERSION}
- echo '#!/bin/bash' > cmd_vivado_${VIVADO_VERSION}/vivado
- echo "apptainer exec --cleanenv --env LANG=C,LC_ALL=C /cvmfs/projects.cern.ch/hls4ml/vitis/${VITIS_VERSION} vivado \"\$@\"" >> cmd_vivado_${VIVADO_VERSION}/vivado
- chmod +x cmd_vivado_${VIVADO_VERSION}/vivado
- mkdir -p cmd_vitis_${VITIS_VERSION}
- echo '#!/bin/bash' > cmd_vitis_${VITIS_VERSION}/vitis-run
- echo "apptainer exec /cvmfs/projects.cern.ch/hls4ml/vitis/${VITIS_VERSION} vitis-run \"\$@\"" >> cmd_vitis_${VITIS_VERSION}/vitis-run
- chmod +x cmd_vitis_${VITIS_VERSION}/vitis-run
- echo '#!/bin/bash' > cmd_vitis_${VITIS_VERSION}/v++
- echo "apptainer exec /cvmfs/projects.cern.ch/hls4ml/vitis/${VITIS_VERSION} v++ \"\$@\"" >> cmd_vitis_${VITIS_VERSION}/v++
- chmod +x cmd_vitis_${VITIS_VERSION}/v++
- echo '#!/bin/bash' > cmd_vitis_${VITIS_VERSION}/vitis
- echo "apptainer exec /cvmfs/projects.cern.ch/hls4ml/vitis/${VITIS_VERSION} vitis \"\$@\"" >> cmd_vitis_${VITIS_VERSION}/vitis
- chmod +x cmd_vitis_${VITIS_VERSION}/vitis
- export PATH=$PWD/cmd_vivado_${VIVADO_VERSION}:$PWD/cmd_vitis_${VITIS_VERSION}:$PATH
- export IMPLEMENTATION_DATASET_DIR=$PWD/test/pytest/implementation
- cd test/pytest
- pytest $PYTESTFILE -s -rA --junitxml=report.xml --randomly-seed=42 --randomly-dont-reorganize --randomly-dont-reset-seed
Loading
Loading