From 7226dca81fe1ff54da714004c636c17cec33b794 Mon Sep 17 00:00:00 2001 From: Johannes Weiss Date: Tue, 14 May 2019 13:54:38 +0100 Subject: [PATCH 1/2] benchmark: NIOChannelPipeline imitation adds a benchmark that imitates SwiftNIO's ChannelPipeline. Recently, Swift master regressed on this benchmark, therefore I believe adding it to Swift provides value as it seems to be different enough to the existing benchmarks. --- benchmark/CMakeLists.txt | 1 + .../single-source/NIOChannelPipeline.swift | 104 ++++++++++++++++++ benchmark/utils/main.swift | 2 + 3 files changed, 107 insertions(+) create mode 100644 benchmark/single-source/NIOChannelPipeline.swift diff --git a/benchmark/CMakeLists.txt b/benchmark/CMakeLists.txt index 39b32d59c0663..3b14a70793559 100644 --- a/benchmark/CMakeLists.txt +++ b/benchmark/CMakeLists.txt @@ -108,6 +108,7 @@ set(SWIFT_BENCH_MODULES single-source/NSError single-source/NSStringConversion single-source/NibbleSort + single-source/NIOChannelPipeline single-source/NopDeinit single-source/ObjectAllocation single-source/ObjectiveCBridging diff --git a/benchmark/single-source/NIOChannelPipeline.swift b/benchmark/single-source/NIOChannelPipeline.swift new file mode 100644 index 0000000000000..d3423044ffdce --- /dev/null +++ b/benchmark/single-source/NIOChannelPipeline.swift @@ -0,0 +1,104 @@ +//===--- NIOChannelPipeline.swift -----------------------------------------===// +// +// This source file is part of the Swift.org open source project +// +// Copyright (c) 2019 Apple Inc. and the Swift project authors +// Licensed under Apache License v2.0 with Runtime Library Exception +// +// See https://swift.org/LICENSE.txt for license information +// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors +// +//===----------------------------------------------------------------------===// + +import TestsUtils + +// Mini benchmark implementing the gist of SwiftNIO's ChannelPipeline as +// implemented by NIO 1 and NIO 2.[01] +let t: [BenchmarkCategory] = [.runtime, .refcount] +let N = 100 + +public let NIOChannelPipeline = [ + BenchmarkInfo( + name: "NIOChannelPipeline", + runFunction: runBench, + tags: t), +] + +public protocol EventHandler: class { + func event(holder: Holder) +} + +extension EventHandler { + public func event(holder: Holder) { + holder.fireEvent() + } +} + +public final class Pipeline { + var head: Holder? = nil + + public init() {} + + public func addHandler(_ handler: EventHandler) { + if self.head == nil { + self.head = Holder(handler) + return + } + + var node = self.head + while node?.next != nil { + node = node?.next + } + node?.next = Holder(handler) + } + + public func fireEvent() { + self.head!.invokeEvent() + } +} + +public final class Holder { + var next: Holder? + let node: EventHandler + + init(_ node: EventHandler) { + self.next = nil + self.node = node + } + + func invokeEvent() { + self.node.event(holder: self) + } + + @inline(never) + public func fireEvent() { + self.next?.invokeEvent() + } +} + +public final class NoOpHandler: EventHandler { + public init() {} +} + +public final class ConsumingHandler: EventHandler { + var consumed = 0 + public init() {} + public func event(holder: Holder) { + self.consumed += 1 + } +} + +@inline(never) +func runBench(iterations: Int) { + let pipeline = Pipeline() + for _ in 0..<5 { + pipeline.addHandler(NoOpHandler()) + } + pipeline.addHandler(ConsumingHandler()) + + for _ in 0 ..< iterations { + for _ in 0 ..< 100 { + pipeline.fireEvent() + } + } +} diff --git a/benchmark/utils/main.swift b/benchmark/utils/main.swift index 5326f853c6b6f..9c1bf3eb3b13b 100644 --- a/benchmark/utils/main.swift +++ b/benchmark/utils/main.swift @@ -93,6 +93,7 @@ import Memset import MonteCarloE import MonteCarloPi import NibbleSort +import NIOChannelPipeline import NSDictionaryCastToSwift import NSError #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) @@ -272,6 +273,7 @@ registerBenchmark(NSErrorTest) registerBenchmark(NSStringConversion) #endif registerBenchmark(NibbleSort) +registerBenchmark(NIOChannelPipeline) registerBenchmark(NopDeinit) registerBenchmark(ObjectAllocation) #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS) From 53f5c5cbc149262aef0824d60d00c6bff3df206d Mon Sep 17 00:00:00 2001 From: Johannes Weiss Date: Tue, 14 May 2019 22:37:13 +0100 Subject: [PATCH 2/2] Update NIOChannelPipeline.swift --- benchmark/single-source/NIOChannelPipeline.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benchmark/single-source/NIOChannelPipeline.swift b/benchmark/single-source/NIOChannelPipeline.swift index d3423044ffdce..59904864accb1 100644 --- a/benchmark/single-source/NIOChannelPipeline.swift +++ b/benchmark/single-source/NIOChannelPipeline.swift @@ -97,7 +97,7 @@ func runBench(iterations: Int) { pipeline.addHandler(ConsumingHandler()) for _ in 0 ..< iterations { - for _ in 0 ..< 100 { + for _ in 0 ..< 1000 { pipeline.fireEvent() } }