Skip to content

Pool receive buffers#41

Merged
arashpayan merged 5 commits intomainfrom
pool_rcv_buffers
Mar 16, 2026
Merged

Pool receive buffers#41
arashpayan merged 5 commits intomainfrom
pool_rcv_buffers

Conversation

@rakitzis
Copy link
Copy Markdown
Collaborator

Introduce a sync.Pool of byte buffers in conn to reuse receive
buffers across reads. The pooled buffer is threaded through tryHandle
into requestResponse so callers can return it after processing.
Compound responses that produce new buffers "leak" the pooled
buf so that it is captured by GC.

Indeed, only the readAt call is fully plumbed through with this set
of changes. If we want to consider further changes we may either
want to set up a pattern (effectively a rewrite of sendRcv) or break
up individual uses of sendRcv as they show up in performance
benchmarking.

Add BenchmarkReadAt exercising the full ReadAt() code path for both
plain and encrypted sessions.
Introduce a sync.Pool of byte buffers in conn to reuse receive
buffers across reads. The pooled buffer is threaded through tryHandle
into requestResponse so callers can return it after processing.
Compound and encrypted responses that produce new buffers release the
pool buffer immediately.
This change threads through the return of pooled buffers to the
pool at the end of a readAt call. This required adding a new
return value to readAtChunk and threading through the response
struct to allow lifecycle management of the pooled read buffers

Before:

```
BenchmarkReadAt/Plain/1KB-10         	  309301	      3871 ns/op	 264.55 MB/s	    1628 B/op	       6 allocs/op
BenchmarkReadAt/Plain/64KB-10        	  110104	     10778 ns/op	6080.70 MB/s	   74221 B/op	       6 allocs/op
BenchmarkReadAt/Plain/1MB-10         	   17011	     69926 ns/op	14995.60 MB/s	 1057380 B/op	       6 allocs/op
BenchmarkReadAt/Encrypted/1KB-10     	  230868	      5120 ns/op	 200.00 MB/s	    3554 B/op	       7 allocs/op
BenchmarkReadAt/Encrypted/64KB-10    	   37930	     31865 ns/op	2056.71 MB/s	  164388 B/op	       7 allocs/op
BenchmarkReadAt/Encrypted/1MB-10     	    3502	    338054 ns/op	3101.80 MB/s	 2377206 B/op	       8 allocs/op
BenchmarkRoundTrip/Plain/1KB-10      	  324889	      3697 ns/op	 277.00 MB/s	    1627 B/op	       6 allocs/op
BenchmarkRoundTrip/Plain/64KB-10     	  126373	      9288 ns/op	7056.29 MB/s	   74212 B/op	       6 allocs/op
BenchmarkRoundTrip/Plain/1MB-10      	   21868	     54787 ns/op	19139.10 MB/s	 1057354 B/op	       6 allocs/op
BenchmarkRoundTrip/Encrypted/1KB-10  	  237756	      5032 ns/op	 203.51 MB/s	    3554 B/op	       7 allocs/op
BenchmarkRoundTrip/Encrypted/64KB-10 	   39066	     30867 ns/op	2123.14 MB/s	  164384 B/op	       7 allocs/op
BenchmarkRoundTrip/Encrypted/1MB-10  	    3765	    311547 ns/op	3365.70 MB/s	 2377363 B/op	       7 allocs/op
```

After:

```
BenchmarkReadAt/Plain/1KB-10         	  339576	      3543 ns/op	 289.05 MB/s	     492 B/op	       5 allocs/op
BenchmarkReadAt/Plain/64KB-10        	  175285	      6744 ns/op	9718.10 MB/s	     520 B/op	       5 allocs/op
BenchmarkReadAt/Plain/1MB-10         	   27549	     42779 ns/op	24511.65 MB/s	     757 B/op	       5 allocs/op
BenchmarkReadAt/Encrypted/1KB-10     	  234076	      4977 ns/op	 205.76 MB/s	    2294 B/op	       6 allocs/op
BenchmarkReadAt/Encrypted/64KB-10    	   42075	     28553 ns/op	2295.28 MB/s	   92763 B/op	       6 allocs/op
BenchmarkReadAt/Encrypted/1MB-10     	    3901	    300217 ns/op	3492.73 MB/s	 1348399 B/op	       7 allocs/op
BenchmarkRoundTrip/Plain/1KB-10      	  329589	      3500 ns/op	 292.53 MB/s	     492 B/op	       5 allocs/op
BenchmarkRoundTrip/Plain/64KB-10     	  253318	      4782 ns/op	13705.62 MB/s	     540 B/op	       5 allocs/op
BenchmarkRoundTrip/Plain/1MB-10      	   54456	     22056 ns/op	47541.85 MB/s	     798 B/op	       5 allocs/op
BenchmarkRoundTrip/Encrypted/1KB-10  	  241818	      4810 ns/op	 212.90 MB/s	    2294 B/op	       6 allocs/op
BenchmarkRoundTrip/Encrypted/64KB-10 	   43735	     27694 ns/op	2366.45 MB/s	   93314 B/op	       6 allocs/op
BenchmarkRoundTrip/Encrypted/1MB-10  	    4075	    288285 ns/op	3637.29 MB/s	 1337363 B/op	       7 allocs/op
```
The decrypt scratch buffer (append of EncryptedData + Signature) was
allocated on every encrypted packet. Get a *recvBuf from conn.recvPool
instead, and thread it back through runReceiver->tryHandle->
requestResponse so the caller's freeRecvBuf returns it to the pool.

Shaves an allocation from the encrypted path

Before:
[see last commit]

After:
```
BenchmarkReadAt/Encrypted/1KB-10     	  245488	      4767 ns/op	 214.83 MB/s	     370 B/op	       4 allocs/op
BenchmarkReadAt/Encrypted/64KB-10    	   46538	     25846 ns/op	2535.60 MB/s	     437 B/op	       4 allocs/op
BenchmarkReadAt/Encrypted/1MB-10     	    4057	    289344 ns/op	3623.97 MB/s	    1663 B/op	       4 allocs/op
BenchmarkRoundTrip/Encrypted/1KB-10  	  294138	      4079 ns/op	 251.05 MB/s	     369 B/op	       4 allocs/op
BenchmarkRoundTrip/Encrypted/64KB-10 	   53742	     23999 ns/op	2730.73 MB/s	     466 B/op	       4 allocs/op
BenchmarkRoundTrip/Encrypted/1MB-10  	    4387	    270263 ns/op	3879.83 MB/s	    2047 B/op	       4 allocs/op
```
Comment thread conn.go Outdated
@arashpayan arashpayan merged commit d2c8b36 into main Mar 16, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants