Skip to content
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

[RFC] Remove RefCell from builder arena #363

Closed

Conversation

marmeladema
Copy link
Contributor

Based on #362 so only the last commit is important here.

The usage of RefCell was noticeable in production flamegraphs I gathered and since it is not strictly required, this proposal attempts to remove it.

There are probably other ways but this way was pretty straightforward, even though, very invasive.

@marmeladema marmeladema force-pushed the arena-remove-refcell branch 4 times, most recently from 4270150 to 313d9b7 Compare January 11, 2023 22:39
@dwrensha
Copy link
Member

Wow, cool. Thanks! That RefCell has bothered me for a long time, but I had convinced myself somehow that removing it was infeasible.

Were you able to measure a performance improvement from this change? When I run the benchmarks in the repo, it looks like things slow down a bit.

$ cargo build --release -p benchmark
$ ./target/release/run_all_benchmarks ./target/release/benchmark

@marmeladema
Copy link
Contributor Author

I'll check the benchmarks tomorrow, thank you for pointing me in the right direction!
Are they time based? If so I am not sure I will get reproducible results on my machines. Frequency vary too much and too quickly, even with turbo boost disabled and core pinning.

@dwrensha
Copy link
Member

Yeah, the benchmarks in the repo just check the system clock before and after processing some randomized data.

@marmeladema
Copy link
Contributor Author

Not sure how reproducible my results are, but I tried running the benchmarks on Linux using the performance governor, with highest process priority on a mostly idle core.
The new code is consistently faster:

--- bench.master.log	2023-01-14 15:13:34.449673954 +0100
+++ bench.refcell.log	2023-01-14 15:10:17.616132232 +0100
@@ -1,71 +1,71 @@
 running carsales with 10000 iterations
 object none reuse
-0.274780196
+0.262815291
 
 object none no-reuse
-0.314452609
+0.290588508
 
 bytes none reuse
-0.323921303
+0.303009961
 
 bytes none no-reuse
-0.367289562
+0.337183638
 
 bytes packed reuse
-0.522327291
+0.483596268
 
 bytes packed no-reuse
-0.583030896
+0.543108862
 
 pipe none reuse
 exit status: 0
-0.379240224
+0.359025021
 
 pipe none no-reuse
 exit status: 0
-0.415696975
+0.391269543
 
 pipe packed reuse
 exit status: 0
-0.591989011
+0.561077035
 
 pipe packed no-reuse
 exit status: 0
-0.657493158
+0.633822245
 
 running catrank with 1000 iterations
 object none no-reuse
-0.650825717
+0.630079401
 
 bytes none no-reuse
-0.705408293
+0.674896325
 
 bytes packed no-reuse
-0.943492149
+0.844120619
 
 pipe none no-reuse
 exit status: 0
-0.781824298
+0.73111535
 
 pipe packed no-reuse
 exit status: 0
-0.971964107
+0.939981865
 
 running eval with 200000 iterations
 object none no-reuse
-0.704358592
+0.633409412
 
 bytes none no-reuse
-0.841810654
+0.786843015
 
 bytes packed no-reuse
-1.291954872
+1.207431156
 
 pipe none no-reuse
 exit status: 0
-1.626859737
+1.523820484
 
 pipe packed no-reuse
 exit status: 0
-2.016225853
+1.960986856

// have lifetime issues. (If `'a: 'b`, then a `&'a (BuilderArena + 'a)` can be
// converted to a `&'b (BuilderArena + 'b)`, but a `&'a mut (BuilderArena + 'a)`
// *cannot* be converted to a `&'b mut (BuilderArena + 'b)`. See some discussion here:
// https://botbot.me/mozilla/rust/2017-01-31/?msg=80228117&page=19 .)
Copy link
Member

Choose a reason for hiding this comment

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

Ah, so this comment captures the reason why I thought that the RefCell was necessary. (I updated it for dyn and reborrow here: 5ad7849.)

I wonder what changed so that this is now possible? Or maybe I was mistaken all along?

Copy link
Member

Choose a reason for hiding this comment

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

Wow, this failed in Rust 1.62: https://godbolt.org/z/4j354zad3
and started working in Rust 1.63: https://godbolt.org/z/3hv5x3vrK

I'm a little bit worried that this means that the borrowchecker is now unsound! But if it's not, then this is good news for us, because it will let us make these methods take &mut self and therefore let us remove the RefCell.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think this is because NLL has been fully stabilized in 1.63.0: https://blog.rust-lang.org/2022/08/05/nll-by-default.html

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looking at the code, I don't see any obvious reasons it should not compile or can be unsound.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can probably ask t-types team on zulip for a confirmation?

Copy link
Member

Choose a reason for hiding this comment

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

Ah, and according to the referece (https://doc.rust-lang.org/reference/subtyping.html#variance),

dyn Trait<T> + 'a is "covariant" in 'a. Pre-NLL it was "invariant", if I understand correctly.

Copy link
Member

Choose a reason for hiding this comment

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

Actually, I can get my little example to typecheck on an even older rustc (e.g. 1.30) if I avoid the ..*self syntax:
https://godbolt.org/z/8EGx4v3zK

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If I understand correctly, 1.63.0 just made it work with the ..*self syntax, but it was working before using regular field assignment. So arguably, we could have introduced such code before 1.63.0 and get rid of RefCell already.

So answering your first question from zulip:

Can I rely on this continuing to typecheck? I'd like to migrate a bunch of my code to depend on this, because I had been working around it previously.

Unless there is something inherently unsound about accepting this pattern; I fail to see why the compiler would suddenly reject it. That code has been working for years and such pattern is probably used in various places; so rejecting it would be tricky.

Given all of this, do you see any blocker that would prevent merging this?

Copy link
Member

Choose a reason for hiding this comment

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

I want to convince myself it's not unsound first. :)

I think this PR should be considered a breaking change and that we should do a version bump soon including it and some of the other stuff that's been waiting on a version bump.

@dwrensha
Copy link
Member

dwrensha commented Jan 16, 2023

Superseded by #365.

@dwrensha dwrensha closed this Jan 16, 2023
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.

2 participants