Skip to content

Add SoCDAML Part III: hands-on lab for adding a new int8 operator - #194

Open
viv-eth wants to merge 11 commits into
pulp-platform:develfrom
viv-eth:fs26ex
Open

Add SoCDAML Part III: hands-on lab for adding a new int8 operator#194
viv-eth wants to merge 11 commits into
pulp-platform:develfrom
viv-eth:fs26ex

Conversation

@viv-eth

@viv-eth viv-eth commented May 20, 2026

Copy link
Copy Markdown
Contributor

This PR adds Part III to Tutorials/SoCDAML.md, a 1-hour hands-on lab in which students add a new int8 operator (iLeakyReLU) to Deeploy and progressively optimize it on Siracusa from a plain-C scalar kernel running on a single core all the way to a tiled, multi-core, XPULP-SIMD kernel. The lab walks through the full compiler pipeline that Parts I and II used as a black box: Parser → Mapper → Binding → Template → TileConstraint → SIMD kernel. Students measure end-to-end cycles at every step and observe the speedup compared to the baseline implementation.

Two coordinated artifact directories ship alongside the markdown:

  • Tutorials/PartIII_skeletons/iLeakyReLU/: student starting kit with TODO(student) markers and per-file destination paths.
  • Tutorials/PartIII_solution/iLeakyReLU/: full TA reference (kernels, parser, template, tile constraint, ONNX + golden tensors) plus a one-shot deploy.sh that patches the live source tree (Parsers.py, Bindings.py, Tiler.py, Platform.py, DeeployPULPMath.h) and copies the new kernel/template/constraint files into place. Re-runnable in scalar / simd / undo modes.

Added

  • Tutorials/PartIII_skeletons/iLeakyReLU/: 8 skeleton files (generate.py, kernel + SIMD kernel skeletons, parser/template/tile-constraint skeletons, header, README).
  • Tutorials/PartIII_solution/iLeakyReLU/: full working reference operator (parser, template, tile + perf constraint, scalar + SIMD kernels, header, ONNX + golden artifacts, deploy.sh, README).
  • New Part III: Adding a New Operator section appended to Tutorials/SoCDAML.md with 6 stepwise tasks and solution dropdowns matching Parts I/II.

Changed

  • Tutorials/SoCDAML.md: appended Part III. Parts I and II are untouched.

Fixed

PR Merge Checklist

  1. The PR is rebased on the latest devel commit and pointing to devel.
  2. Your PR reviewed and approved.
  3. All checks are passing.
  4. The CHANGELOG.md file has been updated.
  5. If the docker was modified, change back its link after review.

@viv-eth
viv-eth marked this pull request as ready for review July 28, 2026 19:03
@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added a complete iLeakyReLU tutorial, including starter materials, reference implementation, scalar and SIMD examples, generated test data, and deployment options.
    • Added step-by-step guidance for creating, testing, tiling, and optimizing a custom operator.
  • Bug Fixes

    • Corrected forwarding of Neureka memory and 3x3 optimization options.
    • Fixed tutorial setup, deployment, tiling constraints, and command-line handling.
  • Documentation

    • Expanded installation and debugging guidance.
    • Documented the current profiling limitation: --profileTiling may crash GVSoC on larger microLlama graphs.

Walkthrough

Adds Part III iLeakyReLU student skeletons and a complete reference solution with deterministic artifacts, scalar/SIMD kernels, parsing, templating, tiling, deployment wiring, runner flag forwarding, and expanded tutorial documentation.

Changes

iLeakyReLU Part III

Layer / File(s) Summary
Supporting fixes and repository updates
.gitignore, CHANGELOG.md, DeeployTest/testUtils/deeployRunner.py, docs/tutorials/debugging.rst
Adds environment/artifact ignore rules, changelog entries, generator flag forwarding, and a punctuation-only debugging documentation correction.
Student skeleton workflow
Tutorials/PartIII_skeletons/iLeakyReLU/*
Adds student-facing generation, parser, kernel, SIMD, template, tile-constraint, header, and README skeletons with TODO(student) placeholders.
Reference implementation and test artifacts
Tutorials/PartIII_solution/iLeakyReLU/generate.py, Tutorials/PartIII_solution/iLeakyReLU/*.{c,h,py}, Tutorials/PartIII_solution/iLeakyReLU/*.onnx, Tutorials/PartIII_solution/iLeakyReLU/*.npz
Adds deterministic ONNX and golden-data generation, scalar and SIMD kernels, parser/template integration, and a conditional tile-size divisibility constraint.
Deployment and live-tree wiring
Tutorials/PartIII_solution/iLeakyReLU/deploy.sh, Tutorials/PartIII_solution/iLeakyReLU/README.md
Adds scalar, SIMD, and undo deployment modes that copy artifacts and patch parser, bindings, tiler, math-header, and platform integration points.
Tutorial installation and operator walkthrough
docs/tutorials/introduction.md
Documents Singularity setup, corrected model/profiling paths, the GVSoC profiling issue, and the end-to-end iLeakyReLU implementation workflow.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant generate.py
  participant deploy.sh
  participant Deeploy
  User->>generate.py: generate ONNX and golden tensors
  generate.py-->>User: network.onnx, inputs.npz, outputs.npz
  User->>deploy.sh: select scalar or SIMD mode
  deploy.sh->>Deeploy: copy artifacts and patch integration files
  User->>Deeploy: run iLeakyReLU test
  Deeploy-->>User: generated and executed kernel results
Loading

Possibly related PRs

Suggested labels: Feature

Suggested reviewers: xeratec

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding SoCDAML Part III as a hands-on lab for a new int8 operator.
Description check ✅ Passed The description is directly related to the changeset and accurately describes the new lab, skeletons, solution, and documentation updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/tutorials/introduction.md`:
- Line 58: Update the introductory description to call the instructions a
“six-step sequence” instead of a “four-step sequence,” leaving the surrounding
Docker and Singularity translation text unchanged.
- Line 115: Update the fenced code blocks in docs/tutorials/introduction.md,
including the blocks near lines 115, 371, 385, 485, 523, and 595, to specify
language identifiers: use text for error-output content and bash for
shell-command examples. Preserve the existing block contents.
- Line 261: Update the profiling description near the --profileTiling flag to
say the transformation inserts print statements displaying runtimes, and revise
the example introduction to say profiling will print the following.
- Line 347: In the tutorial introduction paragraph, update the sentence near
“add your own operator from scratch” to replace the duplicated article in “the
an int8 LeakyReLU” with “an int8 LeakyReLU.”
- Around line 93-97: Update the “Build the writable Singularity sandbox”
instructions to use the course-supported unprivileged build path, such as the
required --fakeroot invocation, and document any necessary subuid/subgid setup
or supported remote-build alternative. Keep the Deeploy image and writable
sandbox behavior unchanged.
- Around line 68-70: Update the tutorial’s Singularity shell setup so CCACHE_DIR
and PIP_CACHE_DIR remain available when --cleanenv is used; pass both variables
through the container environment or export them immediately after entering the
shell, preserving their $SCRATCH-based values.

In `@Tutorials/PartIII_skeletons/iLeakyReLU/generate.py`:
- Around line 55-56: Update the NPZ generation in the tutorial script to save
the arrays under the Deeploy-compatible keys input and output, converting both x
and y to int64 before writing. Preserve the existing input/output data
generation while replacing data_in/data_out and int8 storage.

In `@Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLU_simd.c`:
- Around line 36-39: Update the per-core partitioning in the iLeakyReLU SIMD
worker so rounding does not drop elements or produce zero-sized chunks.
Partition complete 4-element vectors by vector index across cores, then ensure
the size % 4 scalar tail is processed exactly once, preserving coverage of every
element even when size is smaller than or not evenly divisible by nC.

In `@Tutorials/PartIII_skeletons/iLeakyReLU/README.md`:
- Line 12: Update the iLeakyReLU_simd.c entry in the README table to state that
packed shift, max, and final store remain TODOs for the student, while retaining
the existing SIMD chunking context and Step 6b guidance.

In `@Tutorials/PartIII_solution/iLeakyReLU/deploy.sh`:
- Around line 35-43: Update the undo branch in deploy.sh to preserve
pre-existing contents of TESTS_DIR: remove only the copied iLeakyReLU test
artifacts, and remove TESTS_DIR only when it is empty. Keep the cleanup of the
three iLeakyReLU source, header, and template/constraint files unchanged.

In `@Tutorials/PartIII_solution/iLeakyReLU/generate.py`:
- Line 77: Update the integer fixture generation in the visible RNG call to
include the positive int8 boundary by using an exclusive upper bound of 128 or
enabling the inclusive endpoint. Regenerate the corresponding NPZ artifacts
after changing the input distribution.

In `@Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU_simd.c`:
- Around line 36-57: Fix partitioning in
Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU_simd.c lines 36-57 by
distributing complete v4s blocks across cores without rounding each core’s work
to zero or discarding remainders, then have one core process the global scalar
remainder. Update
Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUTileConstraint.py lines 39-51 to
remove the incorrect tail-free guarantee or enforce only constraints still
required by the corrected SIMD partition; use the existing SIMD loop and scalar
tail symbols as integration points.

In `@Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUParser.py`:
- Around line 22-35: Constrain iLeakyReLU parsing to the SIMD contract in both
iLeakyReLUParser.parseNode and the injected parser in deploy.sh: accept only mul
== 1 and a supported non-negative shift, rejecting unsupported parameter
combinations before populating operatorRepresentation. Keep both parser
implementations consistent unless the SIMD implementation is updated to apply
multiplication.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: baff3e72-3778-4433-a52c-cda43b737a42

📥 Commits

Reviewing files that changed from the base of the PR and between 6818f31 and baff9c8.

⛔ Files ignored due to path filters (5)
  • Tutorials/Images/DeeploySystem.png is excluded by !**/*.png
  • Tutorials/Images/EthLogoNeg.png is excluded by !**/*.png
  • Tutorials/Images/Siracusa.png is excluded by !**/*.png
  • Tutorials/Images/Victor_Jung_EDGEAIForumDeeploy_S5.png is excluded by !**/*.png
  • docs/img/DeeployLogoGreen.svg is excluded by !**/*.svg
📒 Files selected for processing (25)
  • .gitignore
  • CHANGELOG.md
  • DeeployTest/testUtils/deeployRunner.py
  • Tutorials/PartIII_skeletons/iLeakyReLU/README.md
  • Tutorials/PartIII_skeletons/iLeakyReLU/generate.py
  • Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLU.c
  • Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLU.h
  • Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLUParser.py
  • Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLUTemplate.py
  • Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLUTileConstraint.py
  • Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLU_simd.c
  • Tutorials/PartIII_solution/iLeakyReLU/README.md
  • Tutorials/PartIII_solution/iLeakyReLU/deploy.sh
  • Tutorials/PartIII_solution/iLeakyReLU/generate.py
  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU.c
  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU.h
  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUParser.py
  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUTemplate.py
  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUTileConstraint.py
  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU_simd.c
  • Tutorials/PartIII_solution/iLeakyReLU/inputs.npz
  • Tutorials/PartIII_solution/iLeakyReLU/network.onnx
  • Tutorials/PartIII_solution/iLeakyReLU/outputs.npz
  • docs/tutorials/debugging.rst
  • docs/tutorials/introduction.md

```bash
docker run -it --name deeploy_main -v $(pwd):/app/Deeploy ghcr.io/pulp-platform/deeploy:main
```
is the four-step sequence below. The key part of the translation: Docker's `-v $(pwd):/app/Deeploy` (bind-mount the host clone) becomes Singularity's `--bind "$SCRATCH/Deeploy:/app/Deeploy"`.

@coderabbitai coderabbitai Bot Jul 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the installation step count.

Line 58 says “four-step sequence,” but the instructions contain six numbered steps. Change it to “six-step sequence.”

[details]

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/tutorials/introduction.md` at line 58, Update the introductory
description to call the instructions a “six-step sequence” instead of a
“four-step sequence,” leaving the surrounding Docker and Singularity translation
text unchanged.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is relevant

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Victor-Jung, thanks for confirming. The introductory wording should be updated to say “six-step sequence” so it matches the six numbered installation steps.

Comment on lines +68 to +70
export SINGULARITY_CACHEDIR="$SCRATCH/.singularity_cache"
export CCACHE_DIR="$SCRATCH/.ccache"
export PIP_CACHE_DIR="$SCRATCH/.pip_cache"

@coderabbitai coderabbitai Bot Jul 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## candidate file section"
if [ -f docs/tutorials/introduction.md ]; then
  nl -ba docs/tutorials/introduction.md | sed -n '55,120p'
else
  echo "docs/tutorials/introduction.md not found"
  fd -a 'introduction\.md$' .
fi

echo
echo "## search for cleanenv/cache env context"
rg -n --fixed-strings "--cleanenv|SINGULARITY_CACHEDIR|APPTAINER_CACHEDIR|CCACHE_DIR|PIP_CACHE_DIR|APPTAINERENV|SINGULARITYENV" docs || true

echo
echo "## relevant tutorial command snippets"
rg -n --fixed-strings "singularity exec|apptainer exec|bash --login|APPTAINERENV|SINGULARITYENV|--cleanenv|SINGULARITY_CACHEDIR|CCACHE_DIR|PIP_CACHE_DIR" docs || true

Repository: pulp-platform/Deeploy

Length of output: 225


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "## candidate file section"
if [ -f docs/tutorials/introduction.md ]; then
  awk '{printf "%6d\t%s\n", NR, $0}' docs/tutorials/introduction.md | sed -n '55,120p'
else
  echo "docs/tutorials/introduction.md not found"
  find . -type f -name 'introduction.md' | sed -n '1,20p'
fi

echo
echo "## search for cleanenv/cache env context"
grep -RInE -- --cleanenv|SINGULARITY_CACHEDIR|APPTAINER_CACHEDIR|CCACHE_DIR|PIP_CACHE_DIR|APPTAINERENV|SINGULARITYENV docs || true

echo
echo "## relevant tutorial command snippets"
grep -RInE -- 'singularity exec|apptainer exec|bash --login|--(env|cleanenv)|APPTAINERENV|SINGULARITYENV|SINGULARITY_CACHEDIR|CCACHE_DIR|PIP_CACHE_DIR' docs || true

Repository: pulp-platform/Deeploy

Length of output: 5156


🌐 Web query:

Singularity/Apptainer --cleanenv environment variables APPTAINERENV_ SINGULARITYENV documentation

💡 Result:

In Apptainer, the --cleanenv (or -e) option and environment variable prefixes are used to manage the runtime environment of a container [1][2]. --cleanenv / -e The --cleanenv option (or its alias -e) prevents host environment variables from being automatically passed into the container [1][3]. When used, the container starts with a minimal set of environment variables necessary for core operation [1][3]. This is particularly useful when host systems set numerous variables (e.g., via environment modules or lmod) that might interfere with software inside the container [1][3]. You can also control this behavior via the environment variable APPTAINER_CLEANENV [4]. APPTAINERENV_ and SINGULARITYENV_ Prefixes These prefixes allow you to inject environment variables into a container at runtime [5][4]. - APPTAINERENV_PREFIX: Setting an environment variable on the host with the prefix APPTAINERENV_ (e.g., APPTAINERENV_FOO=BAR) will create an environment variable named FOO with the value BAR inside the container [5][4]. - Compatibility with SINGULARITYENV_: Apptainer maintains backward compatibility with the legacy SINGULARITYENV_ prefix [5][6]. If a corresponding APPTAINERENV_ variable is not set, Apptainer will respect the SINGULARITYENV_ prefix [5][6]. - Precedence: If both the APPTAINERENV_ and SINGULARITYENV_ versions of a variable are defined, the value set by the APPTAINERENV_ variable takes priority [5][6]. Apptainer will typically issue a warning if both are present to alert you to the potential conflict [5][6]. The use of the SINGULARITYENV_ prefix is considered deprecated, and users are encouraged to transition to the APPTAINERENV_ prefix to ensure long-term compatibility [5][6].

Citations:


Preserve the cache variables through --cleanenv.

Steps 68-70 export CCACHE_DIR and PIP_CACHE_DIR, but step 109 runs singularity shell ... --cleanenv, which does not automatically carry those host variables into the shell. With the shell’s own defaults, ccache/pip can fall back to $HOME and consume the quoted home filesystem. Pass them with --env/APPTAINERENV_/SINGULARITYENV_, or export them after entering the shell.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/tutorials/introduction.md` around lines 68 - 70, Update the tutorial’s
Singularity shell setup so CCACHE_DIR and PIP_CACHE_DIR remain available when
--cleanenv is used; pass both variables through the container environment or
export them immediately after entering the shell, preserving their
$SCRATCH-based values.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe check on that too.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🤖 web_search executed:

Apptainer official documentation --cleanenv host environment variables --env SINGULARITYENV CCACHE_DIR PIP_CACHE_DIR

Length of output: 15995


@Victor-Jung, checked: the finding is valid. Both Apptainer and SingularityCE document that --cleanenv drops regular host environment variables; CCACHE_DIR and PIP_CACHE_DIR therefore are not carried into the shell as currently written. SINGULARITY_CACHEDIR is only needed for the host-side singularity build, so that one is fine.

One extra detail for the fix: forwarding $SCRATCH/.ccache and $SCRATCH/.pip_cache with --env only works if those paths are also visible inside the container. Since the tutorial says the scratch CWD is not available in the container, the revised command should explicitly bind the cache directory (or otherwise use a container-visible scratch path), then set the two variables via --env.

So this should remain open, with the documentation updated to cover both the bind mount and environment forwarding.

Comment thread docs/tutorials/introduction.md
Comment thread docs/tutorials/introduction.md
### Profiling the Execution

To measure the effect of some optimizations in more detail, you can use the `--profileTiling=L2` flag. This flag will enable a code transformation that will insert print displaying the runtime of several critical code sections. For instance, profiling an *Integer Layer Normalization* layer from L2 with two tiles will return the print the following:
To measure the effect of some optimizations in more detail, you can use the `--profileTiling` flag. This flag will enable a code transformation that will insert print displaying the runtime of several critical code sections. For instance, profiling an *Integer Layer Normalization* layer from L2 with two tiles will return the print the following:

@coderabbitai coderabbitai Bot Jul 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the profiling sentence grammar.

The text currently says “insert print displaying” and “will return the print the following.” Use “insert print statements displaying” and “will print the following.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/tutorials/introduction.md` at line 261, Update the profiling description
near the --profileTiling flag to say the transformation inserts print statements
displaying runtimes, and revise the example introduction to say profiling will
print the following.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nitpick

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Victor-Jung, agreed — this is a documentation nitpick.

| `generate.py` | Complete ONNX + golden-value generator | Run it (Step 1) |
| `iLeakyReLU.h` | Complete kernel header | Copy to `TargetLibraries/PULPOpen/inc/kernel/` (Step 3) |
| `iLeakyReLU.c` | Multi-core chunking provided; inner loop TODO | Fill the TODO, copy to `TargetLibraries/PULPOpen/src/` (Step 3) |
| `iLeakyReLU_simd.c` | SIMD chunking + load/max/store provided; one TODO line | Fill in Step 6b after the scalar works |

@coderabbitai coderabbitai Bot Jul 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Align the SIMD description with the skeleton.

Line 12 says load/max/store are provided, but iLeakyReLU_simd.c leaves the packed shift, max, and final store for the student. Update this row so the lab instructions match the actual file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tutorials/PartIII_skeletons/iLeakyReLU/README.md` at line 12, Update the
iLeakyReLU_simd.c entry in the README table to state that packed shift, max, and
final store remain TODOs for the student, while retaining the existing SIMD
chunking context and Step 6b guidance.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe check on this too.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Tutorials/PartIII_skeletons/iLeakyReLU/README.md ---'
cat -n Tutorials/PartIII_skeletons/iLeakyReLU/README.md

printf '%s\n' '--- TODOs and SIMD implementation context ---'
rg -n -C 5 'TODO\(student\)|vOut|vMax|shift|store|load' \
  Tutorials/PartIII_skeletons/iLeakyReLU/iLeakyReLU_simd.c

Length of output: 4223


@Victor-Jung, checked: this is still valid.

The skeleton provides SIMD chunking and the vector load, but the packed shift, packed signed max, and final output store remain TODO(student) work—the current vOut[i] = x is only a placeholder.

A matching Line 12 description would be:

| `iLeakyReLU_simd.c` | SIMD chunking + vector load provided; packed shift/max/store TODO | Fill in Step 6b after the scalar works |

Comment on lines +35 to +43
undo)
echo "Undoing iLeakyReLU additions (file copies only)..."
rm -rf "$TESTS_DIR"
rm -f "$KERNEL_SRC_DIR/iLeakyReLU.c"
rm -f "$KERNEL_INC_DIR/iLeakyReLU.h"
rm -f "$TEMPLATES_DIR/iLeakyReLUTemplate.py"
rm -f "$TILECONSTR_DIR/iLeakyReLUTileConstraint.py"
echo "Note: hand-patches in Parsers.py / Bindings.py / Platform.py / Tiler.py / DeeployPULPMath.h were NOT removed."
echo "If you need a fully clean tree, use: git checkout -- Deeploy/Targets TargetLibraries/PULPOpen/inc/DeeployPULPMath.h"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Do not delete the entire test directory.

Line 37 removes any pre-existing tests or local artifacts under this shared path. Delete only the three copied artifacts and optionally remove the directory if empty.

Proposed fix
-	rm -rf "$TESTS_DIR"
+	rm -f "$TESTS_DIR/network.onnx" "$TESTS_DIR/inputs.npz" "$TESTS_DIR/outputs.npz"
+	rmdir "$TESTS_DIR" 2>/dev/null || true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
undo)
echo "Undoing iLeakyReLU additions (file copies only)..."
rm -rf "$TESTS_DIR"
rm -f "$KERNEL_SRC_DIR/iLeakyReLU.c"
rm -f "$KERNEL_INC_DIR/iLeakyReLU.h"
rm -f "$TEMPLATES_DIR/iLeakyReLUTemplate.py"
rm -f "$TILECONSTR_DIR/iLeakyReLUTileConstraint.py"
echo "Note: hand-patches in Parsers.py / Bindings.py / Platform.py / Tiler.py / DeeployPULPMath.h were NOT removed."
echo "If you need a fully clean tree, use: git checkout -- Deeploy/Targets TargetLibraries/PULPOpen/inc/DeeployPULPMath.h"
undo)
echo "Undoing iLeakyReLU additions (file copies only)..."
rm -f "$TESTS_DIR/network.onnx" "$TESTS_DIR/inputs.npz" "$TESTS_DIR/outputs.npz"
rmdir "$TESTS_DIR" 2>/dev/null || true
rm -f "$KERNEL_SRC_DIR/iLeakyReLU.c"
rm -f "$KERNEL_INC_DIR/iLeakyReLU.h"
rm -f "$TEMPLATES_DIR/iLeakyReLUTemplate.py"
rm -f "$TILECONSTR_DIR/iLeakyReLUTileConstraint.py"
echo "Note: hand-patches in Parsers.py / Bindings.py / Platform.py / Tiler.py / DeeployPULPMath.h were NOT removed."
echo "If you need a fully clean tree, use: git checkout -- Deeploy/Targets TargetLibraries/PULPOpen/inc/DeeployPULPMath.h"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tutorials/PartIII_solution/iLeakyReLU/deploy.sh` around lines 35 - 43, Update
the undo branch in deploy.sh to preserve pre-existing contents of TESTS_DIR:
remove only the copied iLeakyReLU test artifacts, and remove TESTS_DIR only when
it is empty. Keep the cleanup of the three iLeakyReLU source, header, and
template/constraint files unchanged.

Comment thread Tutorials/PartIII_solution/iLeakyReLU/generate.py
Comment on lines +36 to +57
uint32_t per = (size + nC - 1) / nC;
// Round per-core chunk down to a multiple of 4 so the SIMD loop is
// tail-free. The Step 6a tile-size constraint already guarantees that
// size is a multiple of 16.
per &= ~0x3u;
uint32_t start = cid * per;
uint32_t end = (start + per > size) ? size : (start + per);

v4s *vIn = (v4s *)(pIn + start);
v4s *vOut = (v4s *)(pOut + start);
uint32_t nVec = (end - start) >> 2;

for (uint32_t i = 0; i < nVec; i++) {
v4s x = vIn[i];
v4s s = x >> shift; // packed per-lane arith shift
vOut[i] = __builtin_pulp_max4(x, s); // max(x, x>>shift) = LeakyReLU
}

// Scalar tail (only when perf constraint is not installed)
for (uint32_t i = start + (nVec << 2); i < end; i++) {
int32_t xs = (int32_t)pIn[i];
pOut[i] = (int8_t)((xs >= 0) ? xs : (xs >> shift));

@coderabbitai coderabbitai Bot Jul 28, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Fix incomplete SIMD work partitioning. A permitted 16-element tile with eight cores computes per = 2, then Line 40 rounds it to zero, so no core writes output. More generally, rounding per-core work down loses the remainder; last-axis divisibility by 16 cannot guarantee flattened work is divisible into four-byte chunks for every core.

  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU_simd.c#L36-L57: distribute complete v4s blocks across cores, then have one core process the global scalar remainder.
  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUTileConstraint.py#L39-L51: remove the incorrect tail-free guarantee or enforce only constraints actually required after the SIMD partition is corrected.
📍 Affects 2 files
  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU_simd.c#L36-L57 (this comment)
  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUTileConstraint.py#L39-L51
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU_simd.c` around lines 36 -
57, Fix partitioning in Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU_simd.c
lines 36-57 by distributing complete v4s blocks across cores without rounding
each core’s work to zero or discarding remainders, then have one core process
the global scalar remainder. Update
Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUTileConstraint.py lines 39-51 to
remove the incorrect tail-free guarantee or enforce only constraints still
required by the corrected SIMD partition; use the existing SIMD loop and scalar
tail symbols as integration points.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the student testing problem dimensions with remainders?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

for f in \
  Tutorials/PartIII_solution/iLeakyReLU/generate.py \
  Tutorials/PartIII_solution/iLeakyReLU/README.md \
  Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU_simd.c \
  Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUTileConstraint.py \
  Tutorials/PartIII_skeletons/iLeakyReLU/generate.py \
  Tutorials/SoCDAML.md
do
  echo "===== $f ====="
  if [[ "$f" == *.py ]]; then
    ast-grep outline "$f" --items all || true
  fi
  rg -n -C 3 'SHAPE|NUM_CORES|--cores|nC|per\s*=|iLeakyReLU|profileTiling|tile|divisible|shape' "$f" || true
done

Length of output: 12060


@Victor-Jung, not in the supplied full-tensor test: students generate a (1, 16, 64, 64) input (65,536 elements), and the documented SIMD run uses 8 cores. That gives 8,192 elements/core, which is divisible by 4.

However, the tiled run can invoke the kernel on individual tiles. The current constraint only makes the innermost tile dimension divisible by 16; it does not guarantee that every flattened tile has at least 32 elements or that its eight-way split is divisible by 4. So the standard artifact likely won’t reveal the bug, but a permitted 16-element tile would.

Comment on lines +22 to +35
def parseNode(self, node: gs.Node) -> bool:
wellFormed = all([
len(node.inputs) == 1,
len(node.outputs) == 1,
'mul' in node.attrs,
'shift' in node.attrs,
])

if not wellFormed:
return False

self.operatorRepresentation['mul'] = int(node.attrs['mul'])
self.operatorRepresentation['shift'] = int(node.attrs['shift'])
return True

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -n -C2 --glob '*.py' "iLeakyReLU|['\"]mul['\"]|['\"]shift['\"]" \
  Tutorials Deeploy DeeployTest

Repository: pulp-platform/Deeploy

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Candidate iLeakyReLU files:"
git ls-files 'Tutorials/PartIII_solution/iLeakyReLU/*' | sort

echo
echo "Relevant parser/template/kernel/tile generate:"
for f in \
  Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUParser.py \
  Tutorials/PartIII_solution/iLeakyReLU/deploy.sh \
  Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUTemplate.py \
  Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUTileConstraint.py \
  Tutorials/PartIII_solution/iLeakyReLU/generate.py
do
  if [ -f "$f" ]; then
    echo "--- $f"
    cat -n "$f"
  fi
done

echo
echo "Search for iLeakyReLU implementation/kernel references:"
rg -n --glob '*.[ch]' --glob '*.py' --glob '!Tutorials/PartIII_solution/iLeakyReLU/deploy.sh' "PULPiLeakyReLU|iLeakyReLU|leakyReLU|leaky" Tutorials/PartIII_solution/iLeakyReLU Tutorials/PartIII_skeletons Deeploy Targets 2>/dev/null || true

Repository: pulp-platform/Deeploy

Length of output: 26929


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Scalar kernel:"
cat -n Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU.c

echo
echo "SIMD kernel:"
cat -n Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU_simd.c

echo
echo "Header declaration:"
cat -n Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU.h

echo
echo "Read-only verifier: compare scalar behavior to SIMD current implementation around mul/signals"
python3 - <<'PY'
from pathlib import Path
import re

simd_path = Path('Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU_simd.c')
scalar_path = Path('Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLU.c')

simd = simd_path.read_text()
scalar = scalar_path.read_text()

simd_body_start = simd.find('{', simd.find('PULPiLeakyReLU_i8_i8'))
simd_body = simd[simd_body_start:] if simd_body_start != -1 else ''
scalar_body_start = scalar.find('{', scalar.find('PULPiLeakyReLU_i8_i8'))
scalar_body = scalar[scalar_body_start:] if scalar_body_start != -1 else ''

uses_mul = re.search(r'\bmul\b', simd_body) is not None
uses_shift = re.search(r'\bshift\b', simd_body) is not None
uses_packed_ops = bool(re.search(r'__builtin_pulp_vec_(sli|sri|and|unpack)|xpulp.*vec|Vec', simd_body))
scalar_uses_mul = re.search(r'\bmul\b', scalar_body) is not None
scalar_uses_shift = re.search(r'\bshift\b', scalar_body) is not None

print({
    "scalar_uses_mul": scalar_uses_mul,
    "scalar_uses_shift": scalar_uses_shift,
    "simd_uses_mul": uses_mul,
    "simd_uses_shift": uses_shift,
    "simd_uses_packed_ops": uses_packed_ops,
})

# Simulate generated scalar/shift formula as described by generator for representative negative inputs.
def golden_for_case(x, mul, shift):
    import numpy as np
    pos = x.astype(np.int32)
    neg = (mul * pos) >> shift
    return np.clip(np.where(pos >= 0, pos, neg), -128, 127).astype(np.int8)

cases = [((1, 0), -1, 1), ((3, 3), -1, 1)]
print("formula examples neg_input=-1:")
for case, x, shape in cases:
    for m, s in [(1,3),(2,3),(3,3)]:
        print(case, "mul", m, "shift", s, "golden", int(golden_for_case(x, m, s)))
PY

Repository: pulp-platform/Deeploy

Length of output: 5475


Reject iLeakyReLU parameters unsupported by the SIMD implementation. The parser accepts arbitrary mul/shift, but the SIMD path casts mul away and only applies max(x, x >> shift), so a node like mul=2, shift=3 produces wrong outputs under ./deploy.sh simd. Constrain the mapper/parser in both Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUParser.py and the injected deploy.sh parser to the SIMD contract, e.g. mul == 1 and a supported non-negative shift, or implement SIMD multiplication.

🧰 Tools
🪛 Ruff (0.16.0)

[error] 22-22: Undefined name gs

(F821)

📍 Affects 2 files
  • Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUParser.py#L22-L35 (this comment)
  • Tutorials/PartIII_solution/iLeakyReLU/deploy.sh#L98-L109
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Tutorials/PartIII_solution/iLeakyReLU/iLeakyReLUParser.py` around lines 22 -
35, Constrain iLeakyReLU parsing to the SIMD contract in both
iLeakyReLUParser.parseNode and the injected parser in deploy.sh: accept only mul
== 1 and a supported non-negative shift, rejecting unsupported parameter
combinations before populating operatorRepresentation. Keep both parser
implementations consistent unless the SIMD implementation is updated to apply
multiplication.

@Victor-Jung Victor-Jung left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool extension to the tutorial! It will be a very useful example to point at to ppl learning Deeploy. I have some comments before merging but we are in the right track.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs/_static dir already has this file?

Comment on lines +260 to +261
if getattr(args, 'enable_3x3', False):
gen_args_list.append("--enable-3x3")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

--enable-3x3 is removed in #188 as 3x3 are now natively supported.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs/_static/tutorials/introduction dir already has this file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs/_static/tutorials/introduction dir already has this file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docs/_static/tutorials/introduction dir already has this file

| `generate.py` | Complete ONNX + golden-value generator | Run it (Step 1) |
| `iLeakyReLU.h` | Complete kernel header | Copy to `TargetLibraries/PULPOpen/inc/kernel/` (Step 3) |
| `iLeakyReLU.c` | Multi-core chunking provided; inner loop TODO | Fill the TODO, copy to `TargetLibraries/PULPOpen/src/` (Step 3) |
| `iLeakyReLU_simd.c` | SIMD chunking + load/max/store provided; one TODO line | Fill in Step 6b after the scalar works |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe check on this too.

Comment on lines +36 to +57
uint32_t per = (size + nC - 1) / nC;
// Round per-core chunk down to a multiple of 4 so the SIMD loop is
// tail-free. The Step 6a tile-size constraint already guarantees that
// size is a multiple of 16.
per &= ~0x3u;
uint32_t start = cid * per;
uint32_t end = (start + per > size) ? size : (start + per);

v4s *vIn = (v4s *)(pIn + start);
v4s *vOut = (v4s *)(pOut + start);
uint32_t nVec = (end - start) >> 2;

for (uint32_t i = 0; i < nVec; i++) {
v4s x = vIn[i];
v4s s = x >> shift; // packed per-lane arith shift
vOut[i] = __builtin_pulp_max4(x, s); // max(x, x>>shift) = LeakyReLU
}

// Scalar tail (only when perf constraint is not installed)
for (uint32_t i = start + (nVec << 2); i < end; i++) {
int32_t xs = (int32_t)pIn[i];
pOut[i] = (int8_t)((xs >= 0) ? xs : (xs >> shift));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are the student testing problem dimensions with remainders?


void PULPiLeakyReLU_i8_i8(int8_t *pIn, int8_t *pOut, uint32_t size, int32_t mul,
int32_t shift) {
(void)mul; // SIMD path assumes mul == 1

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not apply the scale here? If there is a good reason the parser should test the mul value to be 1 and fail if it's not.

Comment thread CHANGELOG.md
Comment on lines +71 to +74
- Forward `--neureka-wmem` and `--enable-3x3` from `deeployRunner` to the generator. Both were accepted by argparse and then dropped, so enabling the Neureka weight memory produced byte-identical cycle counts; `microLlama64` autoregressive now improves from 776k to 712k cycles with the flag
- Fix Part III `deploy.sh` half-applying its `Platform.py` patch: the parser-import replacement matched a single-line needle that no longer exists (the import block is line-wrapped), so the mapper was injected without its import and every PULP runner failed with `NameError: name 'iLeakyReLUParser' is not defined`. The patch is now anchored on the mapper definition and fails loudly if that anchor disappears
- Fix Part III Step 6a to use `addTileSizeDivisibleConstraint` instead of `addMinTileSizeConstraint`; the latter only forces the leftover tile to be at least `modulo` elements and gives no divisibility guarantee, so the documented multiple-of-16 SIMD alignment did not hold
- Fix Deeploy 101 and Part III tutorial errors: `--profileTiling` is a valueless flag (`--profileTiling=L2` aborts argparse), the intrinsics inventory path moved to `TargetLibraries/third_party/`, Step 2 needs `cd ../../../DeeployTest`, and the Step 4/5 solutions were missing their `Platform.py` imports

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit too verbose for the changelogs, can you compress it?

# ./deploy.sh # apply scalar kernel (Step 3)
# ./deploy.sh simd # apply SIMD kernel (Step 6b) on top
# ./deploy.sh undo # remove the additions (best-effort)
# ----------------------------------------------------------------------

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The patches to the Deeploy core library are very fragile and will break in the future. Could you provide these changes as git patches that can be applied with git apply so that if smth goes wrong ppl will get a merge conflict and can resolve it cleanly?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants