Slide 1

Slide 1 text

Why cgo is slow Filippo Valsorda

Slide 2

Slide 2 text

No content

Slide 3

Slide 3 text

cgo is a FFI (Foreign Function Interface)

Slide 4

Slide 4 text

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!

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

name old time/op new time/op delta CgoCall-4 63.1ns ± 3% 57.1ns ± 0% -9.43%

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

cgo: • cmd/cgo • runtime/cgo • a sprinkle of cmd/link/internal/ld support • not a compiler feature!

Slide 11

Slide 11 text

cgo: • cmd/cgo — a code generator • runtime/cgo • a sprinkle of cmd/link/internal/ld support • not a compiler feature!

Slide 12

Slide 12 text

Reason 1: calling conventions

Slide 13

Slide 13 text

C compiler Go compiler

Slide 14

Slide 14 text

go build -x -work

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

src/runtime/cgocall.go

Slide 20

Slide 20 text

No content

Slide 21

Slide 21 text

No content

Slide 22

Slide 22 text

No content

Slide 23

Slide 23 text

rewritten Go function calling convention trampoline arg unpacking real C function Go ASM C

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

Reason 2: small stacks

Slide 26

Slide 26 text

Initial goroutine stack size: 2048 bytes System stack size: 1–8 megabytes

Slide 27

Slide 27 text

stack

Slide 28

Slide 28 text

function frame

Slide 29

Slide 29 text

No content

Slide 30

Slide 30 text

No content

Slide 31

Slide 31 text

No content

Slide 32

Slide 32 text

No content

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

Function preamble

Slide 35

Slide 35 text

C doesn't call morestack C code needs to run on a system stack cgocall / asmcgocall

Slide 36

Slide 36 text

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/

Slide 37

Slide 37 text

Reason 3: the scheduler

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

The Go scheduler is collaborative. It can't preempt running code. (ProTip: for {} is never what you want. Use select {}.)

Slide 41

Slide 41 text

No content

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

Reason 4: the garbage collector

Slide 45

Slide 45 text

Go memory C memory []byte

Slide 46

Slide 46 text

Go memory C memory GC []byte

Slide 47

Slide 47 text

Go memory C memory GC []byte

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

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

Slide 50

Slide 50 text

The GC must see all the Go pointers.

Slide 51

Slide 51 text

panic: runtime error: cgo argument has Go pointer to Go pointer GODEBUG=cgocheck=2

Slide 52

Slide 52 text

Learn more: • From cgo back to Go @ GopherCon 2016
 https://speakerdeck.com/filosottile/from-cgo-back-to-go-gophercon-2016

Slide 53

Slide 53 text

Thank you! fi[email protected] @FiloSottile Olga Shalakhina artwork under CC 3.0 license based on Renee French under Creative Commons 3.0 Attributions.