Skip to content

Commit def29e6

Browse files
authored
Further reduce allocs (#75)
* Instead of a Semaphore use a channel to re-use an Event to reduce allocs by 7% per request * Update README.md with updated bencmarks
1 parent 75e4c28 commit def29e6

4 files changed

Lines changed: 45 additions & 26 deletions

File tree

README.md

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,13 @@ However, it is unlikely Julia will be used this way in the real world.
2424
```
2525
╭──────────────────────────────────┬─────────────┬────────────────┬────────────┬──────────────┬─────────┬──────┬──────╮
2626
│ Benchmark │ Avg Memory │ Avg Allocs │ Throughput │ Avg duration │ Std-dev │ Min │ Max │
27-
│ │ KiB/message │ allocs/message │ calls/s │ μs │ μs │ μs │ μs │
27+
│ │ KiB/message │ allocs/message │ messages/s │ μs │ μs │ μs │ μs │
2828
├──────────────────────────────────┼─────────────┼────────────────┼────────────┼──────────────┼─────────┼──────┼──────┤
29-
│ workload_smol │ 2.9572.5 │ 1842454 │ 3.54 │ 48 │ 66
30-
│ workload_32_224_224_uint8 │ 637.079.15481826405.4816022730
31-
│ workload_streaming_request │ 0.61 │ 6.6 │ 508983 │ 2 │ 0.67 │ 1 │ 15
32-
│ workload_streaming_response │ 12.99 │ 27.6 │ 194689 │ 5 │ 0.52 │ 4 │ 9
33-
│ workload_streaming_bidirectional │ 1.98 │ 25.5 │ 490718 │ 2 │ 0.59 │ 1 │ 13
29+
│ workload_smol │ 2.7867.5 │ 1834855 │ 3.36 │ 48 │ 70
30+
│ workload_32_224_224_uint8 │ 636.874.55531809370.9315822678
31+
│ workload_streaming_request │ 0.62 │ 6.6 │ 487223 │ 2 │ 0.68 │ 1 │ 14
32+
│ workload_streaming_response │ 13.0 │ 27.6 │ 192730 │ 5 │ 0.52 │ 4 │ 8
33+
│ workload_streaming_bidirectional │ 1.98 │ 25.5 │ 502387 │ 2 │ 0.56 │ 1 │ 14
3434
╰──────────────────────────────────┴─────────────┴────────────────┴────────────┴──────────────┴─────────┴──────┴──────╯
3535
```
3636

@@ -41,13 +41,13 @@ Using more threads isn't great for async IO, but this is likely how most people
4141
```
4242
╭──────────────────────────────────┬─────────────┬────────────────┬────────────┬──────────────┬─────────┬──────┬──────╮
4343
│ Benchmark │ Avg Memory │ Avg Allocs │ Throughput │ Avg duration │ Std-dev │ Min │ Max │
44-
│ │ KiB/message │ allocs/message │ calls/s │ μs │ μs │ μs │ μs │
44+
│ │ KiB/message │ allocs/message │ messages/s │ μs │ μs │ μs │ μs │
4545
├──────────────────────────────────┼─────────────┼────────────────┼────────────┼──────────────┼─────────┼──────┼──────┤
46-
│ workload_smol │ 2.9572.5 │ 18014 │ 56 │ 3.085064
47-
│ workload_32_224_224_uint8 │ 637.079.75671762 │ 99.0716281911
48-
│ workload_streaming_request │ 0.86 │ 6.5 │ 341851 │ 3 │ 1.68 │ 2 │ 30
49-
│ workload_streaming_response │ 13.0 │ 27.7 │ 64515165.12 │ 6 │ 33
50-
│ workload_streaming_bidirectional │ 1.41 │ 25.6 │ 102072 │ 10 │ 6.23 │ 4 │ 52
46+
│ workload_smol │ 2.7867.5 │ 17744 │ 56 │ 3.35166
47+
│ workload_32_224_224_uint8 │ 636.874.15781731 │ 99.3315831899
48+
│ workload_streaming_request │ 0.87 │ 6.5 │ 339916 │ 3 │ 1.61 │ 2 │ 20
49+
│ workload_streaming_response │ 13.0 │ 27.7 │ 65732154.94 │ 6 │ 50
50+
│ workload_streaming_bidirectional │ 1.45 │ 25.6 │ 105133 │ 10 │ 6.06 │ 4 │ 55
5151
╰──────────────────────────────────┴─────────────┴────────────────┴────────────┴──────────────┴─────────┴──────┴──────╯
5252
```
5353

docs/src/index.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,13 @@ benchmark_table()
158158
```
159159
╭──────────────────────────────────┬─────────────┬────────────────┬────────────┬──────────────┬─────────┬──────┬──────╮
160160
│ Benchmark │ Avg Memory │ Avg Allocs │ Throughput │ Avg duration │ Std-dev │ Min │ Max │
161-
│ │ KiB/message │ allocs/message │ calls/s │ μs │ μs │ μs │ μs │
161+
│ │ KiB/message │ allocs/message │ messages/s │ μs │ μs │ μs │ μs │
162162
├──────────────────────────────────┼─────────────┼────────────────┼────────────┼──────────────┼─────────┼──────┼──────┤
163-
│ workload_smol │ 2.9572.5 │ 18014 │ 56 │ 3.085064
164-
│ workload_32_224_224_uint8 │ 637.079.75671762 │ 99.0716281911
165-
│ workload_streaming_request │ 0.86 │ 6.5 │ 341851 │ 3 │ 1.68 │ 2 │ 30
166-
│ workload_streaming_response │ 13.0 │ 27.7 │ 64515165.12 │ 6 │ 33
167-
│ workload_streaming_bidirectional │ 1.41 │ 25.6 │ 102072 │ 10 │ 6.23 │ 4 │ 52
163+
│ workload_smol │ 2.7867.5 │ 17744 │ 56 │ 3.35166
164+
│ workload_32_224_224_uint8 │ 636.874.15781731 │ 99.3315831899
165+
│ workload_streaming_request │ 0.87 │ 6.5 │ 339916 │ 3 │ 1.61 │ 2 │ 20
166+
│ workload_streaming_response │ 13.0 │ 27.7 │ 65732154.94 │ 6 │ 50
167+
│ workload_streaming_bidirectional │ 1.45 │ 25.6 │ 105133 │ 10 │ 6.06 │ 4 │ 55
168168
╰──────────────────────────────────┴─────────────┴────────────────┴────────────┴──────────────┴─────────┴──────┴──────╯
169169
```
170170

src/Curl.jl

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,9 @@ mutable struct gRPCRequest
231231
end
232232

233233
# Reduce number of available requests by one or block if its currently zero
234-
acquire(grpc.sem)
234+
# Also reduces the need to allocate the curl_done_reading Event for every request
235+
# This is a 7% reduction in allocations overall
236+
curl_done_reading = max_reqs_dec(grpc)
235237

236238
easy_handle = curl_easy_init()
237239

@@ -287,7 +289,7 @@ mutable struct gRPCRequest
287289
false,
288290
false,
289291
0,
290-
Event(),
292+
curl_done_reading,
291293
GRPC_OK,
292294
"",
293295
)
@@ -324,7 +326,8 @@ mutable struct gRPCRequest
324326
curl_slist_free_all(headers)
325327
unpreserve_handle(req)
326328
# *MUST* increment the sem or we could deadlock
327-
release(grpc.sem)
329+
max_reqs_inc(grpc, req)
330+
328331
throw(
329332
gRPCServiceCallException(
330333
GRPC_FAILED_PRECONDITION,
@@ -678,7 +681,7 @@ mutable struct gRPCCURL
678681
running::Bool
679682
requests::Vector{gRPCRequest}
680683
# Allows for controlling the maximum number of concurrent gRPC requests/streams
681-
sem::Semaphore
684+
events::Channel{Event}
682685

683686
function gRPCCURL(max_streams = GRPC_MAX_STREAMS)
684687
grpc = new(
@@ -689,9 +692,14 @@ mutable struct gRPCCURL
689692
ReentrantLock(),
690693
true,
691694
Vector{gRPCRequest}(),
692-
Semaphore(max_streams),
695+
Channel{Event}(max_streams),
693696
)
694697

698+
# We use a channel as a Semaphore which also acts as a way to reuse Events to reduce allocations
699+
for _ = 1:max_streams
700+
put!(grpc.events, Event())
701+
end
702+
695703
preserve_handle(grpc)
696704

697705
grpc_multi_init(grpc)
@@ -745,9 +753,13 @@ function Base.open(grpc::gRPCCURL)
745753
grpc.watchers = Dict{curl_socket_t,CURLWatcher}()
746754
end
747755

756+
grpc.events = Channel{Event}(grpc.events.sz_max)
757+
for _ = 1:grpc.events.sz_max
758+
put!(grpc.events, Event())
759+
end
760+
748761
grpc.requests = Vector{gRPCRequest}()
749762
grpc.timer = nothing
750-
grpc.sem = Semaphore(grpc.sem.sem_size)
751763

752764
grpc.running = true
753765
grpc_multi_init(grpc)
@@ -756,6 +768,13 @@ function Base.open(grpc::gRPCCURL)
756768
end
757769
end
758770

771+
max_reqs_dec(grpc::gRPCCURL) = take!(grpc.events)
772+
function max_reqs_inc(grpc::gRPCCURL, req::gRPCRequest)
773+
# Reset before we recycle
774+
reset(req.curl_done_reading)
775+
put!(grpc.events, req.curl_done_reading)
776+
end
777+
759778
function cleanup_request(grpc::gRPCCURL, req::gRPCRequest)
760779
# First remove from the multi
761780
curl_multi_remove_handle(grpc.multi, req.easy)
@@ -766,7 +785,7 @@ function cleanup_request(grpc::gRPCCURL, req::gRPCRequest)
766785
# Allow this to be GC now that there is no risk of use in C callback
767786
unpreserve_handle(req)
768787
# Increment the request semaphore to allow more requests through
769-
release(grpc.sem)
788+
max_reqs_inc(grpc, req)
770789
# Unblock anything waiting on the request
771790
notify(req.ready)
772791
end

utils/gRPCClientUtils.jl/src/Benchmark.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ function benchmark_table()
3939
"Min",
4040
"Max",
4141
],
42-
["", "KiB/message", "allocs/message", "calls/s", "μs", "μs", "μs", "μs"],
42+
["", "KiB/message", "allocs/message", "messages/s", "μs", "μs", "μs", "μs"],
4343
]
4444
all_benchmarks = [
4545
(workload_smol, 1_000),

0 commit comments

Comments
 (0)