Add baseline performance and allocation tests for scheduling tasks and executing (#2009)
### Motivation: In issue https://github.com/apple/swift-nio/issues/1316, we see a large number of allocations to happen when scheduling tasks. This can definitely be optimized. This PR adds a number of baseline allocation and performance tests for both `scheduleTask` and `execute`. In the next PRs, I am going to try a few optimizations to reduce the number of allocations. ### Modifications: Added baseline performance and allocation tests for `scheduleTask` and `execute`
This commit is contained in:
parent
094cd8c6e8
commit
213eb6887e
|
@ -16,20 +16,22 @@ import Dispatch
|
|||
import NIOPosix
|
||||
|
||||
func run(identifier: String) {
|
||||
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
|
||||
let loop = group.next()
|
||||
let dg = DispatchGroup()
|
||||
|
||||
measure(identifier: identifier) {
|
||||
loop.execute {
|
||||
for _ in 0..<10_000 {
|
||||
dg.enter()
|
||||
loop.scheduleTask(in: .nanoseconds(0)) { dg.leave() }
|
||||
}
|
||||
}
|
||||
dg.wait()
|
||||
return 10_000
|
||||
}
|
||||
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
|
||||
let loop = group.next()
|
||||
let counter = try! loop.submit { () -> Int in
|
||||
var counter: Int = 0
|
||||
|
||||
try! group.syncShutdownGracefully()
|
||||
for _ in 0..<10000 {
|
||||
loop.scheduleTask(in: .hours(1)) {
|
||||
counter &+= 1
|
||||
}
|
||||
}
|
||||
|
||||
return counter
|
||||
}.wait()
|
||||
|
||||
try! group.syncShutdownGracefully()
|
||||
return counter
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2021 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Dispatch
|
||||
import NIOPosix
|
||||
|
||||
func run(identifier: String) {
|
||||
let group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
|
||||
let loop = group.next()
|
||||
let dg = DispatchGroup()
|
||||
|
||||
measure(identifier: identifier) {
|
||||
var counter = 0
|
||||
|
||||
try! loop.submit {
|
||||
for _ in 0..<10000 {
|
||||
dg.enter()
|
||||
|
||||
loop.scheduleTask(in: .nanoseconds(0)) {
|
||||
counter &+= 1
|
||||
dg.leave()
|
||||
}
|
||||
}
|
||||
}.wait()
|
||||
dg.wait()
|
||||
|
||||
return counter
|
||||
}
|
||||
|
||||
try! group.syncShutdownGracefully()
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2021 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Foundation
|
||||
import NIOCore
|
||||
import NIOPosix
|
||||
|
||||
final class ExecuteBenchmark: Benchmark {
|
||||
private var group: MultiThreadedEventLoopGroup!
|
||||
private var loop: EventLoop!
|
||||
private var dg: DispatchGroup!
|
||||
private var counter = 0
|
||||
|
||||
func setUp() throws {
|
||||
group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
|
||||
loop = group.next()
|
||||
dg = DispatchGroup()
|
||||
|
||||
// We are preheating the EL to avoid growing the `ScheduledTask` `PriorityQueue`
|
||||
// during the actual test
|
||||
try! self.loop.submit {
|
||||
var counter: Int = 0
|
||||
for _ in 0..<100000 {
|
||||
self.loop.scheduleTask(in: .nanoseconds(0)) {
|
||||
counter &+= 1
|
||||
}
|
||||
}
|
||||
}.wait()
|
||||
}
|
||||
|
||||
func tearDown() { }
|
||||
|
||||
func run() -> Int {
|
||||
try! self.loop.submit {
|
||||
for _ in 0..<10000 {
|
||||
self.dg.enter()
|
||||
|
||||
self.loop.execute {
|
||||
self.counter &+= 1
|
||||
self.dg.leave()
|
||||
}
|
||||
}
|
||||
}.wait()
|
||||
self.dg.wait()
|
||||
|
||||
return self.counter
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2021 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Foundation
|
||||
import NIOCore
|
||||
import NIOPosix
|
||||
|
||||
final class SchedulingAndRunningBenchmark: Benchmark {
|
||||
private var group: MultiThreadedEventLoopGroup!
|
||||
private var loop: EventLoop!
|
||||
private var dg: DispatchGroup!
|
||||
private var counter = 0
|
||||
|
||||
func setUp() throws {
|
||||
group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
|
||||
loop = group.next()
|
||||
dg = DispatchGroup()
|
||||
|
||||
// We are preheating the EL to avoid growing the `ScheduledTask` `PriorityQueue`
|
||||
// during the actual test
|
||||
try! self.loop.submit {
|
||||
var counter: Int = 0
|
||||
for _ in 0..<100000 {
|
||||
self.loop.scheduleTask(in: .nanoseconds(0)) {
|
||||
counter &+= 1
|
||||
}
|
||||
}
|
||||
}.wait()
|
||||
}
|
||||
|
||||
func tearDown() { }
|
||||
|
||||
func run() -> Int {
|
||||
try! self.loop.submit {
|
||||
for _ in 0..<10000 {
|
||||
self.dg.enter()
|
||||
|
||||
self.loop.scheduleTask(in: .nanoseconds(0)) {
|
||||
self.counter &+= 1
|
||||
self.dg.leave()
|
||||
}
|
||||
}
|
||||
}.wait()
|
||||
self.dg.wait()
|
||||
|
||||
return counter
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This source file is part of the SwiftNIO open source project
|
||||
//
|
||||
// Copyright (c) 2021 Apple Inc. and the SwiftNIO project authors
|
||||
// Licensed under Apache License v2.0
|
||||
//
|
||||
// See LICENSE.txt for license information
|
||||
// See CONTRIBUTORS.txt for the list of SwiftNIO project authors
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
import Foundation
|
||||
import NIOCore
|
||||
import NIOPosix
|
||||
|
||||
final class SchedulingBenchmark: Benchmark {
|
||||
private var group: MultiThreadedEventLoopGroup!
|
||||
private var loop: EventLoop!
|
||||
|
||||
func setUp() throws {
|
||||
group = MultiThreadedEventLoopGroup(numberOfThreads: 1)
|
||||
loop = group.next()
|
||||
|
||||
// We are preheating the EL to avoid growing the `ScheduledTask` `PriorityQueue`
|
||||
// during the actual test
|
||||
try! self.loop.submit {
|
||||
var counter: Int = 0
|
||||
for _ in 0..<100000 {
|
||||
self.loop.scheduleTask(in: .nanoseconds(0)) {
|
||||
counter &+= 1
|
||||
}
|
||||
}
|
||||
}.wait()
|
||||
}
|
||||
|
||||
func tearDown() { }
|
||||
|
||||
func run() -> Int {
|
||||
let counter = try! self.loop.submit { () -> Int in
|
||||
var counter: Int = 0
|
||||
for _ in 0..<10000 {
|
||||
self.loop.scheduleTask(in: .hours(1)) {
|
||||
counter &+= 1
|
||||
}
|
||||
}
|
||||
|
||||
return counter
|
||||
}.wait()
|
||||
|
||||
return counter
|
||||
}
|
||||
|
||||
}
|
|
@ -833,4 +833,11 @@ try measureAndPrint(desc: "lock_4_threads_10M_ops",
|
|||
try measureAndPrint(desc: "lock_8_threads_10M_ops",
|
||||
benchmark: LockBenchmark(numberOfThreads: 8, lockOperationsPerThread: 1_250_000))
|
||||
|
||||
try measureAndPrint(desc: "schedule_10000_tasks",
|
||||
benchmark: SchedulingBenchmark())
|
||||
|
||||
try measureAndPrint(desc: "schedule_and_run_10000_tasks",
|
||||
benchmark: SchedulingAndRunningBenchmark())
|
||||
|
||||
try measureAndPrint(desc: "execute_10000",
|
||||
benchmark: ExecuteBenchmark())
|
||||
|
|
|
@ -51,7 +51,8 @@ services:
|
|||
- MAX_ALLOCS_ALLOWED_modifying_byte_buffer_view=2050
|
||||
- MAX_ALLOCS_ALLOWED_ping_pong_1000_reqs_1_conn=4400
|
||||
- MAX_ALLOCS_ALLOWED_read_10000_chunks_from_file=190050
|
||||
- MAX_ALLOCS_ALLOWED_schedule_10000_tasks=90050
|
||||
- MAX_ALLOCS_ALLOWED_schedule_10000_tasks=90150
|
||||
- MAX_ALLOCS_ALLOWED_schedule_and_run_10000_tasks=100050
|
||||
- MAX_ALLOCS_ALLOWED_scheduling_10000_executions=20150
|
||||
- MAX_ALLOCS_ALLOWED_udp_1000_reqs_1_conn=12200
|
||||
- MAX_ALLOCS_ALLOWED_udp_1_reqs_1000_conn=188050
|
||||
|
|
|
@ -51,7 +51,8 @@ services:
|
|||
- MAX_ALLOCS_ALLOWED_modifying_byte_buffer_view=2050
|
||||
- MAX_ALLOCS_ALLOWED_ping_pong_1000_reqs_1_conn=4400
|
||||
- MAX_ALLOCS_ALLOWED_read_10000_chunks_from_file=200050
|
||||
- MAX_ALLOCS_ALLOWED_schedule_10000_tasks=90050
|
||||
- MAX_ALLOCS_ALLOWED_schedule_10000_tasks=90150
|
||||
- MAX_ALLOCS_ALLOWED_schedule_and_run_10000_tasks=100050
|
||||
- MAX_ALLOCS_ALLOWED_scheduling_10000_executions=20150
|
||||
- MAX_ALLOCS_ALLOWED_udp_1000_reqs_1_conn=12200
|
||||
- MAX_ALLOCS_ALLOWED_udp_1_reqs_1000_conn=188050
|
||||
|
|
|
@ -51,7 +51,8 @@ services:
|
|||
- MAX_ALLOCS_ALLOWED_modifying_byte_buffer_view=2050
|
||||
- MAX_ALLOCS_ALLOWED_ping_pong_1000_reqs_1_conn=4400
|
||||
- MAX_ALLOCS_ALLOWED_read_10000_chunks_from_file=190050
|
||||
- MAX_ALLOCS_ALLOWED_schedule_10000_tasks=90050
|
||||
- MAX_ALLOCS_ALLOWED_schedule_10000_tasks=90150
|
||||
- MAX_ALLOCS_ALLOWED_schedule_and_run_10000_tasks=100050
|
||||
- MAX_ALLOCS_ALLOWED_scheduling_10000_executions=20150
|
||||
- MAX_ALLOCS_ALLOWED_udp_1000_reqs_1_conn=12200
|
||||
- MAX_ALLOCS_ALLOWED_udp_1_reqs_1000_conn=190050
|
||||
|
|
|
@ -50,7 +50,8 @@ services:
|
|||
- MAX_ALLOCS_ALLOWED_modifying_byte_buffer_view=2050
|
||||
- MAX_ALLOCS_ALLOWED_ping_pong_1000_reqs_1_conn=4400
|
||||
- MAX_ALLOCS_ALLOWED_read_10000_chunks_from_file=190050
|
||||
- MAX_ALLOCS_ALLOWED_schedule_10000_tasks=90050
|
||||
- MAX_ALLOCS_ALLOWED_schedule_10000_tasks=90150
|
||||
- MAX_ALLOCS_ALLOWED_schedule_and_run_10000_tasks=100050
|
||||
- MAX_ALLOCS_ALLOWED_scheduling_10000_executions=20150
|
||||
- MAX_ALLOCS_ALLOWED_udp_1000_reqs_1_conn=12200
|
||||
- MAX_ALLOCS_ALLOWED_udp_1_reqs_1000_conn=190050
|
||||
|
|
|
@ -51,7 +51,8 @@ services:
|
|||
- MAX_ALLOCS_ALLOWED_modifying_byte_buffer_view=2050
|
||||
- MAX_ALLOCS_ALLOWED_ping_pong_1000_reqs_1_conn=4400
|
||||
- MAX_ALLOCS_ALLOWED_read_10000_chunks_from_file=160050
|
||||
- MAX_ALLOCS_ALLOWED_schedule_10000_tasks=90050
|
||||
- MAX_ALLOCS_ALLOWED_schedule_10000_tasks=90150
|
||||
- MAX_ALLOCS_ALLOWED_schedule_and_run_10000_tasks=100050
|
||||
- MAX_ALLOCS_ALLOWED_scheduling_10000_executions=20150
|
||||
- MAX_ALLOCS_ALLOWED_udp_1000_reqs_1_conn=12200
|
||||
- MAX_ALLOCS_ALLOWED_udp_1_reqs_1000_conn=188050
|
||||
|
|
Loading…
Reference in New Issue