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

Abbreviation parsing performance improvements #451

Merged
merged 3 commits into from
Nov 20, 2019

Conversation

philipc
Copy link
Collaborator

@philipc philipc commented Nov 19, 2019

Reduce the size of abbreviations, and store them in a SmallVec.

 name                                                       before ns/iter  after ns/iter  diff ns/iter   diff %  speedup 
 bench_parsing_debug_abbrev                                 21,492          11,008              -10,484  -48.78%   x 1.95 
 bench_parsing_debug_info                                   1,352,849       1,234,978          -117,871   -8.71%   x 1.10 
 bench_parsing_debug_info_tree                              1,417,695       1,259,731          -157,964  -11.14%   x 1.13 
 bench_parsing_debug_info_with_endian_rc_slice              2,136,618       1,982,039          -154,579   -7.23%   x 1.08 

@philipc philipc requested a review from fitzgen November 19, 2019 10:01
@coveralls
Copy link

Coverage Status

Coverage decreased (-0.05%) to 86.866% when pulling 33ae1b3 on philipc:abbrev-perf into d15d65e on gimli-rs:master.

Copy link
Member

@fitzgen fitzgen left a comment

Choose a reason for hiding this comment

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

LGTM with a small comment about choosing the number of inline elements.

Thanks!

@@ -173,14 +174,16 @@ impl Abbreviations {
}
}

type Attributes = SmallVec<[AttributeSpecification; 6]>;
Copy link
Member

Choose a reason for hiding this comment

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

Because SmallVec always has a capacity: usize regardless of if the elements are inline or on the heap, I think that 4 u16s will be the same size as a regular Vec on 32-bit but we can go up to 8 u16s on 64-bit. Did you choose 6 based on some profiling or anything like that? If not, I think it makes sense to use the most inline elements we can without bloating the structure.

FWIW, we can assert the sizes at compile like this:

const SIZE_IS_SAME: bool = mem::size_of::<Attributes>() == mem::size_of::<Vec<AttributeSpecification>>();
const _ASSERT_SIZE_IS_SAME: () = [()][!SIZE_IS_SAME as usize];

As a practicality, I'd suggest only doing this for 64-bit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I chose 6 based on the benchmark results. However, after repeating the benchmarks for i686, I think 5 is a better number that works for both x86-64 and i686.

Regarding the rest of your comment:

  • AttributeSpecification is 12 bytes with an 8 byte alignment, so effectively 16 bytes (it seems like you thought it was only u16?) The implicit_const_value is taking up a lot of space here for something that is rarely used.
  • The goal isn't to use the same inline size as a Vec. That would be true if we are simply trying to minimize memory usage, but in this case we are trying to find the tradeoff that is best for performance. Since most abbreviations are relatively small, we can make the inline size larger while still using the same average memory as the Vec, and benefiting from avoiding the heap indirection.

Copy link
Member

Choose a reason for hiding this comment

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

(Note, I'm just clarifying my original comment, not arguing against the chosen number here. As I already said, my comments regarding number of inline elements were qualified on not having done extensive profiling of number of inline elements yet.)

* The goal isn't to use the same inline size as a `Vec`.

I should have said "same size as the smallvec's heap variant's data" which, unless I am missing something, is the same size as a regular Vec once you add the capacity. I was thinking, "how many inline elements can we fit without making the SmallVec bigger than it needs to be to represent the elements-in-the-heap variant?"

Anyways, it seems the question is moot!

Copy link
Member

Choose a reason for hiding this comment

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

* (it seems like you thought it was only `u16`?)

Yes, also true; I misread!

The standard does not allow larger values, even for user defined values.
@philipc philipc merged commit b9c63a0 into gimli-rs:master Nov 20, 2019
@philipc philipc deleted the abbrev-perf branch January 10, 2020 05:32
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.

None yet

3 participants