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

За пару мгновений до main() [RUS]

За пару мгновений до main() [RUS]

Oleg Kovalov

April 23, 2021
Tweet

More Decks by Oleg Kovalov

Other Decks in Programming

Transcript

  1. Олег 5 - Опенсорс-зависимый гофер - Фанат линтеров (соавтор go-critic)

    - Один из ведущих подкаста Generic Talks - Веселый и полезный @oleg_log
  2. Олег 6 - Опенсорс-зависимый гофер - Фанат линтеров (соавтор go-critic)

    - Один из ведущих подкаста Generic Talks - Веселый и полезный @oleg_log - А еще Twitter/Telegram @go_perf
  3. - Опенсорс-зависимый гофер - Фанат линтеров (соавтор go-critic) - Один

    из ведущих подкаста Generic Talks - Веселый и полезный @oleg_log - А еще Twitter/Telegram @go_perf - ... olegk.dev Олег 7
  4. - Зачем??? - У нас есть *.exe - Попробуем получить

    код - Пробежимся по коду План доклада 10
  5. - Зачем??? - У нас есть *.exe - Попробуем получить

    код - Пробежимся по коду - Пробежимся по коду - Пробежимся по коду - Пробежимся по коду - Пробежимся по коду - Пробежимся по коду - Пробежимся по коду План доклада 11
  6. - Зачем??? - У нас есть *.exe - Попробуем получить

    код - Пробежимся по коду - Пробежимся по коду - Пробежимся по коду - Пробежимся по коду - Пробежимся по коду - Пробежимся по коду - Пробежимся по коду - Интересное из stdlib - Exit Go 1.16.3, OS Darwin (macOS Big Sur), YMMV План доклада 12
  7. Правда из жизни рантайма 21 Хорошая тулза от Brad Fitzpatrick

    https://github.com/bradfitz/shotizam (нооо пока не работает с Go 1.16) pclntab rodata types
  8. - Проблема вроде бы есть - Но действительно проблематит не

    всех - размер Docker image чаще выступает проблемой - если вы на Ubuntu/Debian строитесь Так о чём это я 28
  9. - Проблема вроде бы есть - Но действительно проблематит не

    всех - размер Docker image чаще выступает проблемой - если вы на Ubuntu/Debian строитесь - + можно через UPX пожать бинарь Так о чём это я 29
  10. Так о чём это я 30 - Проблема вроде бы

    есть - Но действительно проблематит не всех - размер Docker image чаще выступает проблемой - если вы на Ubuntu/Debian строитесь - + можно через UPX пожать бинарь - Но что там минимально-нужного?
  11. Так о чём это я 31 - Проблема вроде бы

    есть - Но действительно проблематит не всех - размер Docker image чаще выступает проблемой - если вы на Ubuntu/Debian строитесь - + можно через UPX пожать бинарь - Но что там минимально-нужного? - Про это и поговорим
  12. ❯ cat main.go package main func main() { // ʕ◔ϖ◔ʔ

    } ❯ go build -o main.exe main.go Куда уж проще? 34
  13. ❯ cat main.go package main func main() { // ʕ◔ϖ◔ʔ

    } ❯ go build -o main.exe main.go ❯ du -sh main.exec 1.1M main.exec Куда уж проще? 35
  14. ❯ cat main.go package main func main() { // ʕ◔ϖ◔ʔ

    } ❯ go build -o main.exe main.go ❯ du -sh main.exec 1.1M main.exec ❯ 👀 Куда уж проще? 36
  15. ❯ go build -o main.exe main.go ❯ go list -json

    . > main.json Что в нашем *.exe? /2 39
  16. go list -json 40 { "Dir": "/Users/olegkovalov/go/src/github.com/cristaloleg/funf", "ImportPath": "github.com/cristaloleg/funf", "Name":

    "main", "Module": {...}, "GoFiles": [ "main.go" ], "Deps": [ "internal/bytealg", "internal/cpu", "runtime", "runtime/internal/atomic", "runtime/internal/math", "runtime/internal/sys", "unsafe" ] }
  17. ❯ go build -o main.exe main.go ❯ go tool objdump

    -S main.exe > main.dump Что в нашем *.exe? /3 41
  18. - Дизассемблирует исполняемые файлы var printCode = flag.Bool("S", false, "print

    Go code alongside assembly") - Еще есть флаг symregexp flag.String("s", "", "only dump symbols matching this regexp") ❯ go tool objdump -S -s runtime.close main.exec go tool objdump 44
  19. ❯ go build -o main.exe main.go ❯ go tool objdump

    -S main.exe > main.dump ❯ du -sh main.dump 5.1M main.dump Итог objdump 46
  20. ❯ go build -o main.exe main.go ❯ go tool objdump

    -S main.exe > main.dump ❯ du -sh main.dump 5.1M main.dump ❯ rg "TEXT runtime." -c main.dump 939 Итог objdump 47
  21. ❯ go build -o main.exe main.go ❯ go tool objdump

    -S main.exe > main.dump ❯ du -sh main.dump 5.1M main.dump ❯ rg "TEXT runtime." -c main.dump 939 ❯ 🔥🔥🔥 Итог objdump 48
  22. Пойдем в main.dump 52 - Обычный текстовый файл - Со

    всеми возможными объявлениями - Полезно, если делаете низкоуровневые оптимизации - Или какой-то там доклад
  23. Настоящий main 56 ...60k lines 0x102fc2b 488b6c2448 MOVQ 0x48(SP), BP

    0x102fc30 4883c450 ADDQ $0x50, SP 0x102fc34 c3 RET func main() { 0x102fc35 e846980200 CALL runtime.morestack_noctxt(SB) 0x102fc3a e941fcffff JMP runtime.main(SB) 0x102fc3f cc INT $0x3 ...60k lines
  24. Настоящий main...уже ближе 57 ...60k lines 0x102fc2b 488b6c2448 MOVQ 0x48(SP),

    BP 0x102fc30 4883c450 ADDQ $0x50, SP 0x102fc34 c3 RET func main() { 0x102fc35 e846980200 CALL runtime.morestack_noctxt(SB) 0x102fc3a e941fcffff JMP runtime.main(SB) 0x102fc3f cc INT $0x3 ...60k lines
  25. runtime.main 58 TEXT runtime.main(SB) /usr/local/Cellar/go/1.16/libexec/src/runtime/proc.go func main() { 0x102f880 65488b0c2530000000

    MOVQ GS:0x30, CX 0x102f889 483b6110 CMPQ 0x10(CX), SP 0x102f88d 0f86a2030000 JBE 0x102fc35 0x102f893 4883ec50 SUBQ $0x50, SP 0x102f897 48896c2448 MOVQ BP, 0x48(SP) 0x102f89c 488d6c2448 LEAQ 0x48(SP), BP 0x102f8a1 0f57c0 XORPS X0, X0 0x102f8a4 0f11442438 MOVUPS X0, 0x38(SP) 0x102f8a9 c644242700 MOVB $0x0, 0x27(SP) g := getg() 0x102f8ae 65488b042530000000 MOVQ GS:0x30, AX 0x102f8b7 4889442430 MOVQ AX, 0x30(SP) g.m.g0.racectx = 0
  26. Что к чему в runtime/proc.go 59 //go:linkname main_main main.main func

    main_main() // ... // The main goroutine. func main() { g := getg() // ... fn := main_main // make an indirect call, // as the linker doesn't know the address // of the main package when laying down the runtime fn() // ...
  27. Так и запишем /1 60 - ... - runtime.main() -

    main_main ~ main.main // магия линковщика - main.main // это мы!
  28. - Есть странные runtime/asm_<arch>.s файлы - где arch - некая

    архитектура (amd64, arm64, mips, …) - *.s - Assembler Вот только это не всё 63
  29. - Есть странные runtime/asm_<arch>.s файлы - где arch - некая

    архитектура (amd64, arm64, mips, …) - *.s - Assembler - 👀 Вот только это не всё 64
  30. - Есть странные runtime/asm_<arch>.s файлы - где arch - некая

    архитектура (amd64, arm64, mips, …) - *.s - Assembler - 👀 - Значит пойдём разбираться Вот только это не всё 65
  31. - Есть странные runtime/asm_<arch>.s файлы - где arch - некая

    архитектура (amd64, arm64, mips, …) - *.s - Assembler - 👀 - Значит пойдём разбираться - Посмотрим на asm_amd64.s - всего лишь 2к строк Вот только это не всё 66
  32. - Есть странные runtime/asm_<arch>.s файлы - где arch - некая

    архитектура (amd64, arm64, mips, …) - *.s - Assembler - 👀 - Значит пойдём разбираться - Посмотрим на asm_amd64.s - всего лишь 2к строк - в остальных + - 1к - arm64.s тоже тяжелый Вот только это не всё 67
  33. - FP: Frame pointer: arguments and locals. - PC: Program

    counter: jumps and branches. - SB: Static base pointer: global symbols. - SP: Stack pointer: top of stack. Словарик читателя Go assembler 68
  34. - FP: Frame pointer: arguments and locals. - PC: Program

    counter: jumps and branches. - SB: Static base pointer: global symbols. - SP: Stack pointer: top of stack. - JMP: jump - LEA: load effective address - MOV dst, src: move src - CALL: invoke function - DATA(+GLOBL): data symbols (global) Словарик читателя Go assembler 69
  35. // _rt0_amd64 is common startup code for most amd64 systems

    when using // internal linking. This is the entry point for the program from the // kernel for an ordinary -buildmode=exe program. The stack holds the // number of arguments and the C-style argv. TEXT _rt0_amd64(SB),NOSPLIT,$-8 MOVQ 0(SP), DI // argc LEAQ 8(SP), SI // argv JMP runtime·rt0_go(SB) Ах вот оно что! 70
  36. // Defined as ABIInternal since it does not use the

    stack-based Go ABI (and // in addition there are no calls to this entry point from Go code). TEXT runtime·rt0_go<ABIInternal>(SB),NOSPLIT,$0 // copy arguments forward on an even stack MOVQ DI, AX // argc MOVQ SI, BX // argv // ... // create istack out of the given (operating system) stack. MOVQ $runtime·g0(SB), DI // ... // find out information about the processor we're on MOVL $0, AX CPUID // ... Пойдем дальше 71
  37. Пойдем дальше 72 TEXT runtime·rt0_go<ABIInternal>(SB),NOSPLIT,$0 // Figure out how to

    serialize RDTSC. // On Intel processors LFENCE is enough. AMD requires MFENCE. // Don't know about the rest, so let's do MFENCE. // ... ok: // set the per-goroutine and per-mach "registers" get_tls(BX) LEAQ runtime·g0(SB), CX MOVQ CX, g(BX) LEAQ runtime·m0(SB), AX // save m->g0 = g0 MOVQ CX, m_g0(AX) // save m0 to g0->m MOVQ AX, g_m(CX)
  38. Пойдем дальше 73 TEXT runtime·rt0_go<ABIInternal>(SB),NOSPLIT,$0 // ... CALL runtime·check(SB) MOVL

    16(SP), AX // copy argc MOVL AX, 0(SP) MOVQ 24(SP), AX // copy argv MOVQ AX, 8(SP) CALL runtime·args(SB) CALL runtime·osinit(SB) CALL runtime·schedinit(SB)
  39. - Да, содержат платформозависимые вещи - Обработка сигналов - Иногда

    таймеры - Рандом - Размеры тредов и прочих системных вещей - Энвы и аргументы программы - речь о environment variables и argc & argv runtime/os_<os>.go 76
  40. - Да, содержат платформозависимые вещи - Обработка сигналов - Иногда

    таймеры - Рандом - Размеры тредов и прочих системных вещей - Энвы и аргументы программы - речь о environment variables и argc & argv - Проверка адекватности машины - o! runtime/os_<os>.go 77
  41. - В файле runtime1.go есть интересная функция - check() -

    проверяем размеры примитивных типов - d uint16 - if unsafe.Sizeof(d) != 2 { throw("bad d") } Проверка адекватности машины 79
  42. - В файле runtime1.go есть интересная функция - check() -

    проверяем размеры примитивных типов - d uint16 - if unsafe.Sizeof(d) != 2 { throw("bad d") } - check() вызывает testAtomic64() Проверка адекватности машины 80
  43. - В файле runtime1.go есть интересная функция - check() -

    проверяем размеры примитивных типов - d uint16 - if unsafe.Sizeof(d) != 2 { throw("bad d") } - check() вызывает testAtomic64() - Как можно догадаться, testAtomic64 про атомики - test_z64 = 42, test_x64 = 0 - if atomic.Cas64(&test_z64, test_x64, 1) { throw("cas64 failed") } Проверка адекватности машины 81
  44. Пойдем дальше 82 TEXT runtime·rt0_go<ABIInternal>(SB),NOSPLIT,$0 // ... CALL runtime·check(SB) MOVL

    16(SP), AX // copy argc MOVL AX, 0(SP) MOVQ 24(SP), AX // copy argv MOVQ AX, 8(SP) CALL runtime·args(SB) CALL runtime·osinit(SB) CALL runtime·schedinit(SB) // при помощи магии и директив линкера это и будет os.Args
  45. Пойдем дальше 84 /Users/olegkovalov/go/src/golang/go/src/runtime/runtime1.go func args(c int32, v **byte) {

    argc = c argv = v sysargs(c, v) } // os_darwin.go func sysargs(argc int32, argv **byte) { // skip over argv, envv and the first string will be the path n := argc + 1 for argv_index(argv, n) != nil { n++ } executablePath = gostringnocopy(argv_index(argv, n+1)) // ... }
  46. Пойдем дальше 85 TEXT runtime·rt0_go<ABIInternal>(SB),NOSPLIT,$0 // ... CALL runtime·check(SB) MOVL

    16(SP), AX // copy argc MOVL AX, 0(SP) MOVQ 24(SP), AX // copy argv MOVQ AX, 8(SP) CALL runtime·args(SB) CALL runtime·osinit(SB) CALL runtime·schedinit(SB)
  47. Пойдем дальше 86 // os_darwin.go // BSD interface for threading.

    func osinit() { // pthread_create delayed until end of goenvs so that we // can look at the environment first. ncpu = getncpu() physPageSize = getPageSize() }
  48. Пойдем дальше 87 TEXT runtime·rt0_go<ABIInternal>(SB),NOSPLIT,$0 // ... CALL runtime·check(SB) MOVL

    16(SP), AX // copy argc MOVL AX, 0(SP) MOVQ 24(SP), AX // copy argv MOVQ AX, 8(SP) CALL runtime·args(SB) CALL runtime·osinit(SB) CALL runtime·schedinit(SB)
  49. Так и запишем /2 88 - runtime·_rt0_amd64 // или какая

    там у вас архитектура - runtime·rt0_go - создадим Вселенную - check - args - osinit - schedinit - runtime.main() - main_main ~ main.main // магия линковщика - main.main // это мы!
  50. Пойдем дальше 89 // The bootstrap sequence is: // //

    call osinit // call schedinit // make & queue new G // call runtime·mstart // // The new G calls runtime·main. func schedinit() { // ...
  51. - G - goroutine - M - worker thread, or

    machine. - P - processor, a resource that is required to execute Go code. - getg() - returns the pointer to the current g - _g_ := getg() - p := getg().m.p.ptr() - tls - thread-local storage Остальное это if-ы, атомики и непонятные алгоритмы. Вроде изян. Словарик читателя runtime 90
  52. func schedinit() { // ... _g_ := getg() sched.maxmcount =

    10000 // maximum number of m's allowed (or die) // The world starts stopped. worldStopped() moduledataverify() // pclntab is correct stackinit() // mallocinit() fastrandinit() // must run before mcommoninit mcommoninit(_g_.m, -1) schedinit /1 91
  53. func schedinit() { // ... _g_ := getg() sched.maxmcount =

    10000 // maximum number of m's allowed (or die) // The world starts stopped. worldStopped() moduledataverify() // pclntab is correct stackinit() // mallocinit() fastrandinit() // must run before mcommoninit mcommoninit(_g_.m, -1) cpuinit() // must run before alginit alginit() // maps must not be used before this call modulesinit() // provides activeModules typelinksinit() // uses maps, activeModules itabsinit() // uses activeModules schedinit /1 92
  54. func schedinit() { // ... goargs() goenvs() parsedebugvars() gcinit() lock(&sched.lock)

    // ... if procresize(procs) != nil { throw("unknown runnable goroutine during bootstrap") } unlock(&sched.lock) // World is effectively started now, as P's can run. worldStarted() // ... } schedinit /2 93
  55. TEXT runtime·rt0_go<ABIInternal>(SB),NOSPLIT,$0 // ... // create a new goroutine to

    start program MOVQ $runtime·mainPC(SB), AX // entry PUSHQ AX PUSHQ $0 // arg size CALL runtime·newproc(SB) POPQ AX POPQ AX ... // mainPC is a function value for runtime.main, to be passed to newproc. // The reference to runtime.main is made via ABIInternal, since the // actual function (not the ABI0 wrapper) is needed by newproc. DATA runtime·mainPC+0(SB)/8,$runtime·main<ABIInternal>(SB) GLOBL runtime·mainPC(SB),RODATA,$8 Еще чуть-чуть Ассемблера 94
  56. Последнее из Ассемблера, честно 95 TEXT runtime·rt0_go<ABIInternal>(SB),NOSPLIT,$0 // ... //

    create a new goroutine to start program MOVQ $runtime·mainPC(SB), AX // entry PUSHQ AX PUSHQ $0 // arg size CALL runtime·newproc(SB) POPQ AX POPQ AX // start this M CALL runtime·mstart(SB) CALL runtime·abort(SB)// mstart should never return RET TEXT runtime·mstart(SB),NOSPLIT|TOPFRAME,$0 CALL runtime·mstart0(SB) RET // not reached
  57. newproc 96 // Create a new g running fn with

    siz bytes of arguments. // Put it on the queue of g's waiting to run. // The compiler turns a go statement into a call to this. // ... func newproc(siz int32, fn *funcval) { argp := add(unsafe.Pointer(&fn), sys.PtrSize) gp := getg() pc := getcallerpc() systemstack(func() { newg := newproc1(fn, argp, siz, gp, pc) _p_ := getg().m.p.ptr() runqput(_p_, newg, true) if mainStarted { wakep() } }) }
  58. // Create a new g running fn with siz bytes

    of arguments. // Put it on the queue of g's waiting to run. // The compiler turns a go statement into a call to this. // ... func newproc(siz int32, fn *funcval) { argp := add(unsafe.Pointer(&fn), sys.PtrSize) gp := getg() pc := getcallerpc() systemstack(func() { newg := newproc1(fn, argp, siz, gp, pc) _p_ := getg().m.p.ptr() runqput(_p_, newg, true) if mainStarted { wakep() } }) } newproc 97
  59. newproc 98 // Create a new g running fn with

    siz bytes of arguments. // Put it on the queue of g's waiting to run. // The compiler turns a go statement into a call to this. // ... func newproc(siz int32, fn *funcval) { argp := add(unsafe.Pointer(&fn), sys.PtrSize) gp := getg() pc := getcallerpc() systemstack(func() { newg := newproc1(fn, argp, siz, gp, pc) _p_ := getg().m.p.ptr() runqput(_p_, newg, true) if mainStarted { wakep() } }) }
  60. systemstack 99 // systemstack runs fn on a system stack.

    // If systemstack is called from the per-OS-thread (g0) stack, or // if systemstack is called from the signal handling (gsignal) stack, // systemstack calls fn directly and returns. // // Otherwise, systemstack is being called from the limited stack // of an ordinary goroutine. In this case, systemstack switches // to the per-OS-thread stack, calls fn, and switches back. // //go:noescape func systemstack(fn func())
  61. Наконец-то scheduler // mstart is the entry-point for new Ms.

    func mstart() // mstart0 is the Go entry-point for new Ms. func mstart0() { _g_ := getg() // ... mstart1() } func mstart1() { _g_ := getg() // ... schedule() } 100
  62. schedule 101 // One round of scheduler: find a runnable

    goroutine and execute it. // Never returns. func schedule() { _g_ := getg() top: pp := _g_.m.p.ptr() pp.preempt = false var gp *g // get some gp execute(gp, inheritTime) }
  63. Так и запишем /3 102 - runtime·_rt0_amd64 // или что

    там у вас по архитектуре и ОС - runtime·rt0_go - check - args - osinit - schedinit - ... - newproc создаст горутину для runtime.main - mstart для выполнения горутины выше - mstart0 -> mstart1 - schedule - runtime.main() - main_main ~ main.main // магия линковщика - main.main // это мы!
  64. - Все озвученное ранее это 250 линий - Остальное это

    runtime-овые вещи (кэп) Оке, а почему там 2к линий? 105
  65. - Все озвученное ранее это 250 линий - Остальное это

    runtime-овые вещи (кэп) - управлением стеком - выполнение defer - различные паники Оке, а почему там 2к линий? 106
  66. - Все озвученное ранее это 250 линий - Остальное это

    runtime-овые вещи (кэп) - управлением стеком - выполнение defer - различные паники - помощь для дебага - любимый cgo - gc barriers Оке, а почему там 2к линий? 107
  67. - Все озвученное ранее это 250 линий - Остальное это

    runtime-овые вещи (кэп) - управлением стеком - выполнение defer - различные паники - помощь для дебага - любимый cgo - gc barriers - таймеры - сигналы - хеши Оке, а почему там 2к линий? 108
  68. Пойдем дальше // func memhash(p unsafe.Pointer, h, s uintptr) uintptr

    // hash function using AES hardware instructions TEXT runtime·memhash<ABIInternal>(SB),NOSPLIT,$0-32 CMPB runtime·useAeshash(SB), $0 JEQ noaes MOVQ p+0(FP), AX // ptr to data MOVQ s+16(FP), CX // size LEAQ ret+24(FP), DX JMP aeshashbody<>(SB) noaes: JMP runtime·memhashFallback<ABIInternal>(SB) /Users/olegkovalov/go/src/golang/go/src/runtime/hash64.go func memhashFallback(p unsafe.Pointer, seed, s uintptr) uintptr { 109
  69. - add GOAMD64 architecture variants #25489 - https://github.com/golang/go/issues/25489 - Сейчас

    можно найти похожие строки - x86HasSSE41 = cpu.X86.HasSSE41 - на самом деле их сильно больше - Из-за чего мы теряем такты процессора - каждая наносекунда на счету :( GOAMD64 proposal 110
  70. - В runtime init-ов не много - Большинство из них

    это просто проверки машины - какие размеры типов - какие флаги у процессора - Но есть 1 интересный в runtime (потом обсудим некоторые пакеты из stdlib) Так что там в init()-ах?? 112
  71. /Users/olegkovalov/go/src/golang/go/src/runtime/proc.go // start forcegc helper goroutine func init() { go

    forcegchelper() } // 5k lines later... Популярная претензия к GC 114
  72. Популярная претензия к GC 115 /Users/olegkovalov/go/src/golang/go/src/runtime/proc.go // start forcegc helper

    goroutine func init() { go forcegchelper() } // 5k lines later... // forcegcperiod is the maximum time in nanoseconds between garbage // collections. If we go this long without a garbage collection, one // is forced to run. // // This is a variable for testing purposes. It normally doesn't change. var forcegcperiod int64 = 2 * 60 * 1e9
  73. func init() { crypto.RegisterHash(crypto.MD5, New) } // Именно поэтому в

    импортах мы делаем: import ( _ "crypto/sha256" // to register a sha256 _ "crypto/sha512" // to register a sha384/512 ) Так что там в crypto/* 118
  74. func init() { crypto.RegisterHash(crypto.MD5, New) } // Именно поэтому в

    импортах мы делаем: import ( _ "crypto/sha256" // to register a sha256 _ "crypto/sha512" // to register a sha384/512 ) // а НЕ это: import ( _ "crypto/sha256" //nolint "crypto/sha512" ) var _ = sha512.<Something_Just_To_Import> Так что там в crypto/* 119
  75. func init() { // ... registerBasics() // ... } Так

    что там в encoding/gob 120
  76. func init() { // ... registerBasics() // ... } func

    registerBasics() { Register(int(0)) Register(int8(0)) Register(int16(0)) Register(int32(0)) Register(int64(0)) // ... Так что там в encoding/gob 121
  77. Так что там в net 122 // net/conf_netcgo.go //go:build netcgo

    // +build netcgo package net // The build tag "netcgo" forces use of the cgo DNS resolver. // It is the opposite of "netgo". func init() { netCgo = true } // net/conf.go netGo bool // go DNS resolution forced netCgo bool // cgo DNS resolution forced
  78. Так что там в net 123 // net/conf_netcgo.go //go:build netcgo

    // +build netcgo package net // The build tag "netcgo" forces use of the cgo DNS resolver. // It is the opposite of "netgo". func init() { netCgo = true } // net/conf.go netGo bool // go DNS resolution forced netCgo bool // cgo DNS resolution forced
  79. // When debugging a particular http server-based test, // this

    flag lets you run // go test -run=BrokenTest -httptest.serve=127.0.0.1:8000 // to start the broken server so you can interact with it manually. // ... // isn't really part of our API. Don't depend on this. var serveFlag string func init() { if has(os.Args, "-httptest.serve=") { flag.StringVar(&serveFlag, "httptest.serve", "", "...") } } Так что там в net/http/httptest 124
  80. // mime/type_freebsd.go func init() { typeFiles = append(typeFiles, "/usr/local/etc/mime.types") }

    // mime/type_openbsd.go func init() { typeFiles = append(typeFiles, "/usr/share/misc/mime.types") } ... Так что там в mime 126 MIME == Multipurpose Internet Mail Extensions
  81. func init() { runtime_registerPoolCleanup(poolCleanup) } func poolCleanup() { for _,

    p := range oldPools { // ... } for _, p := range allPools { // ... } // The pools with non-empty primary caches now have non-empty // victim caches and no pools have primary caches. oldPools, allPools = allPools, nil } Так что там в sync 127
  82. Так что там в sync /2 // sync/runtime.go // Ensure

    that sync and runtime agree on size of notifyList. func runtime_notifyListCheck(size uintptr) func init() { var n notifyList runtime_notifyListCheck(unsafe.Sizeof(n)) } // runtime/sema.go //go:linkname notifyListCheck sync.runtime_notifyListCheck func notifyListCheck(sz uintptr) { if sz != unsafe.Sizeof(notifyList{}) { print("runtime: bad notifyList") throw("bad notifyList size") } } 128
  83. // Package tzdata provides an embedded copy of the timezone

    database. // If this package is imported anywhere in the program, then if // the time package cannot find tzdata files on the system, // it will use this embedded information. // // Importing this package will increase the size of a program by about // 450 KB. // Так что там в time/tzdata 130
  84. // Package tzdata provides an embedded copy of the timezone

    database. // If this package is imported anywhere in the program, then if // the time package cannot find tzdata files on the system, // it will use this embedded information. // // Importing this package will increase the size of a program by about // 450 KB. // Так что там в time/tzdata 131
  85. Так что там в time/tzdata 132 // Package tzdata provides

    an embedded copy of the timezone database. // If this package is imported anywhere in the program, then if // the time package cannot find tzdata files on the system, // it will use this embedded information. // // Importing this package will increase the size of a program by about // 450 KB. // // This package should normally be imported by a program's main package, // not by a library. Libraries normally shouldn't decide whether to // include the timezone database in a program. // // This package will be automatically imported if you build with // -tags timetzdata. package tzdata
  86. Так что там в time/tzdata 133 // Package tzdata provides

    an embedded copy of the timezone database. // If this package is imported anywhere in the program, then if // the time package cannot find tzdata files on the system, // it will use this embedded information. // // Importing this package will increase the size of a program by about // 450 KB. // // This package should normally be imported by a program's main package, // not by a library. Libraries normally shouldn't decide whether to // include the timezone database in a program. // // This package will be automatically imported if you build with // -tags timetzdata. package tzdata
  87. - Часто можно увидеть объявление функции перед использованием - мы

    ведь помним, что когда-то Go был написан на Си :) Интересности в 1 слайд 135
  88. - Часто можно увидеть объявление функции перед использованием - мы

    ведь помним, что когда-то Go был написан на Си :) - Также достаточное количество _ в именах переменных и функций - опять же наследие Си Интересности в 1 слайд 136
  89. - Часто можно увидеть объявление функции перед использованием - мы

    ведь помним, что когда-то Go был написан на Си :) - Также достаточное количество _ в именах переменных и функций - опять же наследие Си - Windows, NetBSD, Wasm, JS и Plan9 особенные - часто из-за них есть осознанные костыли Интересности в 1 слайд 137
  90. - Часто можно увидеть объявление функции перед использованием - мы

    ведь помним, что когда-то Go был написан на Си :) - Также достаточное количество _ в именах переменных и функций - опять же наследие Си - Windows, NetBSD, Wasm, JS и Plan9 особенные - часто из-за них есть осознанные костыли - Cgo is not Go, как говорил Пайк - и этим все сказано Интересности в 1 слайд 138
  91. - Часто можно увидеть объявление функции перед использованием - мы

    ведь помним, что когда-то Go был написан на Си :) - Также достаточное количество _ в именах переменных и функций - опять же наследие Си - Windows, NetBSD, Wasm, JS и Plan9 особенные - часто из-за них есть осознанные костыли - Cgo is not Go, как говорил Пайк - и этим все сказано - Runtime is all about corner cases - такое моё ИМХО Интересности в 1 слайд 139
  92. Вывод 141 - Близко знакомимся с машиной - Создаём горутину

    - Создаём тред, который её выполнит - Выполняем и смотрим что выполнить еще - Всё
  93. - A Quick Guide to Go's Assembler - https://golang.org/doc/asm -

    The Go Memory Model - https://golang.org/ref/mem - Go 1.2 Runtime Symbol Information (2013) - https://docs.google.com/document/d/1lyPIbmsYbXnpNj57a261hgOYVpNRcgydurVQIyZO z_o/pub - runtime/HACKING.md - https://github.com/golang/go/blob/master/src/runtime/HACKING.md Материалы 142
  94. - Anton Repushko - Bogdan Storozhuk - Iskander Sharipov -

    И тебе тоже Благодарности 144
  95. - Anton Repushko - Bogdan Storozhuk - Iskander Sharipov -

    И тебе тоже GopherCon team 👌 Благодарности 145