Skip to content

Update Iterator::eq implementation for better performance #44729

Closed
@bluss

Description

@bluss
Member

The itertools equal function expresses the same functionality as Iterator::eq in a way that compiles better / performs better. Import their implementation into libstd, also see if other iterator comparison functions can be improved.

The problem could be that the libstd code is using match on a tuple of options.

Activity

added
C-bugCategory: This is a bug.
E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.
E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.
I-slowIssue: Problems and improvements with respect to performance of generated code.
T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.
on Sep 20, 2017
bluss

bluss commented on Sep 20, 2017

@bluss
MemberAuthor

The itertools code is not the end station of course, there could be improvements on top of that.

mister-walter

mister-walter commented on Sep 21, 2017

@mister-walter

I'd like to take a shot at this - I'll go check out Gitter when I have time later today (I'm currently on JST)

lezgomatt

lezgomatt commented on Oct 1, 2017

@lezgomatt
Contributor

hey @mister-walter, are you still interested in working on this? If not, I'd like to give this issue a try 😃

bluss

bluss commented on Oct 1, 2017

@bluss
MemberAuthor

Feel free to find me on irc or here

mister-walter

mister-walter commented on Oct 1, 2017

@mister-walter
lezgomatt

lezgomatt commented on Oct 1, 2017

@lezgomatt
Contributor

Awesome, thanks!

I tried a few approaches out and it seems that the matching on the tuples does indeed cause slower code to be generated (best on some quick benchmarking).

The current implementation does the ff:

loop {
    match (self.next(), other.next()) {
        (None, None) => return true,
        (None, _) | (_, None) => return false,
        (Some(x), Some(y)) => if x != y { return false },
    }
}

Modifying the code to separate the matching resulted in some nice gains:

loop {
    match self.next() {
        None => return other.next().is_none(),
        Some(x) => match other.next() {
            None => return false,
            Some(y) => if x != y { return false },
        },
    };
}

Alternatively (to reduce nesting):

loop {
    let x = match self.next() {
        None => return other.next().is_none(),
        Some(val) => val,
    };

    let y = match other.next() {
        None => return false,
        Some(val) => val,
    };

    if x != y {
        return false;
    }
}

I haven't taken a good look at the MIR generated though. I also tested it out on the other comparison functions and noticed similar gains. I'll try to take a deeper look at the code generated soon.

bluss

bluss commented on Oct 1, 2017

@bluss
MemberAuthor

Oh nice, the new versions are side-effect compatible as well right? self.next() and other.next() are called exactly as many times as before.

11 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-bugCategory: This is a bug.E-easyCall for participation: Easy difficulty. Experience needed to fix: Not much. Good first issue.E-mentorCall for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.I-slowIssue: Problems and improvements with respect to performance of generated code.T-libs-apiRelevant to the library API team, which will review and decide on the PR/issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @carols10cents@andjo403@Manishearth@mister-walter@bluss

        Issue actions

          Update Iterator::eq implementation for better performance · Issue #44729 · rust-lang/rust