Skip to content

Add optimized grow()/shrink() functions to Allocator implementation for pool #191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ensh63
Copy link
Contributor

@ensh63 ensh63 commented Aug 15, 2025

Proposed changes

If resizing is requested for the last allocation in the pool, it may be possible to adjust pool data and avoid any real allocations.

Checklist

Before creating a PR, run through this checklist and mark each as complete.

  • I have written my commit messages in the Conventional Commits format.
  • I have read the CONTRIBUTING doc
  • I have added tests (when possible) that prove my fix is effective or that my feature works
  • I have checked that all unit tests pass after adding my changes
  • I have updated necessary documentation
  • I have rebased my branch onto main
  • I will ensure my PR is targeting the main branch and pulling from my branch from my own fork

Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements optimized grow() and shrink() functions for the Pool allocator that can avoid real allocations when resizing the last allocation in the pool by simply adjusting the pool's last pointer.

  • Adds grow() method that can expand the last allocation in-place if there's sufficient space
  • Adds shrink() method that can contract the last allocation in-place by moving the pool's last pointer backward
  • Falls back to allocate-copy-deallocate pattern when in-place resizing isn't possible

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

src/core/pool.rs Outdated
old_layout.size(),
);
self.deallocate(ptr, old_layout);
}
Copy link
Preview

Copilot AI Aug 15, 2025

Choose a reason for hiding this comment

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

Redundant unsafe block: the entire function is already declared as unsafe, so this inner unsafe block is unnecessary.

Suggested change
}
ptr::copy_nonoverlapping(
ptr.as_ptr(),
new_ptr.as_ptr().cast(),
old_layout.size(),
);
self.deallocate(ptr, old_layout);

Copilot uses AI. Check for mistakes.

Copy link
Contributor

@pchickey pchickey Aug 15, 2025

Choose a reason for hiding this comment

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

The right fix is to upgrade the crate to edition 2024, where the code, as written, is required by rustc.

src/core/pool.rs Outdated
old_layout.size(),
);
self.deallocate(ptr, old_layout);
}
Copy link
Preview

Copilot AI Aug 15, 2025

Choose a reason for hiding this comment

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

Redundant unsafe block: the entire function is already declared as unsafe, so this inner unsafe block is unnecessary.

Suggested change
}
ptr::copy_nonoverlapping(
ptr.as_ptr(),
new_ptr.as_ptr().cast(),
old_layout.size(),
);
self.deallocate(ptr, old_layout);

Copilot uses AI. Check for mistakes.

Copy link
Contributor

@xeioex xeioex left a comment

Choose a reason for hiding this comment

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

Some minor nitpicks, for the commit log
Making the commit log shorter and adding a new line for the body.

`feat: Add optimized grow()/shrink() functions for Pool

If resizing is requested for the last allocation in the pool, it may be
possible to adjust pool data and avoid any real allocations.`

?

Otherwise looks good.

@bavshin-f5
Copy link
Member

  1. What about Allocator::grow_zeroed?
  2. new_layout.size() >= old_layout.size() is a safety requirement of the Allocator::grow interface. It is acceptable to assume that the opposite never happens and limit handling of this case to debug_assert.
  3. old_layout.size() == new_layout.size() does not guarantee that old_layout == new_layout.
  4. It seems to me that all 3 methods could be generalized to
    #[inline(always)]
    fn resize_in_place(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> Option<NonNull<[u8]>> { ... }
    
    fn grow(...) {
         ...
         if let Some(new_ptr) = self.resize_in_place(...) {
             Ok(new_ptr)
          } else {
              ...
          }
    }

@ensh63 ensh63 force-pushed the shirykalov/alloc branch 2 times, most recently from 5009a7a to 22992a9 Compare August 16, 2025 00:00
If resizing is requested for the last allocation in the pool, it may be
possible to adjust pool data and avoid any real allocations.
ptr::write_bytes(
new_ptr.as_ptr().cast::<u8>().byte_add(new_layout.size()),
0,
old_layout.size() - new_layout.size(),
Copy link
Contributor

Choose a reason for hiding this comment

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

if new_layout.size() >= old_layout.size()

old_layout.size() - new_layout.size() will be negative?

Copy link
Contributor

Choose a reason for hiding this comment

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

ptr::write_bytes(
    new_ptr.as_ptr().cast::<u8>().add(old_layout.size()),  // Start at end of old data
    0,
    new_layout.size() - old_layout.size(),  // Zero the NEW bytes
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Optimize Allocator::grow and Allocator::shrink for the last allocation in ngx_pool_t.
4 participants