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
This commit is contained in:
parent
9e451149ca
commit
768c3ab328
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue