[SR-14759] class_getImageName is much slower for Swift classes than Obj-C classes #57109
Labels
bug
A deviation from expected or documented behavior. Also: expected but undesirable behavior.
performance
Environment
Swift 5.4
Observed on iOS 14.x, macOS 11.x
Additional Detail from JIRA
md5: dfc2da22081fcc746b00aebf8c99e241
Issue Description:
Calling
class_getImageName
on a Swift class exposed to Objective-C is significantly slower than calling it on an Objective-C-only class, by orders of magnitude. Empirically, we've seen a difference as large as 100x—on a particular device,class_getImageName
on a Swift class takes ~2ms whereas it takes ~20µs on an Obj-C-only class.We believe this to be caused by different dyld functions called to find the image name. In the Objective-C runtime,
class_getImageName
callsdyld_image_path_containing_address
, a private dyld function optimized to return only the image name for an address. <https://github.com/apple-opensource/objc4/blob/a367941bce42b1515aeb2cc17020c65e3a57fa20/runtime/objc-runtime.mm#L626>When the Swift runtime hooks
class_getImageName
with its own version, it callsdladdr
, which takes longer because it populates theDl_info
struct with other information that gets thrown away. (The other class metadata accessor calls are fast, as they merely return pointers or do pointer tests.) <swift/stdlib/public/runtime/ObjCRuntimeGetImageNameFromClass.mm
Lines 72 to 76 in ca5e721
I believe the performance for Swift classes could be brought much closer to that of Objective-C classes if the Swift runtime did one of the following:
Declare
dyld_image_path_containing_address
and call it instead ofdladdr
.If relying on private dyld details is a concern, the approach used by
CFBundle_binary.c
to manually iterate over the images in the process and find the one containing the address would still be more performant. <https://github.com/apple/swift-corelibs-foundation/blob/f8dc3985367ffdc7f3aef5b8c431980df136c72b/CoreFoundation/PlugIn.subproj/CFBundle_Binary.c#L166-L192>By my own rough benchmarking, the CoreFoundation approach is still slower than calling
dyld_image_path_containing_address
directly, but only by a factor of about 4x in an optimized build, so it would still be a large improvement, and perhaps there are other ways to improve it further.Are there drawbacks to doing either of these replacements, or anything I haven't considered?
The text was updated successfully, but these errors were encountered: