swiftlang / swift

The Swift Programming Language
https://swift.org
Apache License 2.0
67.49k stars 10.35k forks source link

Error._domain calculation is inefficient #76954

Open ChrisBenua opened 1 week ago

ChrisBenua commented 1 week ago

Motivation

Error.localizedDescription is widely used in many iOS apps.

But it's calculation needs converting Error to NSError using _swift_stdlib_bridgeErrorToNSError function that calls Error._domain computed-property through _getErrorDomainNSString<A>(_:) call.

Error._domain uses String(reflecting: type(of: self)) that internally performs multiple casts to protocols in OutputStream.swift: CustomDebugStringConvertible, CustomStringConvertible, TextOutputStreamable and CustomReflectable inside Mirror initializer. First conformance check for each pair of (class, protocol) is time-consuming because we need to scan all protocol conformance type descriptors.

That's why calculation Error._domain takes 15 ms on launch. Screenshot from Time Profilers traces is attached:

Screenshot 2024-10-10 at 19 14 17

But internally, String(reflecting:) called on class-type eventually calls _typeName(:qualified:) function with qualified: true.

Full call-stack:

  1. Error._domain
  2. String(reflecting:)
  3. _debugPrint_unlocked. Because Any.Type does not conform any of checked protocols.
  4. _adHocPrint_unlocked
  5. _adHocPrint_unlocked.printTypeName

Proposed solution

Instead of calling _typeName(type, qualified: true) indirectly using String(reflecting:) with significant performance hit because of protocol conformances checks, I suggest to call _typeName(type(of: self), qualified: true) directly in Error._domain computed-property.

Alternatives considered

Leave everything as it is now.

Additional information

No response

ChrisBenua commented 1 week ago

I suggest adding run-time performance label to this issue

Apoorvgarg-creator commented 1 week ago

HI @ChrisBenua Can I work on this issue ? I read your proposed solution and would like to learn by working on this issue.

Thank you