Что такое инлайнинг функций
Что проверяют
Знаете ли вы, что компилятор Go делает сам, и не пытаетесь ли оптимизировать руками то, за что он уже отвечает. Заодно проверяют, умеете ли вы смотреть решения компилятора, а не рассуждать о них.
Как отвечать
Инлайнинг это подстановка тела функции на место её вызова при компиляции. Экономия на самом вызове невелика, и не в ней смысл. Главное в том, что после подстановки компилятор видит тело в контексте вызова и включаются остальные оптимизации, прежде всего анализ побегов: значение, которое раньше уезжало в кучу, остаётся на стеке, и исчезает работа сборщика мусора.
Решение принимает компилятор по бюджету стоимости: тело оценивается в условных единицах по узлам синтаксического дерева, и слишком дорогое не подставляется. Порог небольшой, поэтому внутрь попадают короткие обёртки, геттеры, проверки. Часть конструкций запрещает подстановку целиком, например recover и select, а вызов через интерфейс не подставится, если тип не удалось определить статически.
Решения компилятора видны глазами:
go build -gcflags='-m' ./...
# can inline add
# inlining call to addТочечно запрещает директива //go:noinline, целиком выключает флаг -gcflags=-l, что иногда делают, чтобы профиль читался по исходным функциям.
Где спотыкаются
Говорят, что подставляется то, что вызывается часто. По умолчанию число вызовов компилятору неизвестно, решение принимается по размеру тела; частота учитывается только при сборке с профилем.
Разворачивают функции руками: копируют тело в вызывающий код ради скорости. Либо компилятор сделал бы то же сам, либо тело слишком велико, и тогда стоимость вызова точно не главная статья расходов. В остатке нечитаемый код без выигрыша.
Делают выводы без замера. Подстановка раздувает машинный код и давит на кэш инструкций, поэтому выигрыш подтверждают бенчмарком со сравнением прогонов, а не ощущением от чтения ассемблера.