Peach
Peach

Reputation: 97

Disable array/slice bounds checking in Golang to improve performance

I'm writing a NES/Famicom emulator. I register a callback function that will be called every time a pixel is rendered. It means that my callback function will be called about 3.5 million times (256width * 240height * 60fps).

In my callback function, there are many array/slice operations, and I found that Go will do bounds checking every time I index an element in it. But the indexes are results of bit and operations so I can tell that it will NOT exceed both bounds.

So, I'm here to ask if there is a way to disable bounds checking?

Thank you.

Upvotes: 5

Views: 4017

Answers (3)

Brad Peabody
Brad Peabody

Reputation: 11377

If you really need to avoid the bounds check, you can use the unsafe package and use C-style pointer arithmetic to perform your lookups:

index := 2
size := unsafe.Sizeof(YourStruct{})
p := unsafe.Pointer(&yourStructSlice[0])
indexp := (unsafe.Pointer)(uintptr(p) + size*uintptr(index))
yourStructPtr := (*YourStruct)(indexp)

https://play.golang.org/p/GDNphKsJPOv

You should time it to determine how much CPU run time you are actually saving by doing this, but it is probably true it is possible to make it faster using this approach.

Also, you may want to have a look at the actual generated instructions to make sure that what you outputting is actually more efficient. Doing lookups without bounds checks very well may be more trouble than it's worth. Some info on how to do that here: https://github.com/teh-cmc/go-internals/blob/master/chapter1_assembly_primer/README.md

Another common approach is to write performance critical code in assembly (see https://golang.org/doc/asm). Ain't no automatic bounds checking in asm :)

Upvotes: 2

peterSO
peterSO

Reputation: 166569

The XY Problem

The XY problem is asking about your attempted solution rather than your actual problem.


Your real problem is overall performance. Let's see some benchmarks to show that bounds checking is a significant problem. It may not be a significant problem. For example, less than one millisecond per second,

Bounds check:

BenchmarkPixels-4    300    4034580 ns/op

No bounds check:

BenchmarkPixels-4    500    3150985 ns/op

bounds_test.go:

package main

import (
    "testing"
)

const (
    width  = 256
    height = 240
    frames = 60
)

var pixels [width * height]byte

func writePixel(w, h int) {
    pixels[w*height+h] = 42
}

func BenchmarkPixels(b *testing.B) {
    for N := 0; N < b.N; N++ {
        for f := 0; f < frames; f++ {
            for w := 0; w < width; w++ {
                for h := 0; h < height; h++ {
                    writePixel(w, h)
                }
            }
        }
    }
}

Upvotes: 2

Alireza Bashiri
Alireza Bashiri

Reputation: 452

Using gcflags you can disable bounds checking.

go build -gcflags=-B .

Upvotes: 5

Related Questions