Commit Graph
74 Commits
Author SHA1 Message Date
Kushal Pisavadia 9b92dcd5c2 Replace ConditionLock with wake-one signalling NIOThreadPoolWorkAvailable (#3507)
**TL;DR** This change leads to a ~90% reduction in observed system CPU
time for some use cases by waking a single thread, instead of all idle
threads.

# Changes

Inlining the commit messages here.

## Add NIOThreadPool submit throughput benchmarks

### Motivation

`NIOThreadPool` had no benchmarks measuring submit overhead. This makes
it difficult to evaluate the cost of signalling changes or to catch
latency regressions.

### Modifications

Add thread pool submit benchmarks, covering use cases with 4-thread and
16-thread pools.

### Result

`NIOThreadPool` submit throughput and context-switch overhead are now
tracked by benchmarks.

### Benchmark Results

<details>

```
NIOThreadPool.serial_wakeup(16 threads)
╒══════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                   │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞══════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ Context switches (K)     │        77 │        78 │        79 │        80 │        80 │        92 │        92 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Syscalls (total) (K) *   │       106 │       107 │       108 │       109 │       110 │       116 │       116 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (system CPU) (ms) * │      1649 │      1752 │      1768 │      1795 │      1826 │      1929 │      1929 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (total CPU) (ms) *  │      1701 │      1805 │      1821 │      1849 │      1879 │      1987 │      1987 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (user CPU) (ms) *   │        51 │        52 │        52 │        53 │        53 │        57 │        57 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (wall clock) (ms) * │       167 │       177 │       178 │       181 │       183 │       200 │       200 │        30 │
╘══════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

NIOThreadPool.serial_wakeup(4 threads)
╒══════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                   │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞══════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ Context switches (K)     │        44 │        44 │        44 │        45 │        45 │        45 │        45 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Syscalls (total) (K) *   │        65 │        65 │        65 │        66 │        66 │        67 │        67 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (system CPU) (ms) * │       159 │       162 │       163 │       165 │       166 │       169 │       169 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (total CPU) (ms) *  │       178 │       182 │       183 │       185 │       186 │       190 │       190 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (user CPU) (ms) *   │        19 │        19 │        20 │        20 │        20 │        21 │        21 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (wall clock) (ms) * │        76 │        79 │        79 │        80 │        80 │        82 │        82 │        30 │
╘══════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛
```

</details>

## Replace `ConditionLock` with wake-one signalling
`NIOThreadPoolWorkAvailable`

### Motivation

`NIOThreadPool` used `ConditionLock` which calls
`pthread_cond_broadcast` on every state change, waking all threads when
only one work item is enqueued. This causes a thundering-herd problem.

### Modifications

Add `NIOThreadPoolWorkAvailable` in NIOConcurrencyHelpers that uses
`pthread_cond_signal` (wake-one) for work submission and
`pthread_cond_broadcast` only for shutdown. Replace
`ConditionLock<_WorkState>` and the `_WorkState` enum in `NIOThreadPool`
with this new primitive.

### Result

Submitting a work item wakes exactly **one** thread instead of all
threads.

### Benchmark Results

<details>

```
NIOThreadPool.serial_wakeup(16 threads)
╒══════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                   │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞══════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ Context switches (K)     │        20 │        20 │        20 │        20 │        20 │        20 │        20 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Syscalls (total) (K) *   │        40 │        40 │        40 │        40 │        40 │        40 │        40 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (system CPU) (ms) * │        47 │        49 │        49 │        50 │        50 │        55 │        55 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (total CPU) (ms) *  │        57 │        58 │        59 │        60 │        61 │        67 │        67 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (user CPU) (ms) *   │        10 │        10 │        10 │        10 │        10 │        12 │        12 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (wall clock) (ms) * │        54 │        55 │        56 │        56 │        57 │        65 │        65 │        30 │
╘══════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛

NIOThreadPool.serial_wakeup(4 threads)
╒══════════════════════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╤═══════════╕
│ Metric                   │        p0 │       p25 │       p50 │       p75 │       p90 │       p99 │      p100 │   Samples │
╞══════════════════════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╪═══════════╡
│ Context switches (K)     │        20 │        20 │        20 │        20 │        20 │        20 │        20 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Syscalls (total) (K) *   │        40 │        40 │        40 │        40 │        40 │        40 │        40 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (system CPU) (ms) * │        45 │        46 │        46 │        47 │        57 │        75 │        75 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (total CPU) (ms) *  │        54 │        55 │        56 │        57 │        68 │        87 │        87 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (user CPU) (μs) *   │      9055 │      9372 │      9478 │      9765 │     10887 │     12585 │     12585 │        30 │
├──────────────────────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┼───────────┤
│ Time (wall clock) (ms) * │        52 │        53 │        53 │        54 │        64 │       124 │       124 │        30 │
╘══════════════════════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╧═══════════╛
```

</details>
2026-02-10 20:01:35 +00:00
Marc Prud'hommeaux a24771a4c2 Fix the Android CI workflow by adding a post-install step the configure the SDK (#3424)
Fixes the Android CI workflow

### Motivation:

The recently-added Android SDK workflow
[fails](https://github.com/apple/swift-nio/actions/runs/18718487605/job/53384086329?pr=3418)
(as mentioned at
https://github.com/apple/swift-nio/pull/3418#issue-3540969388). The
confusing error message is due to a post-install step that is needed to
download and link the Android NDK into the Swift SDK's artifactbundle.

This PR also adds a one-line fix to
[Sources/NIOPerformanceTester/main.swift](https://github.com/apple/swift-nio/compare/main...swift-android-sdk:swift-nio:main#diff-de179adbbfacb89c9533f4efd21f7f641eedc0c8642d7d650cdfc9d9278a7a55)
that gets it building for Android so the entire swift-nio package can be
built.

### Modifications:

Adds a post-install step to the SDK installation that is needed for the
Swift SDK for Android. This is the same technique used by
https://github.com/swiftlang/github-workflows/pull/172, and is described
as a necessary step in the [Android getting started
guide](https://github.com/swiftlang/swift-org-website/blob/0dc655ce267e7b6bada2a2032cc7855c3b5e19d9/documentation/articles/swift-android-getting-started.md)

### Result:

The "Android Swift SDK" CI check should now pass successfully. See an
example at
https://github.com/swift-android-sdk/swift-nio/actions/runs/18761057590/job/53525442382

### Note:

This PR will _not_ pass the Android check until it has been merged,
because it relies on being able to down the the script
https://raw.githubusercontent.com/apple/swift-nio/main/scripts/install_swift_sdk.sh
from `apple/swift-nio/main`, which will not include the Android fix
until the PR is merged. But once it is merged, the Android SDK CI should
start passing.
2025-10-30 10:04:17 +00:00
Johannes Weiss 57d65ddf9c inEventLoop benchmark (#3301)
### Motivation:

PR #3297 is changing `inEventLoop` and `inEventLoop` is very much on the
perf path. So let's add a benchmark

### Modifications:

- Add `(!)inEventLoop` benchmark
- Fix a guaranteed deadlock in `TCPThroughputBenchmark` to make the
benchmarks runnable

### Result:

- More benchmarks
- Fewer hangs
2025-07-14 10:50:58 +00:00
Roman A f3645a02b7 a couple grammar fixes (#3259) 2025-05-30 10:34:44 +00:00
George Barnett 4b7854daaa Strict concurrency for NIOPerformanceTester and NIOCrashTester (#3167) 2025-04-07 14:10:48 +00:00
bf41ad1595 Improve HTTPHeaders description performance (#3063)
### Motivation:

As outlined in this
[issue](https://github.com/apple/swift-nio/issues/2930) by @weissi, the
current performance of calling `description` on `HTTPHeaders` is
undermined by the dynamism of Array.

### Modifications:

The proposed solution replaces the implementation of `description` to
iterate over the items and print them out manually. This provides a
faster solution since we bypass the cost of calling into `description`
of an Array.


### Result:

A more performant implementation of `HTTPHeaders` description.

---------

Co-authored-by: Johannes Weiss <johannesweiss@apple.com>
Co-authored-by: Cory Benfield <lukasa@apple.com>
2025-01-20 16:39:21 +00:00
Cory Benfield de116b7eff Clean up Sendability for ChannelInvoker (#2955)
Motivation:

The ChannelInvoker protocols are an awkward beast. They aren't really
something that people can do generic programming against. Instead, they
were designed to do API sharing. Of course, they didn't do that very
well, and the strict concurrency checking world has revealed this.

Much of the API surface on ChannelInvoker is confused. There are
NIOAnys, which aren't Sendable. We allow sending user events without
requiring Sendable. And our two main conforming types are
ChannelPipeline and ChannelHandlerContext, two types with wildly
differing thread-safety semantics.

This PR aims to clean that up.

Modifications:

- Deprecated all API surface on ChannelInvoker protocols that uses
NIOAny.

    ChannelInvoker has to be assumed to be a cross-thread protocol,
    and that requires that it only use Sendable types. NIOAny isn't,
    so these methods are no longer sound.

- Re-add non-deprecated versions on ChannelHandlerContext.

    While it's not safe to use the NIOAny methods on Channel or
    ChannelPipeline, it's totally safe to use them on
    ChannelHandlerContext. So we keep those available and
    undeprecated.

- Provide typed generic replacements on ChannelPipeline and on Channel

    To replace the NIOAny methods on ChannelPipeline and Channel
    we can use some typed generic ones instead. These are not
    defined on ChannelInvoker, as the methods are useless on
    ChannelHandlerContext. This begins the acknowledgement that
    ChannelHandlerContext should not have conformed to these
    protocols at all.

- Add Sendable constraints to the user event witnesses on ChannelInvoker

    Again, these were missing, but must be there for Channel and
    ChannelPipeline.

- Provide non-Sendable overloads on ChannelHandlerContext

    ChannelHandlerContext is thread-bound, and so may safely pass
    non-Sendable user events.

Result:

One step closer to strict concurrency cleanliness for NIOCore.
2024-10-31 11:30:27 +00:00
Ayush Garg 7840b6b067 ChannelOption: Allow types to be accessed with leading dot syntax (#2816)
Motivation:

Since Swift 5.5 and [SE-0299](https://github.com/swiftlang/swift-evolution/blob/main/proposals/0299-extend-generic-static-member-lookup.md) it is possible to add static members to protocols which are discoverable through the shorthand dot syntax.
This change reduces type repetition and improves call-site legibility.

Modifications:

Added extensions for ChannelOption with static members where Self is bound to a concrete type.

Result:

ChannelOption types can be used with the leading dot syntax. For eg:

```
//before
.channelOption(ChannelOptions.explicitCongestionNotification, value: true)
.channelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)

//after
.channelOption(.explicitCongestionNotification, value: true)
.channelOption(.socketOption(.so_reuseaddr), value: 1)
```
2024-07-30 15:19:59 +00:00
Franz Busch c9756e1083 Adopt swift-format (#2794)
* Apply formatting

* Apply no block comments rule

* Apply OmitExplicitReturns

* Apple OnlyOneTrailingClosureArgument

* Apply NoAssignmentInExpressions

* Fix up DontRepeatTypeInStaticProperties lint errors

* Apply `OrderedImports`

* Apply `ReplaceForEachWithForLoop`

* format file

* Enable the formatting pipeline

* Adopt `AmbiguousTrailingClosureOverload`

* Fix license header

* Fix format check

* Fix `EndOfLineComment`

* Fix CI

* Adapt CI script to check if changes when running formatting

* Separate lint and format into to steps

* Fix format

* Adopt `UseEarlyExits`

* Revert "Adopt `UseEarlyExits`"

This reverts commit d1ac5bbe12.
2024-07-19 11:48:17 +02:00
Johannes Weiss 7948ed2104 ChannelHandler: provide static (un)wrap(In|Out)bound(In|Out) (#2791) 2024-07-18 11:55:48 +01:00
ser 196ceab4b2 Fix race in TCPThroughputBenchmark (#2724) 2024-05-20 09:52:05 -07:00
Franz BuschandCory Benfield 63e8c4e1aa Migrate to syncOperations in more places (#2661)
# Motivation

Adding a handler via the regular `pipeline.addHandler` APIs can lead to transferring the handler over isolation regions. To avoid running into `Sendable` warnings here we can use the `syncOperations` of the pipeline to avoid transferring the handlers.

# Modification

This PR is mostly changing code to avoid transferring handlers to and from the event loops in tests. This should be a no-op mostly.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2024-03-01 15:05:22 +00:00
Gregor Milos (Grzegorz Miłoś) 325f762a8b Remove unreliable SchedulingBenchmark (#2650)
* Fix `SchedulingBenchmark` preheating logic.

Motivation:

At the moment `SchedulingBenchmark` preheats single EL to a specified number of tasks. However, the actual performance test runs number of times, and EL doesn't get drained in between the runs.

There are two problems with it:
* perf test will trigger task heap dublings, which the preheating aims to avoid
* each test run will be working with proportionally deeper heap, which means the run times are going to grow with each run

Modifications:

I plumbed through the # of runs to the `Benchmark.setUp`, and prepare ELG with # of ELs that match the expected number of runs.

Result:

Performance test will be more reliable.

* Revert "Fix `SchedulingBenchmark` preheating logic."

This reverts commit 859ba72c78.

* Remove SchedulingBenchmark. Deemed not valuable enough.
2024-03-01 11:10:46 +00:00
Gregor Milos (Grzegorz Miłoś) c3b6f1f3f5 Fix CoW performance bug in NIOThreadPool work queue (#2669)
* Benchmark for measuring NIOThreadPool dispatch

* Avoid CoW cost for NIOThreadPool work queue

* Flip stray `var` to a `let`.

* Use .modifying state to prevent CoW, not a class

* Removing some obselete comment noise.

* Use Deque instead of CirclarBuffer in NIOThreadPool

* Ratchet down the # of allocs for read_10000_chunks_from_file. NIOTheadPool changes reduced the allocations required.
2024-02-28 15:43:52 +00:00
Cory Benfield 52908578ed Fix the broken performance test binary (#2619)
Motivation:

The performance test binary was crashing ever since #2589 added the crash
on deinit flow. Crashes here are preventing us from using the performance
tester.

Modifications:

Correctly clean up the async writer.

Result:

The writer is cleaned up now.
2024-01-03 07:16:25 +00:00
Franz Busch 118de503e2 Add withInboundOutboud to NIOAsyncChannel and deprecate deinit ba… (#2589)
* Add `withInboundOutboud` to `NIOAsyncChannel` and deprecate deinit based cleanup

# Motivation
We just released our new async NIO APIs and have already gotten quite a bunch of feedback from adopters. One of the feedback was that the deinit based closing that we have added to the `NIOAsyncChannel` has caused problems since it leads to unexpected closure of their `Channel`. Furthermore, it makes it impossible to determine how many open sockets a program has at any given time since deinit based clean up relies on the optimizer and can happen at random times.

# Modifications
This PR adds new inits to `NIOAsyncSequenceProducer` and `NIOAsyncWriter` which disable the `deinit` based clean up and instead replace them with an assertion. This allows developers to still catch these issues at debug time. Furthermore, I added a new `withInboundOutbound` scoped access to `NIOAsyncChannel` which will close the channel at the end of the scope. This still gives users a nice API while not having to care much about closing themselves.

# Result
We are no longer using deinit based clean up and bring back one of the core principles of NIO which is deterministic resource usage.

* Review comments

* Internal labels for closure arguments

* Rename to `executeThenCloseChannel`

* Actually call `sinkDeinitialized`

* Change preconditions

* Move logic to deinits

* Rename to `executeThenClose` and review nits
2023-11-13 03:37:54 -08:00
Cory Benfield 54c85cb263 Fix thread-safety issues in TCPThroughputBenchmark (#2537)
Motivation:

Several thread-safety issues were missed in code review. This patch fixes them.

Modifications:

- Removed the use of an unstructured Task, replaced with eventLoop.execute to
  ServerHandler's EventLoop.
- Stopped ClientHandler reaching into the benchmark object without any
  synchronization, used promises and event loop hops instead.

Result:

Thread safety is back
2023-10-25 02:20:49 -07:00
Johannes Weiss 8c3cac7774 perf tests: reset BB indices after every iteration (#2544) 2023-10-10 16:15:11 +01:00
David Nadoba e0cc6dd6ff Throw CancellationError instead of returning nil during early cancellation. (#2401)
### Motivation:
Follow up PR for https://github.com/apple/swift-nio/pull/2399

We currently still return `nil` if the current `Task` is canceled before the first call to `NIOThrowingAsyncSequenceProducer.AsyncIterator.next()` but it should throw `CancellationError` too.

In addition, the generic `Failure` type turns out to be a problem. Just throwing a `CancellationError` without checking that `Failure` type is `any Swift.Error` or `CancellationError` introduced a type safety violation as we throw an unrelated type.

### Modifications:

- throw `CancellationError` on eager cancellation
-  deprecates the generic `Failure` type of `NIOThrowingAsyncSequenceProducer`. It now must always be `any Swift.Error`. For backward compatibility we will still return nil if `Failure` is not `any Swift.Error` or `CancellationError`.

### Result:

`CancellationError` is now correctly thrown instead of returning `nil` on eager cancelation. Generic `Failure` type is deprecated.
2023-04-11 08:58:01 -07:00
carolinacass 5db1dfabb0 Building swift-nio with Swift 5.7 for iOS using Xcode 14.0 at 2.48.0. (#2369)
Motivation:
swift- nio was failing builds that should pass

Modifications:
Adding available to the necessary sections
2023-02-17 10:05:43 -08:00
George Barnett 734a0ba103 Add availability requirements to TCPThroughputBenchmark (#2368)
Motivation:

- Uses Concurrency but missing availability requirements; does not build
  on macOS.

Modifications:

- Add availability requirements/guards

Result:

Compiles on macOS
2023-02-16 11:55:14 +00:00
ser ab43dc6949 TCP channel throughput benchmark. (#2367)
* TCP channel throughput benchmark.

* Cosmetic fixes.

* Add license to the source code.
2023-02-15 16:00:10 +00:00
George Barnett dfd4bdad89 Add UDP performance tests (#2360)
Motivation:

We don't have any UDP performance tests.

Modifications:

- Add UDP perf tests

Result:

We can measure perf improvements for UDP.
2023-02-06 15:50:47 +00:00
Franz BuschandCory Benfield 1abe64c5e6 Add benchmarks for NIOAsyncWriter and NIOAsyncSequenceProducer (#2301)
# Motivation
We landed the async bridge types a while back but never added allocation and performance tests. Since we expect these types to be used performance critical paths we really should cover those with tests.

# Modification
Extends the allocation counter scaffolding to support async tests. Furthermore, add allocations tests for both the writer and producer. Lastly, I a also added a performance test for the producer.

# Result
We now have baseline tests for the `NIOAsyncWriter` and `NIOAsyncSequenceProducer`

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-10-26 03:51:20 -07:00
David Nadoba c7b4989b02 Remove #if compiler(>=5.5) (#2292)
### Motivation
We only support Swift 5.5.2+.

### Modification
Remove all `#if swift(>=5.5)` conditional compilation blocks.

### Result
less branching
2022-10-13 07:17:46 -07:00
Johannes Weiss 4ed8e1e228 rename class Lock to struct NIOLock (#2266) 2022-09-21 07:36:42 -07:00
Franz Busch f144292e5d Implement a NIOAsyncWriter (#2251)
* Implement a `NIOAsyncWriter`

# Motivation
We previously added the `NIOAsyncProducer` to bridge between the NIO channel pipeline and the asynchronous world. However, we still need something to bridge writes from the asynchronous world back to the NIO channel pipeline.

# Modification
This PR adds a new `NIOAsyncWriter` type that allows us to asynchronously `yield` elements to it. On the other side, we can register a `NIOAsyncWriterDelegate` which will get informed about any written elements. Furthermore, the synchronous side can toggle the writability of the `AsyncWriter` which allows it to implement flow control.
A main goal of this type is to be as performant as possible. To achieve this I did the following things:
- Make everything generic and inlinable
- Use a class with a lock instead of an actor
- Provide methods to yield a sequence of things which allows users to reduce the amount of times the lock gets acquired.

# Result
We now have the means to bridge writes from the asynchronous world to the synchronous

* Remove the completion struct and incorporate code review comments

* Fixup some refactoring leftovers

* More code review comments

* Move to holding the lock around the delegate and moved the delegate into the state machine

* Comment fixups

* More doc fixes

* Call finish when the sink deinits

* Refactor the writer to only yield Deques and rename the delegate to NIOAsyncWriterSinkDelegate

* Review

* Fix some warnings

* Fix benchmark sendability

* Remove Failure generic parameter and allow sending of an error through the Sink
2022-09-21 02:53:53 -07:00
Si Beaumont 9294f8da3b NIOPerformanceTester: Increase operations used in lock benchmarks from 1M to 10M (#2121) 2022-05-18 10:53:51 +01:00
Si Beaumont 771257cc23 NIOPerformanceTester: Add DeadlineNowBenchmark for NIODeadline.now() (#2117)
* NIOPerformanceTester: Add DeadlineNowBenchmark for NIODeadline.now()

Signed-off-by: Si Beaumont <beaumont@apple.com>

* fixup: Return counter from benchmark

Signed-off-by: Si Beaumont <beaumont@apple.com>
2022-05-16 19:21:31 +01:00
Si BeaumontandCory Benfield 684c09315f Use unbuffered IO for stdout in NIOPerformanceTester (#2072)
* Use unbuffered IO for stdout in NIOPerformanceTester

Signed-off-by: Si Beaumont <beaumont@apple.com>

* CRASH PERF TESTS: Up task count to 1M to test logging change

* Revert "CRASH PERF TESTS: Up task count to 1M to test logging change"

This reverts commit d8fa50eb15.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-04-20 13:16:14 -07:00
Si Beaumont 1af9615110 Increase runtime of performance tests to O(10 ms) to increase SNR (#2063)
Signed-off-by: Si Beaumont <beaumont@apple.com>
2022-03-24 07:42:24 -07:00
Si BeaumontandCory Benfield be5fb3c170 Add benchmarks for copying CircularBuffer to Array (#2058)
Signed-off-by: Si Beaumont <beaumont@apple.com>

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-03-07 08:39:28 -08:00
Sebastian Vogt 7000510fd7 Add benchmark for BBV contains. (#1385) (#2042)
* Add ByteBufferView contains benchmark.

* Add ByteBufferView contains benchmark.

* Add ByteBufferView contains benchmark.
2022-02-08 22:06:21 -08:00
Cory Benfield 3a3e6cb9e3 Add benchmarks for copying BBV to Array. (#2037)
Motivation:

Protocols like Sequence have "private" hooks that can be implemented to
provide fast-paths for some operations. We missed a few on BBV, and I'd
like to add them. This is one use-case where they can help.

Modifications:

- Add an allocation-counter benchmark and a runtime benchmark for
  copying BBV to Array.

Result:

We have some benchmarks.
2022-02-03 01:36:12 -08:00
Franz Busch 213eb6887e 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`
2021-12-13 16:33:13 +00:00
Johannes Weiss 2ef5cbee6b benchmarks: lock performance for 1, 2, 4, 8 threads wanting lock (#1994)
Motivation:

To judge the cost of `PTHREAD_MUTEX_ERRORCHECK` as well as
`os_unfair_lock` vs `pthread_mutex_t` it's useful to have a few simple
benchmarks.

Modification:

Add lock benchmarks.

Result:

Better data.
2021-11-29 09:07:40 +00:00
Johannes Weiss b2629903ca ByteBuffer: provide multi read/write int methods (#1987)
Motivation:

Many network protocols (especially for example NFS) have quite a number
of integer values next to each other. In NIO, you'd normally parse/write
them with multiple read/writeInteger calls.

Unfortunately, that's a bit wasteful because we're checking the bounds
as well as the CoW state every time.

Modifications:

- Provide read/writeMultipleIntegers for up to 15 FixedWidthIntegers.
- Benchmarks

Result:

Faster code. For 10 UInt32s, this is a 5x performance win on my machine,
see benchmarks.
2021-11-22 14:58:52 +00:00
Cory Benfield d906b890d5 Add perf hooks for testing substring path. (#1976) 2021-10-13 12:08:37 +01:00
George Barnett 7e1ca33bc9 Add performance and allocation tests for canonical form headers (#1953)
Motivation:

To justify performance changes we need to measure the code being
changed. We believe that `HTTPHeaders.subscript(canonicalForm:)` is a
little slow.

Modifications:

- Add allocation and performance tests for fetching header values in
  their canonical form

Results:

More benchmarks!
2021-09-13 16:28:07 +01:00
Cory Benfield b05c6f2206 Move NIO to NIOPosix, make NIO a shell. (#1936)
Motivation:

The remaining NIO code really conceptually belongs in a module called
NIOPosix, and NIOCore should really be called NIO. We can't really do
that last step, but we can prepare by pushing the bulk of the remaining
code into a module called NIOPosix.

Modifications:

- Move NIO to NIOPosix
- Make NIO an umbrella module.

Result:

NIOPosix exists.
2021-08-16 16:50:40 +01:00
Cory BenfieldandGeorge Barnett 64285cbff2 Clean up dependencies and imports. (#1935)
Motivation:

As we've largely completed our move to split out our core abstractions,
we now have an opportunity to clean up our dependencies and imports. We
should arrange for everything to only import NIO if it actually needs
it, and to correctly express dependencies on NIOCore and NIOEmbedded
where they exist.

We aren't yet splitting out tests that only test functionality in
NIOCore, that will follow in a separate patch.

Modifications:

- Fixed up imports
- Made sure our protocols only require NIOCore.

Result:

Better expression of dependencies.

Co-authored-by: George Barnett <gbarnett@apple.com>
2021-08-12 13:49:46 +01:00
Maxim ZaksandCory Benfield cf054f27b5 Add performance test for web socket client random request key (#1863)
* Add performance test for web socket client random request key

* use `reduce` function to minimise memory consumption of the test

Co-authored-by: Cory Benfield <lukasa@apple.com>
2021-06-01 11:08:13 +01:00
Johannes WeissandCory Benfield e0963def86 bring back accidental commented benchmark (#1833)
Motivation:

In #1733 I accidentally commented out a perf benchmark (who knows why).

Modification:

Bring it back.

Result:

Benchmark is back.

Co-authored-by: Cory Benfield <lukasa@apple.com>
2021-04-29 12:06:57 +01:00
Johannes Weiss c5a214f075 B2MD: Don't try to reclaim if continuing to parse (#1733)
Motivation:

B2MD called out to the decoder's `shouldReclaimBytes` after every
parsing attempt, even if the parser said `.continue`.

That's quite pointless because we won't add any bytes into the buffer
before we're trying the parser again.

Modifications:

Only ask the decoder if we should reclaim bytes if the decoder actually
says `.needMoreData`.

Result:

Faster, better, more sensible.
2021-01-29 17:03:04 +00:00
Cory Benfield 8ea768b0b8 Add static vars for common HTTP versions (#1723)
Motivation:

I'm sick of typing `.init(major: 1, minor: 1)`.

Modifications:

- Added static vars for common HTTP versions.

Result:

Maybe I'll never type `.init(major: 1, minor: 1)` ever again.
2021-01-19 17:27:02 +00:00
Peter Adams b671e557fd Only use ascii characters in perf test names. (#1718)
Motivation:

Many other systems don't like non ascii characters.

Modifications:

Change a letter 'a' to a letter 'a' but with a more normal encoding.

Result:

Test names should be in ascii
2021-01-11 07:32:39 +00:00
Johannes Weiss fe10c5c063 Change the class restriction on our protocols to AnyObject (#1702)
Motivation:

In all contemporary Swift versions, the `class` and the `AnyObject`
protocol restriction is the same. And `class` is deprecated which warns
on newer Swift compilers.

Modifications:

Replace `class` with `AnyObject`.

Result:

No warnings on newer Swift compilers.
2020-12-09 19:43:11 +00:00
Cory Benfield 30265d69a8 Adjust names of BSDSocket option values. (#1510)
Motivation:

The names of most of the BSD socket option values were brought over into
their NIO helper properties, with their namespace removed. This vastly
increases the risk of collision, particularly for things like TCP_INFO,
which just became .info.

Modifications:

- Added the prefixes back, e.g. `.info` is now `.tcp_info`.
- Renamed socket type `.dgram` to `.datagram`, as this is the nice clean
  API and we should use nice clean names.

Result:

Better APIs
2020-05-11 15:13:58 +01:00
Saleem AbdulrasoolandCory Benfield bcc180dab6 Add new BSDSocket namespace (#1461)
* NIO: Add new `BSDSocket` namespace

This starts the split of the POSIX/Linux/Darwin/BSD interfaces and the
BSD Socket interfaces in order to support Windows.  The constants on
Windows are not part of the C standard library and need to be explicitly
prefixed.  Use the import by name to avoid the `#if` conditions on the
wrapped versions.  This will allow us to cleanly cleave the dependency
on the underlying C library.

This change adds a `BSDSocket.OptionLevel` and `BSDSocket.Option` types
which allow us to get proper enumerations for these values and pipe them
throughout the NIO codebase.

* Apply suggestions from code review

Co-Authored-By: Cory Benfield <lukasa@apple.com>
2020-04-02 19:06:48 +01:00
Johannes Weiss c6e5fe88e1 ByteBuffer: make getInteger for UInt8 faster (#1380)
Motivation:

getInteger used the normal, generic implementation for UInt8s, however
they can be made considerably faster by using a specialised method.
ByteBufferIterator was also affected by this.

Modifications:

Use a specialised version for UInt8s for getInteger.

Result:

- ByteBufferView can be iterated about 20% faster.
2020-02-06 11:59:10 +00:00