Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/norio-nomura/swiftbenchmark-indexof
https://github.com/norio-nomura/swiftbenchmark-indexof
Last synced: 3 months ago
JSON representation
- Host: GitHub
- URL: https://github.com/norio-nomura/swiftbenchmark-indexof
- Owner: norio-nomura
- Created: 2015-01-14T09:23:26.000Z (almost 10 years ago)
- Default Branch: master
- Last Pushed: 2015-01-15T04:54:30.000Z (almost 10 years ago)
- Last Synced: 2024-05-09T16:23:51.669Z (8 months ago)
- Language: Swift
- Size: 285 KB
- Stars: 8
- Watchers: 3
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# SwiftBenchmark-indexOf
### `swiftc -emit-sil -O`にはSwift標準ライブラリの中身も出力される
---
[ここ](https://github.com/katokichisoft/SimpleGaplessPlayer/blob/master/HKLAVGaplessPlayer/misc/HKLStdLibUtils.swift)でこんなコードをみた。
```swift
extension Array {
/**
Returns the lowest index whose corresponding array value matches a given condition.:discussion: Starting at index 0, each element of the array is passed as the 1st parameter of condition closure until a match is found or the end of the array is reached. Objects are considered equal if the closure returns true.
:param: condition A closure for finding the target object in the array
:returns: The lowest index whose corresponding array value matches a given condition. If none of the objects in the array matches the condition, returns nil.
:refer: http://stackoverflow.com/a/24105493
*/
func indexOf(condition: T -> Bool) -> Int? {
for (idx, element) in enumerate(self) {
if condition(element) {
return idx
}
}
return nil
}
}
```同じ機能を`lazy()`とか使って書いてみた。
```swift
func v1_index_of(domain: C, condition: C.Generator.Element -> Bool) -> C.Index? {
return find(lazy(domain).map(condition), true)
}
```うんシンプル。でもどっちを使うべきだろう?で[ベンチマーク](Benchmark/Benchmark.swift)
> :0: Test Case '-[Benchmark.Benchmark testPerformance_v1]' measured [Time, seconds] average: 1.557,…
> :0: Test Case '-[Benchmark.Benchmark testPerformance_v4]' measured [Time, seconds] average: 2.403,…
**おおよそ1.6倍くらいオリジナルが遅い。**
**やっぱ時代はFunctionalなのか!?**で、Swiftがどんなコードを出力してるのか気になったので、こんなコード
```swift
#!/usr/bin/env xcrun swift -i
import Foundationfunc v1_index_of(domain: C, condition: C.Generator.Element -> Bool) -> C.Index? {
return find(lazy(domain).map(condition), true)
}func v2_index_of(domain: C, condition: C.Generator.Element -> Bool) -> C.Index? {
for (idx, element) in enumerate(domain) {
if condition(element) {
return idx as? C.Index
}
}
return nil
}let a = [1,2,3]
let c = {(e: Int) -> Bool in e == 1}
let result1 = v1_index_of(a, c)
let result2 = v2_index_of(a, c)
```を、以前書いた[swift-demangle-filter.py](https://gist.github.com/norio-nomura/121ef3eacbc6dda87dad)に通す。
`swift-demangle-filter.py -g indexof.swift -o indexof.asm`
[indexof.asm](https://gist.github.com/norio-nomura/7c76756f9827d16d40a1)
うーん、、**Swiftのアセンブリ出力は難しい。** もうちょっと簡単な方法はないか?と`swiftc`の`-emit-sil`を試す。
`swift-demangle-filter.py -emit-sil indexof.swift -o indexof.sil`
[indexof.sil](https://gist.github.com/norio-nomura/f95c5921484da4a55242)
うーん、少し分かりやすくなったかな。あ、最適化オプション-O付け忘れてた。
`swift-demangle-filter.py -emit-sil -O indexof.swift -o indexof-O.sil`
[indexof-O.sil](https://gist.github.com/norio-nomura/e30c5450acfbc0bbf9d9)
あれ?なんか出力がやたら長くない?
```
// Swift.find (A, A.Generator.Element) -> Swift.Optional
sil public_external Swift.find (A, A.Generator.Element) -> A.Index? : $@thin (@out Optional, @in C, @in C.Generator.Element) -> () {
bb0(%0 : $*Optional, %1 : $*C, %2 : $*C.Generator.Element):
%3 = alloc_stack $RangeGenerator // users: %10, %16, %38, %51, %55, %61
// function_ref Swift.Range.generate (Swift.Range)() -> Swift.RangeGenerator
%4 = function_ref Swift.Range.generate (Swift.Range)() -> Swift.RangeGenerator : $@cc(method) @thin <τ_0_0 where τ_0_0 : ForwardIndexType, τ_0_0.Distance : _SignedIntegerType, τ_0_0.Distance.IntegerLiteralType : _BuiltinIntegerLiteralConvertible> (@out RangeGenerator<τ_0_0>, @in Range<τ_0_0>) -> () // user: %10
%5 = alloc_stack $Range // users: %9, %10, %12
// function_ref Swift.indices (A) -> Swift.Range
%6 = function_ref Swift.indices (A) -> Swift.Range : $@thin <τ_0_0 where τ_0_0 : CollectionType, τ_0_0.Generator : GeneratorType, τ_0_0.Index : ForwardIndexType, τ_0_0.Index.Distance : _SignedIntegerType, τ_0_0.Index.Distance.IntegerLiteralType : _BuiltinIntegerLiteralConvertible> (@out Range<τ_0_0.Index>, @in τ_0_0) -> () // user: %9
%7 = alloc_stack $C // users: %8, %9, %11
copy_addr %1 to [initialization] %7#1 : $*C // id: %8
%9 = apply %6(%5#1, %7#1) : $@thin <τ_0_0 where τ_0_0 : CollectionType, τ_0_0.Generator : GeneratorType, τ_0_0.Index : ForwardIndexType, τ_0_0.Index.Distance : _SignedIntegerType, τ_0_0.Index.Distance.IntegerLiteralType : _BuiltinIntegerLiteralConvertible> (@out Range<τ_0_0.Index>, @in τ_0_0) -> ()
%10 = apply %4(%3#1, %5#1) : $@cc(method) @thin <τ_0_0 where τ_0_0 : ForwardIndexType, τ_0_0.Distance : _SignedIntegerType, τ_0_0.Distance.IntegerLiteralType : _BuiltinIntegerLiteralConvertible> (@out RangeGenerator<τ_0_0>, @in Range<τ_0_0>) -> ()
dealloc_stack %7#0 : $*@local_storage C // id: %11
dealloc_stack %5#0 : $*@local_storage Range // id: %12
%13 = alloc_stack $Optional // users: %16, %17, %21, %37, %50, %55, %56
// function_ref Swift.RangeGenerator.next (inout Swift.RangeGenerator)() -> Swift.Optional
%14 = function_ref Swift.RangeGenerator.next (inout Swift.RangeGenerator)() -> A? : $@cc(method) @thin <τ_0_0 where τ_0_0 : ForwardIndexType, τ_0_0.Distance : _SignedIntegerType, τ_0_0.Distance.IntegerLiteralType : _BuiltinIntegerLiteralConvertible> (@out Optional<τ_0_0>, @inout RangeGenerator<τ_0_0>) -> () // users: %16, %55
// function_ref Swift._doesOptionalHaveValue (inout Swift.Optional) -> Builtin.Int1
%15 = function_ref Swift._doesOptionalHaveValue (inout A?) -> Builtin.Int1 : $@thin <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1 // users: %17, %56
%16 = apply %14(%13#1, %3#1) : $@cc(method) @thin <τ_0_0 where τ_0_0 : ForwardIndexType, τ_0_0.Distance : _SignedIntegerType, τ_0_0.Distance.IntegerLiteralType : _BuiltinIntegerLiteralConvertible> (@out Optional<τ_0_0>, @inout RangeGenerator<τ_0_0>) -> ()
%17 = apply [transparent] %15(%13#1) : $@thin <τ_0_0> (@inout Optional<τ_0_0>) -> Builtin.Int1 // user: %18
cond_br %17, bb1, bb2 // id: %18bb1: // Preds: bb0 bb4
```これって、**Swift標準ライブラリの中身も[出力](https://gist.github.com/norio-nomura/e30c5450acfbc0bbf9d9#file-indexof-o-sil-L684-L764)されてる!**
ふむふむ、なるほど。で`find()`の実装を参考にしたらこうなった。
```swift
func v2_1_index_of(domain: C, condition: C.Generator.Element -> Bool) -> C.Index? {
for idx in indices(domain) {
if condition(domain[idx]) {
return idx
}
}
return nil
}
```で、ベンチマークは
> :0: Test Case '-[Benchmark.Benchmark testPerformance_v1]' measured [Time, seconds] average: 1.557,…
> :0: Test Case '-[Benchmark.Benchmark testPerformance_v2_1]' measured [Time, seconds] average: 1.057,…
> :0: Test Case '-[Benchmark.Benchmark testPerformance_v4]' measured [Time, seconds] average: 2.403,…
**おお!`lazy()`版より速くなった!**
# まとめ
**`swiftc -emit-sil -O`にはSwift標準ライブラリの中身も出力されるので、暇な人は読んでみよう!**
---
[@norio_nomura](https:/twitter.com/norio_nomura)