Skip to content

[c++-interop] Improve performance of creating a C++ std::string from a contiguous UTF-8 Swift.String #75608

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

Merged
merged 1 commit into from
Aug 19, 2024

Conversation

CrazyFanFan
Copy link
Contributor

Improve performance of creating a C++ std::string from a contiguous UTF-8 Swift.String #75110

@egorzhdan
Copy link
Contributor

@swift-ci please smoke test

@egorzhdan egorzhdan added the c++ interop Feature: Interoperability with C++ label Aug 1, 2024
@CrazyFanFan
Copy link
Contributor Author

linux compilation failed and I am trying to create a Linux virtual machine to debug the problem

@egorzhdan
Copy link
Contributor

@swift-ci please smoke test

@egorzhdan
Copy link
Contributor

@swift-ci please benchmark

@CrazyFanFan
Copy link
Contributor Author

Hi @egorzhdan

I've made some updates to this PR;

  1. Fixed the Linux compilation failure.
  2. As expected, benchmark results demonstrate a significant efficiency improvement in initializing std::string from Swift.String.

------- Performance (x86_64): -O -------

IMPROVEMENT OLD NEW DELTA RATIO
CxxStringConversion.swift.to.cxx 98.136 0.476 -99.5% 205.74x

------- Performance (x86_64): -Osize -------

IMPROVEMENT OLD NEW DELTA RATIO
CxxStringConversion.swift.to.cxx 82.0 0.48 -99.4% 170.48x

------- Performance (x86_64): -Onone -------

IMPROVEMENT OLD NEW DELTA RATIO
CxxStringConversion.swift.to.cxx 81.864 0.504 -99.4% 162.11x

Could you please review it again when convenient?

Thanks

Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

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

This looks like a massive performance improvement!
I have one question.

self.reserve(utf8.count)
for char in utf8 {
self.push_back(value_type(bitPattern: char))
if string.isContiguousUTF8 {
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this check necessary? I think withCString should handle the non-contiguous case under the hood by falling back to the slow path of copying the string, which should produce similar results to the else branch here.

So I wonder if we could just remove the else branch in this initializer.

@egorzhdan
Copy link
Contributor

@swift-ci please test

@egorzhdan
Copy link
Contributor

@swift-ci please benchmark

@egorzhdan egorzhdan requested a review from Xazax-hun August 16, 2024 12:55
@egorzhdan
Copy link
Contributor

The relevant bits of the benchmark:

Performance (x86_64): -O

Improvement OLD NEW DELTA RATIO
CxxStringConversion.swift.to.cxx 98.143 0.488 -99.5% 200.70x

Code size: -O

Performance (x86_64): -Osize

Improvement OLD NEW DELTA RATIO
CxxStringConversion.swift.to.cxx 81.96 0.479 -99.4% 170.75x

Code size: -Osize

Performance (x86_64): -Onone

Improvement OLD NEW DELTA RATIO
CxxStringConversion.swift.to.cxx 82.077 0.5 -99.4% 163.83x

Code size: -swiftlibs

Copy link
Contributor

@egorzhdan egorzhdan left a comment

Choose a reason for hiding this comment

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

Thanks, this is a significant performance improvement!

@egorzhdan egorzhdan merged commit 28078d6 into swiftlang:main Aug 19, 2024
6 checks passed
@compnerd
Copy link
Member

I think that this might have caused a regression on Windows :(

D:/a/swift-build/swift-build/SourceCache/swift/stdlib/public/Cxx/std/String.swift:24:18: error: cannot convert value of type 'UnsafePointer<Unicode.UTF8.CodeUnit>' (aka 'UnsafePointer<UInt8>') to expected argument type 'std.basic_string<CChar, char_traits<CChar>, allocator<CChar>>'

@egorzhdan
Copy link
Contributor

That is strange, the Windows CI was passing on this patch.
@compnerd is this failing in post-commit CI? If this is failing for you locally, could you please share the full error message?

@compnerd
Copy link
Member

D:/a/swift-build/swift-build/SourceCache/swift/stdlib/public/Cxx/std/String.swift:24:18: error: cannot convert value of type 'UnsafePointer<Unicode.UTF8.CodeUnit>' (aka 'UnsafePointer<UInt8>') to expected argument type 'std.basic_string<CChar, char_traits<CChar>, allocator<CChar>>'
 22 |   public init(_ string: String) {
 23 |     self = string.withCString(encodedAs: UTF8.self) { buffer in
 24 |       std.string(buffer, string.utf8.count, .init())
    |                  `- error: cannot convert value of type 'UnsafePointer<Unicode.UTF8.CodeUnit>' (aka 'UnsafePointer<UInt8>') to expected argument type 'std.basic_string<CChar, char_traits<CChar>, allocator<CChar>>'
 25 |     }
 26 |   }

D:/a/swift-build/swift-build/SourceCache/swift/stdlib/public/Cxx/std/String.swift:30:17: error: cannot convert value of type 'UnsafePointer<CChar>' (aka 'UnsafePointer<Int8>') to expected argument type 'std.basic_string<CChar, char_traits<CChar>, allocator<CChar>>'
 28 |   public init(_ string: UnsafePointer<CChar>?) {
 29 |     if let str = string {
 30 |       self.init(str, UTF8._nullCodeUnitOffset(in: str), .init())
    |                 `- error: cannot convert value of type 'UnsafePointer<CChar>' (aka 'UnsafePointer<Int8>') to expected argument type 'std.basic_string<CChar, char_traits<CChar>, allocator<CChar>>'
 31 |     } else {
 32 |       self.init()

https://github.com/thebrowsercompany/swift-build/actions/runs/10456478071/job/28957616414#step:14:1611

@compnerd
Copy link
Member

@egorzhdan I think that this is due to the Apple CI hosts being very out of date in the VC version.

@CrazyFanFan CrazyFanFan deleted the crazy_fan/75110 branch August 20, 2024 00:06
egorzhdan added a commit that referenced this pull request Sep 30, 2024
Since #75608, the performance of `std::string` <=> `Swift.String` conversions improved significantly. To make sure the workload is significant enough for the benchmark results to be noise-free, this bumps the size of Swift strings that are being tested.
egorzhdan added a commit that referenced this pull request Oct 1, 2024
Since #75608, the performance of `std::string` <=> `Swift.String` conversions improved significantly. To make sure the workload is significant enough for the benchmark results to be noise-free, this bumps the size of Swift strings that are being tested.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++ interop Feature: Interoperability with C++
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants