Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

runtime: _cgoCheckPointer0 extreme overhead #14265

tgulacsi opened this issue Feb 8, 2016 · 2 comments

runtime: _cgoCheckPointer0 extreme overhead #14265

tgulacsi opened this issue Feb 8, 2016 · 2 comments


Copy link

@tgulacsi tgulacsi commented Feb 8, 2016

  1. What version of Go are you using (go version)?
  2. What operating system and processor architecture are you using?
  3. What did you do?
    Call C code with cgo.
  4. What did you expect to see?
    Almost the same performance with GODEBUG=cgocheck=1 and GODEBUG=cgocheck=0.
  5. What did you see instead?
    22 times more running time with GODEBUG=cgocheck=1 than with GODEBUG=cgocheck=0.

The overhead is 22x in practice and 36000 in this contrived example:

$ GODEBUG=cgocheck=1 go test -bench=. -run=-
testing: warning: no tests to run
BenchmarkCGO-4 50 28792524 ns/op
ok 1.855s
:gthomas@waterhouse: ~/src/
$ GODEBUG=cgocheck=0 go test -bench=. -run=-
testing: warning: no tests to run
BenchmarkCGO-4 2000000 796 ns/op
ok 2.988s
:gthomas@waterhouse: ~/src/

The code is at

@bradfitz bradfitz changed the title _cgoCheckPointer0 extreme overhead runtime/cgo: _cgoCheckPointer0 extreme overhead Feb 8, 2016
@bradfitz bradfitz added this to the Unplanned milestone Feb 8, 2016
@ianlancetaylor ianlancetaylor changed the title runtime/cgo: _cgoCheckPointer0 extreme overhead runtime: _cgoCheckPointer0 extreme overhead Feb 8, 2016
Copy link

@ianlancetaylor ianlancetaylor commented Feb 8, 2016

Thanks for the test case. I don't know how to do much better for this kind of example. The pointer passing rules say that if you pass the address of an element of a slice, the C code is permitted to examine every element of the slice. You are passing the address of a 1000000 slice of pointers, so each call needs to check 1000000 pointers to make sure that they are not Go pointers.


Copy link
Contributor Author

@tgulacsi tgulacsi commented Feb 9, 2016

Thanks Ian for the clear description!

Now I think I understand another strange thing: with
s := struct { p C.ub4, q *GoObj }
does not work, but (!) with
s := struct{ p [1]C.ub4, q *GoObj },
does work - here we encapsulated the referent, so cgo does not check q.

Back to the original issue: this understanding allows a not-too-ugly workaround:

    i := i % int(n)
    carr := arr[i : i+1 : i+1]
    i = (i + 100) % int(n)
    darr := arr[i : i+1 : i+1]
    //[i%int(n)], &arr[(i+100)%int(n)])[0], &darr[0])

By calling with a one-element-length array (capped), it works:

:tgulacsi@tgulacsi-Aspire-V3-371: ~/src/
! GODEBUG=cgocheck=0 go test  -run=X -bench=.
testing: warning: no tests to run
BenchmarkCGONaive-4      3000000               494 ns/op
BenchmarkCGOSliced-4     3000000               501 ns/op
BenchmarkCGOCapped-4     3000000               507 ns/op
ok    6.400s
:tgulacsi@tgulacsi-Aspire-V3-371: ~/src/
$ GODEBUG=cgocheck=1 go test  -run=X -bench=.
testing: warning: no tests to run
BenchmarkCGONaive-4          100          18490218 ns/op
BenchmarkCGOSliced-4         100          18211666 ns/op
BenchmarkCGOCapped-4     3000000               568 ns/op
ok    6.305s

Here the "Naive" is the old version, the "Sliced" is the carr := arr[i:i+1] version, and the "Capped" is the above carr := arr[i:i+1:i+1] version.

(same repo has the new code).

I think at least we should document it more explicitly, that the cgo checker checks all reachable pointers in the struct/array/slice level.


tgulacsi pushed a commit to rana/ora that referenced this issue Feb 9, 2016
Go 1.6 has a strict checker to disable passing memory allocated by Go
that contains Go pointers ("Go pointer to Go pointer").
So we have to C.malloc everywhere where we want C to write to memory,
and read it in Go.

See for the
documentation, for the slice tricks,
and!topic/golang-nuts/gnH0nhPf36I for
the hunt.

Put some cgo helper function in bnd_hlp.go, and some C for cycles in

Extra care needed when passing pointers of array/slice elements with
cgo: use the whole array on C side, or move the for cycle to C side.
See golang/go#14265 for details of the cgo
check overhead.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
None yet
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
3 participants