libraries-openly-fused/fusedkernellibrary/fkl-implementing-data-parallel-patterns
Claude Code and agent skill by libraries-openly-fused/fusedkernellibrary
- community
Checking that the SKILL.md file is still in the repository.
Implement a new Data Parallel Pattern (DPP) for the Fused Kernel Library. Covers the anatomy of a DPP struct, device-side invocation of IOps (the IOp-form table, reading inputs, fusing epilogues into the write), compile-time vs runtime types, vector types, the ParArch::CPU and ParArch::CPU_MULTITHREAD (thread pool) implementations, and testing. Use when adding an algorithm to FKL that requires thread coordination, or when debugging a DPP's internal device execution.
Install
npx vskill@latest install libraries-openly-fused/fusedkernellibrary/fkl-implementing-data-parallel-patternsSKILL.md
Implementing FKL Data Parallel Patterns
Anatomy of a DPP
A DPP is composed of three parts:
- Executor implementation: as in include/fused_kernel/core/execution_model/executors.h
- For GPU implementations, a kernel function that gets the DPP parameters and internally calls the DPP (for CPU, nothing;
for CPU_MULTITHREAD, the executor/entry function enqueues the DPP on the stream, see below).
- The DPP implementation.
Every DPP must always have a single thread CPU implementation using the ParArch::CPU, and a ParArch::CPU_MULTITHREAD implementation that reuses it (see "The ParArch::CPU_MULTITHREAD implementation" below), and then it can have implementations for other ParArchs, as in include/fused_kernel/core/execution_model/parallel_architectures.h
The only exception are the attention DPPs in include/fused_kernel/algorithms/attention/ (softmax, flash_attention, flash_attention_mma, flash_decode): the repo owner decided that they remain GPU-only, with no ParArch::CPU nor ParArch::CPU_MULTITHREAD implementation. Do not take them as a precedent for new DPPs.
Every DPP is a STATELESS struct: static exec(). The exec function will get as parameters, DPP details which are external parameters not directly related to the data being processed, and IOps (Instantiable Operations) which will contain the implementation of the instructions to be applied over the data being processed, along with dimensions information.
A DPP must not contain the definition of code that modifies the data (except for the case of tensor core code where it's impossible to apply that abstraction). In order to operate on the data the DPP must use IOps that must have been passed to the DPP as exec function parameters.
Those IOps will be used by each thread to access the device input data, to operate on the data and to write the results back to device memory. The implementation of the DPP exec function is responsible for deciding which threads will execute which IOps in which order, as well as applying any thread synchronization or using any shared memory.
Each one of the IOps can contain a single Operation, or a FusedOperation (several consecutive Operations), or a fk::Tuple of IOps, depending on the structure the DPP requires.
Each DPP defines the number of input ReadOperations and or ReadBackOperations it requires. Each DPP defines the number of compute Operations (non Read/ReadBack and non Write) it requires. Each DPP defines the number of output WriteOperations it requires.
Never pass a raw pointer (T*) to device (global) memory as an input or output parameter to exec function. Device pointers must be passed as part of a Read/ReadBack or Write IOps.
Example TransformDPP which is a special case, because it does not require any specific structure in the IOps passed as parameters. The IOps in this DPP will be executed one after the other by all the threads that have to participate.
The IOp invocation contract (The IOp-form table)
Understanding the IOp signatures is critical when debugging compiler errors or when authoring a new DPP. Every IOp's device-side exec() signature is fixed by its operation type:
| Operation Type | exec call site | |
|---|---|---|
| ReadType | T IOp::Operation::exec(thread, iop) | |
| WriteType | void IOp::Operation::exec(thread, value, iop) | |
| UnaryType | O IOp::Operation::exec(input) | |
| BinaryType | O IOp::Operation::exec(input, iop) | |
| ReadBackType | O IOp::Operation::exec(thread, iop) | |
| TernaryType | O IOp::Operation::exec(input, iop) | |
| MidWriteType | In IOp::Operation::exec(thread, input, iop) (writes AND forwards) | |
| OpenType | O IOp::Operation::exec(thread, input, iop) | |
| ClosedType | void IOp::Operation::exec(thread, iop) |
Key rules for DPP authors invoking these:
- Invoke through the IOp: Call
IOp::Operation::exec(...), passing the wholeiopinstance for the data, NOT justiop.paramsor the raw op struct. - Read takes the
Point thread+iopand returns the value. - Write takes
thread, thevalueto store, andiop. - Unary/Binary are pure register compute: no
thread, just the input (+iopfor Binary).
Invoking Operations Inside the DPP (Device Side)
Inside the DPP's execution logic, you must invoke the IOps passed to the exec() function. If the executor pre-fused a compute chain into the write operation (the epilogue), you invoke it as a single OutputIOp type:
Pitfalls
- Passing `iop.params` instead of `iop`: If you are writing a DPP and pass
iop.paramsto an operation'sexec(), it will route through the wrong template fold path and fail to compile. Always pass the whole IOp wrapper.
The ParArch::CPU_MULTITHREAD implementation
The multithreaded CPU backend runs DPP work on fk::cpuThreadPool(), one pool shared by all streams, with one worker per hardware thread. It exists when FK_CPU_MULTITHREAD_ENABLED is defined (CMake option ENABLE_CPU_MULTITHREAD, which needs the thread-pool submodule). Reference implementation: TransformDPP<ParArch::CPU>::exec_row and TransformDPP<ParArch::CPU_MULTITHREAD> in core/execution_model/data_parallel_patterns.h, and Executor<TransformDPP<ParArch::CPU_MULTITHREAD, TFEN, void>> in core/execution_model/executors.h.
The layering rule (mandatory, decided by the repo owner), the same as with a GPU:
- The stream only orders executions.
Stream_<ParArch::CPU_MULTITHREAD>::enqueue(start)queues an execution;
when the previous executions of the stream have finished, it calls start(const cpu_multithread::Completion& done) on some thread. The stream never touches the pool.
- The DPP never sees a stream. Like a GPU kernel, when its execution starts the DPP splits its work into chunks,
enqueues them with cpu_multithread::enqueueChunks(numChunks, chunkFunction, onComplete), returns, and calls the Completion exactly once when all its work has finished (passing done as onComplete does that, forwarding the first exception a chunk threw).
- Only executors and entry functions use the stream: they validate synchronously, then
stream.enqueue(...) a lambda that calls DPP::exec(done, ...).
- The CPU version exposes `exec_row`: the body of its outer row loop, as a public static function used by both
its own exec() and the CPU_MULTITHREAD exec() (a multi-phase DPP exposes one per phase instead, like MorphologyDPP's load_row/reduce_row/reduce_write_row). Both run the same per-row code, so their results match: integer results bit for bit; float results can differ in the last bits only, because the compiler may contract a * b + c into a fused multiply-add differently where the shared code is inlined.
Multi-phase DPPs (a phase must finish before the next one starts) chain enqueueChunks in onComplete, which runs on the worker that finished the last chunk and must not throw. Scratch memory shared by the phases goes in a std::shared_ptr captured by value. See MorphologyDPP<ParArch::CPU_MULTITHREAD> in algorithms/image_processing/morphology.h:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryChecking.github/skills/fkl-implementing-data-parallel-patterns/SKILL.md
Popularity
- Repository stars
- 58
- Repository forks
- 4
- 7-day trend score
- 20
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/libraries-openly-fused/fusedkernellibrary/fkl-implementing-data-parallel-patterns)