ARM, который мы заслужили
Когда люди только в последнее десятилетие смотрели на SIMD x86_64, параллельно развивался AArch64, на который очень мало обращали внимания. Сейчас обращают больше и хочется рассказать одну историю, о которой редко говорят. И вообще, про ARM никто не пишет, надо исправляться!
У AArch64 намного более серьёзный instruction set, когда дело доходит до conditional moves. В x86_64 есть
И в целом всё, есть только cmov. А вот в AArch64 аналогом является
oper может быть равно eq, ne и так далее. То есть csel if equal, csel if not equal и так далее.
Но помимо conditional select есть ещё многие другие, такие как conditional select increase/inverse/negate:
Но по мне самая недооцененная иструкция это conditional compare, дада, выглядит оно так
То есть можно манипулировать флагами сравнений после cmp через и таким образом проносить флаги дальше. Скажем, чтобы сравнить 16 байт между собой можно сделать
Такой трюк можно использовать, чтобы проносить результаты сравнений. Учитывая то, что ccmp занимает 1 цикл на Neoverse-n1 как и cmp, то это помогает сравнивать регионы памяти с тем же ptest/movmask на x86.
Вообще одно из самых сложных отличий SIMD x86 и ARM Neon заключается в movemask инструкции. Если коротко, для 16 байт оно забирает верхний бит каждого байта (если суффикс b) и обычно используется так
На Arm такой инструкции нет и эмулируется 3-4 инструкциями. Это огромная боль, когда ты хочешь мигрировать одно на другое, теряешь много перфа.
В итоге это один трюк как на AArch64 за примерно такое же количество циклов сравнивать регионы памяти.
Можете оценить сколько movemask используется в ClickHouse [2] -- дада, я сделал огромный issue, чтобы наконец-то починить все перформанс проблемы на AArch64.
В след раз расскажу ещё пару трюков, так как через movemask можно ещё находить первый несовпавший бит в коде выше через всякие count trailing zeros, и текущий трюк уже не работает.
Полезные ссылки.
[1] Этот трюк используется в memcmp в glibc
[2] Можете оценить сколько movemask используется в ClickHouse
[3] Оптимизации через csinc в Google Snappy
[4] Neoverse-N1 optimization guide
[5] Movemask на x86
[6] Как я чинил movemask на AArch64 в Vectorscan, который выдавал некорректные результаты
Когда люди только в последнее десятилетие смотрели на SIMD x86_64, параллельно развивался AArch64, на который очень мало обращали внимания. Сейчас обращают больше и хочется рассказать одну историю, о которой редко говорят. И вообще, про ARM никто не пишет, надо исправляться!
У AArch64 намного более серьёзный instruction set, когда дело доходит до conditional moves. В x86_64 есть
cmov, когда вы двигаете регистр в другой в зависимости от результатов предущего сравненияcmp %rax, %rcx
cmovzq $REG1, $REG2 # move reg1 into reg2 if flag ZF was set
И в целом всё, есть только cmov. А вот в AArch64 аналогом является
csel, conditional select.cmp $something1, $something2
csel $reg1, $reg2, $reg3, oper # reg1 = oper ? reg2 : reg3
oper может быть равно eq, ne и так далее. То есть csel if equal, csel if not equal и так далее.
Но помимо conditional select есть ещё многие другие, такие как conditional select increase/inverse/negate:
csinc $reg1, $reg2, $reg3, oper # reg1 = oper ? reg2 : (reg3 + 1)
csinv $reg1, $reg2, $reg3, oper # reg1 = oper ? reg2 : ~reg3
csneg $reg1, $reg2, $reg3, oper # reg1 = oper ? reg2 : -reg3
Но по мне самая недооцененная иструкция это conditional compare, дада, выглядит оно так
cmp $something1, $something2
ccmp $reg1, $reg2, $flags, oper # flags = oper ? (cmp $reg1, $reg) : $flags
То есть можно манипулировать флагами сравнений после cmp через и таким образом проносить флаги дальше. Скажем, чтобы сравнить 16 байт между собой можно сделать
ldp x3, x4, [src1] # load 8 byte into x3, load 8 byte into x4
ldp x5, x6, [src2] # load 8 byte into x5, load 8 byte into x6
cmp x3, x5 # compare x3 and x5
ccmp x4, x6, 0, eq # if eq, compare x4, x6, otherwise flags are 0
b.ne L_SOMEWHERE # if flags are zero, branch
Такой трюк можно использовать, чтобы проносить результаты сравнений. Учитывая то, что ccmp занимает 1 цикл на Neoverse-n1 как и cmp, то это помогает сравнивать регионы памяти с тем же ptest/movmask на x86.
Вообще одно из самых сложных отличий SIMD x86 и ARM Neon заключается в movemask инструкции. Если коротко, для 16 байт оно забирает верхний бит каждого байта (если суффикс b) и обычно используется так
pcmpeqb %xmm1, %xmm2 # compare 2 regions, those who are equal, set to 0xff, otherwise 0
pmovmskb %xmm2, %ecx # move high bits, those who are equal, set to 1
cmp %ecx, 0xffff # compare
jne L_SOMEWHERE # jump
На Arm такой инструкции нет и эмулируется 3-4 инструкциями. Это огромная боль, когда ты хочешь мигрировать одно на другое, теряешь много перфа.
В итоге это один трюк как на AArch64 за примерно такое же количество циклов сравнивать регионы памяти.
Можете оценить сколько movemask используется в ClickHouse [2] -- дада, я сделал огромный issue, чтобы наконец-то починить все перформанс проблемы на AArch64.
В след раз расскажу ещё пару трюков, так как через movemask можно ещё находить первый несовпавший бит в коде выше через всякие count trailing zeros, и текущий трюк уже не работает.
Полезные ссылки.
[1] Этот трюк используется в memcmp в glibc
[2] Можете оценить сколько movemask используется в ClickHouse
[3] Оптимизации через csinc в Google Snappy
[4] Neoverse-N1 optimization guide
[5] Movemask на x86
[6] Как я чинил movemask на AArch64 в Vectorscan, который выдавал некорректные результаты
GitHub
[Umbrella] Make ClickHouse great on AArch64 · Issue #37005 · ClickHouse/ClickHouse
Objective Improve performance of ClickHouse for AArch64 and share the knowledge on how to do that. Plan This is list of what can be done to improve performance for AArch64. Contrib/third_party libr...
👍50🔥23
Пост, на этот раз про распределённые системы. Я не хочу делать вид, что занимаюсь только низкоуровневыми вещами, тем более на работе я занимаюсь распределёнными системами full time, а вот это всё мои хобби сверху (почти :-)).
В MapReduce/Spark часто возникают проблемы stragglers. Когда какая-то машина тупит, и дальше становится непонятно, что происходит:
1. Попался кусок данных, который невозможно долго процессится? Банальный пример: обрабатываете youtube id и встретилось 10 часовое видео
2. Это Shuffle/Reduce операция, где есть так называемые hot keys? То есть есть ключ, у которого большая порция всего, когда вы делаете Group By операции?
3. А может быть просто машина тупит?
4. А может быть данные перекошены и хоть и нет никакой записи, которая долго выполняется, а шард долго работает?
В общем, практика показывает, что самые частые проблемы возникают в пунктах 2 и 3. Пункт 2 можно детектить алгоритмически, а вот понять пункт 3 уже становится очень сложно, потому что неясно, имеет ли это что-то общее с п 1 или 4.
Придумали решение с так называемыми backups, или по-другому их называют, speculative execution: давайте если какой-то кусок работы тупит, мы сделаем копию и запроцессим два одинаковых куска данных, посмотрим, кто первый закончит.
Обычно это помогает с п.3 и достаточно хорошо работает.
Какие бывают стратегии?
Quantile backup или End-game-backup
Дана квантиль X, мы сделаем две реплики всех после процессинга всех X шардов. Скажем, если X=0.75 (дефолт у Spark), то после 75% всех выполненных шардов, мы оставшихся 25% всех самых медленных задуплицируем.
Skewed backup
Дано число X > 1, мы запускаем backup у тех, кто работает в X раз дольше медианного времени. Дефолт у Spark 1.5.
Min threshold
Чтобы применить что-то выше, нужно подождать ещё какое-то время и убедиться, что действительно надо запускать. Скажем, одну минуту подождать, чтобы запустить skewed backup или end-game backup. В spark этого нет вообще.
Тут вот LinkedIn в своём докладе про Speculative Execution в Spark написал, что правильная policy включения backups принесла им 13-40% меньше времени выполнения и даже сэкономила ресурсы. То, что они поняли:
* Дефолтные значения агрессивны. End-game backup решили включать на 90%, а не на 75% (если честно, моя интуиция тоже так говорит)
* Skewed backup. X = 1.5 тоже было агрессивным. Они поставили 4. По мне многовато, мой опыт говорит в районе 2.5-3 обычно бывает оптимально. Зависит от пайплайна и достаточно легко выучивается по истории.
* Min threshold важен. Мелкие джобы слишком много плодили различных workers и кластер превращался в мусор. Заимплементировали в spark, чтобы подождать 30 секунд для включения skewed/end-game backups
* Сильно улучшили variance, spark/mapreduce всегда страдал от погоды на кластере, тут получше получается, понятно почему, утилизируется кластер намного лучше.
* Даже RAM+CPU уменьшилось (хотя казалось бы, мы включаем доп работу), скорее всего из-за простоя
В общем, backup execution, hedged requests, также как и power of two choices балансировка сильно экономит вам перформанса, если правильно сварить. По мне, некоторые вещи можно выучивать исторически, смотреть как кластер себя ведёт и тд, но то, как обучать перформанс повторяющихся джобов, мы поговорим отдельно.
Распределенные системы такие, да. Speculative execution очень приятно писать в коде, кстати, по себе знаю :) И очень тяжело дебагать, если что-то пошло не так (true story, зафакапили десяток пайплайнов).
В MapReduce/Spark часто возникают проблемы stragglers. Когда какая-то машина тупит, и дальше становится непонятно, что происходит:
1. Попался кусок данных, который невозможно долго процессится? Банальный пример: обрабатываете youtube id и встретилось 10 часовое видео
2. Это Shuffle/Reduce операция, где есть так называемые hot keys? То есть есть ключ, у которого большая порция всего, когда вы делаете Group By операции?
3. А может быть просто машина тупит?
4. А может быть данные перекошены и хоть и нет никакой записи, которая долго выполняется, а шард долго работает?
В общем, практика показывает, что самые частые проблемы возникают в пунктах 2 и 3. Пункт 2 можно детектить алгоритмически, а вот понять пункт 3 уже становится очень сложно, потому что неясно, имеет ли это что-то общее с п 1 или 4.
Придумали решение с так называемыми backups, или по-другому их называют, speculative execution: давайте если какой-то кусок работы тупит, мы сделаем копию и запроцессим два одинаковых куска данных, посмотрим, кто первый закончит.
Обычно это помогает с п.3 и достаточно хорошо работает.
Какие бывают стратегии?
Quantile backup или End-game-backup
Дана квантиль X, мы сделаем две реплики всех после процессинга всех X шардов. Скажем, если X=0.75 (дефолт у Spark), то после 75% всех выполненных шардов, мы оставшихся 25% всех самых медленных задуплицируем.
Skewed backup
Дано число X > 1, мы запускаем backup у тех, кто работает в X раз дольше медианного времени. Дефолт у Spark 1.5.
Min threshold
Чтобы применить что-то выше, нужно подождать ещё какое-то время и убедиться, что действительно надо запускать. Скажем, одну минуту подождать, чтобы запустить skewed backup или end-game backup. В spark этого нет вообще.
Тут вот LinkedIn в своём докладе про Speculative Execution в Spark написал, что правильная policy включения backups принесла им 13-40% меньше времени выполнения и даже сэкономила ресурсы. То, что они поняли:
* Дефолтные значения агрессивны. End-game backup решили включать на 90%, а не на 75% (если честно, моя интуиция тоже так говорит)
* Skewed backup. X = 1.5 тоже было агрессивным. Они поставили 4. По мне многовато, мой опыт говорит в районе 2.5-3 обычно бывает оптимально. Зависит от пайплайна и достаточно легко выучивается по истории.
* Min threshold важен. Мелкие джобы слишком много плодили различных workers и кластер превращался в мусор. Заимплементировали в spark, чтобы подождать 30 секунд для включения skewed/end-game backups
* Сильно улучшили variance, spark/mapreduce всегда страдал от погоды на кластере, тут получше получается, понятно почему, утилизируется кластер намного лучше.
* Даже RAM+CPU уменьшилось (хотя казалось бы, мы включаем доп работу), скорее всего из-за простоя
В общем, backup execution, hedged requests, также как и power of two choices балансировка сильно экономит вам перформанса, если правильно сварить. По мне, некоторые вещи можно выучивать исторически, смотреть как кластер себя ведёт и тд, но то, как обучать перформанс повторяющихся джобов, мы поговорим отдельно.
Распределенные системы такие, да. Speculative execution очень приятно писать в коде, кстати, по себе знаю :) И очень тяжело дебагать, если что-то пошло не так (true story, зафакапили десяток пайплайнов).
YouTube
Databricks
Databricks is the Data and AI company. More than 15,000 organizations worldwide — including Block, Comcast, Conde Nast, Rivian, and Shell, and over 60% of the Fortune 500 — rely on the Databricks Data Intelligence Platform to take control of their data and…
👍68🔥6❤2
Testing on the Toilet
До года так 2005 в Google не было принято писать тесты. Компания переживала бурный рост, а хоть туда уже приходили лучшие инженеры, на тесты как-то время не хватало. Некоторые из разработчиков были недовольны таким положением вещей, и родилась какая-то абсолютно гениальная идея, с которой все единогласно согласились, и надо было лишь правильно ее исполнить.
Testing on the Toilet (TotT) -- одностраничные листовки, расклеенные в туалетных кабинках офисов Google и дающие разработчикам советы о том, как лучше тестировать их код, -- это наш, можно сказать, институт, на котором держится Google. Они упоминались в Washington Post, New York Times и единогласно были высмеяны и признаны воплощением культуры Гугла.
Как и почти все вещи в Google, TotT возник в результате попытки решить одну конкретную проблему. Код стало невозможно писать из-за слишком большого количества багов. В середине 2005 года была создана группа Unittest, чтобы обучать разработчиков, как тестировать свой код. В то время написание тестов не было прям уж нормой в Google. Члены группы начали писать Codelabs (лабораторные пошаговые работы), организовывать Fixit weeks (когда все в команде чинят flaky тесты) и проводить еженедельные лекции для Noogler (New Googler) о том, как важно писать тесты.
Как я бы сказал по-английски: "This trained the Nooglers". А что делать с теми, кого уже наняли? Во время митинга в конце марта 2006 г. один из директоров предложил идею о расклеивании листовок в публичных местах. А куда все ходят точно хотя бы раз в день? Столовые и туалеты. Кафе не были хорошим решением, так как фокус всегда был смещен на еду и общение. Остаются уборные. Что ж. Кто-то посмеялся, но никто не задал вопроса, а нужно ли это делать. В итоге это вошло в OKR, и листовки стали появляться во всех туалетах офисов Google.
Один из инженеров написал первый эпизод: "Better stubbing in Python". Его наклеили везде в офисах Долины и Лондона. Кто-то подхватил и рассказал об этом всем сокомандникам, пошло сарафанное радио. Это было необычно, и все согласились, что это может решить их проблему. TotT распространялся с немыслимой быстротой.
Ana Ulin стала лидером этой программы, когда она добровольна взяла ответственность за вычитку и качество материала. Так идея была подхвачена, на неё нашлись правильные и нужные люди. Это ещё одна часть культуры Google -- если ты что-то делаешь и делаешь это хорошо, ты теперь за это ответственен. Те, кто обожал тестирование, писали свои методы как писать правильные тесты на С++, как работать с Unicode. Абсолютно все офисы стали подхватывать это, и даже в планировки новой постройки стали рисовать места, где будут наклеивать эти листовки.
Со временем многие авторы начали писать свой контент (в том числе появились разделения на Tips of the Week, которые появлялись в блогах), и люди прислушивались к советам. Начались обсуждения, бесконечные дебаты, появились арбитры, но самое главное -- были сообщения о положительных результатах, что теперь кто-то научился правильно писать на Python или смог обойти баг с памятью в C++. Рекламировались и внедрялись новые инструменты и методы. Качество, скейл рос. Люди стали цитировать в код ревью эпизоды, люди доверяли этому источнику. Пусть решения не были идеальными, но все смогли о чём-то договориться.
TotT явно оказал сильное положительное влияние на инженерные практики. Ничего так не сработало как этот изначальный толчок -- необычно, мило, воодушевляюще, а главное, очень полезно.
Несмотря на все изменения, уже сколько раз поменявшихся лидеров программы, TotT уже 17 лет выпускает эпизоды. Появились отдельный культы и программы, которые пишутся для всех технологий. К сожалению, всё не повесишь в туалетах, а некоторые стали невозможными для публичных глаз :)
Google совершенно случайно нашёл решение, как продвигать практики, писать лучше код. Кто бы мог подумать, что можно сказать, что какая-то часть культуры Google стала богаче и сильнее из-за каких-то там туалетов.
Больше и первые эпизоды здесь:
https://mike-bland.com/2011/10/25/testing-on-the-toilet.html
До года так 2005 в Google не было принято писать тесты. Компания переживала бурный рост, а хоть туда уже приходили лучшие инженеры, на тесты как-то время не хватало. Некоторые из разработчиков были недовольны таким положением вещей, и родилась какая-то абсолютно гениальная идея, с которой все единогласно согласились, и надо было лишь правильно ее исполнить.
Testing on the Toilet (TotT) -- одностраничные листовки, расклеенные в туалетных кабинках офисов Google и дающие разработчикам советы о том, как лучше тестировать их код, -- это наш, можно сказать, институт, на котором держится Google. Они упоминались в Washington Post, New York Times и единогласно были высмеяны и признаны воплощением культуры Гугла.
Как и почти все вещи в Google, TotT возник в результате попытки решить одну конкретную проблему. Код стало невозможно писать из-за слишком большого количества багов. В середине 2005 года была создана группа Unittest, чтобы обучать разработчиков, как тестировать свой код. В то время написание тестов не было прям уж нормой в Google. Члены группы начали писать Codelabs (лабораторные пошаговые работы), организовывать Fixit weeks (когда все в команде чинят flaky тесты) и проводить еженедельные лекции для Noogler (New Googler) о том, как важно писать тесты.
Как я бы сказал по-английски: "This trained the Nooglers". А что делать с теми, кого уже наняли? Во время митинга в конце марта 2006 г. один из директоров предложил идею о расклеивании листовок в публичных местах. А куда все ходят точно хотя бы раз в день? Столовые и туалеты. Кафе не были хорошим решением, так как фокус всегда был смещен на еду и общение. Остаются уборные. Что ж. Кто-то посмеялся, но никто не задал вопроса, а нужно ли это делать. В итоге это вошло в OKR, и листовки стали появляться во всех туалетах офисов Google.
Один из инженеров написал первый эпизод: "Better stubbing in Python". Его наклеили везде в офисах Долины и Лондона. Кто-то подхватил и рассказал об этом всем сокомандникам, пошло сарафанное радио. Это было необычно, и все согласились, что это может решить их проблему. TotT распространялся с немыслимой быстротой.
Ana Ulin стала лидером этой программы, когда она добровольна взяла ответственность за вычитку и качество материала. Так идея была подхвачена, на неё нашлись правильные и нужные люди. Это ещё одна часть культуры Google -- если ты что-то делаешь и делаешь это хорошо, ты теперь за это ответственен. Те, кто обожал тестирование, писали свои методы как писать правильные тесты на С++, как работать с Unicode. Абсолютно все офисы стали подхватывать это, и даже в планировки новой постройки стали рисовать места, где будут наклеивать эти листовки.
Со временем многие авторы начали писать свой контент (в том числе появились разделения на Tips of the Week, которые появлялись в блогах), и люди прислушивались к советам. Начались обсуждения, бесконечные дебаты, появились арбитры, но самое главное -- были сообщения о положительных результатах, что теперь кто-то научился правильно писать на Python или смог обойти баг с памятью в C++. Рекламировались и внедрялись новые инструменты и методы. Качество, скейл рос. Люди стали цитировать в код ревью эпизоды, люди доверяли этому источнику. Пусть решения не были идеальными, но все смогли о чём-то договориться.
TotT явно оказал сильное положительное влияние на инженерные практики. Ничего так не сработало как этот изначальный толчок -- необычно, мило, воодушевляюще, а главное, очень полезно.
Несмотря на все изменения, уже сколько раз поменявшихся лидеров программы, TotT уже 17 лет выпускает эпизоды. Появились отдельный культы и программы, которые пишутся для всех технологий. К сожалению, всё не повесишь в туалетах, а некоторые стали невозможными для публичных глаз :)
Google совершенно случайно нашёл решение, как продвигать практики, писать лучше код. Кто бы мог подумать, что можно сказать, что какая-то часть культуры Google стала богаче и сильнее из-за каких-то там туалетов.
Больше и первые эпизоды здесь:
https://mike-bland.com/2011/10/25/testing-on-the-toilet.html
Mike Bland
Testing on the Toilet - Mike Bland
The Testing Grouplet's weekly publication for spreading testing news and views throughout Google, in the most opportune of places
👍96💩73😁18❤16🔥14
Что-то я ничего не писал почти 2 недели. А в целом потому что никаких красивых историй не происходило, не хотелось читать статьи, а работать надо было по 60-70+ часов в неделю. Будем менять, но историю по перформансу я вам привёз, конечно же.
В Google вместо LZ4 мы используем в большинстве мест Snappy, очень похожий на LZ4 кодек, тоже формат вида двух операций
1. Скопировать байты (литералы в терминах LZ4)
2. Скопировать по оффсету те байты, что уже были разжаты (матчи в терминах LZ4)
Отличия Snappy от LZ4 в том, что есть байты теги, мол, инструкции, что надо делать (копировать байты или копировать по оффсету), когда как в LZ4 они чередуются.
LZ4 доказал со временем, что у него скорость разжатия получше, но легаси, все дела, вряд ли мы избавимся от Snappy даже за десять лет. Используется везде правда.
И код понятное дело очень приложенный. Я комитил много туда оптимизаций, мы нашли удивительную ещё одну.
Когда мы копируем байты по оффсету (в этом месте мы знаем, что, копирование происходит меньше чем на 64 байта, так как размер в теге инструкции всегда запакован в 6 битах), то у нас написан такой код
memmove на 64 идёт, потому что это четыре 16 байтных load/store и не вызывается дополнительной функции. Так делать можно, потому что аллоцируют чуть больше, чтобы записать после конца.
На самом деле в идеале код мог бы выглядеть как
А если ещё подумать и почитать кода, то memmove можно заменить на memcpy. Для 64 версии используется memmove, так как указатели могут друг на друга накладываться с размером 64, но не с размером len.
Мы решили посмотреть, какое раcпределение этих len, оказалось, что почти все под 32, большинство под 16 (вы тоже можете из открытых бенчмарков). А мы аж целых 64 копируем для худшего случая.
То есть нам примерно дано:
Well, мы попробовали
Мы получили смешанные результаты
Skylake: +3% on average
Cascade Lake: +2% on average
AMD Zen 2: +20% on average
AMD Zen 3: +25% on average
Neoverse N1 (ARM): +14% on average
Neoverse N2 (ARM): +11% on average
И дальше возникает интересный вопрос, что ж случилось. Я перепроверил и оказалось, что действительно AMD новых поколений разжимают медленнее, чем Intel старых, но сжимают зато быстрее и в целом считаются CPU так процентов на 20 побыстрее.
Каким-то чудом Intel научился понимать, что записи по кешлиниям с байта 32 по 64 очень редко или поздно используются, а вот AMD и ARMы так не научились.
Конечно же, никто нам не расскажет, что произошло. Но это самый большой гэп между Intel и AMD, который я когда либо видел. Увидеть 25% прирост на одном и только 2% на другом это прям удивляет.
И всё ещё удивительно, что тут есть оптимизации. На скейле это очень много денег.
Чем я ещё занимался?
ZSTD соптимизировал для ARMов (в том числе ваших макбуках) на 5%. Готовится огромная история, что произошло, потому что я выбил лучше перф процентов на 20 на Apple M1 по таким функциям как memcmp и так далее. Выбил +5% перфа для хэш таблиц Google Abseil. И кажется ещё дойду до SIMDJSON. Однозначный вывод сделал, ни в Apple, ни в ARM не сидят инженеры, которые понимают за software performance своей архитектуры. Либо я открыл какой-то ящик пандоры. Пока я валидирую у своих коллег, что я не сошёл с ума, пишу уже неделю блог. Какой-то sneak peek вариант смотрите в ZSTD. Да, снова ассемблер армов, потому что это красиво, мать вашу. Я нанял себе аниматора, потому что понял, что про SIMD надо рассказывать с картинками.
В Google вместо LZ4 мы используем в большинстве мест Snappy, очень похожий на LZ4 кодек, тоже формат вида двух операций
1. Скопировать байты (литералы в терминах LZ4)
2. Скопировать по оффсету те байты, что уже были разжаты (матчи в терминах LZ4)
Отличия Snappy от LZ4 в том, что есть байты теги, мол, инструкции, что надо делать (копировать байты или копировать по оффсету), когда как в LZ4 они чередуются.
LZ4 доказал со временем, что у него скорость разжатия получше, но легаси, все дела, вряд ли мы избавимся от Snappy даже за десять лет. Используется везде правда.
И код понятное дело очень приложенный. Я комитил много туда оптимизаций, мы нашли удивительную ещё одну.
Когда мы копируем байты по оффсету (в этом месте мы знаем, что, копирование происходит меньше чем на 64 байта, так как размер в теге инструкции всегда запакован в 6 битах), то у нас написан такой код
const void* from =
tag_type ? reinterpret_cast<void*>(op_base + delta) : old_ip;
memmove(op_base + op, from, 64);
ip += len;
memmove на 64 идёт, потому что это четыре 16 байтных load/store и не вызывается дополнительной функции. Так делать можно, потому что аллоцируют чуть больше, чтобы записать после конца.
На самом деле в идеале код мог бы выглядеть как
memmove(op_base + op, from, len);
А если ещё подумать и почитать кода, то memmove можно заменить на memcpy. Для 64 версии используется memmove, так как указатели могут друг на друга накладываться с размером 64, но не с размером len.
Мы решили посмотреть, какое раcпределение этих len, оказалось, что почти все под 32, большинство под 16 (вы тоже можете из открытых бенчмарков). А мы аж целых 64 копируем для худшего случая.
То есть нам примерно дано:
memcpy(dst, src, len);
len <= 64
len <= 32 в 99% случаях, len <= 16 в 95% случаях
[dst, dst + len) и [src, src + len) непересекающиеся, но если + 64, то могут
dst+64 валидный регион памяти
Well, мы попробовали
// Если len <= 32, это правильно.
memmove(dst, src, 32);
// Если len > 32, мы не перезаписали байты так как [dst, dst + 32) и [src, src + 32) не пересекаются.
if (UNLIKELY(len > 32)) {
memmove(dst + 32, static_cast<const uint8_t*>(src) + 32, 32);
}
Мы получили смешанные результаты
Skylake: +3% on average
Cascade Lake: +2% on average
AMD Zen 2: +20% on average
AMD Zen 3: +25% on average
Neoverse N1 (ARM): +14% on average
Neoverse N2 (ARM): +11% on average
И дальше возникает интересный вопрос, что ж случилось. Я перепроверил и оказалось, что действительно AMD новых поколений разжимают медленнее, чем Intel старых, но сжимают зато быстрее и в целом считаются CPU так процентов на 20 побыстрее.
Каким-то чудом Intel научился понимать, что записи по кешлиниям с байта 32 по 64 очень редко или поздно используются, а вот AMD и ARMы так не научились.
Конечно же, никто нам не расскажет, что произошло. Но это самый большой гэп между Intel и AMD, который я когда либо видел. Увидеть 25% прирост на одном и только 2% на другом это прям удивляет.
И всё ещё удивительно, что тут есть оптимизации. На скейле это очень много денег.
Чем я ещё занимался?
ZSTD соптимизировал для ARMов (в том числе ваших макбуках) на 5%. Готовится огромная история, что произошло, потому что я выбил лучше перф процентов на 20 на Apple M1 по таким функциям как memcmp и так далее. Выбил +5% перфа для хэш таблиц Google Abseil. И кажется ещё дойду до SIMDJSON. Однозначный вывод сделал, ни в Apple, ни в ARM не сидят инженеры, которые понимают за software performance своей архитектуры. Либо я открыл какой-то ящик пандоры. Пока я валидирую у своих коллег, что я не сошёл с ума, пишу уже неделю блог. Какой-то sneak peek вариант смотрите в ZSTD. Да, снова ассемблер армов, потому что это красиво, мать вашу. Я нанял себе аниматора, потому что понял, что про SIMD надо рассказывать с картинками.
GitHub
GitHub - google/snappy: A fast compressor/decompressor
A fast compressor/decompressor. Contribute to google/snappy development by creating an account on GitHub.
🔥111👍40❤3🤔3
Мы делаем llvm::libc, и тут есть забавная история. Достаточно понятно, что в libc самые используемые функции на проде это memcpy, memcmp, memmove, strlen и тд, те, которые работают с памятью, так как они встречаются в векторах/строках и тд. Я сотню раз видел посты, где люди ускоряли эти функции для больших значений, мол, смотрите, мой memcmp работает быстрее на сотню мегабайт в секунду или поиск символа на пару десятков.
К сожалению, в реальности никто не сравнивает большие отрезки массивов, так редко бывает, соответственно ускорения от таких постов хайп, нежели реально помогает (в чем нет ничего плохого, идеи бывают хорошие).
Мы решили опубликовать распределения разных workload'ов у таких функций. Посмотреть их можно здесь. Но если проанализировать в среднем, до 128 байт где-то 99% вызовов, остальное очень редкое. Учитывая это, для оптимального перформанса таких функций, лучше уметь в Profile Guided Optimization, который понимает, что можно во многих местах кода инлайнить маленькие отрезки. Отчасти поэтому мы в Google и решили делать libc со статической линковкой, потому что динамика не позволяет проворачивать пост компиляторные оптимизации. А все SIMD развороты циклов намного меньше решают.
Такой эффект в перформансе мы называем оверфитом, скажем, вы пишете две реализации, одна берет значения из таблички, другая нет, из таблички на бенчмарках будет работать быстрее из-за кешей. А далее важно себе ответить на вопрос -- будет ли этот кеш постоянным
1. Если у вас поисковый шард -- это правда, кеш надо прогреть
2. Если у вас табличка для конвертации 2 байт в десятичное представление, ваша программа вряд ли только и конвертирует. Тру стори, ругался очень долго, что это плохо, но забил, так как там маленькая opportunity.
И в целом мой совет -- если вы видите какой-то бенчмарк, который зависит от данных, и ну уж очень важен, или вы хотите продемонстрировать, что что-то ускорили, имейте в виду и проверяйте несколько вещей:
1. Всякие табличные значения очень хорошо идут в кеш
2. Branch predictor очень хорошо обучается, какое распределение данных вы даёте функции/программе? Можете ли вы дать лучше/ближе к реальности?
Пример: поисковый шард, в запросах всегда есть тренды (иногда мимолётные, скажем, какое-то событие произошло), и вы никогда не знаете, может быть в этом шарде было настолько важные для тренда запросов документы, что запросы на другом шарде дают другой перф?
К сожалению, синтетические бенчмарки шардов никогда не давали точных ускорений, всегда надо было смотреть уже в проде. К счастью, разница была всегда небольшой. Пару раз ловили оверфит, когда оптимизации были именно для кеша шарда. После этого мы начали в поиске думать о том, что в синтетике мы никогда "не прогреем данные так как в проде".
Но это дало понимание, что никогда, ни в коем случае не делать региональные/факторные распределения документов по шардам в больших системах. Эта штука закончится неоднородными решениями в том числе из-за перфа. Региональные кеши -- ок, региональные last resort базы -- нет, спасибо. Как можно равномернее распределять лучше всего.
Другой пример:
В SimdJson очень много используются таблички. В бенчмарках они очень прогретые в L1 кешах. Интересно сколько перфа теряется, когда эти таблицы привносят кеш миссы. Это прекрасная идея для поста, чтобы так поубавить градус фразы "Парсим X гигабайт в секунду". Я ставлю минимум 5-10% теряется, что в целом, не велика потеря, но не даёт полной картины реального мира.
Поэтому в оптимизациях я люблю branch free code, потому что о бранчах в горячих местах порой сложно спекулировать.
Ещё вот в наших гугловских хэштаблицах есть бенчмарки с суффиксом _Hot/_Cold. К сожалению, померить распределение прогретости достаточно тяжело, но это хотя бы что-то, что помогает не оверфититься по кешам.
Как вариант посмотреть для SimdJson -- вытащить таблицы из глобальной памяти и поместить их в динамическую, сделать cold benchmark (создаются тысячи инстансов класса и десереализует случайный).
Мораль: не оверфитьте свои оптимизации под бенчмарк, это может плохо закончиться, думайте о данных тоже.
К сожалению, в реальности никто не сравнивает большие отрезки массивов, так редко бывает, соответственно ускорения от таких постов хайп, нежели реально помогает (в чем нет ничего плохого, идеи бывают хорошие).
Мы решили опубликовать распределения разных workload'ов у таких функций. Посмотреть их можно здесь. Но если проанализировать в среднем, до 128 байт где-то 99% вызовов, остальное очень редкое. Учитывая это, для оптимального перформанса таких функций, лучше уметь в Profile Guided Optimization, который понимает, что можно во многих местах кода инлайнить маленькие отрезки. Отчасти поэтому мы в Google и решили делать libc со статической линковкой, потому что динамика не позволяет проворачивать пост компиляторные оптимизации. А все SIMD развороты циклов намного меньше решают.
Такой эффект в перформансе мы называем оверфитом, скажем, вы пишете две реализации, одна берет значения из таблички, другая нет, из таблички на бенчмарках будет работать быстрее из-за кешей. А далее важно себе ответить на вопрос -- будет ли этот кеш постоянным
1. Если у вас поисковый шард -- это правда, кеш надо прогреть
2. Если у вас табличка для конвертации 2 байт в десятичное представление, ваша программа вряд ли только и конвертирует. Тру стори, ругался очень долго, что это плохо, но забил, так как там маленькая opportunity.
И в целом мой совет -- если вы видите какой-то бенчмарк, который зависит от данных, и ну уж очень важен, или вы хотите продемонстрировать, что что-то ускорили, имейте в виду и проверяйте несколько вещей:
1. Всякие табличные значения очень хорошо идут в кеш
2. Branch predictor очень хорошо обучается, какое распределение данных вы даёте функции/программе? Можете ли вы дать лучше/ближе к реальности?
Пример: поисковый шард, в запросах всегда есть тренды (иногда мимолётные, скажем, какое-то событие произошло), и вы никогда не знаете, может быть в этом шарде было настолько важные для тренда запросов документы, что запросы на другом шарде дают другой перф?
К сожалению, синтетические бенчмарки шардов никогда не давали точных ускорений, всегда надо было смотреть уже в проде. К счастью, разница была всегда небольшой. Пару раз ловили оверфит, когда оптимизации были именно для кеша шарда. После этого мы начали в поиске думать о том, что в синтетике мы никогда "не прогреем данные так как в проде".
Но это дало понимание, что никогда, ни в коем случае не делать региональные/факторные распределения документов по шардам в больших системах. Эта штука закончится неоднородными решениями в том числе из-за перфа. Региональные кеши -- ок, региональные last resort базы -- нет, спасибо. Как можно равномернее распределять лучше всего.
Другой пример:
В SimdJson очень много используются таблички. В бенчмарках они очень прогретые в L1 кешах. Интересно сколько перфа теряется, когда эти таблицы привносят кеш миссы. Это прекрасная идея для поста, чтобы так поубавить градус фразы "Парсим X гигабайт в секунду". Я ставлю минимум 5-10% теряется, что в целом, не велика потеря, но не даёт полной картины реального мира.
Поэтому в оптимизациях я люблю branch free code, потому что о бранчах в горячих местах порой сложно спекулировать.
Ещё вот в наших гугловских хэштаблицах есть бенчмарки с суффиксом _Hot/_Cold. К сожалению, померить распределение прогретости достаточно тяжело, но это хотя бы что-то, что помогает не оверфититься по кешам.
Как вариант посмотреть для SimdJson -- вытащить таблицы из глобальной памяти и поместить их в динамическую, сделать cold benchmark (создаются тысячи инстансов класса и десереализует случайный).
Мораль: не оверфитьте свои оптимизации под бенчмарк, это может плохо закончиться, думайте о данных тоже.
👍83🔥11❤1
1. Интересно почитать о том, насколько быстрой можно сделать коммуникацию по памяти между процессами в Linux
https://mazzo.li/posts/fast-pipes.html
Если коротко, то используется [vm]splice системные вызовы с большими страницами. Интересный факт заключается в том, что эти вызовы в какой-то степени "дарят" страницы другим процессам и тот, кто их создал, не имеет к ним доступа. Бывают полезные кейсы, несколько раз слышал трейдинг их использует, чтобы правильно отдавать память процессам для обработки. Но правильно их использовать замучиться надо ещё. Поэтому я чаще видел как делают shared memory, контролируя весь стек.
Интересный вопрос, а можно ли что-то придумать, чтобы эти страницы помечались copy on write. Мое знание Linux говорит, что да, такой флажок есть, наверное, что-то даже можно сварить из select+poll, но уже становится достаточно тяжело. Отличная идея для io_uring, как по мне :)
Тем не менее, написано понятным языком, и можно узнать много нового.
2. https://www.forrestthewoods.com/blog/benchmarking-malloc-with-doom3/
Проводят benchmark и гистограммы вызовов аллокатора памяти. Не приводят аргументов, но цифры очень похожи на правду. Медиана в 25 наносекунд, 99.9 где-то 20 микросекунд, а когда ядро решает потормозить, уйти в себя, все 500 микросекунд. Отлично почитать, чтобы понимать, насколько быстро современные аллокаторы отдают память.
3. https://arxiv.org/pdf/2205.05982.pdf
Мы тут выложили SIMD сортировку. Честно? Мне не понравилось, идея ок, сравнение и ускорения только для чисел. Невозможно задеплоить в прод адекватно, сортировка чисел не так много цпу занимает. В итоге ни в стандартную библиотеку не включить, ещё и требует зависимости большой SIMD библиотеки. Я не в восторге, так как результат никогда не пойдет в масштабный прод, но если хочется почитать и проникнуться очередными трюками SIMD, welcome.
Я начинаю как-то дифференциацировать оптимизации: либо в тексте должны быть хорошие идеи, которые чему-то учат, либо оптимизации должны уже кому-то помочь. Если первый факт слабый, а второй никому не помог, то я теряю интерес практически моментально.
4. Возможно в ближайшее время будут посты попроще или поменьше. Точно есть ещё на пару недель и один огромный пост, а дальше как-то список закончился. Я расту в Google, мне тяжело, я едва успеваю делать что-то вне работы, плюс ещё полно интересных вещей в обычной смертной жизни происходит. Никогда не думал, что это будет настолько тяжёлая проблема, скейл команды и продукта (а ещё и себя самого), мы растем по количеству пользователей, всем метрикам, а из-за этого количество всех corner case багов увеличивается, нагрузка на support увеличивается и просто уже не хватает ни времени, ни сил. В прошлый раз, когда я чувствовал себя так, я уходил из проекта. На этот раз хочется встретиться с этим и попытаться вытащить продукт на следующий уровень хотя бы 2х по всем параметрам. А 2х по меркам Google это, конечно, очень сложно, и, наверное, самое сложное это community и поддержка проекта, технически уж справимся. Новые испытания, uncomfortably exciting! :)
https://mazzo.li/posts/fast-pipes.html
Если коротко, то используется [vm]splice системные вызовы с большими страницами. Интересный факт заключается в том, что эти вызовы в какой-то степени "дарят" страницы другим процессам и тот, кто их создал, не имеет к ним доступа. Бывают полезные кейсы, несколько раз слышал трейдинг их использует, чтобы правильно отдавать память процессам для обработки. Но правильно их использовать замучиться надо ещё. Поэтому я чаще видел как делают shared memory, контролируя весь стек.
Интересный вопрос, а можно ли что-то придумать, чтобы эти страницы помечались copy on write. Мое знание Linux говорит, что да, такой флажок есть, наверное, что-то даже можно сварить из select+poll, но уже становится достаточно тяжело. Отличная идея для io_uring, как по мне :)
Тем не менее, написано понятным языком, и можно узнать много нового.
2. https://www.forrestthewoods.com/blog/benchmarking-malloc-with-doom3/
Проводят benchmark и гистограммы вызовов аллокатора памяти. Не приводят аргументов, но цифры очень похожи на правду. Медиана в 25 наносекунд, 99.9 где-то 20 микросекунд, а когда ядро решает потормозить, уйти в себя, все 500 микросекунд. Отлично почитать, чтобы понимать, насколько быстро современные аллокаторы отдают память.
3. https://arxiv.org/pdf/2205.05982.pdf
Мы тут выложили SIMD сортировку. Честно? Мне не понравилось, идея ок, сравнение и ускорения только для чисел. Невозможно задеплоить в прод адекватно, сортировка чисел не так много цпу занимает. В итоге ни в стандартную библиотеку не включить, ещё и требует зависимости большой SIMD библиотеки. Я не в восторге, так как результат никогда не пойдет в масштабный прод, но если хочется почитать и проникнуться очередными трюками SIMD, welcome.
Я начинаю как-то дифференциацировать оптимизации: либо в тексте должны быть хорошие идеи, которые чему-то учат, либо оптимизации должны уже кому-то помочь. Если первый факт слабый, а второй никому не помог, то я теряю интерес практически моментально.
4. Возможно в ближайшее время будут посты попроще или поменьше. Точно есть ещё на пару недель и один огромный пост, а дальше как-то список закончился. Я расту в Google, мне тяжело, я едва успеваю делать что-то вне работы, плюс ещё полно интересных вещей в обычной смертной жизни происходит. Никогда не думал, что это будет настолько тяжёлая проблема, скейл команды и продукта (а ещё и себя самого), мы растем по количеству пользователей, всем метрикам, а из-за этого количество всех corner case багов увеличивается, нагрузка на support увеличивается и просто уже не хватает ни времени, ни сил. В прошлый раз, когда я чувствовал себя так, я уходил из проекта. На этот раз хочется встретиться с этим и попытаться вытащить продукт на следующий уровень хотя бы 2х по всем параметрам. А 2х по меркам Google это, конечно, очень сложно, и, наверное, самое сложное это community и поддержка проекта, технически уж справимся. Новые испытания, uncomfortably exciting! :)
mazzo.li
How fast are Linux pipes anyway?
Pipes are ubiquitous in Unix --- but how fast can they go on Linux? In this post we'll iteratively improve a simple pipe-writing benchmark from 3.5GiB/s to 65GiB/s, guided by Linux `perf`.
👍73🔥17❤10
Вообще иногда нахожу какие-то моменты в своей инженерной практике магическими. Я выпал из реальности на пару дней и совершенно не мог двигаться. Последний ~месяц ничего хорошего не происходило в моей жизни в работе.
Зато вчера я занёрдснайпил экспертов ARM и лида Apple одним коммитом :)
Вообще интересный тред от Хектора про Розетту и эмуляцию x86 на Apple M1 (уже и M2)
https://mobile.twitter.com/marcan42/status/1534053625110351872
Коротко: Rosetta хорошо работает не потому что Apple сделали фичей под себя, а потому что хорошо написали розетту и заимплементировали первыми FEAT_* стандарты (в том числе для флагов FEAT_AFP)
А коммит оказался тот самый из наших хеш-таблиц.
Потом Dougall внимательно прочитал и предложил ещё более лучшую версию:
https://twitter.com/dougallj/status/1534213050944802816
Итог: я показал как можно использовать редкие инструкции под ARM, Dougall нашёл ещё более оптимизированный способ, мы сконтачились, созвонимся в ближ пару дней и возможно познакомлюсь с Хектором (легенда же!)
Зато вчера я занёрдснайпил экспертов ARM и лида Apple одним коммитом :)
Вообще интересный тред от Хектора про Розетту и эмуляцию x86 на Apple M1 (уже и M2)
https://mobile.twitter.com/marcan42/status/1534053625110351872
Коротко: Rosetta хорошо работает не потому что Apple сделали фичей под себя, а потому что хорошо написали розетту и заимплементировали первыми FEAT_* стандарты (в том числе для флагов FEAT_AFP)
А коммит оказался тот самый из наших хеш-таблиц.
Потом Dougall внимательно прочитал и предложил ещё более лучшую версию:
https://twitter.com/dougallj/status/1534213050944802816
Итог: я показал как можно использовать редкие инструкции под ARM, Dougall нашёл ещё более оптимизированный способ, мы сконтачились, созвонимся в ближ пару дней и возможно познакомлюсь с Хектором (легенда же!)
🔥155👍12👏1
И в добавок ко всему этому: на работе коллега доделал очень крутую штуку, которую мы не знали как сделать 3 месяца, а один очень талантливый разраб из соседней команды захотел поработать с нами.
Почему хорошие вещи происходят в один день, особенно когда я на полном дне? Я чувствую какой-то подвох/закономерность, что чтобы приключения происходили вокруг тебя, надо обязательно себя кинуть в стену желательно на несколько недель. Хорошие вещи происходят очень хаотично, очень часто в один день как будто что-то прорывает. Weird
P.S. Я в этом году сижу в програмном комитете C++ Zero Cost Conf. Эта конференция про перформанс C++ и любые практические вещи. Мы ищем доклады, подавайтесь, это простой способ поработать со мной над материалом. Даты ещё не определены, где-то июль, насколько я понимаю.
Почему хорошие вещи происходят в один день, особенно когда я на полном дне? Я чувствую какой-то подвох/закономерность, что чтобы приключения происходили вокруг тебя, надо обязательно себя кинуть в стену желательно на несколько недель. Хорошие вещи происходят очень хаотично, очень часто в один день как будто что-то прорывает. Weird
P.S. Я в этом году сижу в програмном комитете C++ Zero Cost Conf. Эта конференция про перформанс C++ и любые практические вещи. Мы ищем доклады, подавайтесь, это простой способ поработать со мной над материалом. Даты ещё не определены, где-то июль, насколько я понимаю.
👍34🔥4👏1
Одна из самых сложных задач для меня в последнее время это рост нашей инфраструктуры. Очень забавно за этим наблюдать, потому что я обычно люблю что-то строить с нуля, а поддерживать намного все сложнее, но менее важным оно не становится. В том же Гугле просто невероятное количество сил убито на поддержку, но, наверное, так в каждом инженерном деле. Вещи ломаются, тут должны быть умные слова про энтропию, а их надо чинить. И надо сильно верить, что вещи должны работать постоянно, чтобы уметь поддерживать продукт. Не как мой провайдер, который решает раз в 3 недели отключить меня на 4 часа.
Для меня в инфраструктурных командах есть 3 стадии: построение, поддержка и неизбежный рост или смерть. Когда вы строите, но у вас нет пользователей, это самое блаженное время, его надо ценить и беречь. Вы можете ошибаться, экспериментировать и знать, как лучше что-то сделать.
Когда у вас появляются пользователи, вы очевидно на поддержке и у вас начинаются проблемы с обратной совместимостью, багами, краевыми случаями. Дальше, как сказал, продукт или растет, или умирает.
Мы закопали MapReduce, об этом даже говорили на одной встрече Cloud, потому что невозможно было поддерживать. Продукт умер, вкопано десятки тысяч часов, но оно закопано. Написали новый движок, и... до сих пор растем.
По суппорту тоже много мыслей. Традиционно один человек в неделю справлялся с нагрузкой, и это было нормально.
Но количество пользователей то растёт. И мы вот достигли точки нашей инфраструктуры, когда уже человек не справляется.
Дальше интересный вопрос, что с этим стоит делать. Можно двух человек ставить на ротации, а потом и трёх и так далее. Только вот команда так не растёт экспоненциально. А ещё люди меняются, экспертиза во многих местах может быть потеряна.
Это тончайший баланс, как растущую инфраструктуру поддерживать, потому что когда одного человека в день на поддержке становится не достаточно, то на самом деле уже поздно.
Хоть это и показывает, что продукт достаточно успешен, но дальнейший рост ограничен пропускной способностью команды, это в итоге выльется, что все будут только на поддержке. Экспонента покажет, что это наступает ой как быстро.
Это сложный вопрос, что надо делать. Я работаю в Гугле, у нас были такие очень сложные эксперименты роста.
* Документация документацией, но практика показала, что намного лучше читают "best practices", советы, написанные человеческим языком о том, как использовать инфраструктуру. Примеры, tips of the week, testing on the toilet -- позволяют намного больше репликации знаний и снижают фактор вопросов экспоненциально. Документация нужна экспертам, чтобы знать все гарантии, но ее нельзя игнорировать.
* Office hours, кейсы дебага онлайн на аудиторию позволяют погрузиться, посмотреть как стоит подходить к проблемам, это тоже понижает фактор вопросов.
* Процесс построения community. Это так называемые readability -- когда чтобы вкоммитить код, нужно получить зелёную галочку от эксперта по языку, а ещё лучше, когда эксперты меняются. Каждый новый эксперт -- multiplicative фактор, он учит много других многим знаниям, оно передается дальше. Получается иерархия, на верху команда, ответственная за продукт, дальше лучшие эксперты, потом чуть похуже, но все они распространены в командах, и значит на верхушку доносятся намного меньше проблем.
* Self-debug. Когда инфраструктура позволяет анализировать проблемы сама -- лучше компиляторные ошибки, понятные логи, интуитивные инструкции. Это самая инновационная и богатая на идеи тема, помогает хорошо, но иногда сложные вещи просто сложные :(
Я начинаю чувствовать, что если всем этим не заниматься одновременно, видя, что инфраструктура растет, в один момент будет поздно. В целом он произошел, сейчас я много времени провожу, чтобы начать создавать community, потому что нас не хватает. Ещё интереснее, как скейлить Cloud, внутри то мы можем все правильно сделать, а снаружи...
Мне страшно, потому что это фундаментально человеческое, страшно, что нет достаточно authority. Страшнее только команду растить :)
Все ещё читаю Google SWE book, там мы об этом много писали.
Для меня в инфраструктурных командах есть 3 стадии: построение, поддержка и неизбежный рост или смерть. Когда вы строите, но у вас нет пользователей, это самое блаженное время, его надо ценить и беречь. Вы можете ошибаться, экспериментировать и знать, как лучше что-то сделать.
Когда у вас появляются пользователи, вы очевидно на поддержке и у вас начинаются проблемы с обратной совместимостью, багами, краевыми случаями. Дальше, как сказал, продукт или растет, или умирает.
Мы закопали MapReduce, об этом даже говорили на одной встрече Cloud, потому что невозможно было поддерживать. Продукт умер, вкопано десятки тысяч часов, но оно закопано. Написали новый движок, и... до сих пор растем.
По суппорту тоже много мыслей. Традиционно один человек в неделю справлялся с нагрузкой, и это было нормально.
Но количество пользователей то растёт. И мы вот достигли точки нашей инфраструктуры, когда уже человек не справляется.
Дальше интересный вопрос, что с этим стоит делать. Можно двух человек ставить на ротации, а потом и трёх и так далее. Только вот команда так не растёт экспоненциально. А ещё люди меняются, экспертиза во многих местах может быть потеряна.
Это тончайший баланс, как растущую инфраструктуру поддерживать, потому что когда одного человека в день на поддержке становится не достаточно, то на самом деле уже поздно.
Хоть это и показывает, что продукт достаточно успешен, но дальнейший рост ограничен пропускной способностью команды, это в итоге выльется, что все будут только на поддержке. Экспонента покажет, что это наступает ой как быстро.
Это сложный вопрос, что надо делать. Я работаю в Гугле, у нас были такие очень сложные эксперименты роста.
* Документация документацией, но практика показала, что намного лучше читают "best practices", советы, написанные человеческим языком о том, как использовать инфраструктуру. Примеры, tips of the week, testing on the toilet -- позволяют намного больше репликации знаний и снижают фактор вопросов экспоненциально. Документация нужна экспертам, чтобы знать все гарантии, но ее нельзя игнорировать.
* Office hours, кейсы дебага онлайн на аудиторию позволяют погрузиться, посмотреть как стоит подходить к проблемам, это тоже понижает фактор вопросов.
* Процесс построения community. Это так называемые readability -- когда чтобы вкоммитить код, нужно получить зелёную галочку от эксперта по языку, а ещё лучше, когда эксперты меняются. Каждый новый эксперт -- multiplicative фактор, он учит много других многим знаниям, оно передается дальше. Получается иерархия, на верху команда, ответственная за продукт, дальше лучшие эксперты, потом чуть похуже, но все они распространены в командах, и значит на верхушку доносятся намного меньше проблем.
* Self-debug. Когда инфраструктура позволяет анализировать проблемы сама -- лучше компиляторные ошибки, понятные логи, интуитивные инструкции. Это самая инновационная и богатая на идеи тема, помогает хорошо, но иногда сложные вещи просто сложные :(
Я начинаю чувствовать, что если всем этим не заниматься одновременно, видя, что инфраструктура растет, в один момент будет поздно. В целом он произошел, сейчас я много времени провожу, чтобы начать создавать community, потому что нас не хватает. Ещё интереснее, как скейлить Cloud, внутри то мы можем все правильно сделать, а снаружи...
Мне страшно, потому что это фундаментально человеческое, страшно, что нет достаточно authority. Страшнее только команду растить :)
Все ещё читаю Google SWE book, там мы об этом много писали.
abseil.io
abseil / Software Engineering at Google
An open-source collection of core C++ library code
🔥44👍26❤4🤔2🎉2
This media is not supported in your browser
VIEW IN TELEGRAM
На дворе 2022 год
Мы находим оптимизации в mem*/str* функциях на мажорных платформах в 20%, которые были доступны как лет 10
Да, это патч в glibc.
В целом история такая: на x86 достаточно легко переходить из векторного кода в скалярный -- если есть вектор сравнения на gif, то на x86 есть PMOVMSKB инструкция, дающая скалярную маску
На ARM такого нет, и все ломали голову как же так сделать. Даже в glibc инженеры Arm делали через 4 цикла и просаживая latency.
Поизучав NEON SIMD, я нашёл инструкцию shrn -- shift right and narrow. На гифке представлен shift right and narrow на 4. Теперь у нас есть маска, не 16 битная, но хотя бы 64, с которой уже можно скалярно работать.
Что произошло в итоге:
1. ZSTD на 5%
2. Хэштаблицы гугла на 3-8%
3. glibc на 10-20% для размеров <=128
4. ClickHouse -- string comparison and sorting на 15%
5. Через 2-3 недели ждите статью, да, это software optimization guide. 3 года назад я студентом увлёкся армами, а вот сейчас я буду писать гайды совместно с вендорами
Mic drop
Мы находим оптимизации в mem*/str* функциях на мажорных платформах в 20%, которые были доступны как лет 10
Да, это патч в glibc.
В целом история такая: на x86 достаточно легко переходить из векторного кода в скалярный -- если есть вектор сравнения на gif, то на x86 есть PMOVMSKB инструкция, дающая скалярную маску
На ARM такого нет, и все ломали голову как же так сделать. Даже в glibc инженеры Arm делали через 4 цикла и просаживая latency.
Поизучав NEON SIMD, я нашёл инструкцию shrn -- shift right and narrow. На гифке представлен shift right and narrow на 4. Теперь у нас есть маска, не 16 битная, но хотя бы 64, с которой уже можно скалярно работать.
Что произошло в итоге:
1. ZSTD на 5%
2. Хэштаблицы гугла на 3-8%
3. glibc на 10-20% для размеров <=128
4. ClickHouse -- string comparison and sorting на 15%
5. Через 2-3 недели ждите статью, да, это software optimization guide. 3 года назад я студентом увлёкся армами, а вот сейчас я буду писать гайды совместно с вендорами
Mic drop
🔥433❤🔥31👍24🤯16🐳14😱3💯2🙏1