1 /* 2 * Copyright 2024 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 Benchmark 18 import CoreFoundation 19 import FlatBuffers 20 21 @usableFromInline 22 struct AA: NativeStruct { 23 public init(a: Double, b: Double) { 24 self.a = a 25 self.b = b 26 } 27 var a: Double 28 var b: Double 29 } 30 31 let benchmarks = { 32 let ints: [Int] = Array(repeating: 42, count: 100) 33 let bytes: [UInt8] = Array(repeating: 42, count: 100) 34 let str10 = (0...9).map { _ -> String in "x" }.joined() 35 let str100 = (0...99).map { _ -> String in "x" }.joined() 36 let array: [AA] = [ 37 AA(a: 2.4, b: 2.4), 38 AA(a: 2.4, b: 2.4), 39 AA(a: 2.4, b: 2.4), 40 AA(a: 2.4, b: 2.4), 41 AA(a: 2.4, b: 2.4), 42 ] 43 44 let metrics: [BenchmarkMetric] = [ 45 .cpuTotal, 46 .wallClock, 47 .mallocCountTotal, 48 .releaseCount, 49 .peakMemoryResident, 50 ] 51 let maxIterations = 1_000_000 52 let maxDuration: Duration = .seconds(3) 53 let singleConfiguration: Benchmark.Configuration = .init( 54 metrics: metrics, 55 warmupIterations: 1, 56 scalingFactor: .one, 57 maxDuration: maxDuration, 58 maxIterations: maxIterations) 59 let kiloConfiguration: Benchmark.Configuration = .init( 60 metrics: metrics, 61 warmupIterations: 1, 62 scalingFactor: .kilo, 63 maxDuration: maxDuration, 64 maxIterations: maxIterations) 65 let megaConfiguration: Benchmark.Configuration = .init( 66 metrics: metrics, 67 warmupIterations: 1, 68 scalingFactor: .mega, 69 maxDuration: maxDuration, 70 maxIterations: maxIterations) 71 72 Benchmark.defaultConfiguration = megaConfiguration 73 74 Benchmark("Allocating 1GB", configuration: singleConfiguration) { benchmark in 75 for _ in benchmark.scaledIterations { 76 blackHole(FlatBufferBuilder(initialSize: 1_024_000_000)) 77 } 78 } 79 80 Benchmark("Clearing 1GB", configuration: singleConfiguration) { benchmark in 81 var fb = FlatBufferBuilder(initialSize: 1_024_000_000) 82 benchmark.startMeasurement() 83 for _ in benchmark.scaledIterations { 84 blackHole(fb.clear()) 85 } 86 } 87 88 Benchmark("Strings 10") { benchmark in 89 var fb = FlatBufferBuilder(initialSize: 1<<20) 90 benchmark.startMeasurement() 91 for _ in benchmark.scaledIterations { 92 blackHole(fb.create(string: str10)) 93 } 94 } 95 96 Benchmark("Strings 100") { benchmark in 97 var fb = FlatBufferBuilder(initialSize: 1<<20) 98 benchmark.startMeasurement() 99 for _ in benchmark.scaledIterations { 100 blackHole(fb.create(string: str100)) 101 } 102 } 103 104 Benchmark("Vector 1 Bytes") { benchmark in 105 var fb = FlatBufferBuilder(initialSize: 1<<20) 106 benchmark.startMeasurement() 107 for _ in benchmark.scaledIterations { 108 blackHole(fb.createVector(bytes: bytes)) 109 } 110 } 111 112 Benchmark("Vector 1 Ints") { benchmark in 113 var fb = FlatBufferBuilder(initialSize: 1<<20) 114 benchmark.startMeasurement() 115 for _ in benchmark.scaledIterations { 116 blackHole(fb.createVector(ints)) 117 } 118 } 119 120 Benchmark("Vector 100 Ints") { benchmark in 121 var fb = FlatBufferBuilder(initialSize: 1<<20) 122 benchmark.startMeasurement() 123 for i in benchmark.scaledIterations { 124 blackHole(fb.createVector(ints)) 125 } 126 } 127 128 Benchmark("Vector 100 Bytes") { benchmark in 129 var fb = FlatBufferBuilder(initialSize: 1<<20) 130 benchmark.startMeasurement() 131 for i in benchmark.scaledIterations { 132 blackHole(fb.createVector(bytes)) 133 } 134 } 135 136 Benchmark("Vector 100 ContiguousBytes") { benchmark in 137 var fb = FlatBufferBuilder(initialSize: 1<<20) 138 benchmark.startMeasurement() 139 for i in benchmark.scaledIterations { 140 blackHole(fb.createVector(bytes: bytes)) 141 } 142 } 143 144 Benchmark( 145 "FlatBufferBuilder Add", 146 configuration: kiloConfiguration) 147 { benchmark in 148 var fb = FlatBufferBuilder(initialSize: 1024 * 1024 * 32) 149 benchmark.startMeasurement() 150 for _ in benchmark.scaledIterations { 151 let off = fb.create(string: "T") 152 let s = fb.startTable(with: 4) 153 fb.add(element: 3.2, def: 0, at: 2) 154 fb.add(element: 4.2, def: 0, at: 4) 155 fb.add(element: 5.2, def: 0, at: 6) 156 fb.add(offset: off, at: 8) 157 blackHole(fb.endTable(at: s)) 158 } 159 } 160 161 Benchmark("Structs") { benchmark in 162 let rawSize = ((16 * 5) * benchmark.scaledIterations.count) / 1024 163 var fb = FlatBufferBuilder(initialSize: Int32(rawSize * 1600)) 164 var offsets: [Offset] = [] 165 166 benchmark.startMeasurement() 167 for _ in benchmark.scaledIterations { 168 let vector = fb.createVector( 169 ofStructs: array) 170 let start = fb.startTable(with: 1) 171 fb.add(offset: vector, at: 4) 172 offsets.append(Offset(offset: fb.endTable(at: start))) 173 } 174 175 let vector = fb.createVector(ofOffsets: offsets) 176 let start = fb.startTable(with: 1) 177 fb.add(offset: vector, at: 4) 178 let root = Offset(offset: fb.endTable(at: start)) 179 fb.finish(offset: root) 180 } 181 182 Benchmark("Vector of Offsets") { benchmark in 183 let rawSize = ((16 * 5) * benchmark.scaledIterations.count) / 1024 184 var fb = FlatBufferBuilder(initialSize: Int32(rawSize * 1600)) 185 benchmark.startMeasurement() 186 for _ in benchmark.scaledIterations { 187 let offsets = [ 188 fb.create(string: "T"), 189 fb.create(string: "2"), 190 fb.create(string: "3"), 191 ] 192 let off = fb.createVector(ofOffsets: [ 193 fb.createVector(ofOffsets: offsets), 194 fb.createVector(ofOffsets: offsets), 195 ]) 196 let s = fb.startTable(with: 2) 197 fb.add(offset: off, at: 2) 198 blackHole(fb.endTable(at: s)) 199 } 200 } 201 } 202