perf: Don't hash the full (byte) string for Symbol interner if it's long - #162529
panstromek wants to merge 6 commits into
Conversation
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
[experiment] don't hash the full (byte) string for Symbol Interner if it's long
|
@bors try cancel This will not work, I didn't realize end index has to be inbounds |
|
Try build cancelled. Cancelled workflows: Hint: if you want to run another try build, you do not need to manually cancel the previous one. Just run |
This comment has been minimized.
This comment has been minimized.
|
@bors try |
This comment has been minimized.
This comment has been minimized.
[experiment] don't hash the full (byte) string for Symbol Interner if it's long
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (2ed7127): comparison URL. Overall result: ✅ improvements - no action neededBenchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. @bors rollup=never rustc-perf Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary 1.3%, secondary 2.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary -0.4%, secondary -1.9%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.0%, secondary 0.0%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 481.923s -> 485.241s (0.69%) |
|
@bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
[experiment] don't hash the full (byte) string for Symbol Interner if it's long
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (c0c7b04): comparison URL. Overall result: ❌✅ regressions and improvements - please read:Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. Next, please: If you can, justify the regressions found in this try perf run in writing along with @bors rollup=never rustc-perf Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary -0.4%, secondary 2.1%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary -0.3%, secondary -0.0%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeResults (primary 0.0%, secondary 0.0%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Bootstrap: 480.225s -> 481.543s (0.27%) |
|
Heh, I tried the same idea in Firefox during the Obama administration. I was looking at the first 1,000 bytes (16-64 bytes feels way too small) and in the end I decided against it because it felt not quite right and pathological inputs could lead to performance disaster. In the rustc context it also feels like it's specializing too much for a single unusual benchmark. |
😄 interesting choice of timestamp format I'll add for context that one motivation at the moment is that this also drastically reduces |
|
Let's try 128. I want to have another CI build for stress testing, and 128 is another intersting boundary because it should be enough to contain most doc comments (doc comments go over 64 bytes fairly often). @bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
perf: Don't hash the full (byte) string for Symbol interner if it's long
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (9eafee5): comparison URL. Overall result: ❌✅ regressions and improvements - please read:Benchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. Next, please: If you can, justify the regressions found in this try perf run in writing along with @bors rollup=never rustc-perf Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary -1.1%, secondary 0.4%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary 0.5%, secondary -4.0%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 493.042s -> 493.985s (0.19%) |
|
I'm a bit suspicious of the regressions in the run above. They look related to symbol interning, but something feels off to me. Anyway, let's try the (assumed) safe limit of 1kb. @bors try @rust-timer queue |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
perf: Don't hash the full (byte) string for Symbol interner if it's long
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking commit (d045a7d): comparison URL. Overall result: ✅ improvements - no action neededBenchmarking means the PR may be perf-sensitive. It's automatically marked not fit for rolling up. Overriding is possible but disadvised: it risks changing compiler perf. @bors rollup=never rustc-perf Instruction countOur most reliable metric. Used to determine the overall result above. However, even this metric can be noisy.
Max RSS (memory usage)Results (primary -0.5%)A less reliable metric. May be of interest, but not used to determine the overall result above.
CyclesResults (primary -0.2%, secondary -3.6%)A less reliable metric. May be of interest, but not used to determine the overall result above.
Binary sizeThis perf run didn't have relevant results for this metric. Bootstrap: 493.58s -> 494.498s (0.19%) |
|
Can you try generating a pathological case and see how badly it performs? Also, I wonder if hashing the first 1k and last 1k is a good idea. Seems like if there are lots of long almost equal strings that the distinguishing characters might be at the end. |
Yes, it's on my todo list. I want to get an idea how it behaves and I haven't found a notable change in crates I've tried so far. It looks like crates that have a lot of symbols also have a ton of other stuff going on, so any change in Symbol interning is barely visible. |
When investigating
include-blobbimodailty, I noticed that we hash the whole included blob (31MB) and every other string that we intern no matter the length. This intuitively seems a bit wasteful - simply speaking, I can't imagine that after 15MB of hashing, we get a meaningful hash quality improvement with 15MB more. This is in the spirit of the comment inrustc-hashreadme:This PR changes the code to only hash the first
Nbytes (more onNlater). The assumption (and intuition) behind this is:Nbytes (+length)eqcheck is very cheap, so it doesn't make that much sense to guard against that collision by computing very expensive hash of the whole string.lenis the same, we can probably assume that the unequal byte occurs pretty early anyway, so similar argument appliesAbout the specific
N, I tried to measure a few options in this PR, mostly picked by intuitioninclude-blobimprovements, some regressions, not sure if relevanthash_bytesin FxHasher, so I wanted to try whether it makes a difference if we always use only that code path (and LLVM could optimize the other branch out)I'm still not 100% confident about picking the number, though, because I'm not sure we have crates in the benchmark suite that would stress the Symbol interner a lot, so I see a few paths to go from here:
just merge with 64 limit and hope for the best 🤞
pick a fairly high "safe choice" (e.g. 1kb) for now
include-blob, but it should rarely affect anything elsefind some crates that stress this code a lot and measure on them
r? nnethercote
I want to know what you think, because you worked on this a lot, or if you have recommendations for crates to test this on. I'll squash and clean it up based on what we decide to do.
View all comments