Skip to content
Permalink
Browse files

Avoid unnecessary allocation by way of tuple conversion. (#994)

Motivation:

Due to https://bugs.swift.org/browse/SR-10614, assigning an array containing a tuple type
to a variable that expects an array containing a different-but-compatible tuple type will cause
an allocation and copy of that array storage.

In some cases this is necessary, but we were doing it in the HTTPHeaders constructors, which meant
that the swift-nio-http2 code was hitting a hilariously over the top number of allocations.

Modifications:

- Change the internal storage type of HTTPHeaders to match the public constructor.

Result:

Fewer allocations when constructing HTTPHeaders
  • Loading branch information...
Lukasa committed May 3, 2019
1 parent 9e45114 commit 768c3ab328a79cb5a4a4f91094050206aaf11328
@@ -19,7 +19,7 @@ token=$(create_token)
start_server "$token"
do_curl "$token" -H "foo: bar" --http1.0 \
"http://foobar.com/dynamic/info" > "$tmp/out"
if ! grep -q '(name: "foo", value: "bar")' "$tmp/out"; then
if ! grep -q '("foo", "bar")' "$tmp/out"; then
fail "couldn't find header in response"
fi
stop_server "$token"
@@ -58,7 +58,7 @@ cd ..
"$swift_bin" run -c release | tee "$tmp/output"
)

for test in 1000_reqs_1_conn 1_reqs_1000_conn ping_pong_1000_reqs_1_conn bytebuffer_lots_of_rw future_lots_of_callbacks scheduling_10000_executions; do
for test in 1000_reqs_1_conn 1_reqs_1000_conn ping_pong_1000_reqs_1_conn bytebuffer_lots_of_rw future_lots_of_callbacks scheduling_10000_executions creating_10000_headers; do
cat "$tmp/output" # helps debugging
total_allocations=$(grep "^$test.total_allocations:" "$tmp/output" | cut -d: -f2 | sed 's/ //g')
not_freed_allocations=$(grep "^$test.remaining_allocations:" "$tmp/output" | cut -d: -f2 | sed 's/ //g')
@@ -452,5 +452,16 @@ public func swiftMain() -> Int {
return 10_000
}

measureAndPrint(desc: "creating_10000_headers") {
var count = 0

for i in 0..<10_000 {
let baseHeaders: [(String, String)] = [("Host", "example.com"), ("Content-Length", "4")]
count += HTTPHeaders(baseHeaders).count
}

return count
}

return 0
}
@@ -278,7 +278,7 @@ extension HTTPHeaders {
/// or split representation, such that header fields that are able to be repeated
/// can be represented appropriately.
public struct HTTPHeaders: CustomStringConvertible, ExpressibleByDictionaryLiteral {
internal var headers: [(name: String, value: String)]
internal var headers: [(String, String)]
internal var keepAliveState: KeepAliveState = .unknown

public var description: String {
@@ -289,7 +289,7 @@ public struct HTTPHeaders: CustomStringConvertible, ExpressibleByDictionaryLiter
return self.headers.map { $0.0 }
}

internal init(_ headers: [Element], keepAliveState: KeepAliveState) {
internal init(_ headers: [(String, String)], keepAliveState: KeepAliveState) {
self.headers = headers
self.keepAliveState = keepAliveState
}
@@ -452,7 +452,7 @@ extension HTTPHeaders: RandomAccessCollection {
public typealias Element = (name: String, value: String)

public struct Index: Comparable {
fileprivate let base: Array<HTTPHeaders>.Index
fileprivate let base: Array<(String, String)>.Index
public static func < (lhs: Index, rhs: Index) -> Bool {
return lhs.base < rhs.base
}
@@ -24,6 +24,7 @@ services:
- MAX_ALLOCS_ALLOWED_ping_pong_1000_reqs_1_conn=4600
- MAX_ALLOCS_ALLOWED_bytebuffer_lots_of_rw=2100
- MAX_ALLOCS_ALLOWED_future_lots_of_callbacks=99100
- MAX_ALLOCS_ALLOWED_creating_10000_headers=10100

test:
image: swift-nio:16.04-5.1
@@ -34,6 +35,7 @@ services:
- MAX_ALLOCS_ALLOWED_ping_pong_1000_reqs_1_conn=4600
- MAX_ALLOCS_ALLOWED_bytebuffer_lots_of_rw=2100
- MAX_ALLOCS_ALLOWED_future_lots_of_callbacks=99100
- MAX_ALLOCS_ALLOWED_creating_10000_headers=10100

echo:
image: swift-nio:16.04-5.1
@@ -23,6 +23,7 @@ services:
- MAX_ALLOCS_ALLOWED_bytebuffer_lots_of_rw=2100
- MAX_ALLOCS_ALLOWED_future_lots_of_callbacks=99100
- MAX_ALLOCS_ALLOWED_scheduling_10000_executions=20150
- MAX_ALLOCS_ALLOWED_creating_10000_headers=10100

test:
image: swift-nio:18.04-5.0
@@ -34,6 +35,7 @@ services:
- MAX_ALLOCS_ALLOWED_bytebuffer_lots_of_rw=2100
- MAX_ALLOCS_ALLOWED_future_lots_of_callbacks=99100
- MAX_ALLOCS_ALLOWED_scheduling_10000_executions=20150
- MAX_ALLOCS_ALLOWED_creating_10000_headers=10100

echo:
image: swift-nio:18.04-5.0

0 comments on commit 768c3ab

Please sign in to comment.
You can’t perform that action at this time.