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"`.

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.

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

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.

Comment on lines +93 to +97
### 3. Build the writable Singularity sandbox
Pull the public Deeploy Docker image and convert it into a writable sandbox under your scratch (takes ~5-10 min the first time):
```bash
singularity build --sandbox DeeployContainer/ docker://ghcr.io/pulp-platform/deeploy:main
```

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
set -euo pipefail

echo "== repo files matching introduction/README/docs =="
git ls-files | rg '(^|/)(docs/|README|.*\.md$)' | head -200

echo
echo "== target excerpt =="
sed -n '80,110p' docs/tutorials/introduction.md 2>/dev/null || true

echo
echo "== nearby tutorial files =="
git ls-files docs | sed -n '1,200p'

echo
echo "== references to Singularity/singularity, fakeroot, sandbox, lab, unprivileged, root =="
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
  'Singularity|singularity|fakeroot|sandbox|unprivileged|rootless|sudo|lab configuration|configuration' docs README* .github 2>/dev/null || true

Repository: pulp-platform/Deeploy

Length of output: 8321


🌐 Web query:

Sylabs Singularity fakeroot unprivileged build documentation 3.6

💡 Result:

In Singularity 3.6, the --fakeroot feature enables unprivileged users to build and run containers as a fake root user by leveraging user namespaces and UID/GID mapping [1][2][3]. Key aspects of the --fakeroot feature in version 3.6 include: Requirements and Configuration 1. Kernel Support: The feature requires a Linux kernel version 3.8 or higher, with 3.18 or higher recommended [1][3]. 2. System Mappings: It relies on subuid and subgid mappings defined in /etc/subuid and /etc/subgid [1][2]. A user must have an entry in these files to use the feature [1][4]. 3. Management Command: System administrators can use the singularity config fakeroot command to manage these mappings safely without manually editing the files [1][2][5]. This command must be executed as root (or via sudo) [1][2]. 4. Unprivileged Installations: If Singularity is installed without setuid (allow setuid = no in singularity.conf), it attempts to use external newuidmap and newgidmap binaries, which must be installed on the system [2]. Using --fakeroot for Builds To build a container without root privileges, add the --fakeroot (or -f) flag to the build command [1][6]: singularity build --fakeroot <container.sif> Limitations: While --fakeroot allows for building images with most restrictions removed, some bootstrap methods requiring the creation of specific block devices may not function [1][3]. For example, debootstrap is known to be incompatible with this feature [1][3]. Singularity employs seccomp filters to manage the illusion of block device creation for other methods, such as yum [1][3]. The --fakeroot option is also available for other commands, including shell, exec, run, and instance start [1][3].

Citations:


Document or enable rootless sandbox builds.

The tutorial targets students who cannot use Docker, but the Singularity build command assumes root privileges instead of explaining how the lab supports --fakeroot / required subuid/subgid mapping, or an alternate remote-build path. Add that lab-specific prerequisite or change the build step to the supported unprivileged mode used by the course.

🤖 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 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.

The `--bind` flag mounts your host clone at `/app/Deeploy` inside the container, i.e.the direct equivalent of Docker's `-v` flag.

If you forget to pre-create the target you'll see:
```

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

Add language identifiers to the fenced code blocks.

Markdownlint flags these new fences. Use text for the error-output block at Line 115 and bash for the shell-command blocks.

Also applies to: 371-371, 385-385, 485-485, 523-523, 595-595

🧰 Tools
🪛 markdownlint-cli2 (0.23.1)

[warning] 115-115: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 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 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.

Source: Linters/SAST tools

### 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:

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.

| `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
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.

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.


def main():
rng = np.random.default_rng(SEED)
x = rng.integers(low = -128, high = 127, size = SHAPE, dtype = np.int8)

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

🧩 Analysis chain

🏁 Script executed:

python - <<'PY'
import numpy as np

rng = np.random.default_rng(0xC0FFEE)
x = rng.integers(-128, 127, size=(1, 16, 64, 64), dtype=np.int8)
assert not np.any(x == 127)
PY

Repository: pulp-platform/Deeploy

Length of output: 159


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== target file =="
wc -l Tutorials/PartIII_solution/iLeakyReLU/generate.py
sed -n '1,140p' Tutorials/PartIII_solution/iLeakyReLU/generate.py

echo "== NPZ artifacts in tree =="
find Tutorials/PartIII_solution/iLeakyReLU -maxdepth 2 -type f -name '*.npz' -o -name '*.npy' | sort | while read -r f; do
  echo "--- $f ---"
  python3 - <<'PY' "$f"
import sys, numpy as np
f = sys.argv[1]
if f.endswith('.npz'):
    z = np.load(f)
    print("keys", list(z.files))
    for name in z.files:
        arr = z[name]
        print(name, arr.shape, arr.dtype, arr.min(), arr.max(), "contains 127:", np.any(arr == 127), "contains -128:", np.any(arr == -128))
else:
    arr = np.load(f)
    print(arr.shape, arr.dtype, arr.min(), arr.max(), "contains 127:", np.any(arr == 127), "contains -128:", np.any(arr == -128))
PY
done

echo "== deterministic bounds probe for current call signature =="
python3 - <<'PY'
import numpy as np
rng = np.random.default_rng(0xC0FFEE)
x = rng.integers(low=-128, high=127, size=(1, 16, 64, 64), dtype=np.int8)
print("dtype x:", x.dtype)
print("unique_min:", x.min(), "unique_max:", x.max())
print("count_127:", np.count_nonzero(x == 127))
print("count_126:", np.count_nonzero(x == 126))
print("count_-128:", np.count_nonzero(x == -128))
print("all_int8_in_range:", np.all((x >= np.iinfo(np.int8).min) & (x <= np.iinfo(np.int8).max)))
PY

Repository: pulp-platform/Deeploy

Length of output: 3587


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== deterministic bounds probe for current call signature =="
python3 - <<'PY'
import numpy as np
try:
    import urllib.request
except Exception as e:
    print("urllib import unavailable:", type(e).__name__, e)

rng = np.random.default_rng(0xC0FFEE)
x = rng.integers(low=-128, high=127, size=(1, 16, 64, 64), dtype=np.int8)
print("dtype x:", x.dtype)
print("unique_min:", x.min(), "unique_max:", x.max())
print("count_127:", np.count_nonzero(x == 127))
print("count_126:", np.count_nonzero(x == 126))
print("count_-128:", np.count_nonzero(x == -128))
print("all_int8_in_range:", np.all((x >= np.iinfo(np.int8).min) & (x <= np.iinfo(np.int8).max)))

try:
    info = np.finfo(np.int8)
except Exception as e:
    print("finfo unavailable:", type(e).__name__, e)
    info = None

if info is not None:
    print("np.finfo(np.int8).max =", info.max)
    print("np.random.Generator.integers(low, high) docs high exclusive:", hasattr(rng, 'integers'))
PY

echo "== regenerated bounds with inclusive high==128 =="
python3 - <<'PY'
import numpy as np
rng = np.random.default_rng(0xC0FFEE)
x = np.asarray([-128, 126, 127], dtype=np.int8)
x2 = rng.integers(low=-128, high=128, size=(1, 16, 64, 64), dtype=np.int8).ravel()
print("manual_edge_contains_127:", 127 in np.unique(x))
print("seeded_max_possible_with_128:", x2.max())
print("seeded_has_127_with_128:", np.any(x2 == 127))
PY

Repository: pulp-platform/Deeploy

Length of output: 337


🌐 Web query:

NumPy Generator.integers high exclusive dtype int8 lower_bound higher_bound documentation

💡 Result:

In NumPy, the numpy.random.Generator.integers method generates random integers from a discrete uniform distribution [1][2]. Key behavioral details for your query include: Lower and Higher Bounds By default, the integers are drawn from the interval [low, high), meaning the low value is inclusive and the high value is exclusive [1][2]. If the high parameter is set to None, the function draws integers from [0, low) [1][3]. You can change this behavior by setting the endpoint parameter to True, which changes the interval to [low, high] (both inclusive) [1][2]. Dtype int8 Usage The integers method accepts an explicit dtype argument, such as np.int8 [1][4]. However, users should be aware that historically, there have been documented reports of potential bias when using small integer types like int8 or int16 directly in the integers method [5]. A recommended workaround if you encounter distribution issues is to generate the integers using the default dtype and then cast the result to your desired type using the.astype method [5]. Summary of Parameters low: Lowest integer to be drawn (or high bound if high is None) [1]. high: One above the largest integer to be drawn [1]. size: Output shape [1]. dtype: Desired dtype of the result (default is np.int64) [1]. endpoint: If True, includes the high bound [1]. For more information, see the official NumPy documentation for numpy.random.Generator.integers [1].

Citations:


Include 127 in the integer LeakyReLU fixture.

rng.integers(low=-128, high=127, dtype=np.int8) samples from [-128, 127), so the positive int8 boundary is never exercised. Change it to high=128 (or endpoint=True), then regenerate the NPZ artifacts.

Proposed fix
-    x = rng.integers(low = -128, high = 127, size = SHAPE, dtype = np.int8)
+    x = rng.integers(low = -128, high = 128, size = SHAPE, dtype = np.int8)
📝 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
x = rng.integers(low = -128, high = 127, size = SHAPE, dtype = np.int8)
x = rng.integers(low = -128, high = 128, size = SHAPE, dtype = np.int8)
🤖 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/generate.py` at 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.

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
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.

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.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants