Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Why cgo is slow @ CapitalGo 2018

Why cgo is slow @ CapitalGo 2018

https://capitalgolang.com/program#filippo_valsorda

This talk uses cgo and its below-average performance as an excuse to look into Go internals and what makes Go different from C.

We learn about calling conventions and the code-generated cgo trampolines; about the small goroutines stacks and how C doesn't know how to grow them; about the Go scheduler and how C doesn't yield to it; and about the garbage collector and how pointers in C memory can't be tracked.

Filippo Valsorda

June 22, 2018
Tweet

More Decks by Filippo Valsorda

Other Decks in Programming

Transcript

  1. Why cgo is slow Filippo Valsorda

  2. None
  3. cgo is a FFI (Foreign Function Interface)

  4. I like FFIs. • From cgo back to Go @

    GopherCon 2016
 https://speakerdeck.com/filosottile/from-cgo-back-to-go-gophercon-2016 • rustgo: Building your own FFI @ GothamGo 2017
 https://speakerdeck.com/filosottile/calling-rust-from-go-without-cgo-at-gothamgo-2017 • Why cgo is slow @ CapitalGo 2018
 Hi!
  5. C function call Java FFI Rust FFI LuaJIT FFI Node.js

    FFI cgo 2.364 ns 9.01 ns 2.386 ns 1.81 ns (!) https://nullprogram.com/blog/2018/05/27/ 18.33 ns 75.95 ns https://github.com/dyu/ffi-overhead
  6. name old time/op new time/op delta CgoCall-4 63.1ns ± 3%

    57.1ns ± 0% -9.43%
  7. C function call Java FFI Rust FFI LuaJIT FFI Node.js

    FFI cgo 2.364 ns 9.01 ns 2.386 ns 1.81 ns (!) https://nullprogram.com/blog/2018/05/27/ 18.33 ns 68.77 ns https://github.com/dyu/ffi-overhead
  8. C function call Java FFI Rust FFI LuaJIT FFI Node.js

    FFI cgo 2.364 ns 9.01 ns 2.386 ns 1.81 ns (!) https://nullprogram.com/blog/2018/05/27/ 18.33 ns 68.77 ns (29x) https://github.com/dyu/ffi-overhead
  9. cgo: • cmd/cgo • runtime/cgo • a sprinkle of cmd/link/internal/ld

    support
  10. cgo: • cmd/cgo • runtime/cgo • a sprinkle of cmd/link/internal/ld

    support • not a compiler feature!
  11. cgo: • cmd/cgo — a code generator • runtime/cgo •

    a sprinkle of cmd/link/internal/ld support • not a compiler feature!
  12. Reason 1: calling conventions

  13. C compiler Go compiler

  14. go build -x -work

  15. None
  16. None
  17. None
  18. None
  19. src/runtime/cgocall.go

  20. None
  21. None
  22. None
  23. rewritten Go function calling convention trampoline arg unpacking real C

    function Go ASM C
  24. Learn more: • src/runtime/cgocall.go • rustgo: Building your own FFI

    @ GothamGo 2017
 https://speakerdeck.com/filosottile/calling-rust-from-go-without-cgo-at-gothamgo-2017
  25. Reason 2: small stacks

  26. Initial goroutine stack size: 2048 bytes System stack size: 1–8

    megabytes
  27. stack

  28. function frame

  29. None
  30. None
  31. None
  32. None
  33. None
  34. Function preamble

  35. C doesn't call morestack C code needs to run on

    a system stack cgocall / asmcgocall
  36. Learn more: • src/runtime/stack.go • src/runtime/cgocall.go • How stacks are

    handled in Go by Daniel Morsing
 https://blog.cloudflare.com/how-stacks-are-handled-in-go/
  37. Reason 3: the scheduler

  38. From https://morsmachine.dk/go-scheduler

  39. From https://morsmachine.dk/go-scheduler

  40. The Go scheduler is collaborative. It can't preempt running code.

    (ProTip: for {} is never what you want. Use select {}.)
  41. None
  42. From https://morsmachine.dk/go-scheduler

  43. Learn more: • src/runtime/proc.go → reentersyscall • The Go scheduler

    by Daniel Morsing
 https://morsmachine.dk/go-scheduler • Performance without the event loop by Dave Cheney
 https://dave.cheney.net/2015/08/08/performance-without-the-event-loop
  44. Reason 4: the garbage collector

  45. Go memory C memory []byte

  46. Go memory C memory GC []byte

  47. Go memory C memory GC []byte

  48. Go memory C memory GC []byte *uint8_t C.some_func()

  49. The cgo rules You may pass a Go pointer …

    if it doesn’t point to other pointers … and C can’t keep a reference to it
  50. The GC must see all the Go pointers.

  51. panic: runtime error: cgo argument has Go pointer to Go

    pointer GODEBUG=cgocheck=2
  52. Learn more: • From cgo back to Go @ GopherCon

    2016
 https://speakerdeck.com/filosottile/from-cgo-back-to-go-gophercon-2016
  53. Thank you! fi[email protected] @FiloSottile Olga Shalakhina artwork under CC 3.0

    license based on Renee French under Creative Commons 3.0 Attributions.