Skip to content

[SR-10682] Swift master, ARC performance regression #53080

@weissi

Description

@weissi
Previous ID SR-10682
Radar rdar://50956754
Original Reporter @weissi
Type Bug
Status Resolved
Resolution Done

Attachment: Download

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, ARC, Optimizer, Performance
Assignee None
Priority Medium

md5: 208e526eb5c9a104ccd7933ca893207e

relates to:

  • SR-10709 Swift needs allocation counter tests

Issue Description:

Attached is cp_perf.swift which is basically "SwiftNIO in a box". Not really but it contains an approximate implementation of NIO's ChannelPipeline. Something I'm just about to optimise. Whilst doing that I just noticed, that Swift master makes it a lot slower!

Repro:

$ jw-swift-5.0 swiftc -Ounchecked cp_perf.swift && time ./cp_perf

real    0m2.858s
user    0m2.839s
sys 0m0.009s
johannes:~/devel/pipeline-optimisation (master)
$ jw-swift-5.1 swiftc -Ounchecked cp_perf.swift && time ./cp_perf

real    0m2.758s
user    0m2.748s
sys 0m0.005s
johannes:~/devel/pipeline-optimisation (master)
$ jw-swift-latest swiftc -Ounchecked cp_perf.swift && time ./cp_perf

real    0m5.098s
user    0m5.067s
sys 0m0.007s

As you can see, the attached file runs in 2.8s for 5.0 and 5.1 but takes 5s on a recent snapshot.

The concrete versions are (all OSS toolchains):

  • 5.0-RELEASE

  • 5.1-DEVELOPMENT-SNAPSHOT-2019-05-09-a

  • DEVELOPMENT-SNAPSHOT-2019-05-12-a

Why?

Swift decides that we need more retains/releases instead of fewer 😉

johannes:~/devel/pipeline-optimisation (master)
$ jw-swift-latest swiftc -Ounchecked -emit-assembly cp_perf.swift > /tmp/cp_perf-latest.s
johannes:~/devel/pipeline-optimisation (master)
$ jw-swift-5.1 swiftc -Ounchecked -emit-assembly cp_perf.swift > /tmp/cp_perf-5.1.s
johannes:~/devel/pipeline-optimisation (master)
$ diff -U0 /tmp/cp_perf-* | grep call
+   callq   _swift_unknownObjectRetain
+   callq   _swift_release
+   callq   _swift_unknownObjectRetain
+   callq   _swift_release
+   callq   _swift_unknownObjectRetain
-   callq   *8(%r14)
+   callq   *%r12
+   callq   _swift_unknownObjectRetain
+   callq   _swift_unknownObjectRelease

Specifically in this function:

    @inline(never)
    public func fireEvent() {
        self.next?.invokeEvent()
    }

we now seem to retain both the existential box and I think (??) the PWT too? The lines that are marked red in the screenshot below are the new retain/releases.

Metadata

Metadata

Assignees

No one assigned

    Labels

    ARCFeature: automatic reference countingSILOptimizerArea → compiler: SIL optimization passesbugA deviation from expected or documented behavior. Also: expected but undesirable behavior.compilerThe Swift compiler itselfperformance

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions