-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Improve sort buffer sizing heuristics and honor explicit --buffer-size #8833
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
base: main
Are you sure you want to change the base?
Conversation
GNU testsuite comparison:
|
GNU testsuite comparison:
|
GNU testsuite comparison:
|
GNU testsuite comparison:
|
you have to refresh the fuzz/Cargo.lock file |
GNU testsuite comparison:
|
please follow this documentation for the performance work: We would like to see hyperfine results and codspeed benchmark :) |
src/uu/sort/src/sort.rs
Outdated
.filter(|s| matches!(s.settings.mode, SortMode::GeneralNumeric)) | ||
.count(); | ||
|
||
self.precomputed.fast_lexicographic = self.mode == SortMode::Default |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it needs comments, and moved into a function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
let file_hint = file_size_hint(files); | ||
let mem_hint = available_memory_hint(); | ||
|
||
match (file_hint, mem_hint) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the cases need comments here
it is a bit cryptic
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now pattern-matches file_size_hint and available_memory_hint, selecting the smaller of the two when both are present. If only one hint is available, it uses that; when neither is available, it falls back to FALLBACK_AUTOMATIC_BUF_SIZE.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Comment in the code, not here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/uu/sort/src/sort.rs
Outdated
quarter.max(max) | ||
} | ||
|
||
#[cfg(target_os = "linux")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i was already not convinced in #8802
but
there is probably a better way than parsing /proc/meminfo
esp in the sort.rs code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented it using a different method
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I said it in the other pr but it does not belong to sort but uucore
And maybe we already have such functions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it total_physical_memory? Does it perform the same processing?
Is it acceptable to modify uucore to add available memory?
} | ||
} | ||
|
||
fn ascii_case_insensitive_cmp(a: &[u8], b: &[u8]) -> Ordering { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is that necessary ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/uu/sort/src/sort.rs:1931 adds ascii_case_insensitive_cmp in commit da5bd03 (2025-10-06 “fix”) so the new fast_ascii_insensitive path in compare_by can bypass the heavier general comparator and deliver a cheap ASCII fold when sort -f-style settings allow it.
src/uu/sort/src/sort.rs:1934 is tweaked one commit later (5fe2b48, also “fix”) to use to_ascii_lowercase, relying on the standard helper for clarity and correct handling of non-uppercase bytes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand what your Ai wrote here, sorry
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strcasecmp is affected by locale settings, so we implemented it separately.
Should we use strcasecmp?
path: Option<PathBuf>, | ||
} | ||
|
||
fn handler_state() -> Arc<Mutex<HandlerRegistration>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.clone() | ||
} | ||
|
||
fn ensure_signal_handler_installed(state: Arc<Mutex<HandlerRegistration>>) -> UResult<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same, it needs some explanations
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensures the SIGINT handler for sort is registered only once via an AtomicBool, shares the current temp-dir lock/path through a global HandlerRegistration so the handler can safely delete the directory and exit, and resets the flag plus surfaces a localized error if handler setup fails; commits b3b721f (introducing this stateful handler) and 5fe2b48 (cleanup of the returned error) capture the change.
CodSpeed Performance ReportMerging #8833 will degrade performances by 2.69%Comparing Summary
Benchmarks breakdown
Footnotes
|
impressive wins :) |
Replaced fixed 1GB buffer size with dynamic calculation based on input file sizes and available memory. Added heuristics to clamp buffer size within 512 KiB to 128 MiB range, preventing overcommitment on constrained systems while optimizing for typical workloads. Updated dependencies and imports to use libc directly for better portability.
- Add sysconf to codespell ignore list to prevent false positives - Remove "NOTE:" from buffer heuristics comment for cleaner style
587a73c
to
287d6c4
Compare
GNU testsuite comparison:
|
Modified conditional compilation in physical_memory_bytes() to skip Unix-specific sysconf calls on Redox OS, ensuring compatibility by returning None for unsupported platforms.
GNU testsuite comparison:
|
GNU testsuite comparison:
|
GNU testsuite comparison:
|
please try to avoid commit messages like "fix" |
The getrlimit function call in the sort module was missing the libc prefix, which could lead to compilation errors. Added the libc:: qualifier to ensure proper function resolution and maintain code clarity.
src/uu/sort/src/sort.rs
Outdated
use fnv::FnvHasher; | ||
#[cfg(target_os = "linux")] | ||
use nix::libc::{RLIMIT_NOFILE, getrlimit, rlimit}; | ||
use libc::{RLIMIT_NOFILE, rlimit}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was more here. why do you move to libc ?
what was wrong with nix ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I was using libc elsewhere, I thought it would be better to match that, but the original code is better.
Switch from direct libc import to nix::libc for the getrlimit function to leverage the nix crate's safer Unix API abstractions, improving portability and maintainability.
Removed the unused `getrlimit` function from the nix libc imports in sort.rs to clean up the code and eliminate dead imports.
GNU testsuite comparison:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
・Add comment
・Change to Nix
path: Option<PathBuf>, | ||
} | ||
|
||
fn handler_state() -> Arc<Mutex<HandlerRegistration>> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
} | ||
} | ||
|
||
fn ascii_case_insensitive_cmp(a: &[u8], b: &[u8]) -> Ordering { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/uu/sort/src/sort.rs:1931 adds ascii_case_insensitive_cmp in commit da5bd03 (2025-10-06 “fix”) so the new fast_ascii_insensitive path in compare_by can bypass the heavier general comparator and deliver a cheap ASCII fold when sort -f-style settings allow it.
src/uu/sort/src/sort.rs:1934 is tweaked one commit later (5fe2b48, also “fix”) to use to_ascii_lowercase, relying on the standard helper for clarity and correct handling of non-uppercase bytes.
.clone() | ||
} | ||
|
||
fn ensure_signal_handler_installed(state: Arc<Mutex<HandlerRegistration>>) -> UResult<()> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ensures the SIGINT handler for sort is registered only once via an AtomicBool, shares the current temp-dir lock/path through a global HandlerRegistration so the handler can safely delete the directory and exit, and resets the flag plus surfaces a localized error if handler setup fails; commits b3b721f (introducing this stateful handler) and 5fe2b48 (cleanup of the returned error) capture the change.
let file_hint = file_size_hint(files); | ||
let mem_hint = available_memory_hint(); | ||
|
||
match (file_hint, mem_hint) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
now pattern-matches file_size_hint and available_memory_hint, selecting the smaller of the two when both are present. If only one hint is available, it uses that; when neither is available, it falls back to FALLBACK_AUTOMATIC_BUF_SIZE.
src/uu/sort/src/sort.rs
Outdated
quarter.max(max) | ||
} | ||
|
||
#[cfg(target_os = "linux")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented it using a different method
src/uu/sort/src/sort.rs
Outdated
use fnv::FnvHasher; | ||
#[cfg(target_os = "linux")] | ||
use nix::libc::{RLIMIT_NOFILE, getrlimit, rlimit}; | ||
use libc::{RLIMIT_NOFILE, rlimit}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since I was using libc elsewhere, I thought it would be better to match that, but the original code is better.
I have doubt about the memory functions being in sort itself. Should be in uucore if we already don't have any. Also please keep in mind that you are writing to a human. If I want an Ai explaining me things, I can do it myself :) |
…cations This change modifies the buffer size handling in the external sort functionality to halve requests exceeding 512MiB, reducing memory usage and avoiding potential allocation issues.
Removed the `nix::libc::` prefix from the `getrlimit` function call in `get_rlimit()`, likely to use a direct import from `libc` for cleaner code and reduced dependency specificity.
Added a comment and updated the match logic in `automatic_buffer_size` to prefer the minimum of file and memory hints when both are available, ensuring a more conservative buffer size estimate for better performance and resource management.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added comments to the source code.
let file_hint = file_size_hint(files); | ||
let mem_hint = available_memory_hint(); | ||
|
||
match (file_hint, mem_hint) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
src/uu/sort/src/sort.rs
Outdated
quarter.max(max) | ||
} | ||
|
||
#[cfg(target_os = "linux")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it total_physical_memory? Does it perform the same processing?
Is it acceptable to modify uucore to add available memory?
} | ||
} | ||
|
||
fn ascii_case_insensitive_cmp(a: &[u8], b: &[u8]) -> Ordering { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strcasecmp is affected by locale settings, so we implemented it separately.
Should we use strcasecmp?
Added `getrlimit` to the nix::libc imports in sort.rs to enable checking resource limits, likely for handling file descriptor limits on Linux systems.
…eutils into sort_performan-ce
GNU testsuite comparison:
|
- Moved `available_memory_bytes` function from `src/uu/sort/src/sort.rs` to `src/uucore/src/lib/features/parser/parse_size.rs` to centralize memory parsing logic in the core library. - Updated the function to read `/proc/meminfo` more robustly using a new helper `parse_meminfo_line`, improving accuracy and modularity for better code reuse across utilities.
move memory functions to uucore |
Add automatic buffer-size heuristics (ported from commit a0e77d9). We now size external-sort chunks based on input file sizes and available memory, clamping to 512 KiB–128 MiB so we avoid both tiny buffers and risky overcommit on constrained systems.
Respect user-provided --buffer-size. Only automatically computed sizes are raised to the safety minimum; explicit values are left untouched, which keeps external sorting and --compress-program working even when users choose small buffers.
Performance Comparison (baseline vs. current)
Measurements come from hyperfine --warmup 3 --runs 10; values are means in milliseconds (lower is better).