Repository navigation
Conversation
|
rustbot has assigned @Mark-Simulacrum. Use Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
1627e2f to
33e69e1
Compare
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
33e69e1 to
ed9d33d
Compare
This comment has been minimized.
This comment has been minimized.
ed9d33d to
0b0f84c
Compare
This comment has been minimized.
This comment has been minimized.
0b0f84c to
8ed33ea
Compare
This comment was marked as outdated.
This comment was marked as outdated.
2151b8f to
83cdbed
Compare
This comment was marked as outdated.
This comment was marked as outdated.
83cdbed to
3921fff
Compare
0a25dda to
92e0132
Compare
|
New benchmarking results. You can see what the benchmark code looks like here and run it yourself to see if there are any difference in measurements on your end: This is the measurement of the current implementation of This is the measurement of the new implementation of Edit: Updated |
|
Here are the benchmark results with black box: From current From this Edit: Updated Edit 2: Took off Path ordering benchmark here since it was incorrect see below to see corrected path ordering benchmarks. |
92e0132 to
574d7f2
Compare
|
I'm confident this code works (passed CI in previous run, the current amended commit change I made doesn't change logic, but makes the code written in a more idiomatic way). In my opinion, the logic in this code should look more readable than how |
|
@rustbot label +I-libs-nominated Since |
This comment has been minimized.
This comment has been minimized.
|
💔 Test for 86c1566 failed: CI. Failed job:
|
|
@bors try jobs=test-x86_64-msvc-,test-i686-msvc,test-aarch64-msvc- |
This comment has been minimized.
This comment has been minimized.
Split `Components` iterator to prefixed and non-prefixed versions and optimize `Components` for non-prefix path based platforms try-job: test-x86_64-msvc-* try-job: test-i686-msvc try-job: test-aarch64-msvc-*
|
@rustbot ready |
… of mutating and subslicing path field; as a result, Components iterator memory size goes from 64 bytes to 40 bytes and as_path does not use cloning at all
…ity, added safety comments, and check for root dir after Prefix component (e.g., '\\?\checkout\src\tools' should produce Prefix, RootDir, Normal, Normal, None, ...) in Components::parse_single_component
…ng iter().position()/rposition()
…here to use iter().position()/.iter().rposition(), refactored code in compare_components, and removed stale comments
…omponents::normalize_back instead, refactored Components::as_path code
…e in previous implementation, but making it work with Components<'_> front index
…nt_front and consume_first_component_back. Also introduced aggressive inlining.
…comparison (normalizing paths if needed) and return Ordering Equal/Greater/Less if possible before needing to fall back on Iterator::cmp
… make it simpler or have it documented in the appropriate areas, and renamed a couple of methods/field members, and simplified Components::next_back relative first component branch
…yte equality and Iterator::eq directly. Co-authored-by: =?UTF-8?q?=E7=A6=BE=E5=8F=AF?= <chengkelfan@qq.com>
…path check to Components/Path equality by finding first mismatched byte, separated Components iterator into different versions and re-exported them accordingly based on target os. This also ends up removing HAS_PREFIXES because it becomes unused.
…rtialOrd implementation for non-prefixed Components via directly comparing mismatched byte if it's not a separator byte or cur dir byte; refactor while loop code to use iter().enumerate().find() instead
…e conditional style code rather than match cases (degrades Components::next_back for some reason)
…zes away trailing separator bytes and non-starting current directory component a well as added Components::is_sep_byte for nonprefixed_path.rs
…t.path == right.path in the future
0aa1bf8 to
c3ba843
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
View all comments
This PR fixes #154521 specifically for Unix/non-prefixed platforms. By non-prefixed filepath platforms this includes:
all(target_vendor = "fortanix", target_env = "sgx")not(any(target_os = "cygwin", target_os = "uefi", target_os = "solid_asp3", target_os = "windows")(the default/fallback_path insys/path/mod.rs, which notably includes Unix platforms)For every other prefixed filepath platforms (notably Windows), the
Componentsiterator implementation remains largely unchanged (just some minor refactoring).The point of the non-prefixed
Componentsimplementation is to:Prefixcomponents that Windows/other prefixed-based filepath platform use as Unix-based platforms do not have those prefix components in their filepaths;Componentsiterator traversal algorithm as well as improvePathequality andPathcomparisonFrom benchmarking, I noticed that all the
Prefixchecking/returning code specific for Windows affects howComponentsperform on Unix, though to be fair, part of the reason that is the case is because thePrefixenum takes up 40 bytes to represent (which we shouldn't want Unix to take the consequence of handlingPrefix). There are other factors in the currentComponents::next/Components::next_backimplementation that could've been optimized better or written in a way that would enable the compiler to optimize that code better (e.g. autovectorization optimizations). It's certainly possible that the prefixed/currentComponentsimplementation could be enhanced to make performance better on Windows, but I will leave that to someone who can verifiably test and benchmark those changes on Windows.In terms of the optimizations I made for the non-prefixed
Components, a smaller one I could talk about first is that the size ofComponentshas been reduced. In the current/originalComponentswe have this:This overall takes up 64 bytes to represents
ComponentsNow, without the need to account for
Prefix, we can simplify theComponentsstruct to:This prefix-less
Componentstakes up 24 bytes to represent.Implementation-wise,
Components::nextandComponents::next_backtakes a similar approach to the originalComponentsiterator by subslicing thepathfield to present the left over unconsumed path. However, one of the key differences with thisComponents::nextandComponents::next_backis that we normalize away in between and trailing separator + cur dir bytes after parsing the component (e.g. "foo///bar", when we parse "foo" viaComponents::nextor "bar" viaComponents::next_back", the in between separator bytes will be subsliced from thepathfield in preparation for the nextComponents::next/Components::next_back). Normalizing away these bytes in preparation for the nextComponents::next/Components::next_backwere not done in the original implementation, which meant thatwhile !self.is_finishedloop in the original ran through multiple iterations to actually normalize away those separator bytes and find the next component to parse. Moreover, I relied on iterator methods to make that normalization process really fast, as it appears to be autovectorized and optimized really well by the compiler. Also noteworthy is that the optimization made to normalizing away in between/trailing separator/cur dir bytes using iterator methods enhances the performance ofComponents::as_pathsignificantly.As for
Pathequality andPathcomparison, which largely rely onComponentsunderneath the hood, there are many optimizations we introduce there to increase performance.Starting with
Pathequality, we check for the following:Paths when converted as anOsStrs are equal. If so, we can just return true immediately. Otherwise, we have to hinge onComponents(e.g. of "/foo" is equivalent to "/foo/").Componentsstatefield to determine if we're looking at an empty path (reading 1 byte via theState::Doneenum rather than directly looking at each path's length)Componentspath field and just rely onComponents::next_backto handle the rest on determining whether the two paths are equivalent or not.As for
Pathcomparison, we do the following:Ordering::Equalimmediately.Ordering::GreaterorOrdering::Lessas appropriate).Componentspath field and just rely onComponents::nextto handle the rest on determining whether to returnOrdering::Equal,Ordering::Less, orOrdering::Greater.Componentsimplementation, so this code/idea was just taken from there.All of these enhances the performance of
Pathequality and comparison significantly, which you can see from benchmarking results.Regarding benchmarking, I did all benchmarking and experimentation on this
Componentsimplementation within a separate repository. You can take a look here to see the raw and markdown formatted results and the methodology I chose to go about benchmarking thisComponentsiterator implementation.