Skip to content

Conversation

ldematte
Copy link
Contributor

@ldematte ldematte commented Jun 24, 2025

The cuVS C API we are leveraging uses a common C pattern for "object creation": you pass down a pointer, and that gets populated. Often, this is a **, and memory gets allocated on the other side:

create(voi**ptrPtr) {
   *ptrPtr = new Something;
}
void** ptrPtr = // allocate space for a pointer
create(ptrPtr);
void* ptr = *ptrPtr;

In Panama, this means

  • allocating a small pointer size MemorySegment, very short lived
  • call create
  • extract a MemorySegment from the MemorySegment

Existing code sometimes skipped the extraction bit (the dereference), and/or created the structure directly instead of using the C create functions; this lead to some segfaults (addressing the wrong memory/wrong size) and to some double frees (the JVM freed MemorySegments we allocated via an arena, but we also called the destroy functions, so the C side tried to free them too).

Plus, this PR tries to reduce the lifetime of some allocations, avoiding to use the CuVSResources arena when it is clearly not needed -- but I did not want to expand the scope too much, so I just did the more obvious ones. Optimizing memory allocation is still a WIP, especially on the search side, but this I think will deserve its own PR.

These changes makes the test suite pass reliably - I have not seen a segmentation fault over hundreds of executions locally, and lowers the native memory occupied a little.

Copy link

copy-pr-bot bot commented Jun 24, 2025

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.

@benfred benfred added improvement Improves an existing functionality non-breaking Introduces a non-breaking change labels Jun 24, 2025
@benfred
Copy link
Member

benfred commented Jun 24, 2025

/ok to test b26ff62

@mythrocks
Copy link
Contributor

mythrocks commented Jun 24, 2025

create(voi**ptrPtr) {
   *ptrPtr = new Something;
}
void** ptrPtr = // allocate space for a pointer
create(ptrPtr);
void* ptr = *ptrPtr;

Correct me if I'm wrong, but I thought the code flow was more like:

create(void** ptrPtr) {
   *ptrPtr = new Something;
}
void* ptr; // (Automatically) allocate space for a pointer.
create(&ptr);

Edit: I think I might be nitpicking. I'll examine the crux of your fix shortly.

@ldematte
Copy link
Contributor Author

ldematte commented Jun 25, 2025

Correct me if I'm wrong, but I thought the code flow was more like:

create(void** ptrPtr) {
   *ptrPtr = new Something;
}
void* ptr; // (Automatically) allocate space for a pointer.
create(&ptr);

You are absolutely correct, I was writing "C the way we can use in Java": if we cannot generate a "pointer" (a MemorySegment) referencing a stack variable, void* ptr; create(&ptr); becomes

void** ptrPtr = (void*)malloc(sizeof(void*)); 
create(ptrPtr);
void* ptr = *ptrPtr;
free(ptrPtr);

or, equivalent in Java

try (var localArena = Arena.ofConfined) {
   MemorySegment ptrPtr = localArena.allocate(C_POINTER); // malloc
   create(ptrPtr)
   MemorySegment ptr = ptrPtr.get(...); // dereference
} // free

My point is: the original code was missing the indirection and dereference.

@chatman
Copy link
Contributor

chatman commented Jun 25, 2025

Excellent catch, thanks a lot @ldematte.

Optimizing memory allocation is still a WIP, especially on the search side, but this I think will deserve its own PR.

We can use this issue, if needed: #1037
Some thoughts I had around this was to perform some tests/checks for memory leaks (esp. non-heap) in our tests. Not sure how easy it would be without diving deeper into it.

Copy link
Contributor

@mythrocks mythrocks left a comment

Choose a reason for hiding this comment

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

I'm generally positive on this change.

There are a couple of minor quibbles, and some clarifying questions.

@benfred
Copy link
Member

benfred commented Jun 27, 2025

/ok to test 0fb438e

@ldematte ldematte requested a review from mythrocks July 3, 2025 07:10
Copy link
Contributor

@ChrisHegarty ChrisHegarty left a comment

Choose a reason for hiding this comment

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

LGTM. Thanks for fixing this intermittent failure.

@mythrocks
Copy link
Contributor

/ok to test a87d96e

Copy link
Contributor

@mythrocks mythrocks left a comment

Choose a reason for hiding this comment

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

LGTM! Good catch, @ldematte. 👏

@mythrocks
Copy link
Contributor

/merge

@rapids-bot rapids-bot bot merged commit dc8b945 into rapidsai:branch-25.08 Jul 3, 2025
96 of 102 checks passed
rapids-bot bot pushed a commit that referenced this pull request Jul 15, 2025
This PR tidies up the lifecycle of `MemorySegment`s by using specific confined `Arena`s where possible, and specific index-bound `Arena`s where the lifetime needs to be bound to the lifetime of an index.

It addresses all remaining usages of `CuVSResources#arena` after #1024 and #1045; as such, we can remove `CuVSResources#arena` completely, and force native memory usages to be tracked and dealt with specifically.

This would towards the goal of #1037

Authors:
  - Lorenzo Dematté (https://github.com/ldematte)
  - MithunR (https://github.com/mythrocks)
  - Ben Frederickson (https://github.com/benfred)

Approvers:
  - Chris Hegarty (https://github.com/ChrisHegarty)
  - MithunR (https://github.com/mythrocks)

URL: #1069
punAhuja pushed a commit to SearchScale/cuvs that referenced this pull request Jul 16, 2025
This PR tidies up the lifecycle of `MemorySegment`s by using specific confined `Arena`s where possible, and specific index-bound `Arena`s where the lifetime needs to be bound to the lifetime of an index.

It addresses all remaining usages of `CuVSResources#arena` after rapidsai#1024 and rapidsai#1045; as such, we can remove `CuVSResources#arena` completely, and force native memory usages to be tracked and dealt with specifically.

This would towards the goal of rapidsai#1037

Authors:
  - Lorenzo Dematté (https://github.com/ldematte)
  - MithunR (https://github.com/mythrocks)
  - Ben Frederickson (https://github.com/benfred)

Approvers:
  - Chris Hegarty (https://github.com/ChrisHegarty)
  - MithunR (https://github.com/mythrocks)

URL: rapidsai#1069
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

improvement Improves an existing functionality non-breaking Introduces a non-breaking change

Development

Successfully merging this pull request may close these issues.

5 participants