[swift-evolution] [Review] SE-0007 Remove C-style for-loops with conditions and incrementers
David Owens II
david at owensd.io
Thu Dec 10 17:36:52 CST 2015
Here’s my basic test case:
let first = 10000000
let second = 20000000
class LoopPerfTests: XCTestCase {
func testZipStride() {
self.measureBlock {
var sum = 0
for (i, j) in zip(first.stride(to: 0, by: -1), second.stride(to: 0, by: -2)) {
if i % 2 == 0 { continue }
sum += 1
}
print(sum)
}
}
func testCStyleFor() {
self.measureBlock {
var sum = 0
for var i = first, j = second; i > 0 && j > 0; i -= 1, j -= 2 {
if i % 2 == 0 { continue }
sum += 1
}
print(sum)
}
}
}
Non-optimized timings:
testCStyleFor - 0.126s
testZipStride - 2.189s
Optimized timings:
testCStyleFor - 0.008s
testZipStride - 0.015s
That’s a lot worse than 34%; even in optimized builds, that’s 2x slower and in debug builds, that’s 17x slower. I think it’s unreasonable to force people to write a more verbose while-loop construct to simply get the performance they need.
Also, the readability argument is very subjective; for example, I don’t find the zip version more readability. In fact, I think it obscures what the logic of the loop is doing. But again, that’s subjective.
-David
> On Dec 10, 2015, at 2:41 PM, Paul Cantrell <cantrell at pobox.com> wrote:
>
>> Is there any guarantee that these two loops have the exact same runtime performance?
>>
>> for (i, j) in zip(10.stride(to: 0, by: -1), 20.stride(to: 0, by: -2)) {
>> if i % 2 == 0 { continue }
>> print(i, j)
>> }
>>
>> for var i = 10, j = 20; i > 0 && j > 0; i -= 1, j -= 2 {
>> if i % 2 == 0 { continue }
>> print(i, j)
>> }
>
>
> In a quick and dirty test, the second is approximately 34% slower.
>
> I’d say that’s more than acceptable for the readability gain. If you’re in that rare stretch of critical code where the extra 34% actually matters, write it using a while loop instead.
>
> P
>
>
>
>> On Dec 10, 2015, at 4:07 PM, David Owens II via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>
>>
>>> On Dec 10, 2015, at 1:57 PM, thorsten--- via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>>
>>> Yes, performance is one thing neglected by the discussions and the proposal.
>>
>> This is my primary objection to to this proposal; it assumes (or neglects?) that all of the types used can magically be inlined to nothing but the imperative code. This isn’t magical, someone has to implement the optimizations to do this.
>>
>> Is there any guarantee that these two loops have the exact same runtime performance?
>>
>> for (i, j) in zip(10.stride(to: 0, by: -1), 20.stride(to: 0, by: -2)) {
>> if i % 2 == 0 { continue }
>> print(i, j)
>> }
>>
>> for var i = 10, j = 20; i > 0 && j > 0; i -= 1, j -= 2 {
>> if i % 2 == 0 { continue }
>> print(i, j)
>> }
>>
>>
>> And can you guarantee that performance is relatively the same across debug and release builds? Because historically, Swift has suffered greatly in this regard with respects to the performance of optimized versus non-optimized builds.
>>
>> These types of optimizer issues are real-world things I’ve had to deal with (and have written up many blog posts about). I get the desire to simplify the constructs, but we need an escape hatch to write performant code when the optimizer isn’t up to the job.
>>
>> -David
>>
>> _______________________________________________
>> swift-evolution mailing list
>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20151210/feb89cb7/attachment.html>
More information about the swift-evolution
mailing list