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

derive: Avoid emitting provided PartialEq, PartialOrd methods for c-like enums #31977

Merged
merged 3 commits into from
Mar 19, 2016

Conversation

bluss
Copy link
Member

@bluss bluss commented Feb 29, 2016

derive: Avoid emitting provided PartialEq, PartialOrd method for c-like enums

ne is completely symmetrical with the method eq, and we can save
rust code size and compilation time here if we only emit one of them
when possible.

One case where it's easy to recognize is when it's a C-like enum. Most
other cases can not omit ne, because any value field may have a custom
PartialEq implementation.

`ne` is completely symmetrical with the method `eq`, and we can save
rust code size and compilation time here if we only emit one of them
when possible.

One case where it's easy to recognize is when it's a C-like enum. Most
other cases can not omit ne, because any value field may have a custom
PartialEq implementation.
@rust-highfive
Copy link
Collaborator

r? @brson

(rust_highfive has picked a reviewer for you, use r? to override)

@bluss
Copy link
Member Author

bluss commented Feb 29, 2016

Using perf stat -r5 to measure compile time on a small test crate with 140 ten-variant enums (source).

  • Before: 2.54 seconds time elapsed ( +- 9,03% ) 2170,409698 task-clock (msec)
  • After: 1.55 seconds time elapsed ( +- 9,60% ) 1305,038461 task-clock (msec)

match item.node {
ItemKind::Enum(ref enum_def, _) => {
enum_def.variants.iter().all(|v|
if let VariantData::Unit(..) = v.node.data {
Copy link
Contributor

Choose a reason for hiding this comment

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

Unit is not necessary, zero fields would be enough.

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean, enum E { V {} } isn't considered "C-like", but it's still amenable to this derive optimization.

Copy link
Contributor

Choose a reason for hiding this comment

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

Also, #[derive(PartialEq)] for struct S;/struct S {} can be optimized too.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good points. I'll try to incorporate that. Do I need to pretend zero field tuple variants can exist (they are disallowed)?

Copy link
Contributor

Choose a reason for hiding this comment

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

derive can just use variant_data.fields().is_empty(), caring about empty tuple structs is not its responsibility.

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks for the pointer. I usually don't poke around in these parts!

@bluss
Copy link
Member Author

bluss commented Feb 29, 2016

Timing on src/libgraphviz (which has two enums that match this optimization)

libgraphviz debug build (perf stat -r20)

  • before 0,90 seconds time elapsed ( +- 3,18% )
  • after 0,76 seconds time elapsed ( +- 2,67% )

libgraphviz -O build (perf stat -r20)

  • before 1,72 seconds time elapsed ( +- 2,86% )
  • after 1,46 seconds time elapsed ( +- 4,07% )

as a control, librand (no enums match) debug build

  • before 1,53 seconds time elapsed ( +- 4,48% )
  • after 1,49 seconds time elapsed ( +- 3,64% )

@bluss
Copy link
Member Author

bluss commented Feb 29, 2016

Part of issue #31972

@brson
Copy link
Contributor

brson commented Feb 29, 2016

r=me

Great little optimization.

Also detect unit structs and enums with zero field struct variants.
@durka
Copy link
Contributor

durka commented Feb 29, 2016

Just for paranoia, did you confirm no runtime impact?

@bluss
Copy link
Member Author

bluss commented Feb 29, 2016

I didn't, I can try.

@bluss
Copy link
Member Author

bluss commented Feb 29, 2016

It's still the same. Testcase was just this microbenchmark though https://gist.github.com/bluss/ce593a7a75bd55896948

Using the same logic as for `PartialEq`, when possible define only
`partial_cmp` and leave `lt, le, gt, ge` to their default
implementations. This works well for c-like enums.
@bluss bluss changed the title derive: Avoid emitting PartialEq::ne for c-like enums derive: Avoid emitting provided PartialEq, PartialOrd method for c-like enums Mar 1, 2016
@bluss
Copy link
Member Author

bluss commented Mar 1, 2016

I did some tests using only the partial_cmp for a c-like enum versus the full ensemble partial_cmp, lt, le, gt, ge. It seems like there is no performance change.

So I added a commit to treat PartialOrd the same way, it has four methods we can let have just the default implementation. It saves a lot of code for an enum of many variants. However, PartialOrd is not at all as common as PartialEq.

Since the code is general for "enum or struct has no fields", it also affects unit structs, which are relatively common.

@bluss bluss changed the title derive: Avoid emitting provided PartialEq, PartialOrd method for c-like enums derive: Avoid emitting provided PartialEq, PartialOrd methods for c-like enums Mar 1, 2016
@brson
Copy link
Contributor

brson commented Mar 18, 2016

@bors r+

@bors
Copy link
Contributor

bors commented Mar 18, 2016

📌 Commit edcc02b has been approved by brson

@bluss
Copy link
Member Author

bluss commented Mar 18, 2016

Oh right thanks! I remember I didn't want to bother you with the PR during release rush.. two weeks ago.

@bors
Copy link
Contributor

bors commented Mar 18, 2016

⌛ Testing commit edcc02b with merge 02954ae...

bors added a commit that referenced this pull request Mar 18, 2016
derive: Avoid emitting provided PartialEq, PartialOrd methods for c-like enums

derive: Avoid emitting provided PartialEq, PartialOrd method for c-like enums

`ne` is completely symmetrical with the method `eq`, and we can save
rust code size and compilation time here if we only emit one of them
when possible.

One case where it's easy to recognize is when it's a C-like enum. Most
other cases can not omit ne, because any value field may have a custom
PartialEq implementation.
@bors bors merged commit edcc02b into rust-lang:master Mar 19, 2016
@bluss bluss deleted the partial-eq-save branch March 19, 2016 00:38
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.

6 participants