Skip to content

Nixlbench fix deallocate memory order - #1590

Merged
ofer merged 6 commits into
ai-dynamo:mainfrom
scality:nixlbench_fix_deallocateMemory_order
Jun 4, 2026
Merged

ofer merged 6 commits into
ai-dynamo:mainfrom
scality:nixlbench_fix_deallocateMemory_order

Conversation

@oliviergaraud

@oliviergaraud oliviergaraud commented Apr 27, 2026 •

Copy link
Copy Markdown
Contributor

What?

Fix memory management issues in deallocateMemory/allocateMemory:

deallocateMemory deregistered IOVs in the wrong order:
remote IOVs (OBJ/BLK/FILE) must be deregistered before local IOVs,
and for OBJ the deregistration must happen before cleanup to avoid use-after-free.
+
memset in allocateMemory use iov.len instead of buffer_size.
This could be wrong if the actual allocation size differed, but the original was not a bug as in this loop the allocation was to buffer_size anyways.

Summary by CodeRabbit

  • Bug Fixes

    • Initialize each I/O buffer using its exact length to prevent partial writes and ensure correct validation.
    • Close backing file resources exactly once to avoid leaks.
    • Reorder deallocation so remote registrations are torn down before related local cleanup, reducing use-after-free risks.
  • Refactor

    • Cleanup logic reorganized to enforce strict ordering and more robust resource tracking.

Two bugs fixed:
- deallocateMemory: deregister remote IOVs (OBJ/BLK/FILE) before local
  IOVs, and for OBJ deregister before cleanup to avoid use-after-free
- memset in allocateMemory: use iov.len instead of buffer_size, which
  could be wrong when the actual allocation size differs

Signed-off-by: Olivier Garaud <olivier.garaud@scality.com>
…allocateMemory

Deregister memory before closing file descriptors in the FILE_SEG path,
matching the fix already applied to OBJ_SEG. Backends like GDS or POSIX
may need the FD open during deregistration.

Signed-off-by: Olivier Garaud <olivier.garaud@scality.com>
…ocateMemory

Signed-off-by: Olivier Garaud <olivier.garaud@scality.com>
@copy-pr-bot

copy-pr-bot Bot commented Apr 27, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@github-actions

Copy link
Copy Markdown

👋 Hi oliviergaraud! Thank you for contributing to ai-dynamo/nixl.

Your PR reviewers will review your contribution then trigger the CI to test your changes.

🚀

@coderabbitai

coderabbitai Bot commented Apr 27, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

Failed to post review comments

📝 Walkthrough

Walkthrough

This change sizes DRAM consistency memset to each IOV's iov.len and restructures deallocateMemory so remote registrations are deregistered and immediately cleaned up (with backing-file deduplication), then local descriptor deregistration and per-descriptor cleanup (DRAM/VRAM) proceed afterward. (35 words)

Changes

Memory Management and Cleanup Logic

Layer / File(s) Summary
Data Shape / Initialization
benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
DRAM consistency init now calls memset((void*)iov.addr, 0, iov.len) per IOV instead of using the shared buffer_size.
Core Implementation
benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
deallocateMemory control flow reworked: for remote lists call agent->deregisterMem(...) then immediately perform per-IOV remote cleanup; when backend is storage, closed backing FDs are tracked with std::unordered_set to ensure each fd is cleaned exactly once.
Local Cleanup Ordering
benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
Local iov_lists are deregistered first, then each iov is cleaned per seg_type via a switch (DRAM -> cleanupBasicDescDram, VRAM -> cleanupBasicDescVram).
Comments / Control Flow
benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
Added ordering-invariant comments and reorganized branches so remote deregistration precedes its cleanup and local cleanup follows.
sequenceDiagram
  participant Caller
  participant Worker as xferBenchNixlWorker
  participant Agent
  participant Storage as StorageBackend
  participant LocalMem as LocalMemory

  Caller->>Worker: deallocateMemory()
  Worker->>Agent: deregisterMem(remote_iov_list)
  Agent-->>Worker: ack
  alt remote has storage-backed IOVs
    Worker->>Storage: cleanupBasicDescFile(fd) [track via unordered_set]
    Storage-->>Worker: closed
  else remote other segments (OBJ/GUSLI/FILE)
    Worker->>Worker: per-IOV remote cleanup (OBJ/GUSLI/FILE branches)
  end
  Worker->>LocalMem: deregisterMem(local_iov_list)
  LocalMem-->>Worker: ack
  Worker->>Worker: per-IOV local cleanup switch (DRAM / VRAM -> cleanupBasicDesc*)
  Worker-->>Caller: done
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested reviewers

  • brminich
  • aranadive
  • ovidiusm
  • ofer

Poem

🐰 I zero each iov with gentle care,
I tell the agent, "Please deregister there",
Remote fds closed once, then local springs,
Cleanup hops tidy on nimble wings,
A rabbit's tidy code — neat as a hare.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.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 and specifically describes the main change: fixing the deallocation memory order in Nixlbench, which matches the core purpose of the PR.
Description check ✅ Passed The PR description covers all required template sections (What and Why) with specific details about the memory management fixes, though it omits the optional How section.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp`:
- Around line 994-1042: Add an inline comment above the cleanup loop that
explains the required invariant: remote_iovs (OBJ_SEG/BLK_SEG/FILE_SEG) must be
deregistered before the local iov_lists (DRAM_SEG/VRAM_SEG) and that for OBJ_SEG
and FILE_SEG deregistration must occur before per-iov cleanup because
deregisterMem (agent->deregisterMem) may reference object metadata or the fd;
reference the symbols remote_iovs, iov_lists, agent->deregisterMem,
cleanupBasicDescObj, cleanupBasicDescFile, and
cleanupBasicDescDram/cleanupBasicDescVram so future maintainers understand why
the current ordering is necessary and must not be reversed.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: dcd057b3-cd7d-476b-ae2e-6ef8421c1a42

📥 Commits

Reviewing files that changed from the base of the PR and between 2dbbf40 and c0eab22.

📒 Files selected for processing (1)
  • benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp

Comment thread benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
ofer
ofer previously approved these changes Apr 27, 2026

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

♻️ Duplicate comments (1)
benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp (1)

1018-1025: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't close FILE descriptors per remote IOV list.

Line 918 reuses remote_fds[file_idx].fd across multiple descriptors when num_files < num_buffers. With the new per-list cleanup, the first loop can close an fd that later agent->deregisterMem() calls still need, so teardown becomes order-dependent again for shared files. Keep the new “deregister before cleanup” invariant, but defer FILE closes until all FILE_SEG deregistrations are finished, and close each backing fd once.

Suggested fix
     } else if (xferBenchConfig::isStorageBackend()) {
         for (auto &iov_list : remote_iovs) {
             nixl_reg_dlist_t desc_list(FILE_SEG);
             iovListToNixlRegDlist(iov_list, desc_list);
             CHECK_NIXL_ERROR(agent->deregisterMem(desc_list, &opt_args), "deregisterMem failed");
-            for (auto &iov : iov_list) {
-                cleanupBasicDescFile(iov);
-            }
+        }
+        for (auto &fd_state : remote_fds) {
+            if (close(fd_state.fd) != 0) {
+                std::cerr << "Failed to close file descriptor " << fd_state.fd << ": "
+                          << strerror(errno) << std::endl;
+                exit(EXIT_FAILURE);
+            }
         }
     }
🤖 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 `@benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp` around lines 1018 -
1025, The current per-list cleanup closes FILEs too early; instead, first
perform deregistrations for every iov list (preserving the existing loop using
iovListToNixlRegDlist and agent->deregisterMem on desc_list/FILE_SEG), but
postpone calling cleanupBasicDescFile(FILE_SEG) until you know no other
descriptors reference the same backing fd. Implement a small reference-count or
seen-set keyed by the file index found in each iov (derive from remote_iovs
entries or remote_fds[file_idx]): increment counts while scanning remote_iovs,
do all deregisterMem calls, then do a second pass that calls
cleanupBasicDescFile(iov) only when the reference count for that file reaches
zero (decrementing per call) so each backing fd is closed exactly once and only
after all FILE_SEG deregistrations complete.
🤖 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.

Duplicate comments:
In `@benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp`:
- Around line 1018-1025: The current per-list cleanup closes FILEs too early;
instead, first perform deregistrations for every iov list (preserving the
existing loop using iovListToNixlRegDlist and agent->deregisterMem on
desc_list/FILE_SEG), but postpone calling cleanupBasicDescFile(FILE_SEG) until
you know no other descriptors reference the same backing fd. Implement a small
reference-count or seen-set keyed by the file index found in each iov (derive
from remote_iovs entries or remote_fds[file_idx]): increment counts while
scanning remote_iovs, do all deregisterMem calls, then do a second pass that
calls cleanupBasicDescFile(iov) only when the reference count for that file
reaches zero (decrementing per call) so each backing fd is closed exactly once
and only after all FILE_SEG deregistrations complete.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8d21e1f6-82c4-4733-ba44-f9836a58ab2f

📥 Commits

Reviewing files that changed from the base of the PR and between c0eab22 and cd6f64d.

📒 Files selected for processing (1)
  • benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp

Signed-off-by: Olivier Garaud <olivier.garaud@scality.com>
…all deregistrations

Multiple IOVs can share the same backing fd due to file_idx wrapping.
Split the FILE_SEG cleanup into two passes: first deregister all lists,
then close each unique fd exactly once using a seen-set.

Signed-off-by: Olivier Garaud <olivier.garaud@scality.com>
@oliviergaraud
oliviergaraud force-pushed the nixlbench_fix_deallocateMemory_order branch from cd6f64d to fb5397d Compare May 5, 2026 12:40

@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: 1

🤖 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 `@benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp`:
- Around line 1018-1033: The code correctly deduplicates closing backing file
descriptors using closed_fds to avoid double-close after deregisterMem, but
needs an explicit inline note tying the dedup key to a FILE_SEG backing fd;
locate the block that declares closed_fds (the loop after deregisterMem in the
same scope as remote_iovs) and add a concise comment above closed_fds
(referencing closed_fds, iov.devId, FILE_SEG, and cleanupBasicDescFile) stating
that iov.devId is a POSIX file descriptor for FILE_SEG and is being deduplicated
to ensure each backing FD is closed exactly once; keep the comment short and
explicit so future changes won’t mistakenly reuse devId for non-FD identifiers.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: d5ec72e3-3df4-41b8-b53e-ba6cc3d17110

📥 Commits

Reviewing files that changed from the base of the PR and between cd6f64d and fb5397d.

📒 Files selected for processing (1)
  • benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp

Comment thread benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
@aranadive

Copy link
Copy Markdown
Contributor

/ok to test fb5397d

@aranadive

Copy link
Copy Markdown
Contributor

/build

Comment thread benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
Comment thread benchmark/nixlbench/src/worker/nixl/nixl_worker.cpp
@ofer

ofer commented May 31, 2026

Copy link
Copy Markdown
Contributor

@oliviergaraud please rebase to pick up some CI fixes

@oliviergaraud

Copy link
Copy Markdown
Contributor Author

@oliviergaraud please rebase to pick up some CI fixes

done

@ofer

ofer commented Jun 2, 2026

Copy link
Copy Markdown
Contributor

/ok to test 02e96b6

@ofer

ofer commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

/build

@ofer
ofer merged commit d377a97 into ai-dynamo:main Jun 4, 2026
16 checks passed
@oliviergaraud
oliviergaraud deleted the nixlbench_fix_deallocateMemory_order branch June 4, 2026 07:42

This branch was previously deployed

1 inactive deployment
SWX_AWS — 02e96b66 Deployed Jun 2, 2026 by copy-pr-bot[bot] via Run AWS Tests #7509
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