Новая оптимизация — это раздувание кодовой базы, усложнение проекта.
Да, но для новых SSA правил обычно порог принятия довольно низок. Если выглядит полезным — вливают. Уровень усложнения кодовой базы считается невысоким.
А нет ли какого-то правила, определяющего, можно ли добавлять данную оптимизацию в компилятор?
Каждый коммит в компилятор рекомендуется сопровождать бенчмарками и, если релевантно, статистикой изменения размера бинарников (тут помогают утилиты benchstat и bincmp). Самой ленивой проверкой является запуск ./make.bash с подсчётом срабатываний нового правила.
Если оптимизация именно на Go дистрибутиве не очень срабатывает, но выглядит полезной, стоит найти другой проект, где она срабатывает и даёт измеримый прирост.
Чем больше аргументов и статистики на руках — тем лучше.
При генерации кода из Rules можно передать параметр -log:
flag.Bool("log", false, "generate code that logs; for debugging only")
Тогда при ./make.bash (и вообще любом компилировании) будут подсчитываться все срабатывания правил. Только осторожно, там между запусками будет append в файл, так что он может до нескольких гигабайт вырасти достаточно незаметно; не забудьте выключить. :)
В ней присутствуют false positive срабатывания для безымянных параметров. Если бы их не было, всё равно был бы вредным?
И если вы хотите иметь opinionated проверки
В недавнем обновлении по умолчанию experimental и opinionated выключены из -enable=all. В идеале eventually придём к более-менее нормальному default набору, но в качестве интеграции куда-то всё равно лучше явный список использовать.
Ну и отсутствие интеграции с редакторами/gometalinter делает ваш проект заметно менее привлекательным, ведь если уже кто-то заморочился с новой проверкой она должна быть полностью интегрирована в процесс разработки.
Уже в golangci-lint добавиться планируем, там есть интеграции в том числе с редакторами. В gometalinter, наверное, тоже можно. Для проекта эти интеграции важны, согласен полностью.
Есть общепризнанный и лаконичный аналог на Русском, или только полная форма «статический анализатор»? Возможно, «анализатор» был бы уместным компромиссом.
В англоязычном слаке (https://gophers.slack.com) есть канал contributor-workshop, где он предложил нам разместиться при следующем проведении. Из плюсов: там очень много людей из "Go core team".
Если у нас больше регистров, нужно меньше spill'ов в память, если в функции можно обойтись без «локальных слотов» внутри фрейма, фрейм у функции будет меньше или вообще нулевой, тогда при вызовах функции стек будет расти медленнее. Меньше стеки — меньше потребление памяти. Вот это имел в виду выше.
Мне не известны ваши познания в этой теме, но в своих я не настолько уверен, чтобы про все векторные инструкции тут говорить обобщая. Есть специальные инструкции, которые не требуют выравнивания, причём в случае, если данные выровнены, они работают не хуже, чем формы, требующие выравнивания. В Go даже стек, насколько помню, не выровнен…
Можем закрыть эту тему?
Я не понимаю ваших мотивов и того, чего вы хотите.
Очевидно, мои ответы вам не помогают/не нравятся.
Go в том числе в датацентрах используется, а там есть понятие tail latency.
Издержки на него можно сократить, если Go работает быстрее.
Сделать Go быстрее для всех, без надобности учить людей писать более быстрый код можно с помощью ускорения рантайма и улучшения компилятора (например, научить его использовать дополнительные регистры для уменьшения количества spill'ов, правда это немного надуманный пример).
Хуже от того, что Go будет становиться более быстрым и/или потреблять меньше памяти, никому не будет.
Конкретно пример с VADDPD привёл для подчёркивания того, что старый код будет собираться по-старому, с VEX префиксом. В редких ситуациях EVEX префикс мог бы дать небольшой выигрыш в размере машинного кода за счёт compressed displacement, но для более детерменированного поведения и в том числе для обратной совместимости, выбрана цитируемая вами схема. Плюс тем, кто «без словаря» не помнит всех нюансов, спокойнее (например мне).
AVX-512 и EVEX может появляться только в новом коде, когда программист сознательно запросил данное поведение (использовал новые регистры или суффиксы опкода).
Способа «переопределить» поведение нет. То есть нельзя попросить тот VADDPD кодировать по схеме AVX-512.
У Go тулчейна есть задача быть максимально независимым от других утилит, в частности внешних ассемблеров.
Тем более если кому-то векторизация не нужна, он о ней не задумывается.
А в рантайме Go, может быть, даже применение найдётся.
Я сейчас не обязательно про новые «модные» инструкции и 512-битные регистры, к которым у многих есть своё отношение, а про приятные дополнения к предыдущим AVX. Насколько мне известно, положительные эксперименты как минимум в пакетах крипты уже были.
Я не пытаюсь вас переубедить. Просто предоставляю контекст, который может быть полезен и, возможно, ускользнул от вас.
Неужели так много программистов желают колупаться с ассемблером в вебе?
Нет, их мало и они не совсем веб-разработчики. То, что они делают, потом используют в том числе веб-разработчики.
Ещё одним «пользователем» ассемблера является сам тулчейн.
Можете пробежаться по статье Архитектура ассемблера Go. Разница лишь в том, что нет этапа парсинга.
Ассемблер в Go — одно из промежуточных представлений компилятора (низкоуровневый IR).
Если через 10 лет везде будет AVX-512, то, возможно, вместо 16 векторных регистров он будет использовать 32 (в них float'ы хранятся). Либо у нас будет что-то типа вот этого: GOAMD64 architecture flag и получить преимущества EVEX префикса можно будет значительно раньше.
Ещё раз, разговор не о том, что все обязаны перерабатывать, ночевать и все выходные на работе проводить да ещё бесплатно. И не в том, что конкретный работник уходит ровно. А в том, что десяток человек не могут быть вашими клонами и вести себя одинаково.
Я эту часть упустил в ветке.
Мой ответ тогда лучше воспринимать как субъективное мнение, не сильно привязанное ко всем вашим высказываниям.
У человека дома даже без семьи могут быть задачки поинтереснее, в том числе интеллектуальные, в том числе в программировании. Не знаю как у других, у меня задачек меньше, чем на несколько часов или дней почти не бывает. С такими обычно даже на час задерживаться смысла мало, корректность важнее, а для неё нужно быть свободным от желания переключиться.
Даже интересная работа под конец дня может вызвать желание переключиться (обычно это гораздо чаще одного раза в день происходит, просто 18 часов выглядят отметкой, которая удобна для переключения). Это нормально.
И вообще, тут виновато расписание «с 9 до 18».
Вводим понятие «важен результат, а не уйти в 18», но при этом есть чёткий график.
Я могу и в 16, условно, уже на сегодня всё сделать, а оставшиеся часы планировать дальнейшие дни и недели, и тут вполне удобно оторваться от рабочего компьютера ровно по расписанию. Это тоже часть работы, но задерживаться ради неё смысла нет.
А ещё у человека может быть депрессия и ему хочется поскорее домой, потому что он не ищет компании.
Меня очень расстраивает, когда весь коллектив задерживается а тех, кто уходит вовремя (и приходит вовремя), порицают.
Расписываюсь, что в курсе холиварности этой темы. Тут куча простора для недопонимания и альтернативных точек зрения.
А выгорание едва ли начнётся, если к домашнему опенсорсу относиться как к хобби.
Очень любопытно стало, а вам свойственно доводить хобби проекты «до конца»?
Ваш опыт может отличаться, но по моим наблюдениям в какой-то момент основной интерес и элегантность проекта улетучивается и чтобы продолжать нужно больше сил, чем при старте.
Большое количество покинутых проектов меня сильно демотивирует.
В крайних случаях может сопутствовать выгоранию.
Возможно мне действительно не хватит знаний продолжить диалог, но стало любопытно: а если член структуры является полиморфным типом, разве компилятор сможет в каких-то случаях избежать перерасхода памяти?
Про спекулятивную девиртуализацию поищу.
Anyway, в Go можно явно сказать: «Тут мне полиморфный тип, а тут просто структру T».
В C++ же полиморфность является свойством самого типа T. Right?
Возможно проблема в том, что у Go нет своего pip.
Go build и то, что близ него — это довольно низкоуровневые вещи.
Мне не очевидно, насколько github.com/constabulary/gb юзабелен, но скорее всего со временем появится хороший project-based тул, который станет тем самым pip для Go.
Я хотел бы заметить, что в случае C++ добавив в класс [тип T] виртуальный метод, у вас каждый экземпляр типа T будет содержать таблицу виртуальных методов.
В случае Go сам тип T, реализующий интерфейсы, таблицы виртаульных методов не содержит никогда, поэтому когда мы не используем полиморфное поведение, не будет лишнего жира. Когда T передаётся как интерфейсный тип, вот там уже будет боксинг с аллокацией.
Насколько это хорошо или плохо — не хочу полемизировать, но подчеркнуть, что это не «Как в C++», всё-таки захотелось.
Самый честный ответ: никак. Все оптимизации локальны для одной функции.
Только в случае встраивания вызываемой процедуры будет нормальная оптимизация.
В ближайшем будущем максимум, чего можно ожидать:
Возможно если бы кто-то показал, что глобальная оптимизация Go программ имеет эти свойства:
То со временем это бы вливали в мастер. Сначала в виде эксперимента, потом в виде поведения по умолчанию, если бы не было значительных недостатков.
Да, но для новых SSA правил обычно порог принятия довольно низок. Если выглядит полезным — вливают. Уровень усложнения кодовой базы считается невысоким.
Каждый коммит в компилятор рекомендуется сопровождать бенчмарками и, если релевантно, статистикой изменения размера бинарников (тут помогают утилиты benchstat и bincmp). Самой ленивой проверкой является запуск
./make.bash
с подсчётом срабатываний нового правила.Если оптимизация именно на Go дистрибутиве не очень срабатывает, но выглядит полезной, стоит найти другой проект, где она срабатывает и даёт измеримый прирост.
Чем больше аргументов и статистики на руках — тем лучше.
При генерации кода из Rules можно передать параметр
-log
:Тогда при
./make.bash
(и вообще любом компилировании) будут подсчитываться все срабатывания правил. Только осторожно, там между запусками будет append в файл, так что он может до нескольких гигабайт вырасти достаточно незаметно; не забудьте выключить. :)В ней присутствуют false positive срабатывания для безымянных параметров. Если бы их не было, всё равно был бы вредным?
В недавнем обновлении по умолчанию experimental и opinionated выключены из
-enable=all
. В идеале eventually придём к более-менее нормальному default набору, но в качестве интеграции куда-то всё равно лучше явный список использовать.Уже в golangci-lint добавиться планируем, там есть интеграции в том числе с редакторами. В gometalinter, наверное, тоже можно. Для проекта эти интеграции важны, согласен полностью.
В Лондоне, кстати, совсем скоро будет workshop:
https://www.meetup.com/Go-London-User-Group/events/251046966/
Организует упомянутый в статье Daniel Martí.
В англоязычном слаке (https://gophers.slack.com) есть канал
contributor-workshop
, где он предложил нам разместиться при следующем проведении. Из плюсов: там очень много людей из "Go core team".Мне не известны ваши познания в этой теме, но в своих я не настолько уверен, чтобы про все векторные инструкции тут говорить обобщая. Есть специальные инструкции, которые не требуют выравнивания, причём в случае, если данные выровнены, они работают не хуже, чем формы, требующие выравнивания. В Go даже стек, насколько помню, не выровнен…
Можем закрыть эту тему?
Я не понимаю ваших мотивов и того, чего вы хотите.
Очевидно, мои ответы вам не помогают/не нравятся.
Издержки на него можно сократить, если Go работает быстрее.
Сделать Go быстрее для всех, без надобности учить людей писать более быстрый код можно с помощью ускорения рантайма и улучшения компилятора (например, научить его использовать дополнительные регистры для уменьшения количества spill'ов, правда это немного надуманный пример).
Хуже от того, что Go будет становиться более быстрым и/или потреблять меньше памяти, никому не будет.
VADDPD
привёл для подчёркивания того, что старый код будет собираться по-старому, с VEX префиксом. В редких ситуациях EVEX префикс мог бы дать небольшой выигрыш в размере машинного кода за счёт compressed displacement, но для более детерменированного поведения и в том числе для обратной совместимости, выбрана цитируемая вами схема. Плюс тем, кто «без словаря» не помнит всех нюансов, спокойнее (например мне).AVX-512 и EVEX может появляться только в новом коде, когда программист сознательно запросил данное поведение (использовал новые регистры или суффиксы опкода).
Способа «переопределить» поведение нет. То есть нельзя попросить тот
VADDPD
кодировать по схеме AVX-512.У Go тулчейна есть задача быть максимально независимым от других утилит, в частности внешних ассемблеров.
Тем более если кому-то векторизация не нужна, он о ней не задумывается.
А в рантайме Go, может быть, даже применение найдётся.
Я сейчас не обязательно про новые «модные» инструкции и 512-битные регистры, к которым у многих есть своё отношение, а про приятные дополнения к предыдущим AVX. Насколько мне известно, положительные эксперименты как минимум в пакетах крипты уже были.
Я не пытаюсь вас переубедить. Просто предоставляю контекст, который может быть полезен и, возможно, ускользнул от вас.
Нет, их мало и они не совсем веб-разработчики. То, что они делают, потом используют в том числе веб-разработчики.
Ещё одним «пользователем» ассемблера является сам тулчейн.
Можете пробежаться по статье Архитектура ассемблера Go. Разница лишь в том, что нет этапа парсинга.
Ассемблер в Go — одно из промежуточных представлений компилятора (низкоуровневый IR).
Если через 10 лет везде будет AVX-512, то, возможно, вместо 16 векторных регистров он будет использовать 32 (в них float'ы хранятся). Либо у нас будет что-то типа вот этого: GOAMD64 architecture flag и получить преимущества EVEX префикса можно будет значительно раньше.
quasilyte.github.io/blog/post/go-asm-complementary-reference
Стараюсь все интересности туда по мере обнаружения (и добавления) дописывать.
Как будет готов AVX512, впишу туда детали (ссылка на обсуждения там приведена).
Я эту часть упустил в ветке.
Мой ответ тогда лучше воспринимать как субъективное мнение, не сильно привязанное ко всем вашим высказываниям.
Даже интересная работа под конец дня может вызвать желание переключиться (обычно это гораздо чаще одного раза в день происходит, просто 18 часов выглядят отметкой, которая удобна для переключения). Это нормально.
И вообще, тут виновато расписание «с 9 до 18».
Вводим понятие «важен результат, а не уйти в 18», но при этом есть чёткий график.
Я могу и в 16, условно, уже на сегодня всё сделать, а оставшиеся часы планировать дальнейшие дни и недели, и тут вполне удобно оторваться от рабочего компьютера ровно по расписанию. Это тоже часть работы, но задерживаться ради неё смысла нет.
А ещё у человека может быть депрессия и ему хочется поскорее домой, потому что он не ищет компании.
Меня очень расстраивает, когда весь коллектив задерживается а тех, кто уходит вовремя (и приходит вовремя), порицают.
Расписываюсь, что в курсе холиварности этой темы. Тут куча простора для недопонимания и альтернативных точек зрения.
[Картинка «This is fine», всё в огне]
Спасибо.
По мне так наоборот, пусть живёт и процветает.
Первый CL из этой серии уже улетел на go-review.
Возможно в Go 1.11 будет новый x86.csv. И ещё кое-что полезное…
Очень любопытно стало, а вам свойственно доводить хобби проекты «до конца»?
Ваш опыт может отличаться, но по моим наблюдениям в какой-то момент основной интерес и элегантность проекта улетучивается и чтобы продолжать нужно больше сил, чем при старте.
Большое количество покинутых проектов меня сильно демотивирует.
В крайних случаях может сопутствовать выгоранию.
Про спекулятивную девиртуализацию поищу.
Anyway, в Go можно явно сказать: «Тут мне полиморфный тип, а тут просто структру T».
В C++ же полиморфность является свойством самого типа T. Right?
Go build и то, что близ него — это довольно низкоуровневые вещи.
Мне не очевидно, насколько github.com/constabulary/gb юзабелен, но скорее всего со временем появится хороший project-based тул, который станет тем самым pip для Go.
В случае Go сам тип T, реализующий интерфейсы, таблицы виртаульных методов не содержит никогда, поэтому когда мы не используем полиморфное поведение, не будет лишнего жира. Когда T передаётся как интерфейсный тип, вот там уже будет боксинг с аллокацией.
Насколько это хорошо или плохо — не хочу полемизировать, но подчеркнуть, что это не «Как в C++», всё-таки захотелось.