Skip to content

feat(kernels): add fused masking + variable-length pack-and-pad op #182

Open
Chen-BUPT wants to merge 9 commits into
RL-Align:mainfrom
Chen-BUPT:feat/pack-and-pad
Open

feat(kernels): add fused masking + variable-length pack-and-pad op #182
Chen-BUPT wants to merge 9 commits into
RL-Align:mainfrom
Chen-BUPT:feat/pack-and-pad

Conversation

@Chen-BUPT

@Chen-BUPT Chen-BUPT commented Jun 23, 2026

Copy link
Copy Markdown

Fused masking + variable-length pack-and-pad op (#42)

What this adds

A pack operator that compacts the active rows of a dense [B, S, *tail]
tensor (selected by a [B, S] mask) into a contiguous [Total_Active, *tail]
tensor, returns per-row cu_seqlens, and scatters gradients back to the dense
layout on the backward pass.

Backend Class Notes
PyTorch (CPU/GPU fallback) NativePackOp Portable reference; defines the numerical contract. Packing order matches SyntheticRLKernelBatch.compact_completion_values.
Triton (CUDA & ROCm) TritonPackOp Host-side prefix-sum for destination indices; gather/scatter kernels move the tail vectors. Numerically identical to the native op.

Registry dispatch for "pack": Triton on GPU, PyTorch fallback on CPU.

Correctness

  • 18/18 tests in tests/test_pack.py pass on an NVIDIA H20 (SM90, CUDA 13.0).
  • Native op validated against the repo's canonical compaction + gradcheck.
  • Triton op validated against the native op (forward + backward); max-abs
    drift = 0.000e+00
    across all benchmarked shapes.

Why it matters: end-to-end VRAM

In RL training only the response / non-padding tokens contribute to the loss.
Packing the hidden states before the vocab projection means the full
[B, S, V] logits are never materialized for masked-out tokens — exactly the
saving #42 targets ("saved memory can be used for larger batches or longer
CoT").

Benchmark: hidden=4096 -> lm_head -> logits -> selected logp, bf16,
B=32, S=1024, comparing dense (full logits) vs pack-then-project.

vocab = 131072

mask_density valid_tokens dense logp (GB) packed logp (GB) VRAM saving speedup pack_drift
0.05 1638 17.31 2.12 87.8 % 0.23 0
0.10 3277 17.33 2.96 82.9 % 0.29 0
0.30 9830 17.43 6.31 63.8 % 0.45 0
0.50 16384 17.53 9.66 44.9 % 0.57 0
1.00 32768 17.78 18.03 -1.4 % 0.74 0

vocab = 32768

mask_density valid_tokens dense logp (GB) packed logp (GB) VRAM saving speedup pack_drift
0.05 1638 4.56 0.77 83.1 % 0.25 0
0.10 3277 4.58 1.01 78.0 % 0.32 0
0.30 9830 4.68 1.96 58.2 % 0.46 0
0.50 16384 4.78 2.91 39.2 % 0.54 0
1.00 32768 5.03 5.28 -5.0 % 0.78 0

(Full data: pack_h20.csv.)

How to read the numbers

  • VRAM saving is the headline. With a sparse loss mask (long prompt, short
    response — the common RL case), packing before the projection cuts peak logp
    memory by up to ~88 % (density 0.05). The 17 GB -> 2 GB drop lets the
    same GPU fit a much larger batch or longer CoT.
  • density = 1.0 (all active) is the control group: saving ≈ 0 % (a small
    pack overhead), as expected — there is nothing to compact, so nothing is
    saved. This confirms the measurement is honest.
  • Latency (speedup < 1) is reported as-is. The pack op itself is
    memory-bound and a touch slower than PyTorch's boolean indexing
    (index_select is already highly tuned). Its absolute cost is 0.06–0.35 ms,
    negligible against the multi-GB memory it saves. This PR targets the VRAM
    win ([FEAT][kernels]: implement Fused Masking and Variable-Length Sequence Packing (Pack-and-Pad) #42's stated motivation);

Reproduce

PYTHONPATH=. python -m pytest tests/test_pack.py -v        # correctness (needs CUDA for Triton cases)

PYTHONPATH=. python benchmarks/benchmark_pack.py \
  --num-prompts 4 --g-sizes 8 --hidden-dim 4096 \
  --mask-densities 0.05,0.1,0.3,0.5,1.0 \
  --completion-lens 1024 --vocab-sizes 32768,131072 \
  --output benchmarks/results/pack_h20.csv

Notes for reviewers

  • Hardware fallback: no GPU / no Triton → automatically dispatches to
    NativePackOp (CPU path); Triton tests skip cleanly.
  • ROCm: the Triton kernels are wavefront-agnostic (plain gather/scatter), so
    they run on ROCm via Triton without CUDA-specific intrinsics.
  • Please add the needs-gpu-ci label so the GPU CI exercises the Triton
    path.

Summary by CodeRabbit

  • New Features

    • Added pack-and-pad support to compact active sequence tokens into packed tensors with sequence-length metadata.
    • Added unpack support to restore packed data to dense layouts, including multidimensional data.
    • Enabled pack operation dispatch across CPU, CUDA, and ROCm environments.
    • Added a benchmark runner with smoke-test mode and CSV output.
  • Documentation

    • Added operator documentation, navigation links, usage details, and benchmarking instructions.
  • Tests

    • Added coverage for masking, gradients, round trips, edge cases, validation, and registry dispatch.

sadlerchen added 3 commits June 23, 2026 11:46
…AM) (RL-Align#42)

Measure TritonPackOp vs a PyTorch boolean-index baseline for pack latency,
and the end-to-end peak VRAM of dense logp vs pack->logp to quantify the
memory saving on sparse masks (the motivation behind RL-Align#42). Follows the
existing benchmark_ratio_kl.py conventions (CUDA-event median timing,
max_memory_allocated, CSV output, --smoke).
Pack hidden states before the vocab projection so the dense [B,S,V] logits
are never materialized for masked-out tokens, which is the actual RL-Align#42 saving.
Drop the fp32 upcast in selected-logp (use logits - logsumexp) so the dense
path's peak memory reflects the logits, not an fp32 copy. Add --hidden-dim.
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a PyTorch pack-and-pad operator with autograd support, registry dispatch across platforms, correctness tests, a configurable latency and memory benchmark, and documentation.

Changes

Pack-and-pad operator

Layer / File(s) Summary
NativePackOp implementation
rl_engine/kernels/ops/pytorch/packing/*
Adds validation, active-row packing, cu_seqlens generation, gradient scattering, and unpack.
Registry dispatch and correctness validation
rl_engine/kernels/registry.py, tests/test_pack.py
Routes pack to NativePackOp on CUDA, ROCm, and CPU, with coverage for forward, backward, unpack, validation, and dispatch.
Pack and log-probability benchmark runner
benchmarks/benchmark_pack.py
Adds configurable sweeps measuring pack latency, tensor drift, dense-versus-packed log-probability memory, CSV output, smoke mode, blocked runs, and OOM rows.
Operator and benchmark documentation
docs/operators/*, docs/benchmarking/README.md, docs/.nav.yml
Documents the operator contract, behavior, benchmarks, tests, and navigation entries.

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

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant KernelRegistry
  participant NativePackOp
  participant _PackFunction

  Caller->>KernelRegistry: get_op("pack")
  KernelRegistry-->>Caller: NativePackOp
  Caller->>NativePackOp: __call__(x, mask)
  NativePackOp->>_PackFunction: apply(x, mask)
  _PackFunction-->>NativePackOp: packed, cu_seqlens
  NativePackOp-->>Caller: packed, cu_seqlens
Loading

Suggested reviewers: inaniloquentee, kjldefeated, ethanzero2hero

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding a fused masking and pack-and-pad kernel/op.
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

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
rl_engine/kernels/ops/pytorch/packing/pack.py (1)

27-37: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Remove the duplicate dimension check.

The mask.dim() < 1 guard at Lines 35-36 is dead code — it repeats the identical check at Lines 28-29, and the shape comparison in between never alters mask.dim().

♻️ Proposed cleanup
 def _validate(x: torch.Tensor, mask: torch.Tensor) -> None:
     if mask.dim() < 1:
         raise ValueError("mask must have at least one dimension.")
     if mask.shape != x.shape[: mask.dim()]:
         raise ValueError(
             f"mask shape {tuple(mask.shape)} must match the leading dims of "
             f"x.shape {tuple(x.shape)} (expected {tuple(x.shape[: mask.dim()])})."
         )
-    if mask.dim() < 1:
-        raise ValueError("mask must have at least one dimension.")
🤖 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 `@rl_engine/kernels/ops/pytorch/packing/pack.py` around lines 27 - 37, The
_validate function contains a duplicate dimension check for mask.dim() < 1 that
appears after the shape validation logic. Remove the second occurrence of the
identical check (the one appearing after the shape comparison) since the
intermediate validation logic does not modify mask.dim() and therefore makes the
repeated check dead code. Keep only the initial dimension check and remove the
redundant check that follows the shape validation.
rl_engine/kernels/ops/triton/packing/pack.py (1)

99-102: 🚀 Performance & Scalability | 🔵 Trivial | ⚖️ Poor tradeoff

Gather grid launches a program for every source row, including inactive ones.

The grid is sized over n_rows = B*S, and each program loads dest and early-exits when the row is inactive (dest < 0). For the low-density packing this op targets (e.g. 0.05), the large majority of launched programs do no work. Launching over the n_active rows via a packed→source inverse index would avoid the wasted launches on the hot path. This is the design tradeoff already acknowledged in the PR, so feel free to defer.

🤖 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 `@rl_engine/kernels/ops/triton/packing/pack.py` around lines 99 - 102, The grid
in the `_pack_gather_kernel` launch is currently sized over `n_rows` which
includes all source rows, causing programs to be launched for inactive rows that
do no work (they just early-exit when dest < 0). To optimize this for sparse
packing scenarios, resize the grid to be sized over `n_active` instead of
`n_rows`, and introduce a packed-to-source inverse index mapping that the kernel
can use to look up which source rows are actually active. This eliminates wasted
kernel launches on inactive rows while keeping the same kernel logic.
🤖 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 `@benchmarks/benchmark_pack.py`:
- Around line 214-252: The broad except Exception block that catches all
exceptions and sets status to "blocked" masks real execution errors
(kernel/runtime/math failures) as if the candidate backend is simply
unavailable. Replace the generic except Exception handler with specific
exception handling that only catches exceptions that genuinely indicate
unavailability (such as ImportError for missing kernel_registry or RuntimeError
for unavailable backends), and allow other exceptions like runtime/math/kernel
errors to propagate or be handled separately so they surface as actual failures
rather than being silently masked as blocked candidates.

In `@tests/test_pack.py`:
- Around line 18-31: The TritonPackOp import on line 18 happens unconditionally
before the Triton availability check, causing test collection to fail in
environments without Triton. Move the TritonPackOp import into the try block
alongside the triton import, and add a fallback assignment in the except block
(such as TritonPackOp = None) so the name can be safely referenced elsewhere in
the code. This ensures tests are properly skipped by the requires_triton_cuda
marker instead of failing during collection.

---

Nitpick comments:
In `@rl_engine/kernels/ops/pytorch/packing/pack.py`:
- Around line 27-37: The _validate function contains a duplicate dimension check
for mask.dim() < 1 that appears after the shape validation logic. Remove the
second occurrence of the identical check (the one appearing after the shape
comparison) since the intermediate validation logic does not modify mask.dim()
and therefore makes the repeated check dead code. Keep only the initial
dimension check and remove the redundant check that follows the shape
validation.

In `@rl_engine/kernels/ops/triton/packing/pack.py`:
- Around line 99-102: The grid in the `_pack_gather_kernel` launch is currently
sized over `n_rows` which includes all source rows, causing programs to be
launched for inactive rows that do no work (they just early-exit when dest < 0).
To optimize this for sparse packing scenarios, resize the grid to be sized over
`n_active` instead of `n_rows`, and introduce a packed-to-source inverse index
mapping that the kernel can use to look up which source rows are actually
active. This eliminates wasted kernel launches on inactive rows while keeping
the same kernel logic.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: b134abab-ef3b-4adc-8ca3-c50dd21ef7ae

📥 Commits

Reviewing files that changed from the base of the PR and between 51b8b21 and b6ed34f.

📒 Files selected for processing (7)
  • benchmarks/benchmark_pack.py
  • rl_engine/kernels/ops/pytorch/packing/__init__.py
  • rl_engine/kernels/ops/pytorch/packing/pack.py
  • rl_engine/kernels/ops/triton/packing/__init__.py
  • rl_engine/kernels/ops/triton/packing/pack.py
  • rl_engine/kernels/registry.py
  • tests/test_pack.py

Comment thread benchmarks/benchmark_pack.py Outdated
Comment thread tests/test_pack.py Outdated
The second mask.dim() < 1 guard was dead code: the intervening shape check
does not alter mask.dim(). Addresses CodeRabbit review on RL-Align#182.
packed = flat_x.index_select(0, index)

# cu_seqlens: prefix-sum of per-row active counts, for varlen consumers.
per_row_active = mask.reshape(mask.shape[0], -1).to(torch.int64).sum(dim=1)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

packed uses mask.to(bool), but cu_seqlens sums the raw mask. Non-bool masks can produce wrong prefix sums. Please either require bool masks or compute counts from the bool mask.

Packing selects rows via mask.to(bool) (nonzero == active), but cu_seqlens
summed the raw mask, so a non-bool mask (e.g. values in {0, 2}) inflated the
prefix sum beyond the number of rows actually packed. Count from the same
bool mask so cu_seqlens always matches the packed row count. Adds a
regression test. Addresses review feedback on RL-Align#182.
@Chen-BUPT
Chen-BUPT requested a review from inaniloquentee June 24, 2026 03:31
Co-authored-by: Cursor <cursoragent@cursor.com>

@Flink-ddd Flink-ddd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Excellent work! but need add related doc file and Please revise the following review comments. Everything else is very well done. Once these are done, I will approve it. Thanks.

counts = active.to(torch.int64)
# Exclusive prefix sum: position of each active row in the packed buffer.
excl = torch.cumsum(counts, dim=0) - counts
n_active = int(counts.sum().item())

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(_dest_index, n_active = int(counts.sum().item())) .item() forces a device-to-host sync that blocks the stream, since torch.empty(n_active, ...) depends on this Python int. It's hard to avoid given the output shape depends on n_active, but please add a comment marking this as an intentional sync point so it isn't duplicated on the hot path later.

grid = (n_rows, triton.cdiv(T, _BLOCK_T))
_pack_gather_kernel[grid](src, packed, dest, T, BLOCK_T=_BLOCK_T)

per_row_active = flat_mask.to(torch.bool).reshape(mask.shape[0], -1).to(torch.int64).sum(1)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(per_row_active = ...reshape(mask.shape[0], -1)...) cu_seqlens treats mask.shape[0] as the batch dim, but packing supports an arbitrary-dim leading mask. For mask.dim() > 2 the per-row grouping no longer matches the row-major pack order. Please document that cu_seqlens is only well-defined for a 2D [B, S] mask.

"""forward: gather active rows; backward: scatter grads to active rows."""

@staticmethod
def forward(ctx, x: torch.Tensor, mask: torch.Tensor):

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(_PackFunction.forward / _validate) If x and mask are on different devices, index_select throws a low-level device-mismatch error. Please add a device check in _validate for a clear message, consistent with the shape check.

return _PackFunction.apply(x, mask)

@staticmethod
def unpack(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(NativePackOp.unpack) When tail_shape is passed explicitly and the element count happens to match but dims differ, reshape silently produces a wrong shape. Consider asserting tail_shape against packed.shape[1:].

return parser


def main() -> None:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(main(), OOM handler) The OOM-row dict duplicates the structure of _pack_row's return value, so it's easy to miss when CSV_COLUMNS changes. Consider a _blank_row(config, status, notes) helper.

Comment thread tests/test_pack.py Outdated
assert torch.equal(packed_t, packed_n)
assert cu_t.tolist() == [0, 2, 4]


Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Add a negative test where x and mask are on different devices, asserting a clear error is raised (matches the native/triton device-check suggestion above).

Comment thread tests/test_pack.py Outdated
packed_n, cu_n = NativePackOp()(x, batch.completion_mask)
assert torch.equal(packed_t, packed_n)
assert torch.equal(cu_t, cu_n)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

(Triton tests) Add a dedicated n_active == 0 test asserting the Triton path doesn't launch the kernel (the if n_active > 0 guard) and returns the correct [0, ...] shape.

@Flink-ddd Flink-ddd left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Correction: my previous review was approved by mis-click. The doc and the review comments above still need to be addressed before this can be merged re-submitting as Request changes. Will approve once they're done. Thanks!

@KJLdefeated KJLdefeated left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The native op is clean and correct gather/scatter, race-free (unique dest indices, no atomics), drift-free by construction. Aligning with Flink's existing requested-changes (device check, unpack tail_shape assert, cu_seqlens-is-2D-only doc, _blank_row helper, the negative-device test — all fair, should land).

Comment on lines +133 to +141
class TritonPackOp:
"""Triton fused masking + variable-length packing (pack-and-pad).

Forward packs the active rows of ``x`` (selected by ``mask``) into a
contiguous ``[Total_Active, *tail]`` tensor and returns the per-row
``cu_seqlens`` prefix-sum. Backward scatters the upstream gradient back to the
original ``[*mask.shape, *tail]`` layout, leaving zeros at inactive positions.
Numerically identical to ``NativePackOp``; CUDA & ROCm via Triton.
"""

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

What does the Triton path buy over index_select today? Reading the benchmark honestly: TritonPackOp runs 1.3–4× slower than the PyTorch boolean index baseline (speedup 0.23–0.78), and its output and peak memory are identical to NativePackOp. It's the same copy. So as it stands the Triton kernel is strictly dominated by x[mask] / the native op on every axis.
The only justification I can see is future fusion, folding this gather into the downstream lm_head/logp kernel so the packed hidden is never materialized as a standalone tensor. But that fused consumer isn't in this PR, so right now we'd be committing to maintain a slower-than-native CUDA/ROCm kernel with no caller that needs it.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
rl_engine/kernels/ops/pytorch/packing/pack.py (2)

94-96: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Simplify redundant conditional expression for tail_shape.

In Python, unpacking an empty tuple inside a function argument list naturally expands to nothing. The explicit if tail_shape: conditional evaluates to the exact same result whether tail_shape is empty or not, and can be safely removed for cleaner code. (This simplification also applies to the x.reshape conditional in the forward pass).

♻️ Proposed refactoring
-        grad_flat = grad_packed.new_zeros(
-            (ctx.flat_rows, *tail_shape) if tail_shape else (ctx.flat_rows,)
-        )
+        grad_flat = grad_packed.new_zeros((ctx.flat_rows, *tail_shape))
🤖 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 `@rl_engine/kernels/ops/pytorch/packing/pack.py` around lines 94 - 96, Remove
the redundant tail_shape conditional in the grad_flat allocation so the tuple
uses direct unpacking. Apply the same simplification to the x.reshape
conditional in the forward pass, preserving identical behavior for both empty
and non-empty tail_shape values.

74-76: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider cloning the empty view to strictly preserve the non-aliasing contract.

Although an empty tensor naturally prevents data corruption upon mutation, returning a direct view of flat_x skips the strict non-aliasing intent established in the all_active fast path. Appending .clone() keeps the returned tensor fully detached from x's storage without incurring any memory cost.

♻️ Proposed refactoring
         elif ctx.none_active:
-            packed = flat_x[:0]
+            packed = flat_x[:0].clone()
             ctx.save_for_backward()
🤖 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 `@rl_engine/kernels/ops/pytorch/packing/pack.py` around lines 74 - 76, Update
the none_active branch of the packing operation to clone the empty tensor
produced from flat_x before assigning it to packed. Preserve the existing empty
shape and ctx.save_for_backward() behavior while ensuring the result does not
alias flat_x storage.
🤖 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.

Nitpick comments:
In `@rl_engine/kernels/ops/pytorch/packing/pack.py`:
- Around line 94-96: Remove the redundant tail_shape conditional in the
grad_flat allocation so the tuple uses direct unpacking. Apply the same
simplification to the x.reshape conditional in the forward pass, preserving
identical behavior for both empty and non-empty tail_shape values.
- Around line 74-76: Update the none_active branch of the packing operation to
clone the empty tensor produced from flat_x before assigning it to packed.
Preserve the existing empty shape and ctx.save_for_backward() behavior while
ensuring the result does not alias flat_x storage.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f246fdae-274a-4e14-b50c-dfdc1849064e

📥 Commits

Reviewing files that changed from the base of the PR and between 3379cbe and 0954497.

📒 Files selected for processing (8)
  • benchmarks/benchmark_pack.py
  • docs/.nav.yml
  • docs/benchmarking/README.md
  • docs/operators/README.md
  • docs/operators/pack-and-pad.md
  • rl_engine/kernels/ops/pytorch/packing/pack.py
  • rl_engine/kernels/registry.py
  • tests/test_pack.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • benchmarks/benchmark_pack.py

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants