1 /*
2 * Copyright 2021 Google Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 import CoreFoundation
18 import FlatBuffers
19
20 struct Benchmark {
21 var name: String
22 var value: Double
23
24 var description: String { "\(String(format: "|\t%@\t\t|\t\t%fs\t|", name, value))"}
25 }
26
27 func run(name: String, runs: Int, action: () -> Void) -> Benchmark {
28 action()
29 let start = CFAbsoluteTimeGetCurrent()
30 for _ in 0..<runs {
31 action()
32 }
33 let ends = CFAbsoluteTimeGetCurrent()
34 let value = Double(ends - start) / Double(runs)
35 print("done \(name): in \(value)")
36 return Benchmark(name: name, value: value)
37 }
38
39
createDocumentnull40 func createDocument(Benchmarks: [Benchmark]) -> String {
41 let separator = "-------------------------------------"
42 var document = "\(separator)\n"
43 document += "\(String(format: "|\t%@\t\t|\t\t%@\t\t|", "Name", "Scores"))\n"
44 document += "\(separator)\n"
45 for i in Benchmarks {
46 document += "\(i.description) \n"
47 document += "\(separator)\n"
48 }
49 return document
50 }
51
52 @inlinable
create10Stringsnull53 func create10Strings() {
54 var fb = FlatBufferBuilder(initialSize: 1<<20)
55 for _ in 0..<10_000 {
56 _ = fb.create(string: "foobarbaz")
57 }
58 }
59
60 @inlinable
create100Stringsnull61 func create100Strings(str: String) {
62 var fb = FlatBufferBuilder(initialSize: 1<<20)
63 for _ in 0..<10_000 {
64 _ = fb.create(string: str)
65 }
66 }
67
68 @inlinable
benchmarkFiveHundredAddsnull69 func benchmarkFiveHundredAdds() {
70 var fb = FlatBufferBuilder(initialSize: 1024 * 1024 * 32)
71 for _ in 0..<500_000 {
72 let off = fb.create(string: "T")
73 let s = fb.startTable(with: 4)
74 fb.add(element: 3.2, def: 0, at: 2)
75 fb.add(element: 4.2, def: 0, at: 4)
76 fb.add(element: 5.2, def: 0, at: 6)
77 fb.add(offset: off, at: 8)
78 _ = fb.endTable(at: s)
79 }
80 }
81
82 @inlinable
benchmarkThreeMillionStructsnull83 func benchmarkThreeMillionStructs() {
84 let structCount = 3_000_000
85
86 let rawSize = ((16 * 5) * structCount) / 1024
87
88 var fb = FlatBufferBuilder(initialSize: Int32(rawSize * 1600))
89
90 var offsets: [Offset] = []
91 for _ in 0..<structCount {
92 fb.startVector(5 * MemoryLayout<AA>.size, elementSize: MemoryLayout<AA>.alignment)
93 for _ in 0..<5 {
94 _ = fb.create(struct: AA(a: 2.4, b: 2.4))
95 }
96 let vector = fb.endVector(len: 5)
97 let start = fb.startTable(with: 1)
98 fb.add(offset: vector, at: 4)
99 offsets.append(Offset(offset: fb.endTable(at: start)))
100 }
101 let vector = fb.createVector(ofOffsets: offsets)
102 let start = fb.startTable(with: 1)
103 fb.add(offset: vector, at: 4)
104 let root = Offset(offset: fb.endTable(at: start))
105 fb.finish(offset: root)
106 }
107
108 @usableFromInline
109 struct AA: NativeStruct {
110 public init(a: Double, b: Double) {
111 self.a = a
112 self.b = b
113 }
114 var a: Double
115 var b: Double
116
117 }
118
benchmarknull119 func benchmark(numberOfRuns runs: Int) {
120 var benchmarks: [Benchmark] = []
121 let str = (0...99).map { _ -> String in "x" }.joined()
122 benchmarks.append(run(name: "500_000", runs: runs, action: benchmarkFiveHundredAdds))
123 benchmarks.append(run(name: "10 str", runs: runs, action: create10Strings))
124 let hundredStr = run(name: "100 str", runs: runs) {
125 create100Strings(str: str)
126 }
127 benchmarks.append(run(name: "3M strc", runs: 1, action: benchmarkThreeMillionStructs))
128 benchmarks.append(hundredStr)
129 print(createDocument(Benchmarks: benchmarks))
130 }
131
132 benchmark(numberOfRuns: 20)
133