Performance benchmarks can be found below. Obviously, a 8 KiB
request/response is tailored to showcase this improvement as this is
where codec buffer reuse shines, but I've run other benchmarks too (like
1-byte requests and responses) and there's no discernable impact on
performance.
We do not allow reuse of buffers when stat handlers or binlogs are
turned on. This is because those two may need access to the data and
payload even after the data has been written to the wire. In such cases,
we never return the data back to the pool.
A buffer reuse threshold of 1 KiB was determined after several
experiments. There's diminished returns when buffer reuse is enabled for
smaller messages (actually, a negative impact).
unary-networkMode_none-bufConn_false-keepalive_false-benchTime_40s-trace_false-latency_0s-kbps_0-MTU_0-maxConcurrentCalls_6-reqSize_8192B-respSize_8192B-compressor_off-channelz_false-preloader_false
Title Before After Percentage
TotalOps 839638 906223 7.93%
SendOps 0 0 NaN%
RecvOps 0 0 NaN%
Bytes/op 103788.29 80592.47 -22.35%
Allocs/op 183.33 189.30 3.27%
ReqT/op 1375662899.20 1484755763.20 7.93%
RespT/op 1375662899.20 1484755763.20 7.93%
50th-Lat 238.746µs 225.019µs -5.75%
90th-Lat 514.253µs 456.439µs -11.24%
99th-Lat 711.083µs 702.466µs -1.21%
Avg-Lat 285.45µs 264.456µs -7.35%
Continuing the war on stacks, we can reduce the amount of stack required
per-RPC by combining defers from different components into one.
Each defer statement in process{Unary,Streaming}RPC goes on the stack
and occupies about 56-64 bytes the entire lifetime of an RPC, which
could be very long. More importantly, a call to runtime.morestack is
often required to allocate a new, larger stack when the handler
goroutine runs out of stack memory (Go's default stack size is 2 KiB).
Before:
$ go tool objdump <binary> | grep "TEXT.*processUnaryRPC(SB)" -A 10 | grep "SUBQ.*SP"
server.go:867 0x9132fb 4881ec80030000 SUBQ $0x380, SP
$ go tool objdump <binary> | grep "TEXT.*processStreamingRPC(SB)" -A 10 | grep "SUBQ.*SP"
server.go:1099 0x9151bb 4881ec68020000 SUBQ $0x268, SP
After:
$ go tool objdump <binary> | grep "TEXT.*processUnaryRPC(SB)" -A 10 | grep "SUBQ.*SP"
server.go:867 0x9132fb 4881ecd0020000 SUBQ $0x2d0, SP
$ go tool objdump <binary> | grep "TEXT.*processStreamingRPC(SB)" -A 10 | grep "SUBQ.*SP"
server.go:1116 0x9150fb 4881ecf8010000 SUBQ $0x1f8, SP
As one can observe, the processUnaryRPC's stack goes down from 0x380
bytes to 0x2d0 bytes (896 - 720 = 176 bytes) while processStreamingRPC's
stack goes down from 0x2d8 bytes to 0x1f8 bytes (616 - 504 = 112 bytes).
There are probably other things we can do here, but these are some low
hanging fruits to pick off.
The client-side traces were otherwise only showing `RPC: to <nil>`,
which is not helpful.
Also clean up construction of traceInfo and firstLine in a few places.
Also includes:
- Export `NewLoggerFromConfigString` so it can be also used when config string is specified in another way (e.g. command line flag)
- Export `Logger` so user can install custom sink
- Add temp file sink implementation
This is a breaking change, but the transport package was never intended for use outside of grpc. Any current users that we are aware of are incorrect or have a preferred alternative.
Reverts grpc/grpc-go#2098
Appengine will fail with the error below:
```
go-app-builder: Failed parsing input: parser: bad import "syscall" in google.golang.org/grpc/channelz/funcs.go from GOPATH
```
The root cause of it is in type_linux.go.
629f6bc5e5/channelz/types_linux.go (L21-L25)
This reverts commit 7cc2837209c4fa87008717b4e94a085820d7d779.
The PR breaks darwin builds
src/google.golang.org/grpc/channelz/types_unix.go:35:15: undefined: unix.TCPInfo
* Don't send nil requests.
* Fix import name and get rid of condition.
* Let registered encoder deal with nil requests.
* Break encode into encode and compress.