[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M73AYWD9TMPVMA98FFPRDFX2":3,"skill-same:01M73AYWD9TMPVMA98FFPRDFX2":59},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":15,"categories":16,"keywords":17,"publishedAt":18,"linkOnly":19,"markdownContent":20,"markdownBody":21,"frontMatter":22,"refName":37,"commitSha":38,"skillDirectory":39,"forksCount":40,"repositoryHtmlUrl":41,"repositoryHomepageUrl":6,"ownerHtmlUrl":42,"ownerBlogUrl":43,"ownerDescription":6,"updatedAt":44,"install":45,"resources":58},"01M73AYWD9TMPVMA98FFPRDFX2","pipeline-gpu-kernel",null,"Apply software pipelining (double-buffering) to a tiled GPU kernel to overlap global memory loads with Tensor Core computation. Covers prologue\u002Floop\u002Fepilogue restructuring, LDG-register vs cp.async (LDGSTS) variant selection based on compute\u002Fload ratio, shared memory budget verification against architecture-specific occupancy cliffs, and SASS-level verification of load\u002Fcompute overlap.","roohe\u002Fagentic-super-skills","roohe","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F99054084?v=4","01M734WCDFP6RZVT5CNM00QR26","01M734WCE4BD0T4NZS5PCV9V5F",10,"MIT","https:\u002F\u002Fgithub.com\u002Froohe\u002Fagentic-super-skills\u002Fblob\u002Fmaster\u002Fskills_library\u002Fpipeline-gpu-kernel\u002FSKILL.md",[],[],"2026-11-11 15:11:14",false,"---\nname: pipeline-gpu-kernel\nlocale: caveman-lite\nsource_locale: en\nsource_commit: 82c77053\ntranslator: \"Julius Brussee homage — caveman\"\ntranslation_date: \"2026-04-19\"\ndescription: >\n  Apply software pipelining (double-buffering) to a tiled GPU kernel to overlap\n  global memory loads with Tensor Core computation. Covers prologue\u002Floop\u002Fepilogue\n  restructuring, LDG-register vs cp.async (LDGSTS) variant selection based on\n  compute\u002Fload ratio, shared memory budget verification against architecture-specific\n  occupancy cliffs, and SASS-level verification of load\u002Fcompute overlap.\nlicense: MIT\nallowed-tools: Read Write Edit Bash Grep Glob\nmetadata:\n  author: Philipp Thoss\n  version: \"1.0\"\n  domain: gpu-optimization\n  complexity: advanced\n  language: CUDA\n  tags: gpu, software-pipelining, double-buffer, cp-async, ldgsts, tensor-core, smem, occupancy\n---\n\n# Pipeline GPU Kernel\n\nApply software pipelining (double-buffering) to a tiled GPU kernel so that global memory loads for tile N+1 overlap with Tensor Core computation on tile N. Transform a sequential load-sync-compute-sync K-loop into a prologue\u002Floop\u002Fepilogue structure, choose between LDG-register and cp.async (LDGSTS) variants based on compute\u002Fload ratio, verify shared memory stays under the architecture occupancy cliff, and confirm load\u002Fcompute overlap in the final SASS.\n\n## When to Use\n\n- When `analyze-kernel-bottleneck` identifies a memory-bound kernel with low compute\u002Fload ratio per tile\n- When warp interleaving alone cannot hide DRAM latency (~300 cycles on GA104)\n- When the kernel has a sequential load-sync-compute-sync K-loop that can be restructured\n- Not needed when compute\u002Fload ratio is high (>20:1) and 8+ warps are active\n\n## Inputs\n\n- **Required**: CUDA kernel source file (`.cu`) with a tiled K-loop containing separate load and compute phases\n- **Required**: Target GPU architecture (e.g., GA104 \u002F sm_86 — determines smem cliff and occupancy limits)\n- **Required**: Current tile sizes (BM, BN, BK) and data type (FP16, FP32, INT8)\n- **Optional**: Compute\u002Fload ratio per tile (from `analyze-kernel-bottleneck`; will be estimated if not provided)\n- **Optional**: Benchmark baseline (non-pipelined performance at target problem size)\n\n## Procedure\n\n### Step 1: Verify Preconditions\n\nConfirm the kernel has a tiled K-loop with distinct load and compute phases separated by `__syncthreads()`. Calculate the doubled shared memory cost and verify it stays under the architecture occupancy cliff.\n\n1. Locate the K-loop in the kernel. It must have this sequential structure: load A and B tiles from global to shared memory, `__syncthreads()`, compute (HMMA\u002FIMMA\u002FFFMA) on the shared memory tiles, `__syncthreads()`.\n2. Record the single-buffer shared memory sizes: `smem_a_size = BM * BK * sizeof(T)` and `smem_b_size = BK * BN * sizeof(T)`.\n3. Calculate the double-buffer cost: `smem_doubled = smem_a_size * 2 + smem_b_size * 2`.\n4. Compare against the architecture cliff. GA104 (sm_86): 100 KB max smem\u002FSM, cliff at 50 KB\u002Fblock (above 50 KB = 1 block\u002FSM = 4 warps, 2x occupancy collapse).\n\n```\nSingle buffer: smem_a[BM*BK] + smem_b[BK*BN] = 2 KB + 2 KB = 4 KB\nDouble buffer: smem_a[2][BM*BK] + smem_b[2][BK*BN] = 4 KB + 4 KB = 8 KB\n8 KB \u003C\u003C 50 KB cliff -> 2 blocks\u002FSM -> 8 warps\n```\n\n5. Verify the loop iteration count: `num_tiles = K \u002F BK`. Pipelining requires `num_tiles >= 2` (at least one prologue + one main loop iteration).\n\n**Got:** A shared memory budget table showing single-buffer and double-buffer costs, confirming the doubled allocation stays under the architecture cliff with at least 2 blocks\u002FSM occupancy.\n\n**If fail:** If double-buffer exceeds the cliff, reduce tile size (halve BK or BM) until `smem_doubled \u003C= 50 KB` for GA104. Alternatively, use register-only prefetch (LDG variant) without doubling shared memory — store prefetched data in registers and write to the same single buffer after `__syncthreads()`.\n\n### Step 2: Choose Variant\n\nSelect between LDG-register and cp.async (LDGSTS) based on the compute\u002Fload ratio per tile.\n\n1. Calculate the compute\u002Fload ratio: `ratio = (2 * BM * BN * BK) \u002F ((BM * BK + BK * BN) * sizeof(T))` for GEMM-like kernels (2 FLOPs per multiply-add, bytes loaded per tile).\n2. Apply the decision rule:\n\n**LDG-register variant** (ratio >= 5 or CUDA \u003C 11.0):\n- LDG tile N+1 into registers (non-blocking global loads).\n- Compute on `buf[N % 2]` (overlaps with outstanding LDGs).\n- `__syncthreads()`, then STS registers into `buf[(N+1) % 2]`, `__syncthreads()`.\n- Simpler implementation, no pipeline API dependency.\n- Adds register pressure: ~`(BM * BK + BK * BN) \u002F BLOCK_SIZE` registers per thread for staging.\n\n**cp.async (LDGSTS) variant** (ratio \u003C 5, CUDA >= 11.0):\n- `__pipeline_memcpy_async` tile N+1 directly to `buf[(N+1) % 2]` (async, bypasses register file).\n- `__pipeline_commit()` before compute.\n- Compute on `buf[N % 2]`.\n- `__pipeline_wait_prior(0)` + `__syncthreads()` after compute.\n- Better overlap, zero register pressure for prefetch. Requires `#include \u003Ccuda_pipeline.h>`.\n\n3. Decision thresholds (measured on GA104 with IGEMM at 4096x4096x4096):\n   - Ratio \u003C 5:1 — prefer cp.async (+35% measured on IGEMM).\n   - Ratio 5-20:1 — implement both and benchmark to decide.\n   - Ratio > 20:1 — pipelining likely not beneficial (warp interleaving sufficient).\n\n**Got:** Selected variant with justification based on compute\u002Fload ratio and target architecture.\n\n**If fail:** If the ratio is ambiguous (5-20:1 range), implement both variants and benchmark. The cp.async variant is the safer default when CUDA version supports it.\n\n### Step 3: Restructure the K-Loop\n\nTransform the sequential load-sync-compute-sync loop into a pipelined prologue\u002Floop\u002Fepilogue structure.\n\n1. **Identify the three sections**: The original loop body becomes three pieces:\n   - **Prologue**: Load tile 0 into `buf[0]`, synchronize, then enter the main loop.\n   - **Main loop**: For tiles 1 through `num_tiles - 1`, overlap loading tile N+1 with computing tile N.\n   - **Epilogue**: Compute the last tile (already loaded by the final main loop iteration).\n\n2. **LDG-register variant structure**:\n\n```c\n\u002F\u002F === LDG-register variant ===\n\u002F\u002F Prologue: load tile 0 into buf[0]\ncooperative_load_tile(smem_a[0], smem_b[0], global_a, global_b, \u002F*k_offset=*\u002F0);\n__syncthreads();\n\nfor (int tile = 0; tile \u003C num_tiles - 1; tile++) {\n    int cur_buf = tile & 1;\n    int next_buf = 1 - cur_buf;\n\n    \u002F\u002F Phase 1: LDG next tile into registers (non-blocking)\n    float reg_a[ELEMS_PER_THREAD_A], reg_b[ELEMS_PER_THREAD_B];\n    prefetch_tile_to_registers(reg_a, reg_b, global_a, global_b,\n                               (tile + 1) * BK);\n\n    \u002F\u002F Phase 2: Compute on current buffer (overlaps with LDG flight)\n    tensor_core_mma(smem_a[cur_buf], smem_b[cur_buf], acc);\n\n    \u002F\u002F Phase 3: Drain registers into next buffer\n    __syncthreads();\n    store_registers_to_smem(smem_a[next_buf], smem_b[next_buf],\n                            reg_a, reg_b);\n    __syncthreads();\n}\n\n\u002F\u002F Epilogue: compute last tile\ntensor_core_mma(smem_a[(num_tiles - 1) & 1], smem_b[(num_tiles - 1) & 1], acc);\n```\n\n3. **cp.async variant structure**:\n\n```c\n\u002F\u002F === cp.async variant ===\n#include \u003Ccuda_pipeline.h>\n\n\u002F\u002F Prologue: async load tile 0 into buf[0]\ncpasync_load_tile(smem_a[0], smem_b[0], global_a, global_b, \u002F*k_offset=*\u002F0);\n__pipeline_commit();\n__pipeline_wait_prior(0);\n__syncthreads();\n\nfor (int tile = 0; tile \u003C num_tiles - 1; tile++) {\n    int cur_buf = tile & 1;\n    int next_buf = 1 - cur_buf;\n\n    \u002F\u002F Phase 1: cp.async next tile into next buffer (async, direct to smem)\n    cpasync_load_tile(smem_a[next_buf], smem_b[next_buf],\n                      global_a, global_b, (tile + 1) * BK);\n    __pipeline_commit();\n\n    \u002F\u002F Phase 2: Compute on current buffer (overlaps with LDGSTS in flight)\n    tensor_core_mma(smem_a[cur_buf], smem_b[cur_buf], acc);\n\n    \u002F\u002F Phase 3: Wait for async copies to complete\n    __pipeline_wait_prior(0);\n    __syncthreads();\n}\n\n\u002F\u002F Epilogue: compute last tile\ntensor_core_mma(smem_a[(num_tiles - 1) & 1], smem_b[(num_tiles - 1) & 1], acc);\n```\n\n4. Verify the loop count: the main loop runs `num_tiles - 1` iterations (tiles 0 through `num_tiles - 2` indexing which tiles to compute, loading tiles 1 through `num_tiles - 1`). The epilogue computes the tile loaded in the last iteration.\n\n**Got:** Restructured K-loop source code with clear prologue, main loop, and epilogue sections for the chosen variant.\n\n**If fail:** The most common bug is an off-by-one in buffer indexing or forgetting the epilogue compute pass. Verify: prologue loads into `buf[0]`, first main loop iteration computes `buf[0]` and loads into `buf[1]`, second iteration computes `buf[1]` and loads into `buf[0]`, and so on. The epilogue computes `buf[(num_tiles - 1) & 1]`.\n\n### Step 4: Implement Double-Buffer\n\nDeclare the double-buffered shared memory and implement the load functions.\n\n1. Replace single-buffer shared memory declarations with double-buffered arrays:\n\n```c\n\u002F\u002F Before (single buffer)\n__shared__ half smem_a[BM * BK];\n__shared__ half smem_b[BK * BN];\n\n\u002F\u002F After (double buffer)\n__shared__ half smem_a[2][BM * BK];\n__shared__ half smem_b[2][BK * BN];\n```\n\n2. For the cp.async variant, implement the async load function using the pipeline API:\n\n```c\n__device__ void cpasync_load_tile(half* dst_a, half* dst_b,\n                                  const half* src_a, const half* src_b,\n                                  int k_offset) {\n    \u002F\u002F Each thread copies its portion (16 bytes = 8 half values per cp.async)\n    int tid = threadIdx.x;\n    int bytes_per_thread = 16;  \u002F\u002F cp.async.cg supports 4, 8, or 16 bytes\n\n    \u002F\u002F A tile: BM * BK elements, distributed across BLOCK_SIZE threads\n    int elems_a = BM * BK \u002F BLOCK_SIZE;\n    for (int i = 0; i \u003C elems_a; i += 8) {\n        int idx = tid * elems_a + i;\n        __pipeline_memcpy_async(dst_a + idx,\n                                src_a + k_offset * BM + idx,\n                                bytes_per_thread);\n    }\n\n    \u002F\u002F B tile: BK * BN elements, distributed similarly\n    int elems_b = BK * BN \u002F BLOCK_SIZE;\n    for (int i = 0; i \u003C elems_b; i += 8) {\n        int idx = tid * elems_b + i;\n        __pipeline_memcpy_async(dst_b + idx,\n                                src_b + k_offset * BN + idx,\n                                bytes_per_thread);\n    }\n}\n```\n\n3. For the LDG variant, implement register staging arrays and store functions:\n\n```c\n\u002F\u002F Declare register staging (size = elements per thread)\nhalf reg_a[BM * BK \u002F BLOCK_SIZE];\nhalf reg_b[BK * BN \u002F BLOCK_SIZE];\n\n\u002F\u002F Prefetch: LDG from global to registers (non-blocking, issued early)\nfor (int i = 0; i \u003C BM * BK \u002F BLOCK_SIZE; i++) {\n    int idx = threadIdx.x * (BM * BK \u002F BLOCK_SIZE) + i;\n    reg_a[i] = global_a[k_offset * BM + idx];\n}\n\u002F\u002F ... similarly for reg_b\n\n\u002F\u002F Store: STS from registers to shared memory (after __syncthreads)\nfor (int i = 0; i \u003C BM * BK \u002F BLOCK_SIZE; i++) {\n    int idx = threadIdx.x * (BM * BK \u002F BLOCK_SIZE) + i;\n    smem_a[next_buf][idx] = reg_a[i];\n}\n```\n\n4. Keep `__launch_bounds__(BLOCK_SIZE)` on the kernel to give the compiler accurate occupancy information.\n5. Compile: `nvcc --cubin -arch=sm_86 -O2 -o kernel.sm_86.cubin kernel.cu`.\n\n**Got:** Compilable kernel with double-buffered shared memory and the chosen load mechanism. Successful cubin generation with no errors.\n\n**If fail:** If compilation fails on pipeline API calls, ensure `#include \u003Ccuda_pipeline.h>` is present and CUDA toolkit is >= 11.0. If register spills occur (check `nvcc --resource-usage`), reduce the register staging array sizes by increasing BLOCK_SIZE or reducing BK.\n\n### Step 5: Verify Correctness\n\nRun the pipelined kernel against the CPU reference to confirm identical numerical output.\n\n1. Compile the benchmark: `nvcc -arch=sm_86 -O2 -o bench bench.cu -lcuda -I..\u002F..\u002Fphase2\u002Fcommon`.\n2. Run at a small problem size first (512x512x512) to catch indexing bugs before scaling up.\n3. Apply the correct tolerance for the data type:\n   - INT8 Tensor Core (IMMA): `abs=0.5, rel=0.1`\n   - FP16 Tensor Core (HMMA): `abs=1e-2, rel=1e-2`\n   - FP32 scalar (FFMA): `abs=1e-3, rel=1e-3`\n4. Pipelining does not change the arithmetic — it only reorders loads. If correctness fails, the bug is in buffer indexing, not in the compute logic.\n5. Test at the target problem size (e.g., 4096x4096x4096) to verify boundary handling.\n\n**Got:** PASS at both small and target problem sizes with error bounds identical to the non-pipelined baseline.\n\n**If fail:** Buffer indexing bug is the most likely cause. Verify: compute reads from `buf[tile & 1]` while loads write to `buf[1 - (tile & 1)]`. Check the epilogue processes buffer index `(num_tiles - 1) & 1`, not `num_tiles & 1`. For cp.async, verify `__pipeline_wait_prior(0)` completes before `__syncthreads()` — otherwise compute may read partially-written data.\n\n### Step 6: Benchmark and Compare\n\nMeasure the pipelined kernel against the non-pipelined baseline at the target problem size.\n\n1. Run the non-pipelined baseline and record GFLOPS or bandwidth (depending on kernel type).\n2. Run each pipelined variant and record the same metric.\n3. Calculate speedup: `speedup = pipelined_metric \u002F baseline_metric`.\n4. Expected gains by compute\u002Fload ratio (measured on GA104):\n   - Low ratio (\u003C5:1): +15-35% from cp.async (IGEMM measured: LDG +18%, cp.async +35% at 4096x4096x4096).\n   - Medium ratio (5-20:1): +5-15%.\n   - High ratio (>20:1): 0-5% or regression.\n5. If both variants were implemented, select the faster one for production use.\n\n```\n| Variant          | GFLOPS | Speedup vs Baseline |\n|------------------|--------|---------------------|\n| Baseline         | XXX    | 1.00x               |\n| LDG-register     | XXX    | X.XXx               |\n| cp.async (LDGSTS)| XXX    | X.XXx               |\n```\n\n**Got:** Performance comparison table showing improvement. The chosen variant should show measurable speedup consistent with the compute\u002Fload ratio prediction.\n\n**If fail:** If performance regresses, check three things: (1) SASS for unexpected instruction overhead (extra BAR.SYNC, register spills). (2) Shared memory did not cross the occupancy cliff — verify with `nvcc --resource-usage` or `cuobjdump -res-usage`. (3) The problem size produces enough tiles (`K \u002F BK >= 4`) for pipelining to amortize the prologue\u002Fepilogue overhead.\n\n### Step 7: Verify SASS Overlap\n\nInspect the compiled SASS to confirm that global loads and Tensor Core instructions overlap within the main loop body.\n\n1. Disassemble: `cuobjdump -sass kernel.sm_86.cubin | grep -E 'IMMA|HMMA|LDGSTS|LDG|BAR'`.\n2. In the main loop body, verify this ordering pattern:\n   - `LDGSTS` or `LDG` instructions appear **before** `HMMA` or `IMMA` instructions.\n   - No `BAR.SYNC` between the load instructions and the compute instructions (they must be free to overlap in the warp scheduler).\n   - `BAR.SYNC` appears **after** the compute block, gating the next iteration's use of the loaded data.\n3. Check stall codes on HMMA\u002FIMMA instructions — S08 for HMMA pipeline delay is expected and unavoidable. S01-S04 for IMMA is normal. Stalls on LDG\u002FLDGSTS should be low (S01) since the warp scheduler can switch to compute while loads are in flight.\n4. Count total HMMA\u002FIMMA instructions per loop iteration — this should match the non-pipelined version (pipelining should not change compute volume).\n\n```bash\n# Full SASS pipeline verification\ncuobjdump -sass kernel.sm_86.cubin | grep -E 'IMMA|HMMA|LDGSTS|LDG|BAR'\n\n# Count compute instructions per loop\ncuobjdump -sass kernel.sm_86.cubin | grep -c 'HMMA\\|IMMA'\n\n# Check for register spills\nnvcc --resource-usage --cubin -arch=sm_86 -O2 kernel.cu 2>&1 | grep -i spill\n```\n\n**Got:** Annotated SASS excerpt showing the load-before-compute pattern with no intervening barriers. Zero register spills.\n\n**If fail:** If the compiler reordered loads after compute (defeating the overlap), try: (1) `#pragma unroll 1` on the main loop to prevent over-aggressive unrolling. (2) Separate load and compute into distinct inline functions to create a sequencing hint. (3) Use `asm volatile(\"\" ::: \"memory\")` as a compiler fence between load and compute blocks (last resort — may inhibit other optimizations).\n\n## Validation\n\n- [ ] Double-buffer smem stays under architecture cliff (GA104: 50 KB\u002Fblock)\n- [ ] Both buffers used alternately (`buf[tile & 1]` pattern)\n- [ ] Prologue loads tile 0 into `buf[0]`\n- [ ] Epilogue computes last tile from `buf[(num_tiles - 1) & 1]`\n- [ ] Correctness PASS against CPU reference at both small and target sizes\n- [ ] SASS confirms load\u002Fcompute overlap (no `BAR.SYNC` between LDGSTS\u002FLDG and IMMA\u002FHMMA)\n- [ ] Performance improved over non-pipelined baseline\n- [ ] No register spill from LDG variant (check `nvcc --resource-usage`)\n\n## Pitfalls\n\n- **Crossing the smem cliff by doubling buffers** — GA104 cliff is 50 KB\u002Fblock, not 64 KB. Always calculate `smem_doubled` before implementing. A kernel using 28 KB single-buffered jumps to 56 KB doubled, crossing the cliff and halving occupancy. This can turn a +20% pipelining gain into a -50% occupancy regression.\n- **Forgetting the epilogue compute pass** — The last tile loaded in the final main loop iteration needs its own compute phase outside the loop. Without it, the last BK columns of the K dimension are silently dropped, producing incorrect results that may appear as small numerical errors rather than obvious failures.\n- **Buffer indexing off-by-one** — Use `buf[tile & 1]` for the current compute buffer and `buf[1 - (tile & 1)]` for the next load buffer. A common mistake is using `buf[(tile + 1) & 1]` for the next buffer, which is equivalent to `buf[1 - (tile & 1)]` only when the buffer count is 2 — but reads wrong if accidentally applied to the compute index.\n- **cp.async commit\u002Fwait ordering** — `__pipeline_commit()` must be called BEFORE the compute phase (it seals the batch of async copies). `__pipeline_wait_prior(0)` must be called AFTER the compute phase (it blocks until all committed copies complete). Swapping these makes the async copies synchronous, eliminating all overlap benefit.\n- **Missing __syncthreads** — In the LDG variant, a `__syncthreads()` is needed between compute and the STS drain (so compute finishes reading the current buffer before it gets overwritten). Another `__syncthreads()` is needed after the STS drain (so all threads finish writing before the next iteration reads). In the cp.async variant, `__syncthreads()` after `__pipeline_wait_prior(0)` ensures all threads see the completed async copies.\n- **Boundary handling in cp.async** — `__pipeline_memcpy_async` requires the source address to be valid and aligned. At matrix edges where `K` is not a multiple of `BK`, the last tile may read out of bounds. Fall back to scalar loads with bounds checking for the final tile, or pad the input matrices to a multiple of BK.\n\n## Related Skills\n\n- `analyze-kernel-bottleneck` — identify whether the kernel is memory-bound and calculate the compute\u002Fload ratio that drives variant selection\n","# Pipeline GPU Kernel\n\nApply software pipelining (double-buffering) to a tiled GPU kernel so that global memory loads for tile N+1 overlap with Tensor Core computation on tile N. Transform a sequential load-sync-compute-sync K-loop into a prologue\u002Floop\u002Fepilogue structure, choose between LDG-register and cp.async (LDGSTS) variants based on compute\u002Fload ratio, verify shared memory stays under the architecture occupancy cliff, and confirm load\u002Fcompute overlap in the final SASS.\n\n## When to Use\n\n- When `analyze-kernel-bottleneck` identifies a memory-bound kernel with low compute\u002Fload ratio per tile\n- When warp interleaving alone cannot hide DRAM latency (~300 cycles on GA104)\n- When the kernel has a sequential load-sync-compute-sync K-loop that can be restructured\n- Not needed when compute\u002Fload ratio is high (>20:1) and 8+ warps are active\n\n## Inputs\n\n- **Required**: CUDA kernel source file (`.cu`) with a tiled K-loop containing separate load and compute phases\n- **Required**: Target GPU architecture (e.g., GA104 \u002F sm_86 — determines smem cliff and occupancy limits)\n- **Required**: Current tile sizes (BM, BN, BK) and data type (FP16, FP32, INT8)\n- **Optional**: Compute\u002Fload ratio per tile (from `analyze-kernel-bottleneck`; will be estimated if not provided)\n- **Optional**: Benchmark baseline (non-pipelined performance at target problem size)\n\n## Procedure\n\n### Step 1: Verify Preconditions\n\nConfirm the kernel has a tiled K-loop with distinct load and compute phases separated by `__syncthreads()`. Calculate the doubled shared memory cost and verify it stays under the architecture occupancy cliff.\n\n1. Locate the K-loop in the kernel. It must have this sequential structure: load A and B tiles from global to shared memory, `__syncthreads()`, compute (HMMA\u002FIMMA\u002FFFMA) on the shared memory tiles, `__syncthreads()`.\n2. Record the single-buffer shared memory sizes: `smem_a_size = BM * BK * sizeof(T)` and `smem_b_size = BK * BN * sizeof(T)`.\n3. Calculate the double-buffer cost: `smem_doubled = smem_a_size * 2 + smem_b_size * 2`.\n4. Compare against the architecture cliff. GA104 (sm_86): 100 KB max smem\u002FSM, cliff at 50 KB\u002Fblock (above 50 KB = 1 block\u002FSM = 4 warps, 2x occupancy collapse).\n\n```\nSingle buffer: smem_a[BM*BK] + smem_b[BK*BN] = 2 KB + 2 KB = 4 KB\nDouble buffer: smem_a[2][BM*BK] + smem_b[2][BK*BN] = 4 KB + 4 KB = 8 KB\n8 KB \u003C\u003C 50 KB cliff -> 2 blocks\u002FSM -> 8 warps\n```\n\n5. Verify the loop iteration count: `num_tiles = K \u002F BK`. Pipelining requires `num_tiles >= 2` (at least one prologue + one main loop iteration).\n\n**Got:** A shared memory budget table showing single-buffer and double-buffer costs, confirming the doubled allocation stays under the architecture cliff with at least 2 blocks\u002FSM occupancy.\n\n**If fail:** If double-buffer exceeds the cliff, reduce tile size (halve BK or BM) until `smem_doubled \u003C= 50 KB` for GA104. Alternatively, use register-only prefetch (LDG variant) without doubling shared memory — store prefetched data in registers and write to the same single buffer after `__syncthreads()`.\n\n### Step 2: Choose Variant\n\nSelect between LDG-register and cp.async (LDGSTS) based on the compute\u002Fload ratio per tile.\n\n1. Calculate the compute\u002Fload ratio: `ratio = (2 * BM * BN * BK) \u002F ((BM * BK + BK * BN) * sizeof(T))` for GEMM-like kernels (2 FLOPs per multiply-add, bytes loaded per tile).\n2. Apply the decision rule:\n\n**LDG-register variant** (ratio >= 5 or CUDA \u003C 11.0):\n- LDG tile N+1 into registers (non-blocking global loads).\n- Compute on `buf[N % 2]` (overlaps with outstanding LDGs).\n- `__syncthreads()`, then STS registers into `buf[(N+1) % 2]`, `__syncthreads()`.\n- Simpler implementation, no pipeline API dependency.\n- Adds register pressure: ~`(BM * BK + BK * BN) \u002F BLOCK_SIZE` registers per thread for staging.\n\n**cp.async (LDGSTS) variant** (ratio \u003C 5, CUDA >= 11.0):\n- `__pipeline_memcpy_async` tile N+1 directly to `buf[(N+1) % 2]` (async, bypasses register file).\n- `__pipeline_commit()` before compute.\n- Compute on `buf[N % 2]`.\n- `__pipeline_wait_prior(0)` + `__syncthreads()` after compute.\n- Better overlap, zero register pressure for prefetch. Requires `#include \u003Ccuda_pipeline.h>`.\n\n3. Decision thresholds (measured on GA104 with IGEMM at 4096x4096x4096):\n   - Ratio \u003C 5:1 — prefer cp.async (+35% measured on IGEMM).\n   - Ratio 5-20:1 — implement both and benchmark to decide.\n   - Ratio > 20:1 — pipelining likely not beneficial (warp interleaving sufficient).\n\n**Got:** Selected variant with justification based on compute\u002Fload ratio and target architecture.\n\n**If fail:** If the ratio is ambiguous (5-20:1 range), implement both variants and benchmark. The cp.async variant is the safer default when CUDA version supports it.\n\n### Step 3: Restructure the K-Loop\n\nTransform the sequential load-sync-compute-sync loop into a pipelined prologue\u002Floop\u002Fepilogue structure.\n\n1. **Identify the three sections**: The original loop body becomes three pieces:\n   - **Prologue**: Load tile 0 into `buf[0]`, synchronize, then enter the main loop.\n   - **Main loop**: For tiles 1 through `num_tiles - 1`, overlap loading tile N+1 with computing tile N.\n   - **Epilogue**: Compute the last tile (already loaded by the final main loop iteration).\n\n2. **LDG-register variant structure**:\n\n```c\n\u002F\u002F === LDG-register variant ===\n\u002F\u002F Prologue: load tile 0 into buf[0]\ncooperative_load_tile(smem_a[0], smem_b[0], global_a, global_b, \u002F*k_offset=*\u002F0);\n__syncthreads();\n\nfor (int tile = 0; tile \u003C num_tiles - 1; tile++) {\n    int cur_buf = tile & 1;\n    int next_buf = 1 - cur_buf;\n\n    \u002F\u002F Phase 1: LDG next tile into registers (non-blocking)\n    float reg_a[ELEMS_PER_THREAD_A], reg_b[ELEMS_PER_THREAD_B];\n    prefetch_tile_to_registers(reg_a, reg_b, global_a, global_b,\n                               (tile + 1) * BK);\n\n    \u002F\u002F Phase 2: Compute on current buffer (overlaps with LDG flight)\n    tensor_core_mma(smem_a[cur_buf], smem_b[cur_buf], acc);\n\n    \u002F\u002F Phase 3: Drain registers into next buffer\n    __syncthreads();\n    store_registers_to_smem(smem_a[next_buf], smem_b[next_buf],\n                            reg_a, reg_b);\n    __syncthreads();\n}\n\n\u002F\u002F Epilogue: compute last tile\ntensor_core_mma(smem_a[(num_tiles - 1) & 1], smem_b[(num_tiles - 1) & 1], acc);\n```\n\n3. **cp.async variant structure**:\n\n```c\n\u002F\u002F === cp.async variant ===\n#include \u003Ccuda_pipeline.h>\n\n\u002F\u002F Prologue: async load tile 0 into buf[0]\ncpasync_load_tile(smem_a[0], smem_b[0], global_a, global_b, \u002F*k_offset=*\u002F0);\n__pipeline_commit();\n__pipeline_wait_prior(0);\n__syncthreads();\n\nfor (int tile = 0; tile \u003C num_tiles - 1; tile++) {\n    int cur_buf = tile & 1;\n    int next_buf = 1 - cur_buf;\n\n    \u002F\u002F Phase 1: cp.async next tile into next buffer (async, direct to smem)\n    cpasync_load_tile(smem_a[next_buf], smem_b[next_buf],\n                      global_a, global_b, (tile + 1) * BK);\n    __pipeline_commit();\n\n    \u002F\u002F Phase 2: Compute on current buffer (overlaps with LDGSTS in flight)\n    tensor_core_mma(smem_a[cur_buf], smem_b[cur_buf], acc);\n\n    \u002F\u002F Phase 3: Wait for async copies to complete\n    __pipeline_wait_prior(0);\n    __syncthreads();\n}\n\n\u002F\u002F Epilogue: compute last tile\ntensor_core_mma(smem_a[(num_tiles - 1) & 1], smem_b[(num_tiles - 1) & 1], acc);\n```\n\n4. Verify the loop count: the main loop runs `num_tiles - 1` iterations (tiles 0 through `num_tiles - 2` indexing which tiles to compute, loading tiles 1 through `num_tiles - 1`). The epilogue computes the tile loaded in the last iteration.\n\n**Got:** Restructured K-loop source code with clear prologue, main loop, and epilogue sections for the chosen variant.\n\n**If fail:** The most common bug is an off-by-one in buffer indexing or forgetting the epilogue compute pass. Verify: prologue loads into `buf[0]`, first main loop iteration computes `buf[0]` and loads into `buf[1]`, second iteration computes `buf[1]` and loads into `buf[0]`, and so on. The epilogue computes `buf[(num_tiles - 1) & 1]`.\n\n### Step 4: Implement Double-Buffer\n\nDeclare the double-buffered shared memory and implement the load functions.\n\n1. Replace single-buffer shared memory declarations with double-buffered arrays:\n\n```c\n\u002F\u002F Before (single buffer)\n__shared__ half smem_a[BM * BK];\n__shared__ half smem_b[BK * BN];\n\n\u002F\u002F After (double buffer)\n__shared__ half smem_a[2][BM * BK];\n__shared__ half smem_b[2][BK * BN];\n```\n\n2. For the cp.async variant, implement the async load function using the pipeline API:\n\n```c\n__device__ void cpasync_load_tile(half* dst_a, half* dst_b,\n                                  const half* src_a, const half* src_b,\n                                  int k_offset) {\n    \u002F\u002F Each thread copies its portion (16 bytes = 8 half values per cp.async)\n    int tid = threadIdx.x;\n    int bytes_per_thread = 16;  \u002F\u002F cp.async.cg supports 4, 8, or 16 bytes\n\n    \u002F\u002F A tile: BM * BK elements, distributed across BLOCK_SIZE threads\n    int elems_a = BM * BK \u002F BLOCK_SIZE;\n    for (int i = 0; i \u003C elems_a; i += 8) {\n        int idx = tid * elems_a + i;\n        __pipeline_memcpy_async(dst_a + idx,\n                                src_a + k_offset * BM + idx,\n                                bytes_per_thread);\n    }\n\n    \u002F\u002F B tile: BK * BN elements, distributed similarly\n    int elems_b = BK * BN \u002F BLOCK_SIZE;\n    for (int i = 0; i \u003C elems_b; i += 8) {\n        int idx = tid * elems_b + i;\n        __pipeline_memcpy_async(dst_b + idx,\n                                src_b + k_offset * BN + idx,\n                                bytes_per_thread);\n    }\n}\n```\n\n3. For the LDG variant, implement register staging arrays and store functions:\n\n```c\n\u002F\u002F Declare register staging (size = elements per thread)\nhalf reg_a[BM * BK \u002F BLOCK_SIZE];\nhalf reg_b[BK * BN \u002F BLOCK_SIZE];\n\n\u002F\u002F Prefetch: LDG from global to registers (non-blocking, issued early)\nfor (int i = 0; i \u003C BM * BK \u002F BLOCK_SIZE; i++) {\n    int idx = threadIdx.x * (BM * BK \u002F BLOCK_SIZE) + i;\n    reg_a[i] = global_a[k_offset * BM + idx];\n}\n\u002F\u002F ... similarly for reg_b\n\n\u002F\u002F Store: STS from registers to shared memory (after __syncthreads)\nfor (int i = 0; i \u003C BM * BK \u002F BLOCK_SIZE; i++) {\n    int idx = threadIdx.x * (BM * BK \u002F BLOCK_SIZE) + i;\n    smem_a[next_buf][idx] = reg_a[i];\n}\n```\n\n4. Keep `__launch_bounds__(BLOCK_SIZE)` on the kernel to give the compiler accurate occupancy information.\n5. Compile: `nvcc --cubin -arch=sm_86 -O2 -o kernel.sm_86.cubin kernel.cu`.\n\n**Got:** Compilable kernel with double-buffered shared memory and the chosen load mechanism. Successful cubin generation with no errors.\n\n**If fail:** If compilation fails on pipeline API calls, ensure `#include \u003Ccuda_pipeline.h>` is present and CUDA toolkit is >= 11.0. If register spills occur (check `nvcc --resource-usage`), reduce the register staging array sizes by increasing BLOCK_SIZE or reducing BK.\n\n### Step 5: Verify Correctness\n\nRun the pipelined kernel against the CPU reference to confirm identical numerical output.\n\n1. Compile the benchmark: `nvcc -arch=sm_86 -O2 -o bench bench.cu -lcuda -I..\u002F..\u002Fphase2\u002Fcommon`.\n2. Run at a small problem size first (512x512x512) to catch indexing bugs before scaling up.\n3. Apply the correct tolerance for the data type:\n   - INT8 Tensor Core (IMMA): `abs=0.5, rel=0.1`\n   - FP16 Tensor Core (HMMA): `abs=1e-2, rel=1e-2`\n   - FP32 scalar (FFMA): `abs=1e-3, rel=1e-3`\n4. Pipelining does not change the arithmetic — it only reorders loads. If correctness fails, the bug is in buffer indexing, not in the compute logic.\n5. Test at the target problem size (e.g., 4096x4096x4096) to verify boundary handling.\n\n**Got:** PASS at both small and target problem sizes with error bounds identical to the non-pipelined baseline.\n\n**If fail:** Buffer indexing bug is the most likely cause. Verify: compute reads from `buf[tile & 1]` while loads write to `buf[1 - (tile & 1)]`. Check the epilogue processes buffer index `(num_tiles - 1) & 1`, not `num_tiles & 1`. For cp.async, verify `__pipeline_wait_prior(0)` completes before `__syncthreads()` — otherwise compute may read partially-written data.\n\n### Step 6: Benchmark and Compare\n\nMeasure the pipelined kernel against the non-pipelined baseline at the target problem size.\n\n1. Run the non-pipelined baseline and record GFLOPS or bandwidth (depending on kernel type).\n2. Run each pipelined variant and record the same metric.\n3. Calculate speedup: `speedup = pipelined_metric \u002F baseline_metric`.\n4. Expected gains by compute\u002Fload ratio (measured on GA104):\n   - Low ratio (\u003C5:1): +15-35% from cp.async (IGEMM measured: LDG +18%, cp.async +35% at 4096x4096x4096).\n   - Medium ratio (5-20:1): +5-15%.\n   - High ratio (>20:1): 0-5% or regression.\n5. If both variants were implemented, select the faster one for production use.\n\n```\n| Variant          | GFLOPS | Speedup vs Baseline |\n|------------------|--------|---------------------|\n| Baseline         | XXX    | 1.00x               |\n| LDG-register     | XXX    | X.XXx               |\n| cp.async (LDGSTS)| XXX    | X.XXx               |\n```\n\n**Got:** Performance comparison table showing improvement. The chosen variant should show measurable speedup consistent with the compute\u002Fload ratio prediction.\n\n**If fail:** If performance regresses, check three things: (1) SASS for unexpected instruction overhead (extra BAR.SYNC, register spills). (2) Shared memory did not cross the occupancy cliff — verify with `nvcc --resource-usage` or `cuobjdump -res-usage`. (3) The problem size produces enough tiles (`K \u002F BK >= 4`) for pipelining to amortize the prologue\u002Fepilogue overhead.\n\n### Step 7: Verify SASS Overlap\n\nInspect the compiled SASS to confirm that global loads and Tensor Core instructions overlap within the main loop body.\n\n1. Disassemble: `cuobjdump -sass kernel.sm_86.cubin | grep -E 'IMMA|HMMA|LDGSTS|LDG|BAR'`.\n2. In the main loop body, verify this ordering pattern:\n   - `LDGSTS` or `LDG` instructions appear **before** `HMMA` or `IMMA` instructions.\n   - No `BAR.SYNC` between the load instructions and the compute instructions (they must be free to overlap in the warp scheduler).\n   - `BAR.SYNC` appears **after** the compute block, gating the next iteration's use of the loaded data.\n3. Check stall codes on HMMA\u002FIMMA instructions — S08 for HMMA pipeline delay is expected and unavoidable. S01-S04 for IMMA is normal. Stalls on LDG\u002FLDGSTS should be low (S01) since the warp scheduler can switch to compute while loads are in flight.\n4. Count total HMMA\u002FIMMA instructions per loop iteration — this should match the non-pipelined version (pipelining should not change compute volume).\n\n```bash\n# Full SASS pipeline verification\ncuobjdump -sass kernel.sm_86.cubin | grep -E 'IMMA|HMMA|LDGSTS|LDG|BAR'\n\n# Count compute instructions per loop\ncuobjdump -sass kernel.sm_86.cubin | grep -c 'HMMA\\|IMMA'\n\n# Check for register spills\nnvcc --resource-usage --cubin -arch=sm_86 -O2 kernel.cu 2>&1 | grep -i spill\n```\n\n**Got:** Annotated SASS excerpt showing the load-before-compute pattern with no intervening barriers. Zero register spills.\n\n**If fail:** If the compiler reordered loads after compute (defeating the overlap), try: (1) `#pragma unroll 1` on the main loop to prevent over-aggressive unrolling. (2) Separate load and compute into distinct inline functions to create a sequencing hint. (3) Use `asm volatile(\"\" ::: \"memory\")` as a compiler fence between load and compute blocks (last resort — may inhibit other optimizations).\n\n## Validation\n\n- [ ] Double-buffer smem stays under architecture cliff (GA104: 50 KB\u002Fblock)\n- [ ] Both buffers used alternately (`buf[tile & 1]` pattern)\n- [ ] Prologue loads tile 0 into `buf[0]`\n- [ ] Epilogue computes last tile from `buf[(num_tiles - 1) & 1]`\n- [ ] Correctness PASS against CPU reference at both small and target sizes\n- [ ] SASS confirms load\u002Fcompute overlap (no `BAR.SYNC` between LDGSTS\u002FLDG and IMMA\u002FHMMA)\n- [ ] Performance improved over non-pipelined baseline\n- [ ] No register spill from LDG variant (check `nvcc --resource-usage`)\n\n## Pitfalls\n\n- **Crossing the smem cliff by doubling buffers** — GA104 cliff is 50 KB\u002Fblock, not 64 KB. Always calculate `smem_doubled` before implementing. A kernel using 28 KB single-buffered jumps to 56 KB doubled, crossing the cliff and halving occupancy. This can turn a +20% pipelining gain into a -50% occupancy regression.\n- **Forgetting the epilogue compute pass** — The last tile loaded in the final main loop iteration needs its own compute phase outside the loop. Without it, the last BK columns of the K dimension are silently dropped, producing incorrect results that may appear as small numerical errors rather than obvious failures.\n- **Buffer indexing off-by-one** — Use `buf[tile & 1]` for the current compute buffer and `buf[1 - (tile & 1)]` for the next load buffer. A common mistake is using `buf[(tile + 1) & 1]` for the next buffer, which is equivalent to `buf[1 - (tile & 1)]` only when the buffer count is 2 — but reads wrong if accidentally applied to the compute index.\n- **cp.async commit\u002Fwait ordering** — `__pipeline_commit()` must be called BEFORE the compute phase (it seals the batch of async copies). `__pipeline_wait_prior(0)` must be called AFTER the compute phase (it blocks until all committed copies complete). Swapping these makes the async copies synchronous, eliminating all overlap benefit.\n- **Missing __syncthreads** — In the LDG variant, a `__syncthreads()` is needed between compute and the STS drain (so compute finishes reading the current buffer before it gets overwritten). Another `__syncthreads()` is needed after the STS drain (so all threads finish writing before the next iteration reads). In the cp.async variant, `__syncthreads()` after `__pipeline_wait_prior(0)` ensures all threads see the completed async copies.\n- **Boundary handling in cp.async** — `__pipeline_memcpy_async` requires the source address to be valid and aligned. At matrix edges where `K` is not a multiple of `BK`, the last tile may read out of bounds. Fall back to scalar loads with bounds checking for the final tile, or pad the input matrices to a multiple of BK.\n\n## Related Skills\n\n- `analyze-kernel-bottleneck` — identify whether the kernel is memory-bound and calculate the compute\u002Fload ratio that drives variant selection\n",{"name":5,"locale":23,"license":14,"metadata":24,"translator":31,"description":32,"allowed-tools":33,"source_commit":34,"source_locale":35,"translation_date":36},"caveman-lite",{"tags":25,"author":26,"domain":27,"version":28,"language":29,"complexity":30},"gpu, software-pipelining, double-buffer, cp-async, ldgsts, tensor-core, smem, occupancy","Philipp Thoss","gpu-optimization","1.0","CUDA","advanced","Julius Brussee homage — caveman","Apply software pipelining (double-buffering) to a tiled GPU kernel to overlap global memory loads with Tensor Core computation. Covers prologue\u002Floop\u002Fepilogue restructuring, LDG-register vs cp.async (LDGSTS) variant selection based on compute\u002Fload ratio, shared memory budget verification against architecture-specific occupancy cliffs, and SASS-level verification of load\u002Fcompute overlap.\n","Read Write Edit Bash Grep Glob","82c77053","en","2026-04-19","master","f483e54f3ad5f202a77d45f2e57f8d970b71195f","skills_library\u002Fpipeline-gpu-kernel",2,"https:\u002F\u002Fgithub.com\u002Froohe\u002Fagentic-super-skills","https:\u002F\u002Fgithub.com\u002Froohe","yoou.link","2026-05-19 15:56:07",{"source":8,"skillName":5,"commands":46,"prompt":56,"zipAvailable":57},[47,50,53],{"tool":48,"command":49},"npx","npx skills add roohe\u002Fagentic-super-skills --skill pipeline-gpu-kernel",{"tool":51,"command":52},"bunx","bunx skills add roohe\u002Fagentic-super-skills --skill pipeline-gpu-kernel",{"tool":54,"command":55},"pnpm","pnpm dlx skills add roohe\u002Fagentic-super-skills --skill pipeline-gpu-kernel","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Froohe\u002Fagentic-super-skills\u002Fblob\u002Fmaster\u002Fskills_library\u002Fpipeline-gpu-kernel\u002FSKILL.md",true,[],[60,67,74,81,88,95],{"skillNo":61,"name":62,"nameZh":6,"description":63,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":64,"categories":65,"keywords":66,"publishedAt":18},"01M73D865CZME2FCMKA4PQM348","zarr-python","Chunked N-D arrays for cloud storage. Compressed arrays, parallel I\u002FO, S3\u002FGCS integration, NumPy\u002FDask\u002FXarray compatible, for large-scale scientific computing pipelines.","https:\u002F\u002Fgithub.com\u002Froohe\u002Fagentic-super-skills\u002Fblob\u002Fmaster\u002Fskills_library\u002Fzarr-python\u002FSKILL.md",[],[],{"skillNo":68,"name":69,"nameZh":6,"description":70,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":71,"categories":72,"keywords":73,"publishedAt":18},"01M73D7Z64J4ABWZJD7P44XBBF","youtube-downloader","Download and process YouTube content for research. Use when: downloading competitor videos for analysis; extracting audio for podcasts; getting transcripts for content repurposing; archiving webinars; research content curation","https:\u002F\u002Fgithub.com\u002Froohe\u002Fagentic-super-skills\u002Fblob\u002Fmaster\u002Fskills_library\u002Fyoutube-downloader\u002FSKILL.md",[],[],{"skillNo":75,"name":76,"nameZh":6,"description":77,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":78,"categories":79,"keywords":80,"publishedAt":18},"01M73D7K8778TGZV3GJFR3703D","yc-pitch-deck","Create a compelling startup pitch deck that follows the structure proven to raise billions from top investors. Master the YC and Sequoia formats that get founders funded. Use when: **Fundraising** to create investor pitch decks; **YC application** to structure your narrative; **Demo Day prep** to craft your 2-minute pitch; **Angel investors** to communicate your opportunity; **Partnership pitches** to structure compelling asks","https:\u002F\u002Fgithub.com\u002Froohe\u002Fagentic-super-skills\u002Fblob\u002Fmaster\u002Fskills_library\u002Fyc-pitch-deck\u002FSKILL.md",[],[],{"skillNo":82,"name":83,"nameZh":6,"description":84,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":85,"categories":86,"keywords":87,"publishedAt":18},"01M73D70KJSE0E8Z28YMNNRT04","x-twitter-scraper","Use when the user needs X (Twitter) data or confirmation-gated X actions through Xquik: tweet search, user lookup, follower extraction, media download, monitoring, webhooks, MCP, SDKs, posting, likes, DMs, and profile updates. Requires a Xquik API key. Never ask for X login material.","https:\u002F\u002Fgithub.com\u002Froohe\u002Fagentic-super-skills\u002Fblob\u002Fmaster\u002Fskills_library\u002Fx-twitter-scraper\u002FSKILL.md",[],[],{"skillNo":89,"name":90,"nameZh":6,"description":91,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":94,"publishedAt":18},"01M73D6ED01GV077R7K4NZNFZJ","write-vignette","Create R package vignettes using R Markdown or Quarto. Covers vignette setup, YAML configuration, code chunk options, building and testing, and CRAN requirements for vignettes. Use when adding a Getting Started tutorial, documenting complex workflows spanning multiple functions, creating domain-specific guides, or when CRAN submission requires user-facing documentation beyond function help pages.","https:\u002F\u002Fgithub.com\u002Froohe\u002Fagentic-super-skills\u002Fblob\u002Fmaster\u002Fskills_library\u002Fwrite-vignette\u002FSKILL.md",[],[],{"skillNo":96,"name":97,"nameZh":6,"description":98,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":6,"repositoryNo":12,"starsCount":13,"licenseSpdxId":14,"licenseFileUrl":6,"sourceHtmlUrl":99,"categories":100,"keywords":101,"publishedAt":18},"01M73D69YJR0BK3NFHE0CYG3EF","write-validation-documentation","Write IQ\u002FOQ\u002FPQ validation documentation for computerized systems in regulated environments. Covers protocols, reports, test scripts, deviation handling, and approval workflows. Use when validating R or other software for regulated use, preparing for a regulatory audit, documenting qualification of computing environments, or creating and updating validation protocols and reports for new or re-qualified systems.","https:\u002F\u002Fgithub.com\u002Froohe\u002Fagentic-super-skills\u002Fblob\u002Fmaster\u002Fskills_library\u002Fwrite-validation-documentation\u002FSKILL.md",[],[]]