jeudi 9 juin 2016

The cost of a function

I can't find the source anymore, but I remember reading a few years ago that Go, when compiling, copies (when it can) the inners of simple functions in-place before compiling to so optimize the code and skip the base-overhead of each function allocation (4kb or so?).

I was working on jsonparser which is so amazing, as it can byte-browse a gigantic JSON file without actually having to parse the whole thing based on an interface or a struct and just pick exactly what you need. While I was benchmarking this I noticed some nanosecond-fluctuations and suddenly noticed that it was the one-linerfunction I was using for error-checking.

So taking these 3 tests:

  1. α tests in-place, no functions
  2. β tests with a function and parsing a copy of the error object
  3. γ tests with a function and parsing a reference of the error object (I know this is unsafe, but this is merely for testing purposes)

_

func testα(b *testing.B) {
    for i := 0; i < b.N; i++ { // Base of 0.33ns
        err := errors.New("Oh no!")
        if nil != err {

        }
    }
}

func testβ(b *testing.B) {
    for i := 0; i < b.N; i++ { // Base of 0.33ns
        err := errors.New("Oh no!")
        perror1(err)
    }
}

func testγ(b *testing.B) {
    for i := 0; i < b.N; i++ { // Base of 0.33ns
        err := errors.New("Oh no!")
        perror2(&err)
    }
}

func perror1(err error) {
    if nil == err {
        panic(err)
    }
}

func perror2(err *error) {
    if nil == *err {
        panic(*err)
    }
}

These are the results (including the average base of 0.33 nanosecond per empty basis test loop cycle):

1.

5.33 ns/op
300000000 iterations
1.599625123s total time,
0 allocs,
0 MB memory allocated

2.

39.56 ns/op
30000000 iterations
1.186849777s total time,
30002037 allocs,
457 MB memory allocated

3.

37.43 ns/op
50000000 iterations
1.87172856s total time,
50003443 allocs,
762 MB memory allocated

I'm wondering why test testα and testβ don't seem to be copied in-place. Does this explicitly require a compiler flag or does it not work when only testing code with go run and it always needs to be go build with params to make that work?

Aucun commentaire:

Enregistrer un commentaire