swift-server / swift-server/async-http-client

Undesired (as in older faster than newer) perf delta between older and newer APIs

Open
#756 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Swift
Stars
1.1k
Forks
156
PR merge metrics
No merged PRs in 30d

Description

Expected behavior

The newer AHC interfaces should be as fast as the older ones (or faster!). At least if installing NIO as the Concurrency executor (or NIO executor preference) to avoid thread hops.

Actual behavior

Slower. My (silly and not super scientific) benchmark is

  • 100k real but super basic (just GET / response just HTTP/1.1 200 ok\r\n\r\nHello World) HTTP requests to a real server (NIOHTTP1Server) over loopback on macOS (but using MultiThreadedEventLoopGroup.singleton for perf). Thread hop costs should be minimal here because it should be just a single hop onto the I/O and back. And we'll need to wait for the server anyway.

Here are the results:

  • AHC with future-based API: 5.9s
  • AHC with async API and NIO as executor (no hops): 7.1s (+ 1.2 seconds)
  • AHC with async API and default executor (a few hops): 8.7s ( + 1.6 seconds from no hops and + 2.8s from futures based)

The last two roughly line up. Cost of a thread hop ~10us: 100k * 10us * 2 (cause onto and off of I/O) = 2s and the actual difference is 1.6s. So the real costs were slightly lower (8 µs) which makes sense. We know

I was however a little surprised that the async API was 1.2s slower without adding any thread hops.

The most egregious and avoidable time wasters were a silly EventLoop.debugDescription and NSURL in general which I filed as separate issues:
https://github.com/swift-server/async-http-client/issues/754
https://github.com/swift-server/async-http-client/issues/755

Steps to reproduce
  1. check out https://github.com/weissi/async-http-client/commit/bf7dbeb933433bc111942808ec5ed9108c44be72
  2. swift build -c release
  3. .build/release/AsyncHTTPClientPerfTester

to test without NIO as the executor, comment out these lines: let success = NIOSingletons.unsafeTryInstallSingletonPosixEventLoopGroupAsConcurrencyGlobalExecutor() and precondition(success)

If possible, minimal yet complete reproducer code (or URL to code)

[anything to help us reproducing the issue]

See also

Two other issues turned up which should make all of the above APIs significantly faster (could be about 15% better if both were completely fixed)

  • #754
  • #755

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the benchmark at commit bf7dbeb933433bc111942808ec5ed9108c44be72 and run swift build -c release followed by .build/release/AsyncHTTPClientPerfTester. Compare the future-based and async APIs with and without the NIO concurrency executor, while considering the separate issues #754 and #755. Done means identifying and resolving the remaining performance gap so the newer APIs are at least as fast under this benchmark.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
networking, performance
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.