Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ let benchmarks = {
for _ in benchmark.scaledIterations {
blackHole(ByteBuffer(assumingMemoryBound: memory, capacity: Int(oneGB)))
}
benchmark.stopMeasurement()
}

Benchmark("Clearing 1GB", configuration: singleConfiguration) { benchmark in
Expand All @@ -105,6 +106,7 @@ let benchmarks = {
for _ in benchmark.scaledIterations {
blackHole(fb.clear())
}
benchmark.stopMeasurement()
}

Benchmark("Strings 10") { benchmark in
Expand All @@ -113,6 +115,7 @@ let benchmarks = {
for _ in benchmark.scaledIterations {
blackHole(fb.create(string: str10))
}
benchmark.stopMeasurement()
}

Benchmark("Strings 100") { benchmark in
Expand All @@ -121,6 +124,7 @@ let benchmarks = {
for _ in benchmark.scaledIterations {
blackHole(fb.create(string: str100))
}
benchmark.stopMeasurement()
}

Benchmark("Vector 1 Bytes") { benchmark in
Expand All @@ -129,6 +133,7 @@ let benchmarks = {
for _ in benchmark.scaledIterations {
blackHole(fb.createVector(bytes: bytes))
}
benchmark.stopMeasurement()
}

Benchmark("Vector 1 Ints") { benchmark in
Expand All @@ -137,6 +142,7 @@ let benchmarks = {
for _ in benchmark.scaledIterations {
blackHole(fb.createVector(ints))
}
benchmark.stopMeasurement()
}

Benchmark("Vector 100 Ints") { benchmark in
Expand All @@ -145,6 +151,7 @@ let benchmarks = {
for i in benchmark.scaledIterations {
blackHole(fb.createVector(ints))
}
benchmark.stopMeasurement()
}

Benchmark("Vector 100 Bytes") { benchmark in
Expand All @@ -153,6 +160,7 @@ let benchmarks = {
for i in benchmark.scaledIterations {
blackHole(fb.createVector(bytes))
}
benchmark.stopMeasurement()
}

Benchmark("Vector 100 ContiguousBytes") { benchmark in
Expand All @@ -161,6 +169,7 @@ let benchmarks = {
for i in benchmark.scaledIterations {
blackHole(fb.createVector(bytes: bytes))
}
benchmark.stopMeasurement()
}

Benchmark(
Expand All @@ -178,6 +187,7 @@ let benchmarks = {
fb.add(offset: off, at: 8)
blackHole(fb.endTable(at: s))
}
benchmark.stopMeasurement()
}

Benchmark(
Expand All @@ -190,6 +200,7 @@ let benchmarks = {
let s = fb.startTable(with: 4)
blackHole(fb.endTable(at: s))
}
benchmark.stopMeasurement()
}

Benchmark("Struct") { benchmark in
Expand All @@ -198,6 +209,7 @@ let benchmarks = {
for _ in benchmark.scaledIterations {
blackHole(fb.create(struct: array.first!))
}
benchmark.stopMeasurement()
}

Benchmark("Structs") { benchmark in
Expand All @@ -219,6 +231,7 @@ let benchmarks = {
fb.add(offset: vector, at: 4)
let root = Offset(offset: fb.endTable(at: start))
blackHole(fb.finish(offset: root))
benchmark.stopMeasurement()
}

Benchmark("Vector of Offsets") { benchmark in
Expand All @@ -239,12 +252,15 @@ let benchmarks = {
fb.add(offset: off, at: 2)
blackHole(fb.endTable(at: s))
}
benchmark.stopMeasurement()
}

Benchmark("Reading Doubles") { benchmark in
let byteBuffer = ByteBuffer(data: data)
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
blackHole(byteBuffer.read(def: Double.self, position: 0))
}
benchmark.stopMeasurement()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*
* Copyright 2024 Google Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import Benchmark
import FlexBuffers
import Foundation

let benchmarks = {
let data = {
var array = [8888.88, 8888.88]
var data = Data()
array.withUnsafeBytes { ptr in
data.append(contentsOf: ptr)
}
return data
}()
let ints: [Int32] = Array(repeating: 42, count: 100)
let str10 = (0...9).map { _ -> String in "x" }.joined()
let str100 = (0...99).map { _ -> String in "x" }.joined()

// A representative map: 50 keyed scalars, a keyed string and a keyed vector
// of 100 scalars. Used for the realistic decode benchmarks.
let mapBuffer: ByteBuffer = {
var fbx = FlexBuffersWriter(initialSize: 1 << 16)
fbx.map {
for i in 0..<50 { $0.add(int: i, key: "i\(i)") }
$0.add(string: "hello world", key: "s")
$0.vector(key: "v") { v in
for x in 0..<100 { v.add(int: x) }
}
}
fbx.finish()
return fbx.sizedByteBuffer
}()

let metrics: [BenchmarkMetric] = [
.cpuTotal,
.wallClock,
.mallocCountTotal,
.releaseCount,
.peakMemoryResident,
]
let maxIterations = 1_000_000
let maxDuration: Duration = .seconds(3)
let megaConfiguration: Benchmark.Configuration = .init(
metrics: metrics,
warmupIterations: 1,
scalingFactor: .mega,
maxDuration: maxDuration,
maxIterations: maxIterations)

Benchmark.defaultConfiguration = megaConfiguration

// Decode (read path)

// Raw scalar read: isolates `read<T: BitwiseCopyable>` and the `let` blob.
Benchmark("Reading Doubles") { benchmark in
let byteBuffer = ByteBuffer(data: data)
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
blackHole(byteBuffer.read(def: Double.self, position: 0))
}
benchmark.stopMeasurement()
}

// Realistic decode: resolve root map and read a keyed scalar.
Benchmark("Decode Map Scalar") { benchmark in
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
let map = try! getRoot(buffer: mapBuffer)!.map!
blackHole(map["i25"]?.int)
}
benchmark.stopMeasurement()
}

// Realistic decode: resolve root map and read a keyed string.
Benchmark("Decode Map String") { benchmark in
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
let map = try! getRoot(buffer: mapBuffer)!.map!
blackHole(map["s"]?.string())
}
benchmark.stopMeasurement()
}

// Realistic decode: resolve a nested vector and sum its scalars.
Benchmark("Decode Vector") { benchmark in
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
let map = try! getRoot(buffer: mapBuffer)!.map!
let vector = map["v"]!.vector!
var sum: Int64 = 0
for i in 0..<vector.count {
sum &+= vector[i]?.int ?? 0
}
blackHole(sum)
}
benchmark.stopMeasurement()
}

// Encode (write path)
// Writers are reused with `reset(keepingCapacity:)` so per-iteration
// allocation does not dominate and mask the write-path cost (which is what
// the `@exclusivity(unchecked)` storage pointer affects).

Benchmark("Strings 10") { benchmark in
var fbx = FlexBuffersWriter(initialSize: 1 << 20)
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
fbx.add(string: str10)
fbx.finish()
blackHole(fbx.sizedByteBuffer)
fbx.reset(keepingCapacity: true)
}
benchmark.stopMeasurement()
}

Benchmark("Strings 100") { benchmark in
var fbx = FlexBuffersWriter(initialSize: 1 << 20)
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
fbx.add(string: str100)
fbx.finish()
blackHole(fbx.sizedByteBuffer)
fbx.reset(keepingCapacity: true)
}
benchmark.stopMeasurement()
}

Benchmark("Encoding Vector Of Ints") { benchmark in
var fbx = FlexBuffersWriter(initialSize: 1 << 20)
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
fbx.vector {
$0.create(vector: ints)
}
fbx.finish()
blackHole(fbx.sizedByteBuffer)
fbx.reset(keepingCapacity: true)
}
benchmark.stopMeasurement()
}

Benchmark("Encoding Map") { benchmark in
var fbx = FlexBuffersWriter(initialSize: 1 << 20)
benchmark.startMeasurement()
for _ in benchmark.scaledIterations {
fbx.map {
for i in 0..<50 { $0.add(int: i, key: "i\(i)") }
$0.add(string: "hello world", key: "s")
$0.vector(key: "v") { v in
for x in 0..<100 { v.add(int: x) }
}
}
fbx.finish()
blackHole(fbx.sizedByteBuffer)
fbx.reset(keepingCapacity: true)
}
benchmark.stopMeasurement()
}
}
10 changes: 10 additions & 0 deletions benchmarks/swift/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,14 @@ let package = Package(
plugins: [
.plugin(name: "BenchmarkPlugin", package: "package-benchmark"),
]),
.executableTarget(
name: "FlexBuffersBenchmarks",
dependencies: [
.product(name: "FlexBuffers", package: "flatbuffers"),
.product(name: "Benchmark", package: "package-benchmark"),
],
path: "Benchmarks/FlexBuffersBenchmarks",
plugins: [
.plugin(name: "BenchmarkPlugin", package: "package-benchmark"),
]),
])
2 changes: 1 addition & 1 deletion swift/Sources/Common/Scalar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public let FileIdLength = 4
/// Protocol that All Scalars should conform to
///
/// Scalar is used to conform all the numbers that can be represented in a FlatBuffer. It's used to write/read from the buffer.
public protocol Scalar: Equatable {
public protocol Scalar: Equatable, BitwiseCopyable {
associatedtype NumericValue
var convertedEndian: NumericValue { get }
}
Expand Down
Loading
Loading