ribilynn
(ribilynn)
1
I want to parse numbers from a string that contains multiple numbers separated by a space. After splitting the string, however, I found that rather than converting the split Substring to Int directly, converting it to String at first and then converting to Int is much faster.
I did a benchmark using Google's swift-benchmark:
// inputline is like "86 47 85 19 37 38 73"
let inputline: String = (1...10000)
.map{ _ in String(Int.random(in: 0...1000)) }
.joined(separator: " ")
let substrings = inputline.split(separator: " ")
benchmark("Substring -> Int") {
let _ = substrings.map { Int($0)! }
}
benchmark("Substring -> String -> Int") {
let _ = substrings.map { Int(String($0))! }
}
name time std iterations
---------------------------------------------------------------
Substring -> Int 6714750.000 ns ± 11.37 % 188
Substring -> String -> Int 450150.000 ns ± 11.97 % 2755
Theoretically, the Int initializer should just read the (sub)string's memory and won't modify it in any way. So there shouldn't be any additional memory tasks. I checked the source code of IntegerParser.swift but couldn't find any information.
Couldn't understand why it happens. Any thoughts would be appreciated.
1 Like
xwu
(Xiaodi Wu)
2
I'm going to guess that you're measuring performance of a debug build. Here's what I get running your code with a release build:
name time std iterations
--------------------------------------------------------------
Substring -> Int 278842.000 ns ± 9.61 % 4875
Substring -> String -> Int 462670.500 ns ± 5.66 % 2976
ribilynn
(ribilynn)
3
I ran it on Xcode 12.5.1 and CLI (swift 5.4.2), both in release mode, and got the same result indicating the latter one is faster. Strange.
xwu
(Xiaodi Wu)
4
Ah, you're using Swift 5.4! The code you're reading in IntegerParsing.swift was rewritten (by me) in March, so you'll need macOS 12/Swift 5.5 to see the results I posted. The previous implementation was indeed over 10 times slower for Substring, one of the reasons I rewrote it.
My main preoccupation during the rewrite was making sure code size didn't regress; improving the performance of Substring was so obviously happening that I neglected to include a benchmark. However, it'd probably be wise to add one to the standard library repository so that future revisions don't cause an unintended regression--that's a good starter issue I think. I'm happy to point you in the right direction if you're interested; if not, perhaps you could file a starter bug at bugs.swift.org?
4 Likes
ribilynn
(ribilynn)
5
Aha, yes! I ran it on Xcode13-beta and got the correct result, much faster. Great job!
Pretty sure I have the interest to contribute to the standard library, but not sure what you're suggesting to me. Are you saying post an issue to the repository that suggests adding a benchmark? Or even further, to write some benchmark code then PR…?
xwu
(Xiaodi Wu)
6
However much you're comfortable with! Issues are posted at bugs.swift.org, not on GitHub, but if you have a little experience with git (or even if you don't), creating a PR to add a benchmark is a pretty nice way to dip your toes into contributing to the standard library--the biggest barrier will be setting up the project to build locally, and the instructions are now pretty good.
ribilynn
(ribilynn)
7
Okay. I'm familiar with git but have no experience about contributing to Swift (nor even compiling it). Took a look at Contributing and thought there'll be a long way to go but I'm glad to try it.
Thanks!
4 Likes