Promise to the Go compiler that your Reads and Writes are well-behaved

noescape

GoDoc Go Report Card

go get lukechampine.com/noescape

noescape provides Read and Write functions that do not heap-allocate their argument.

Normally, when you pass a []byte to an io.Reader or io.Writer, the compiler must heap-allocate the slice data. This is because, at compile-time, there is no way to know which concrete type is satisfying the interface, and therefore the compiler cannot prove that the slice data will not be retained.

This is sad, because the vast majority of Read and Write methods do not retain their argument, but still incur the performance penalty of heap-allocation. The noescape package allows you to promise to the compiler that your Read or Write method is perfectly safe, thank you very much, thus allowing you to avoid the allocation.

This can be illustrated via benchmark:

type yesReader struct{}

func (yesReader) Read(p []byte) (int, error) {
    return copy(p, "yes"), nil
}

func BenchmarkConcrete(b *testing.B) {
    r := yesReader{}
    for i := 0; i < b.N; i++ {
        buf := make([]byte, 100)
        r.Read(buf)
    }
}

func BenchmarkInterface(b *testing.B) {
    var r io.Reader = yesReader{}
    for i := 0; i < b.N; i++ {
        buf := make([]byte, 100)
        r.Read(buf)
    }
}

func BenchmarkNoEscape(b *testing.B) {
    var r io.Reader = yesReader{}
    for i := 0; i < b.N; i++ {
        buf := make([]byte, 100)
        noescape.Read(r, buf)
    }
}
BenchmarkConcrete-4     1000000000        0.372 ns/op       0 B/op      0 allocs/op
BenchmarkInterface-4      28114684       44.8 ns/op       112 B/op      1 allocs/op
BenchmarkNoEscape-4       88440447       11.8 ns/op        0 B/op       0 allocs/op

How?

The gc compiler recognizes a //go:noescape pragma that promises to the compiler that a function's arguments do not escape. So we just need to stick this pragma on top of our Read and Write functions:

//go:noescape
func Read(r io.Reader, b []byte) (int, error) { return r.Read(b) }
//go:noescape
func Write(w io.Writer, b []byte) (int, error) { return w.Write(b) }

There's a complication, though: the go:noescape pragma can only be applied to externally-defined functions. So in order to use it, we need to implement Read and Write in assembly! Not a big deal, it's just one line of Go, after all; but it turned out to be trickier than I thought. If you're interested in the details, check out the comments in noescape_amd64.s.

On that note: only amd64 is supported for now. If you want to contribute implementations for other architectures, I'll gladly merge them. Also, for maximum compatibility, I should add non-assembly implementations; this would defeat the whole point, but it would also allow this package to be used in cross-platform code as an architecture-dependent optimization.

Owner
Luke Champine
"If the world were perfect, it wouldn't be." - Yogi Berra
Luke Champine
Similar Resources

Grumpy is a Python to Go source code transcompiler and runtime.

Grumpy: Go running Python Overview Grumpy is a Python to Go source code transcompiler and runtime that is intended to be a near drop-in replacement fo

Jan 7, 2023

High-performance PHP application server, load-balancer and process manager written in Golang

High-performance PHP application server, load-balancer and process manager written in Golang

RoadRunner is an open-source (MIT licensed) high-performance PHP application server, load balancer, and process manager. It supports running as a serv

Dec 30, 2022

Mathematical expression parsing and calculation engine library. 数学表达式解析计算引擎库

Math-Engine 使用 Go 实现的数学表达式解析计算引擎库,它小巧,无任何依赖,具有扩展性(比如可以注册自己的函数到引擎中),比较完整的完成了数学表达式解析执行,包括词法分析、语法分析、构建AST、运行。 go get -u github.com/dengsgo/math-engine 能够

Jan 3, 2023

Runcmd - just golang binary that runs commands from url or local file and logs output

runcmd just golang binary that runs commands from url or local file and logs out

Feb 2, 2022

A distributed append only commit log used for quick writes and reads to any scale

A distributed append only commit log used for quick writes and reads to any scale

Maestro-DB A distributed append only commit log used for quick writes and reads to any scale Part 1 - Scaffolding Part-1 Notes Going to start off with

Nov 28, 2021

Leftright - A concurrent map that is optimized for scenarios where reads are more frequent than writes

leftright A concurrent map that is optimized for scenarios where reads are more

Jan 30, 2022

Promise library for Go.

Promise library for Go.

Feb 10, 2022

Go compiler made from scratch, which can compile itself. It's going to be the smallest and simplest go compiler in the world.

Babygo, a go compiler made from scratch Babygo is a small and simple go compiler. (Smallest and simplest in the world, I believe.) It is made from scr

Jan 8, 2023

Compiler as a Service is a compiler that is available over http/https and gRPC

BlakBoks(CaaS) Elasticsearch but for compiling untrusted code Compiler as a Service is a compiler that is available over http/2 and gRPC. Setup First

Nov 24, 2021

ReCT-Go-Compiler - A compiler for the ReCT programming language written in Golang

ReCT-Go-Compiler A compiler for the ReCT programming language written in Golang

Nov 30, 2022

ReCT-Go-Compiler - A compiler for the ReCT programming language written in Golang

ReCT-Go-Compiler A compiler for the ReCT programming language written in Golang

Nov 30, 2022

The go mod init command initializes and writes a new go.mod file in the current directory

go mod: The go mod init command initializes and writes a new go.mod file in the current directory, in effect creating a new module rooted at the curre

Nov 21, 2021

Quality of life tool for diablo2r. Automatically counts up and writes the game name into clipboard.

Quality of life tool for diablo2r. Automatically counts up and writes the game name into clipboard.

counterbaal Quality of life tool for people hosting diablo2 baalruns. Automatically counts up and writes the game name into clipboard. Probably only u

Jan 1, 2022

Reads from existing Cloud Providers (reverse Terraform) and generates your infrastructure as code on Terraform configuration

Reads from existing Cloud Providers (reverse Terraform) and generates your infrastructure as code on Terraform configuration

TerraCognita Imports your current Cloud infrastructure to an Infrastructure As Code Terraform configuration (HCL) or/and to a Terraform State. At Cycl

Dec 30, 2022

Cogger is a standalone binary and a golang library that reads an internally tiled geotiff

Cogger is a standalone binary and a golang library that reads an internally tiled geotiff (optionally with overviews and masks) and rewrites it

Dec 12, 2022

Reads Sets and Deletes a key from Redis cache

Reads Sets and Deletes a key from Redis cache

Nov 2, 2021

A simple app that reads NBMiner status REST API data and sends it to InfluxDB

NBMiner Reporter A simple Go app that reads NBMiner status REST API data and sends it to InfluxDB. Usage Using the reporter is quite easy, specially i

Feb 8, 2022

Reads MAWS formatted data and converts it into JSON output stream.

maws2json Usage examples Over serial line (stdin pipe) Lets assume that Vaisala weather station is connected via RS232 to USB serial dongle in /dev/tt

Feb 6, 2022

Reads JSON object (stream) from file/stdin and routes it/them to GCP Pub/Sub topics.

json2pubsub Publish JSON object (stream) into GCP Pub/Sub topic based on a field value. Usage: json2pubsub --project=STRING mapping ... Reads JSON

Nov 3, 2022
Comments
  • Seg violation

    Seg violation

    Thanks for writing this program, it's great!

    When running 'testing' ReadTest(...), I got this seg violation, not sure of the root cause, didn't investigate deeply.

    This occurred on a AMD64 (intel cpu) Mac Mini.

    c@macmini ~/D/noescape (master) [1]> go test .
    --- FAIL: TestRead (0.00s)
    panic: runtime error: invalid memory address or nil pointer dereference [recovered]
    	panic: runtime error: invalid memory address or nil pointer dereference
    [signal SIGSEGV: segmentation violation code=0x1 addr=0xd pc=0x10efd7e]
    
    goroutine 6 [running]:
    testing.tRunner.func1.2({0x11036e0, 0x11f3b20})
    	/usr/local/go/src/testing/testing.go:1389 +0x24e
    testing.tRunner.func1()
    	/usr/local/go/src/testing/testing.go:1392 +0x39f
    panic({0x11036e0, 0x11f3b20})
    	/usr/local/go/src/runtime/panic.go:838 +0x207
    github.com/lukechampine/noescape.TestRead(0xc0001004e0)
    	/Users/c/Documents/noescape/noescape_test.go:21 +0x15e
    testing.tRunner(0xc0001004e0, 0x1128d00)
    	/usr/local/go/src/testing/testing.go:1439 +0x102
    created by testing.(*T).Run
    	/usr/local/go/src/testing/testing.go:1486 +0x35f
    FAIL	github.com/lukechampine/noescape	0.089s
    FAIL
    c@macmini ~/D/noescape (master) [1]>
    
  • Go 1.18RC1 benchmark

    Go 1.18RC1 benchmark

    This is a nice piece of work!

    I re-integrated the benchmarks from the README into the _test file, and here is what I got on an AMD64 Mac mini.

    c@macmini ~/D/noescape (master)> go test  -bench='^Benchmark' . -run='^$' .
    
    goos: darwin
    goarch: amd64
    pkg: github.com/lukechampine/noescape
    cpu: Intel(R) Core(TM) i5-8500B CPU @ 3.00GHz
    BenchmarkXConcrete-6    	1000000000	         0.2582 ns/op
    BenchmarkXInterface-6   	257929678	         4.679 ns/op
    BenchmarkXNoEscape-6    	144387786	         8.297 ns/op
    PASS
    ok  	github.com/lukechampine/noescape	4.091s
    c@macmini ~/D/noescape (master)> go version
    go version go1.18rc1 darwin/amd64
    
Related tags
GopherLua: VM and compiler for Lua in Go

GopherLua: VM and compiler for Lua in Go. GopherLua is a Lua5.1 VM and compiler written in Go. GopherLua has a same goal with Lua: Be a scripting lang

Jan 9, 2023
A Lua 5.3 VM and compiler written in Go.

DCLua - Go Lua Compiler and VM: This is a Lua 5.3 VM and compiler written in Go. This is intended to allow easy embedding into Go programs, with minim

Dec 12, 2022
A compiler from Go to JavaScript for running Go code in a browser

GopherJS - A compiler from Go to JavaScript GopherJS compiles Go code (golang.org) to pure JavaScript code. Its main purpose is to give you the opport

Dec 30, 2022
Automated compiler obfuscation for nim

Denim Makes compiling nim code with obfuscator-llvm easy! Windows only for now, but do you even need compiler obfuscation on other platforms? Setup In

Dec 31, 2022
JIT compiler in Go

jit-compiler This is a Golang library containing an x86-64 assembler (see 'asm/') and a higher level intermediate representation that compiles down in

Dec 24, 2022
Compiler for a small language into x86-64 Assembly

Compiler This project is a small compiler, that compiles my own little language into X86-64 Assembly. It then uses yasm and ld to assemble and link in

Dec 13, 2022
The Project Oberon RISC compiler ported to Go.

oberon-compiler This is a port of the Project Oberon compiler for RISC-5 (not to be confused with RISC-V) from Oberon to Go. The compiled binaries can

Dec 6, 2022
The golang tool of the zig compiler automatically compiles different targets according to the GOOS GOARCH environment variable. You need to install zig.

The golang tool of the zig compiler automatically compiles different targets according to the GOOS GOARCH environment variable. You need to install zig.

Nov 18, 2022
Logexp - Logical expression compiler for golang

Logical Expression Compiler Functions: - Compile(exp string) - Match(text string

Jan 24, 2022
A compiler for the ReCT programming language written in Golang

ReCT-Go-Compiler A compiler for the ReCT programming language written in Golang

Nov 30, 2022