Skip to content

Instantly share code, notes, and snippets.

@florianl
Created September 26, 2025 09:49
Show Gist options
  • Select an option

  • Save florianl/22b50787ce38f0d637df17ed7875be42 to your computer and use it in GitHub Desktop.

Select an option

Save florianl/22b50787ce38f0d637df17ed7875be42 to your computer and use it in GitHub Desktop.
From 39729efd92ad61b13d6b4db1b49f1eb521e5b7ed Mon Sep 17 00:00:00 2001
From: Florian Lehner <florian.lehner@elastic.co>
Date: Fri, 26 Sep 2025 11:47:49 +0200
Subject: [PATCH] benchmark-confighttp-syncPool
Signed-off-by: Florian Lehner <florian.lehner@elastic.co>
---
config/confighttp/compression_test.go | 181 ++++++++++++++++++++++++++
1 file changed, 181 insertions(+)
diff --git a/config/confighttp/compression_test.go b/config/confighttp/compression_test.go
index 7f7404b09..1a3f59b88 100644
--- a/config/confighttp/compression_test.go
+++ b/config/confighttp/compression_test.go
@@ -613,3 +613,184 @@ func compressLz4(tb testing.TB, body []byte) *bytes.Buffer {
require.NoError(tb, lz.Close())
return &buf
}
+
+// compressRoundTripperNoPool is a version of compressRoundTripper without sync.Pool
+// for benchmarking comparison
+type compressRoundTripperNoPool struct {
+ rt http.RoundTripper
+ compressionType configcompression.Type
+ compressionParams configcompression.CompressionParams
+ compressor *compressor
+}
+
+func newCompressRoundTripperNoPool(rt http.RoundTripper, compressionType configcompression.Type, compressionParams configcompression.CompressionParams) (*compressRoundTripperNoPool, error) {
+ encoder, err := newCompressor(compressionType, compressionParams)
+ if err != nil {
+ return nil, err
+ }
+ return &compressRoundTripperNoPool{
+ rt: rt,
+ compressionType: compressionType,
+ compressionParams: compressionParams,
+ compressor: encoder,
+ }, nil
+}
+
+func (r *compressRoundTripperNoPool) RoundTrip(req *http.Request) (*http.Response, error) {
+ if req.Header.Get(headerContentEncoding) != "" {
+ return r.rt.RoundTrip(req)
+ }
+
+ // Create new buffer every time (no pooling)
+ buf := bytes.NewBuffer([]byte{})
+ if err := r.compressor.compress(buf, req.Body); err != nil {
+ return nil, err
+ }
+
+ cReq, err := http.NewRequestWithContext(req.Context(), req.Method, req.URL.String(), buf)
+ if err != nil {
+ return nil, err
+ }
+
+ cReq.Header = req.Header.Clone()
+ cReq.Header.Add(headerContentEncoding, string(r.compressionType))
+
+ return r.rt.RoundTrip(cReq)
+}
+
+// BenchmarkBufferAllocation compares buffer allocation performance with and without sync.Pool
+func BenchmarkBufferAllocation(b *testing.B) {
+ payload := make([]byte, 10*1024) // 10KB test data
+ for i := range payload {
+ payload[i] = byte(i % 256)
+ }
+
+ compressionParams := newCompressionParams(gzip.DefaultCompression)
+
+ b.Run("WithPool", func(b *testing.B) {
+ rt, err := newCompressRoundTripper(http.DefaultTransport, configcompression.TypeGzip, compressionParams)
+ require.NoError(b, err)
+
+ b.ResetTimer()
+ b.ReportAllocs()
+
+ for i := 0; i < b.N; i++ {
+ req, err := http.NewRequest("POST", "http://example.com", bytes.NewReader(payload))
+ require.NoError(b, err)
+
+ // Only test the buffer allocation and compression part
+ buf := rt.bufferPool.Get().(*bytes.Buffer)
+ err = rt.compressor.compress(buf, req.Body)
+ require.NoError(b, err)
+ buf.Reset()
+ rt.bufferPool.Put(buf)
+ }
+ })
+
+ b.Run("NoPool", func(b *testing.B) {
+ rt, err := newCompressRoundTripperNoPool(http.DefaultTransport, configcompression.TypeGzip, compressionParams)
+ require.NoError(b, err)
+
+ b.ResetTimer()
+ b.ReportAllocs()
+
+ for i := 0; i < b.N; i++ {
+ req, err := http.NewRequest("POST", "http://example.com", bytes.NewReader(payload))
+ require.NoError(b, err)
+
+ // Test buffer allocation without pool
+ buf := bytes.NewBuffer([]byte{})
+ err = rt.compressor.compress(buf, req.Body)
+ require.NoError(b, err)
+ }
+ })
+}
+
+// BenchmarkCompressRoundTripper compares performance with and without sync.Pool
+func BenchmarkCompressRoundTripper(b *testing.B) {
+ testData := []struct {
+ name string
+ dataSize int
+ }{
+ {"Small_1KB", 1024},
+ {"Medium_10KB", 10 * 1024},
+ {"Large_100KB", 100 * 1024},
+ {"XLarge_1MB", 1024 * 1024},
+ }
+
+ compressionTypes := []configcompression.Type{
+ configcompression.TypeGzip,
+ configcompression.TypeZstd,
+ configcompression.TypeSnappy,
+ }
+
+ for _, data := range testData {
+ for _, compressionType := range compressionTypes {
+ // Create test payload
+ payload := make([]byte, data.dataSize)
+ for i := range payload {
+ payload[i] = byte(i % 256)
+ }
+
+ compressionParams := newCompressionParams(gzip.DefaultCompression)
+
+ b.Run(fmt.Sprintf("%s_%s_WithPool", data.name, compressionType), func(b *testing.B) {
+ // Set up a test server that just returns OK
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ }))
+ defer server.Close()
+
+ // Create round tripper with pool
+ rt, err := newCompressRoundTripper(http.DefaultTransport, compressionType, compressionParams)
+ require.NoError(b, err)
+
+ client := &http.Client{Transport: rt}
+
+ b.ResetTimer()
+ b.ReportAllocs()
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ req, err := http.NewRequest("POST", server.URL, bytes.NewReader(payload))
+ require.NoError(b, err)
+ req.Header.Set("Content-Type", "application/octet-stream")
+
+ resp, err := client.Do(req)
+ require.NoError(b, err)
+ resp.Body.Close()
+ }
+ })
+ })
+
+ b.Run(fmt.Sprintf("%s_%s_NoPool", data.name, compressionType), func(b *testing.B) {
+ // Set up a test server that just returns OK
+ server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ }))
+ defer server.Close()
+
+ // Create round tripper without pool
+ rt, err := newCompressRoundTripperNoPool(http.DefaultTransport, compressionType, compressionParams)
+ require.NoError(b, err)
+
+ client := &http.Client{Transport: rt}
+
+ b.ResetTimer()
+ b.ReportAllocs()
+
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ req, err := http.NewRequest("POST", server.URL, bytes.NewReader(payload))
+ require.NoError(b, err)
+ req.Header.Set("Content-Type", "application/octet-stream")
+
+ resp, err := client.Do(req)
+ require.NoError(b, err)
+ resp.Body.Close()
+ }
+ })
+ })
+ }
+ }
+}
--
2.39.5
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment