Владимир, как обычно, топ-темы рассматриваешь. Очень хочется увидеть и поработать с такими необычными темами и на твоем курсе по concurreny в go. За данный видос огромный респект!
Очень известная штука в профессиональных c++ кругах. Если вместо sequential consistency бахнуть acquire-release семантику, вы ускорите ещё раза в 3-4) Но в го отказались от такого для простоты (см. go memory model). Очень подойдёт тем, кто занимается разработкой чего-то низкоуровнего, я сам был в шоке когда увидел в первый раз такие оптимизации)
Так выравнивание получается как бы "растягивает" счётчик на какое-то кол-во байт, хотя по факту их не использует, чтоб другой счётчик гарантировано попал в другую кэш линию ?
А если у нас куча других задач помимо счетчика, ? Могу быть не прав, но это звучит так как будто в вакууме это финт ушами уровня магистра, но если взять реальный сервис, который, условно, съедает 70% ресурсов машины, ? Или еще лучше рассмотреть ситуацию , когда запросов настолько много, что условный сервис должен ?
Это решение будет ускорять в 10 раз и при наличии другой работы в коде? Помимо инкрементирования счетчика, приложение делает ещё что-то и переменные тоже могут попадать в кэш. Возможно не очень понял, но мы как будто затрем весь кэш при инкрементироварии счётчика таким способом и это замедлит код вокруг
Это если счётчик будет разбит на 1024 shard'а для 64K cache'а L1 или на 4096 shard'а для 256К. Пока на shard'ы тратится малый процент cache'а, такой опасности нет.
Спасибо! Правда нет комментария, почему переход на атомики дал прирост в два раза. Просто потому что мьютексы медленнее атомиков? И по итогу нужно ли проводить шардирование для такой оптимизации, или достаточно просто выравнивания?
Какие вы ресурсы изучали чтобы знать тонкости всего процессора и библиотек языка? Вы настолько детально все изучили, что как будто бы вы с другой планеты) Было очень интересно!
А какие минусы у такой оптимизации? Получается, что мы резервируем себе участок памяти кэша в котором полезных данных 4 байта, а всё остальное не используется никак? Как будто это оптимизация будет сильно отъедать память, когда количество горутин будет значительно больше, чем число ядер, и тогда относительно не быстрая зашаренные данные, будут эффективнее по памяти, но медленнее исполняться. Вопрос какой баланс в итоге лучший, всегда по ситуации?
Нуу, 64 байта это очень немного. L1 кеш на большинстве современных процессоров имеет объем 32kb, соответственно туда поместится 512 таких переменных на одно ядро, но насолько я понимаю при работе в одном потоке процессор не будет загружать в себя данные всех переменных, хотя это под вопросом. Я думаю если протестировать данный лайфхак на большом количестве корутин, то получится что он все равно будет значительно быстрее, чем без этого приема. Хотя не уверен, надо бы протестировать.
Я так понял у Вас intel. Вот не могу, сколько не пробую, на M1 хак повторить, максимальной производительности добиваюсь при атомиках и дальше никак. Не получилось нагуглить как с кэш линией работает М1 Pro. Если у кого-то есть инфа, буду благодарен, потому что интересно повторить выравнивание на своем компе.
В самом начале у нас вроде как у каждого ядра свой кэш, а после последней версии у всех ядер один кэш(-линия)? Или это разные кэши? В целом прикольная оптимизации, но насколько понял, ее эффективность зависит от конкретной архитектуры/модели процоессора, т.е. где-то можно не сработать. Хотя, если дело доходит до такой низкоуровневой ерунды, то наверное заранее известно, на каких процессорах будет запускаться код в проде )
добрый вечер, а есть ли публичный репозиторий с примером данного кода для более внимательного изучения? в записанном видео быстрое перемещение по коду и тем речи высокий, не всегда удобно для моментального восприятия
Как ты вообще додумался до этого? Мозг капитальный. Постфактум, конечно, кажется очевидным, но изначально к этой мысли бы никогда в жизни не пришел самостоятельно
Забавно, возможно я что-то делаю ни так, но у меня все варианты не сильно друг от друга отличаются по производительности: BenchmarkAtomicCounter-10 10 1538 ns/op BenchmarkMutexCounter-10 10 412.5 ns/op BenchmarkRWMutexCounter-10 10 658.3 ns/op BenchmarkShardedAtomicCounter-10 10 570.9 ns/op BenchmarkAtomicCounterOptimize-10 10 775.0 ns/op
я тоже попробовал проделать всё тоже самое. ShardedAtomic c alignment не сильно ушёл от Atomic и ShardedAtomic. 349.7 ns/op, 455.7 ns/op, 385.9 ns/op соответственно.
Присоединяйтесь к моему каналу в Телеграм: t.me/vladimir_balun_programming
Данная логика с оптимизацией хорошо рассписана в книжке «100 ошибок Go и как их избежать» в последней главе.
Спасибо, я не дочитал
Ну брат ну ты даёшь это всё очень круто. Думаю всем будет уроком немножко процессор и память изучить.
Спасибо!
Крайне интересная информация, спасибо! Коротко и очень необычно) Спасибо!
Спасибо!
Владимир, как обычно, топ-темы рассматриваешь. Очень хочется увидеть и поработать с такими необычными темами и на твоем курсе по concurreny в go. За данный видос огромный респект!
Спасибо, курс как раз будет 2 мая - там в том числе и это разбирается)
Вова, ты крут, очень понравилась данная рубрика, спасибо!)
Спасибо!
Супер! Респект и удачи тебе!
Спасибо!
Млин, Вов, как всегда - огонь!!!
Спасибо!
Приятненько. Это похоже как и на порядок полей в структурах
Да, Балун реально шарит, мощь. Нетривиальный ролик. И классный пример того как понимание подкапотной работы помогает реально оптимизировать код...
Круто! Вы фокусник! ))
Спасибо за крутой лайфхак! Полезно 😊
Спасибо!
Очень интересно! спасибо
Спасибо!
Очень круто, спасибо
Спасибо, очень интересное видео!
Спасибо!
Пушка. Наконец-то я понял зачем нужно знать устройство памяти и всего прочего, прям конкретный кейс, спасибо)
Нужно не всегда, но иногда эти знания бывают очень полезными)
чудеса на виражах прям какие-то)
Магия)
Очень известная штука в профессиональных c++ кругах. Если вместо sequential consistency бахнуть acquire-release семантику, вы ускорите ещё раза в 3-4) Но в го отказались от такого для простоты (см. go memory model).
Очень подойдёт тем, кто занимается разработкой чего-то низкоуровнего, я сам был в шоке когда увидел в первый раз такие оптимизации)
alignment это выравнивание , offset смещение)
годный контент
Все так)
Если уж придираться к неймингу, то такой заполнитель обычно называют padding.
это называется wet blanket) а если серьезно, то везде используется именно field alignment. учите матчасть!)
Выравниванием мы увеличиваем размер счетчика чтобы он не влезал в одну линию шарда? А если таких счетчиков множество на памяти же отразится?
На превьюшку поставить:
_ [60]byte
↖
Это увеличит скорость кода в 10 раз
почему цикл не в самом начале функции benchmark?
for j := 0; j < b.N; j++ {
Прикольно ) Красавчик! ;)
Так выравнивание получается как бы "растягивает" счётчик на какое-то кол-во байт, хотя по факту их не использует, чтоб другой счётчик гарантировано попал в другую кэш линию ?
Осталось только коммент в коде написать, чтобы другой программист не грохнул неиспользуемую память)
Хорошее замечание)
так регресс и появляется
А если у нас куча других задач помимо счетчика, ? Могу быть не прав, но это звучит так как будто в вакууме это финт ушами уровня магистра, но если взять реальный сервис, который, условно, съедает 70% ресурсов машины, ? Или еще лучше рассмотреть ситуацию , когда запросов настолько много, что условный сервис должен ?
Это решение будет ускорять в 10 раз и при наличии другой работы в коде? Помимо инкрементирования счетчика, приложение делает ещё что-то и переменные тоже могут попадать в кэш. Возможно не очень понял, но мы как будто затрем весь кэш при инкрементироварии счётчика таким способом и это замедлит код вокруг
Это если счётчик будет разбит на 1024 shard'а для 64K cache'а L1 или на 4096 shard'а для 256К.
Пока на shard'ы тратится малый процент cache'а, такой опасности нет.
Спасибо! Правда нет комментария, почему переход на атомики дал прирост в два раза. Просто потому что мьютексы медленнее атомиков? И по итогу нужно ли проводить шардирование для такой оптимизации, или достаточно просто выравнивания?
Желательно выравнивать к длине кешлинии архитектуры на которой запускается код, иначе оптимизации не будет, т.к значения будут затирать друг друга.
Какие вы ресурсы изучали чтобы знать тонкости всего процессора и библиотек языка? Вы настолько детально все изучили, что как будто бы вы с другой планеты) Было очень интересно!
Я не знаю очень много всего все еще - а то, что знаю, просто последовательный путь изучения тем, которые постепенно друг с другом переплетаются)
ШИКАААРРРРРРНООО!!! брат давай такие видео по всем темам и ты ТОП! такой шикраный контент и на русском
Круто! Не думал попробовать решить 1 billion row challenge на golang?
А какие минусы у такой оптимизации? Получается, что мы резервируем себе участок памяти кэша в котором полезных данных 4 байта, а всё остальное не используется никак? Как будто это оптимизация будет сильно отъедать память, когда количество горутин будет значительно больше, чем число ядер, и тогда относительно не быстрая зашаренные данные, будут эффективнее по памяти, но медленнее исполняться. Вопрос какой баланс в итоге лучший, всегда по ситуации?
Нуу, 64 байта это очень немного. L1 кеш на большинстве современных процессоров имеет объем 32kb, соответственно туда поместится 512 таких переменных на одно ядро, но насолько я понимаю при работе в одном потоке процессор не будет загружать в себя данные всех переменных, хотя это под вопросом. Я думаю если протестировать данный лайфхак на большом количестве корутин, то получится что он все равно будет значительно быстрее, чем без этого приема. Хотя не уверен, надо бы протестировать.
Привет. Не подскажешь какой у тебя доп. монитор стоит?
Можно исходники?
Я так понял у Вас intel. Вот не могу, сколько не пробую, на M1 хак повторить, максимальной производительности добиваюсь при атомиках и дальше никак.
Не получилось нагуглить как с кэш линией работает М1 Pro. Если у кого-то есть инфа, буду благодарен, потому что интересно повторить выравнивание на своем компе.
Ты, наверно, просто тест с атомиками запускал. А надо шардированный тест со смещением структуры AtomicCounter
В самом начале у нас вроде как у каждого ядра свой кэш, а после последней версии у всех ядер один кэш(-линия)? Или это разные кэши?
В целом прикольная оптимизации, но насколько понял, ее эффективность зависит от конкретной архитектуры/модели процоессора, т.е. где-то можно не сработать. Хотя, если дело доходит до такой низкоуровневой ерунды, то наверное заранее известно, на каких процессорах будет запускаться код в проде )
добрый вечер, а есть ли публичный репозиторий с примером данного кода для более внимательного изучения? в записанном видео быстрое перемещение по коду и тем речи высокий, не всегда удобно для моментального восприятия
Есть курс по concurrency МФТИ , можешь посмотреть его , там 20+ часов :)
@@КонстантинСердюк-ь5ю а ссыль можно, пожалуйста?
ниче не понятно, но очень интересно
Попробуйте почитать мой большой комментарий-ответ другому собеседнику ниже про 64-байтные блоки адресного пространства.
Возможно, что-то прояснится.
Подскажите , а на плюсах такие проблемы возникают?
Это актуально для всех языков, так как проблема завязана на принципах работы cpu
@@dmikoss плюсую)
Жаль что go не оптимизирует это сам на этапе компиляции
Коротко о том как увеличить использование памяти приложения в 16 раз )
@@doingwell5629 я имел ввиду в структуре 🙂
@@НиколайВикторович-х3г это почти всегда компромисс - что-то получаем, чем-то жертвуя при этом
Как ты вообще додумался до этого? Мозг капитальный. Постфактум, конечно, кажется очевидным, но изначально к этой мысли бы никогда в жизни не пришел самостоятельно
Цыганские фокусы
зачем мьютекс на чтение? Какаю то ересь прочитать невозможно, либо текущее значение, либо текущее + 1
Забавно, возможно я что-то делаю ни так, но у меня все варианты не сильно друг от друга отличаются по производительности:
BenchmarkAtomicCounter-10 10 1538 ns/op
BenchmarkMutexCounter-10 10 412.5 ns/op
BenchmarkRWMutexCounter-10 10 658.3 ns/op
BenchmarkShardedAtomicCounter-10 10 570.9 ns/op
BenchmarkAtomicCounterOptimize-10 10 775.0 ns/op
я тоже попробовал проделать всё тоже самое. ShardedAtomic c alignment не сильно ушёл от Atomic и ShardedAtomic. 349.7 ns/op, 455.7 ns/op, 385.9 ns/op соответственно.
А может различаются размеры этих кэш-линий на разных процах? Но это я просто предположил, если так то смысла мало от этой оптимизации