From daacd95ecddb9bfde0076a52114970b840aed028 Mon Sep 17 00:00:00 2001 From: Gusted Date: Fri, 10 Nov 2023 22:09:53 +0100 Subject: [PATCH] Lazy load stackless functions - I noticed that fasthttp was taking up 1.8MB of heap memory, even though it wasn't being used. This turned out to be the stackless function: 1.80MB github.com/valyala/fasthttp/stackless.NewFunc - Lazy load the stackless functions with sync.Once, given this a simple atomic read, it shouldn't affect performance for the fast-path (I haven't seen benchmarks with compression enabled). --- brotli.go | 12 +++++++++++- compress.go | 24 ++++++++++++++++++++++-- stackless/writer.go | 13 ++++++++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/brotli.go b/brotli.go index c829c39fa7..032bd953ec 100644 --- a/brotli.go +++ b/brotli.go @@ -132,7 +132,17 @@ func WriteBrotliLevel(w io.Writer, p []byte, level int) (int, error) { } } -var stacklessWriteBrotli = stackless.NewFunc(nonblockingWriteBrotli) +var ( + stacklessWriteBrotliOnce sync.Once + stacklessWriteBrotliFunc func(ctx interface{}) bool +) + +func stacklessWriteBrotli(ctx interface{}) { + stacklessWriteBrotliOnce.Do(func() { + stacklessWriteBrotliFunc = stackless.NewFunc(nonblockingWriteBrotli) + }) + stacklessWriteBrotliFunc(ctx) +} func nonblockingWriteBrotli(ctxv interface{}) { ctx := ctxv.(*compressCtx) diff --git a/compress.go b/compress.go index 8494d569be..1f44f1e6fc 100644 --- a/compress.go +++ b/compress.go @@ -177,7 +177,17 @@ func WriteGzipLevel(w io.Writer, p []byte, level int) (int, error) { } } -var stacklessWriteGzip = stackless.NewFunc(nonblockingWriteGzip) +var ( + stacklessWriteGzipOnce sync.Once + stacklessWriteGzipFunc func(ctx interface{}) bool +) + +func stacklessWriteGzip(ctx interface{}) { + stacklessWriteGzipOnce.Do(func() { + stacklessWriteGzipFunc = stackless.NewFunc(nonblockingWriteGzip) + }) + stacklessWriteGzipFunc(ctx) +} func nonblockingWriteGzip(ctxv interface{}) { ctx := ctxv.(*compressCtx) @@ -270,7 +280,17 @@ func WriteDeflateLevel(w io.Writer, p []byte, level int) (int, error) { } } -var stacklessWriteDeflate = stackless.NewFunc(nonblockingWriteDeflate) +var ( + stacklessWriteDeflateOnce sync.Once + stacklessWriteDeflateFunc func(ctx interface{}) bool +) + +func stacklessWriteDeflate(ctx interface{}) { + stacklessWriteDeflateOnce.Do(func() { + stacklessWriteDeflateFunc = stackless.NewFunc(nonblockingWriteDeflate) + }) + stacklessWriteDeflateFunc(ctx) +} func nonblockingWriteDeflate(ctxv interface{}) { ctx := ctxv.(*compressCtx) diff --git a/stackless/writer.go b/stackless/writer.go index b0d3e8dd96..347e464a29 100644 --- a/stackless/writer.go +++ b/stackless/writer.go @@ -4,6 +4,7 @@ import ( "errors" "fmt" "io" + "sync" "github.com/valyala/bytebufferpool" ) @@ -98,7 +99,17 @@ func (w *writer) do(op op) error { var errHighLoad = errors.New("cannot compress data due to high load") -var stacklessWriterFunc = NewFunc(writerFunc) +var ( + stacklessWriterFuncOnce sync.Once + stacklessWriterFuncFunc func(ctx interface{}) bool +) + +func stacklessWriterFunc(ctx interface{}) bool { + stacklessWriterFuncOnce.Do(func() { + stacklessWriterFuncFunc = NewFunc(writerFunc) + }) + return stacklessWriterFuncFunc(ctx) +} func writerFunc(ctx interface{}) { w := ctx.(*writer)