Я по-моему уже где-то спрашивал, но зачем на работе всегда пишут приветствия с восклицательным знаком, я мб не грамотный, но я не могу придумать применения восклицательному знаку, кроме цитирования устной речи или чего-то вроде "?!??!?".
Ну и обычно если вы с кем-то здороваетесь устно, вы говорите это спокойно?
В общем странная фигня какая-то.
Ну и обычно если вы с кем-то здороваетесь устно, вы говорите это спокойно?
В общем странная фигня какая-то.
Ещё прочитал статьи:
https://research.swtch.com/mm
tldr
1) Классические примеры хардварной модели памяти, и какие исполнения допускают процессоры.
2) Почему несмотря на относительную простоту 1) все на самом деле сложно: оптимизации компиляторов, необходимость или relaxed atomic-ов или валидности программ с data race
3) Собственно про изменения которые они планируют в golang.
Из интересного:
1. В отличие от Java/JavaScript, они явно утверждают, что если в программе обнаружится гонка то программа может сообщить о ней и упасть, а не как-то "не очень опасно" работать
2. Оказывается разработчики архитектур думают о нас простых смертных и делают seq_cst/java volatile более дешёвым с точки зрения исполнения, например на armv8 acq_rel ~ seq_cst для load/store, как следствие наверно в будущем все сведётся к наличию seq_cst и relaxed(unsync) атомикам. Потому что кажется, без последних достаточно сложно обеспечить хорошую производительность некоторых thread safe структур данных/статистики
https://research.swtch.com/mm
tldr
1) Классические примеры хардварной модели памяти, и какие исполнения допускают процессоры.
2) Почему несмотря на относительную простоту 1) все на самом деле сложно: оптимизации компиляторов, необходимость или relaxed atomic-ов или валидности программ с data race
3) Собственно про изменения которые они планируют в golang.
Из интересного:
1. В отличие от Java/JavaScript, они явно утверждают, что если в программе обнаружится гонка то программа может сообщить о ней и упасть, а не как-то "не очень опасно" работать
2. Оказывается разработчики архитектур думают о нас простых смертных и делают seq_cst/java volatile более дешёвым с точки зрения исполнения, например на armv8 acq_rel ~ seq_cst для load/store, как следствие наверно в будущем все сведётся к наличию seq_cst и relaxed(unsync) атомикам. Потому что кажется, без последних достаточно сложно обеспечить хорошую производительность некоторых thread safe структур данных/статистики
Loser story
https://youtu.be/M2fKMP47slQ Прикольный доклад про хешмапы, интересные вариации https://engineering.fb.com/2019/04/25/developer-tools/f14 https://abseil.io/about/design/swisstables собственно как я понимаю та табличка которая в докладе аналог google flat…
https://youtu.be/ncHmEUmJZf4
https://youtu.be/JZE3_0qvrMg
Кст глянул тут доклады именно про swiss table.
В первом больше про то как они пришли к такому дизайну, а во втором как они переходили в проде и с какими проблемами столкнулись.
https://youtu.be/JZE3_0qvrMg
Кст глянул тут доклады именно про swiss table.
В первом больше про то как они пришли к такому дизайну, а во втором как они переходили в проде и с какими проблемами столкнулись.
YouTube
CppCon 2017: Matt Kulukundis “Designing a Fast, Efficient, Cache-friendly Hash Table, Step by Step”
http://CppCon.org
—
Presentation Slides, PDFs, Source Code and other presenter materials are available at: https://github.com/CppCon/CppCon2017
—
Hash tables consume a large volume of both compute resources and memory across Google's production system. The…
—
Presentation Slides, PDFs, Source Code and other presenter materials are available at: https://github.com/CppCon/CppCon2017
—
Hash tables consume a large volume of both compute resources and memory across Google's production system. The…
photo_2021-08-14_23-45-00.png
165.9 KB
Я видимо перепоступил на фиит пмпу (кст бтв 0 знакомых оттуда, в отличие от пми, ну узнаю что за шарага)
Loser story
Ещё прочитал статьи: https://research.swtch.com/mm tldr 1) Классические примеры хардварной модели памяти, и какие исполнения допускают процессоры. 2) Почему несмотря на относительную простоту 1) все на самом деле сложно: оптимизации компиляторов, необходимость…
Кст хейтерам mm в rust, а точнее ее отсутствию или фразы "пока как в плюсах".
Вы можете привести пример, как относительно разумно может измениться модель памяти в rust так, чтобы сломать ваш код, при этом не требуя изменения кода (то есть кейс, когда вы сменили версию компилятора, код скомпилировался, но перестал быть корректным)
Вы можете привести пример, как относительно разумно может измениться модель памяти в rust так, чтобы сломать ваш код, при этом не требуя изменения кода (то есть кейс, когда вы сменили версию компилятора, код скомпилировался, но перестал быть корректным)
Я тут подумал что хочу немного разобраться в том как можно сжимать данные, а то мои знания ограничиваются как написать jpeg encoder/decoder.
Может кто посоветует книжечку/курс?
Может кто посоветует книжечку/курс?
Недавно начали писать с друзьями весьма интересную библиотеку, уже сейчас фьючи весьма хороши, и лучше большинства аналогов, а будут ещё лучше)
В общем, если у кого какие-то вопросы, или есть желание поконтрибутить, пишите
В общем, если у кого какие-то вопросы, или есть желание поконтрибутить, пишите
Telegram
lofi channel
https://github.com/YACLib/YACLib/blob/main/doc/DESIGN_DOC_RU.md
Написали дизайн-док к нашей библиотеке конкурентного исполнения задач, пока на русском, скоро переведем. В-общем, читайте, ставьте звездочки, скоро будет норм документация (наверное)
Написали дизайн-док к нашей библиотеке конкурентного исполнения задач, пока на русском, скоро переведем. В-общем, читайте, ставьте звездочки, скоро будет норм документация (наверное)
Как же мне надоел репозиторий llvm mirror который устарел.
Можно его как то убрать из поисковой выдачи?
Можно его как то убрать из поисковой выдачи?
В общем надо и что-то полезное иногда писать:
Сегодня хочу рассказать о двух оптимизациях (они не связаны между собой, просто так совпало):
Начнем с чего попроще:
У вас есть такой код:
Верно, log(some_n) аллокаций.
Как это исправить?
Верно, вызвать
Любопытно, что такую оптимизацию умеет в простых кейсах распознавать даже clang-tidy: https://clang.llvm.org/extra/clang-tidy/checks/performance-inefficient-vector-operation.html
Продолжим, что если мы не знаем сколько push_back будет?
Мы можем сделать reserve на максимум/минимум/среднее/етс, если его знаем, а что если при этом нам важно потребление памяти?
32 битные системы, большие объемы данных, выделения для gpu, для них все становится несколько хуже, и начинаются, например, вызовы shrink_to_fit:
https://github.com/mapbox/vector-tile/blob/master/include/mapbox/vector_tile.hpp#L284
Который может быть пустой заглушкой,хотя в реализациях обычно все ок, да и решает это проблему лишь отчасти.
На самом деле в таких случаях, хорошим подходом может быть выполнить часть вычислений без сохранения результата, посчитать количество необходимых байт.
В итоге мы получим одну аллокацию под размер данных.
Отлично, но вроде мы замедлили код 2 раза?
На самом деле, как правило нет.
1) Обычно нужно сделать предварительных вычислений в несколько раз меньше, так как нужно узнать только количество вызовов push_back/аналога, то есть замедление не в 2 раза, а в 1 + 1/k, где k это то насколько меньше мы можем считать.
2) Большие аллокации это дорого (как правило работа с деревьями поиска внутри аллокатора), мы избавились от всех кроме одной.
3) Часто наш код многопоточный, а большие аллокации это глобальная синхронизация внутри аллокатора (для мелких < 4-65 КБ, обычно есть тредлокал/етс пулы, для остальных же глобальный спинлок/мьютекс етс)
4) Возможно мы смогли получить более плоскую и cache friendly структуру на данных.
Я несколько раз применял эту идею и получал значительно более компактную и простую структуру данных, ещё и работало быстрее.
Почему я вообще вспомнил об этом?
Недавно на лекции по GPGPU про sparse matrix рассказали о таком же подходе для перемножения матриц, и том что он там также оказался хорош.
Пара примеров из open source проектов (оказалось я совершенно без понятия как такое искать, ведь в большинстве таких мест, скорее всего будет использоваться не vector::reserve, а какая-то ручная аллокация), поэтому закину тривиальный пример, join строк: https://github.com/abseil/abseil-cpp/blob/master/absl/strings/internal/str_join_internal.h#L233
Про вторую оптимизацию более кратко:
Допустим есть некоторая операция, которая в начале увеличивает атомарный счётчик, а в конце уменьшает.
При достижении нуля происходит что то тяжёлое.
Собственно происходит добавление кучи таких параллельных операций.
Как добиться того чтобы тяжёлая операция происходила не более одного раза?
Предлагается до всех добавлений увеличить счётчик, так чтобы достижение нуля было невозможно, и уменьшить на соответствующую величину после добавлений.
Пример: https://github.com/YACLib/YACLib/blob/main/include/yaclib/algo/detail/wait_impl.hpp#L17
Пример из ядра линукса: TODO
Сегодня хочу рассказать о двух оптимизациях (они не связаны между собой, просто так совпало):
Начнем с чего попроще:
У вас есть такой код:
std::vector<Data> storage;
for (int i = 0; i < some_n; ++i) {
storage.push_back(some_data);
}
Что с ним не так?Верно, log(some_n) аллокаций.
Как это исправить?
Верно, вызвать
storage.reserve(some_n)
.Любопытно, что такую оптимизацию умеет в простых кейсах распознавать даже clang-tidy: https://clang.llvm.org/extra/clang-tidy/checks/performance-inefficient-vector-operation.html
Продолжим, что если мы не знаем сколько push_back будет?
Мы можем сделать reserve на максимум/минимум/среднее/етс, если его знаем, а что если при этом нам важно потребление памяти?
32 битные системы, большие объемы данных, выделения для gpu, для них все становится несколько хуже, и начинаются, например, вызовы shrink_to_fit:
https://github.com/mapbox/vector-tile/blob/master/include/mapbox/vector_tile.hpp#L284
Который может быть пустой заглушкой,
На самом деле в таких случаях, хорошим подходом может быть выполнить часть вычислений без сохранения результата, посчитать количество необходимых байт.
В итоге мы получим одну аллокацию под размер данных.
Отлично, но вроде мы замедлили код 2 раза?
На самом деле, как правило нет.
1) Обычно нужно сделать предварительных вычислений в несколько раз меньше, так как нужно узнать только количество вызовов push_back/аналога, то есть замедление не в 2 раза, а в 1 + 1/k, где k это то насколько меньше мы можем считать.
2) Большие аллокации это дорого (как правило работа с деревьями поиска внутри аллокатора), мы избавились от всех кроме одной.
3) Часто наш код многопоточный, а большие аллокации это глобальная синхронизация внутри аллокатора (для мелких < 4-65 КБ, обычно есть тредлокал/етс пулы, для остальных же глобальный спинлок/мьютекс етс)
4) Возможно мы смогли получить более плоскую и cache friendly структуру на данных.
Я несколько раз применял эту идею и получал значительно более компактную и простую структуру данных, ещё и работало быстрее.
Почему я вообще вспомнил об этом?
Недавно на лекции по GPGPU про sparse matrix рассказали о таком же подходе для перемножения матриц, и том что он там также оказался хорош.
Пара примеров из open source проектов (оказалось я совершенно без понятия как такое искать, ведь в большинстве таких мест, скорее всего будет использоваться не vector::reserve, а какая-то ручная аллокация), поэтому закину тривиальный пример, join строк: https://github.com/abseil/abseil-cpp/blob/master/absl/strings/internal/str_join_internal.h#L233
Про вторую оптимизацию более кратко:
Допустим есть некоторая операция, которая в начале увеличивает атомарный счётчик, а в конце уменьшает.
При достижении нуля происходит что то тяжёлое.
Собственно происходит добавление кучи таких параллельных операций.
Как добиться того чтобы тяжёлая операция происходила не более одного раза?
Предлагается до всех добавлений увеличить счётчик, так чтобы достижение нуля было невозможно, и уменьшить на соответствующую величину после добавлений.
Пример: https://github.com/YACLib/YACLib/blob/main/include/yaclib/algo/detail/wait_impl.hpp#L17
Пример из ядра линукса: TODO
В общем уволился из мыла.
Основная причина то, что не было достаточно интересно, решал в основном задачи, решения которых хорошо предсталял.
Из интересного более активно потыкал Vulkan, раньше работал только с OpenGL.
Теперь работаю в команде поиска в https://github.com/arangodb/arangodb. Меня заинтересовало потому что это:
1) Возможность поменять область на другую интересную мне, базы данных
2) Больше интересных задач с асинхронностью и многопоточкой (например есть планы затащить io uring), к тому же можно тыкать распределенность
3) open source
4) Может быть получится затащить свою библиотеку в популярный open source проект)
Кстати вышла забавная ситуация приехал курьер с документами и за оборудованием.
Сказал что не увезет монитор без коробки, у меня её естественно нет. В итоге он ничего не забрал и приедет только в понедельник(
Ну и минутка бесполезной инфы, чтобы включить дабл кас на гсс/кланге (если он есть офк), нужно использовать опцию
Кст за что такие https://github.com/progschj/ThreadPool репозитории имеют 5к звёздочек?
В этой реализации ужасно все, там создаётся
std::function с std::shared_ptr внутри который внутри содержит ещё один shared ptr.
Все это обмазано мьютексами и ужасно неэффективной реализацией.
А вот у https://github.com/YACLib/YACLib меньше 100 звёздочек, несмотря на множество красивых идей и оптимизаций (хочу чтобы было 100+ до доклада, поставьте плз🥲)
Основная причина то, что не было достаточно интересно, решал в основном задачи, решения которых хорошо предсталял.
Из интересного более активно потыкал Vulkan, раньше работал только с OpenGL.
Теперь работаю в команде поиска в https://github.com/arangodb/arangodb. Меня заинтересовало потому что это:
1) Возможность поменять область на другую интересную мне, базы данных
2) Больше интересных задач с асинхронностью и многопоточкой (например есть планы затащить io uring), к тому же можно тыкать распределенность
3) open source
4) Может быть получится затащить свою библиотеку в популярный open source проект)
Кстати вышла забавная ситуация приехал курьер с документами и за оборудованием.
Сказал что не увезет монитор без коробки, у меня её естественно нет. В итоге он ничего не забрал и приедет только в понедельник(
Ну и минутка бесполезной инфы, чтобы включить дабл кас на гсс/кланге (если он есть офк), нужно использовать опцию
-mcx16
Кст за что такие https://github.com/progschj/ThreadPool репозитории имеют 5к звёздочек?
В этой реализации ужасно все, там создаётся
std::function с std::shared_ptr внутри который внутри содержит ещё один shared ptr.
Все это обмазано мьютексами и ужасно неэффективной реализацией.
А вот у https://github.com/YACLib/YACLib меньше 100 звёздочек, несмотря на множество красивых идей и оптимизаций (хочу чтобы было 100+ до доклада, поставьте плз🥲)
GitHub
GitHub - arangodb/arangodb: 🥑 ArangoDB is a native multi-model database with flexible data models for documents, graphs, and key…
🥑 ArangoDB is a native multi-model database with flexible data models for documents, graphs, and key-values. Build high performance applications using a convenient SQL-like query language or JavaSc...
Читал я тут блог автора перфбука
https://paulmck.livejournal.com/66175.html
Ничего разумного кроме lkmm и C++ mm для слабых mm не придумали.
Поэтому предлагается порассуждать об их отличиях
https://wg21.link/p0124r7
Основная разница в наличие более интересных барьеров и операций в линуксе, и наличию control, data, address dependency, что позволяет исключить OOTA (следствие этого некоторое различие между *_once и *_relaxed)
Но так как написание такого кода сложно, а его проверка статическими инструментами невозможна(?), автор приходит к выводу, что C++ mm (без relaxed) подходит для safe Rust куда больше (для тех кто забыл сейчас и safe и unsafe Rust "наследует" C++ mm, в том числе relaxed и связанные с ним костыли (OOTA)).
Лично на мой взгляд хотя вывод и достаточно разумный, мне близки идеи из статьи про golang mm, где автор предлагает выпилить acq/rel, оставить в safe расте только seq_cst звучит любопытно.
С другой стороны это приводит к проблеме, что на платформах с strong memory model (x86), мы получаем ценой чуть более простых гарантий менее эффективный код. И в отличие от relaxed статические инструменты легко работают с acq/rel семантикой.
То есть в правильном и эффективном коде станет больше unsafe и это печально.
Как вариант наверно можно подумать над тем чтобы позволить в safe разные порядки для load/store и для rmw операций?
В прочем это верно и для предложения автора, в основном из-за того, что есть несколько очень популярных паттернов, когда нам нужен relaxed, и мы знаем, что его использование корректно.
Но возможно такие паттерны стоит формализовать и обобщить некоторыми абстракциями?
Собственно про это автор пишет в
https://wg21.link/p2055r0
это самая полезная из приведенных ссылок с практической точки зрения.
https://paulmck.livejournal.com/63517.html
Так же он упоминает несколько других любопытных документов в контексте OOTA.
Напоминаю, что на практике его не существует.
Поэтому мне кажется что результаты https://wg21.link/p0422r0 весьма интересны.
Только компилятор, который умеет различать OOTA приводящий к проблемам от просто переупорядочиваний, может применять такие оптимизации, чтобы сделать OOTA возможным на практике.
А это значит, что если компилятор мог бы научится делать такие оптимизации, появился бы инструмент, чтобы проверять корректность такого кода, а это невозможно.
В конце же дается ссылка на любопытные исследования
https://www.cl.cam.ac.uk/~jp622/popl16-thinair
Но тут меня уже не хватило на чтение самих статьей, как-нибудь в другой раз.
https://paulmck.livejournal.com/66175.html
Ничего разумного кроме lkmm и C++ mm для слабых mm не придумали.
Поэтому предлагается порассуждать об их отличиях
https://wg21.link/p0124r7
Основная разница в наличие более интересных барьеров и операций в линуксе, и наличию control, data, address dependency, что позволяет исключить OOTA (следствие этого некоторое различие между *_once и *_relaxed)
Но так как написание такого кода сложно, а его проверка статическими инструментами невозможна(?), автор приходит к выводу, что C++ mm (без relaxed) подходит для safe Rust куда больше (для тех кто забыл сейчас и safe и unsafe Rust "наследует" C++ mm, в том числе relaxed и связанные с ним костыли (OOTA)).
Лично на мой взгляд хотя вывод и достаточно разумный, мне близки идеи из статьи про golang mm, где автор предлагает выпилить acq/rel, оставить в safe расте только seq_cst звучит любопытно.
С другой стороны это приводит к проблеме, что на платформах с strong memory model (x86), мы получаем ценой чуть более простых гарантий менее эффективный код. И в отличие от relaxed статические инструменты легко работают с acq/rel семантикой.
То есть в правильном и эффективном коде станет больше unsafe и это печально.
Как вариант наверно можно подумать над тем чтобы позволить в safe разные порядки для load/store и для rmw операций?
В прочем это верно и для предложения автора, в основном из-за того, что есть несколько очень популярных паттернов, когда нам нужен relaxed, и мы знаем, что его использование корректно.
Но возможно такие паттерны стоит формализовать и обобщить некоторыми абстракциями?
Собственно про это автор пишет в
https://wg21.link/p2055r0
это самая полезная из приведенных ссылок с практической точки зрения.
https://paulmck.livejournal.com/63517.html
Так же он упоминает несколько других любопытных документов в контексте OOTA.
Напоминаю, что на практике его не существует.
Поэтому мне кажется что результаты https://wg21.link/p0422r0 весьма интересны.
Только компилятор, который умеет различать OOTA приводящий к проблемам от просто переупорядочиваний, может применять такие оптимизации, чтобы сделать OOTA возможным на практике.
А это значит, что если компилятор мог бы научится делать такие оптимизации, появился бы инструмент, чтобы проверять корректность такого кода, а это невозможно.
В конце же дается ссылка на любопытные исследования
https://www.cl.cam.ac.uk/~jp622/popl16-thinair
Но тут меня уже не хватило на чтение самих статьей, как-нибудь в другой раз.
Livejournal
What Memory Model Should the Rust Language Use?
UNDER CONSTRUCTION This blog post discusses a few alternative Rust-language memory models. I hope that this discussion is of value to the Rust community, but in the end, it is their language, so it is also their choice of memory model. This discussion takes…
Блин почему гитхаб до сих пор не сделал страницы для истории коммитов, мб есть какой то лайфхак?
Сегодня расскажу что-то полезное.
Это wait-free "алгоритм" для некоторого подобия взаимного исключения и очереди. Звучит конечно круто, но на практике это простейший код,как и почти все действительно полезные wait/lock-free алгоритмы.
Допустим есть некоторая асинхронная операция, с общим состоянием, запрос на ее вызов может возникать в разных тредах.
При этом операцию нельзя исполнять параллельно, она требует взаимного исключения.
Также есть одно важное дополнительное условие, нам неважно сколько раз была вызвана операция, но при этом мы хотим, чтобы наиболее актуальный вызов был совершен, ну и конечно мы не хотим делать бесполезную работу.
Наверно нихуя не понятно, я не умею нормально объяснить, приведу пример.
Допустим у вас есть некоторая тяжёлая операция, например пересчитать какой-то кеш, эта операция выполняется в отдельном потоке, а запрос на нее приходит из вызов в разных тредах, часть зависит от действий юзера, часть по таймауту, етс
Самое банальное решение просто очередь задач под мьютексом.
Понятно, что оно не оптимально именно с точки зрения того, что операция будет вызываться множество раз, даже если это уже не нужно.
Оптимально будет сделать так:
Я написал такой код ещё в транзасе, там было обновление кеша прореживания объектов по таймауту, а также некоторым действиям пользователя.
Там также нашлось несколько других мест где этот паттерн был полезен.
И недавно мне понадобился этот "алгоритм" в ArangoDB, решил с вами поделиться)
Кстати в yaclib (star plz https://github.com/YACLib/YACLib) я все планирую написать специальный тип таски на такой паттерн (там ещё в push аллокации не будет), да все руки не доходят (issue есть: https://github.com/YACLib/YACLib/issues/10)
Это wait-free "алгоритм" для некоторого подобия взаимного исключения и очереди. Звучит конечно круто, но на практике это простейший код,
Допустим есть некоторая асинхронная операция, с общим состоянием, запрос на ее вызов может возникать в разных тредах.
При этом операцию нельзя исполнять параллельно, она требует взаимного исключения.
Также есть одно важное дополнительное условие, нам неважно сколько раз была вызвана операция, но при этом мы хотим, чтобы наиболее актуальный вызов был совершен, ну и конечно мы не хотим делать бесполезную работу.
Наверно нихуя не понятно, я не умею нормально объяснить, приведу пример.
Допустим у вас есть некоторая тяжёлая операция, например пересчитать какой-то кеш, эта операция выполняется в отдельном потоке, а запрос на нее приходит из вызов в разных тредах, часть зависит от действий юзера, часть по таймауту, етс
Самое банальное решение просто очередь задач под мьютексом.
Понятно, что оно не оптимально именно с точки зрения того, что операция будет вызываться множество раз, даже если это уже не нужно.
Оптимально будет сделать так:
void forceAsyncRequest() {
some_thread.push([this] {
counter_.store(1);
...do it...
// если за это время пришел новый asyncRequest мы перезапустим сами себя в конце
if (counter_.fetch_sub(1) > 1) {
forceAsyncRequest();
}
}
}
void asyncRequest() {
if (counter_.fetch_add(1) == 0) {
forceAsyncRequest();
}
}
Я написал такой код ещё в транзасе, там было обновление кеша прореживания объектов по таймауту, а также некоторым действиям пользователя.
Там также нашлось несколько других мест где этот паттерн был полезен.
И недавно мне понадобился этот "алгоритм" в ArangoDB, решил с вами поделиться)
Кстати в yaclib (star plz https://github.com/YACLib/YACLib) я все планирую написать специальный тип таски на такой паттерн (там ещё в push аллокации не будет), да все руки не доходят (issue есть: https://github.com/YACLib/YACLib/issues/10)
GitHub
GitHub - YACLib/YACLib: Yet Another Concurrency Library
Yet Another Concurrency Library. Contribute to YACLib/YACLib development by creating an account on GitHub.
Кстати сегодня впервые задумался, а какая libc на macOS?
https://github.com/apple-open-source-mirror/Libc какая-то имплементация есть, но интересно с кого она спизжена, с bsd libc, glibc или прям совсем своя?
На linux из адекватного кажется есть две альтернативы:
glibc (если используете в виде .so, то велики шансы, что у вас проблемы с поддержкой разных дистрибутиво,а использовать не .so по сути нельзя)
musl относительно адекватный вариант для статической линковки
Правда не забудьте использовать не системный аллокатор.
musl alloc это тупо заглушка в случае многопоточной среды, даже в сравнении с ptmalloc2
Возможно когда-нибудь у нас будет llvm libc, ждём
На windows это видимо msvc рантайм какой-то, иногда видимо mingw рантайм, хз
Вообще я тут недавно участвовал в дискуссии, что было бы лучше, если у нас была не libc, а memory_libc.a, string_libc.a, alloc_libc.a, io_libc.a, etc
В общем набор маленьких библиотек, со статической линковкой в одну большую .so или в ваш проект, вероятно тогда у нас было бы больше альтернатив и конкуренции, сейчас же, даже если ты знаешь как написать самый быстрый strstr (twoway топ), то тебе либо надо мучаться с попытками затащить это в glibc, либо писать свою/тащить в другую маргинальную libc. Оба варианта сложные, иногда сложнее самой задачи, как мне кажется это весьма печально.
https://github.com/apple-open-source-mirror/Libc какая-то имплементация есть, но интересно с кого она спизжена, с bsd libc, glibc или прям совсем своя?
На linux из адекватного кажется есть две альтернативы:
glibc (если используете в виде .so, то велики шансы, что у вас проблемы с поддержкой разных дистрибутиво,
musl относительно адекватный вариант для статической линковки
Правда не забудьте использовать не системный аллокатор.
musl alloc это тупо заглушка в случае многопоточной среды, даже в сравнении с ptmalloc2
Возможно когда-нибудь у нас будет llvm libc, ждём
На windows это видимо msvc рантайм какой-то, иногда видимо mingw рантайм, хз
Вообще я тут недавно участвовал в дискуссии, что было бы лучше, если у нас была не libc, а memory_libc.a, string_libc.a, alloc_libc.a, io_libc.a, etc
В общем набор маленьких библиотек, со статической линковкой в одну большую .so или в ваш проект, вероятно тогда у нас было бы больше альтернатив и конкуренции, сейчас же, даже если ты знаешь как написать самый быстрый strstr (twoway топ), то тебе либо надо мучаться с попытками затащить это в glibc, либо писать свою/тащить в другую маргинальную libc. Оба варианта сложные, иногда сложнее самой задачи, как мне кажется это весьма печально.
Loser story
Ждите доклад на cpp russia про фьючи и чутка про остальное в yaclib)0) Супер рад
Собственно подъехали отзывы о докладе. Из приятного если время считается правильно, то большинство посмотрели целиком.
По лично моему впечатлению получилось несколько проблем:
1) Действительно кароче чем можно было, вроде минут 35.
Но с другой стороны, говорить больше сторонней информации, по типу введения не хотелось (у меня были такие слайды, выпилил), также не хотелось добавлять ещё больше кода на слайды так как по-моему в докладе достаточно сложности
2) По поводу презентации, мне казалось она офигенно выглядит, видимо не так, попробую сменить размер текста и тему
3) Ну и я вероятно действительно рассказал все несколько быстрее и монотоннее чем нужно, основная проблема лично для меня была, что в процессе доклада ты по сути говоришь все самому себе и не видно никакой реакции -- понятно/не понятно.
Возможно стоило предложить задавать вопросы в процессе доклада (узнал о такой возможности только когда смотрел другой доклад)
Презентация в комментах
Запись видимо будет когда-то весной, я скину)
По лично моему впечатлению получилось несколько проблем:
1) Действительно кароче чем можно было, вроде минут 35.
Но с другой стороны, говорить больше сторонней информации, по типу введения не хотелось (у меня были такие слайды, выпилил), также не хотелось добавлять ещё больше кода на слайды так как по-моему в докладе достаточно сложности
2) По поводу презентации, мне казалось она офигенно выглядит, видимо не так, попробую сменить размер текста и тему
3) Ну и я вероятно действительно рассказал все несколько быстрее и монотоннее чем нужно, основная проблема лично для меня была, что в процессе доклада ты по сути говоришь все самому себе и не видно никакой реакции -- понятно/не понятно.
Возможно стоило предложить задавать вопросы в процессе доклада (узнал о такой возможности только когда смотрел другой доклад)
Презентация в комментах
Запись видимо будет когда-то весной, я скину)
Пока еду в такси, захотелось что-то написать (тем более все пишут)
В 2021 я кажется (хотя наверно ещё рано судить, но все-таки) нашел классную команду и работу
Бросил уник
Сдавал классные и не очень домашки
Организовал и писал опенсурс проект (и надеюсь заюзать его полноценно в следующем году)
Выступил на конференции по плюсам
Завел кота
Ещё не совсем одичал и всё ещё общаюсь с людьми
Стал лучше в английском (всё ещё ужасен)
Прочитал несколько классных книжек
Написал каркас и альфу для большого проекта с нуля
Хотелось бы в следующем году:
Стать лучше в английском
Сделать много классных тасок
Быть ответственнее по отношению к коту
Больше читать полезного
Попробовать себя в роли преподавателя, хотелось бы прочитать такой курс в ксц https://gist.github.com/MBkkt/296baa71181de5d95110048f358e564e, но не знаю как сложится пока (кст пишите критику)
Заюзать yaclib в arangodb
Меньше забивать на свое здоровье
Больше отдыхать, больше успевать.
В общем если получится половина будет неплохо)
Всех с наступающим новым годом)
В 2021 я кажется (хотя наверно ещё рано судить, но все-таки) нашел классную команду и работу
Бросил уник
Сдавал классные и не очень домашки
Организовал и писал опенсурс проект (и надеюсь заюзать его полноценно в следующем году)
Выступил на конференции по плюсам
Завел кота
Ещё не совсем одичал и всё ещё общаюсь с людьми
Стал лучше в английском (всё ещё ужасен)
Прочитал несколько классных книжек
Написал каркас и альфу для большого проекта с нуля
Хотелось бы в следующем году:
Стать лучше в английском
Сделать много классных тасок
Быть ответственнее по отношению к коту
Больше читать полезного
Попробовать себя в роли преподавателя, хотелось бы прочитать такой курс в ксц https://gist.github.com/MBkkt/296baa71181de5d95110048f358e564e, но не знаю как сложится пока (кст пишите критику)
Заюзать yaclib в arangodb
Меньше забивать на свое здоровье
Больше отдыхать, больше успевать.
В общем если получится половина будет неплохо)
Всех с наступающим новым годом)
Gist
Allocator course
Allocator course. GitHub Gist: instantly share code, notes, and snippets.
Опять давно не писал...
В плюсах есть built-in
Мне недавно это пригодилось, чтобы написать код аккуратнее код, который работает с несколькими разными лямбдами без захвата, как с переменными одного типа.
А теперь резкий переход, cегодня вспоминал
Ниже речь пойдет только про Linux.
В Linux до относитель недавнего времени (5.1) существовало по сути два способа взаимодействия с файловой системой:
Способные блокировать поток, сисколы (
Aсинхронное API (
Также на мой личный взгляд, если вы не считаете, что ваш процесс единственный нагруженный в юзерспейсе ОС, использовать его сомнительно.
В ядре 5.1 появилось новое API —
Некоторая предыстория моего знакомства с этим API:
Года так 3 назад, я задавался вопросом, а можно ли как-то сделать асинхронный
И тогда ответом было, что такого способа нет (может прийти идея создавать поток на каждый
Позже его приняли, и разобравшись в том, что это такое, я однозначно могу сказать, что на сегодняшний день эта задача прекрасно решается с помощью
В плюсах есть built-in
T* operator+(T*)
, он как и некоторые другие built-in операторы нужен в основном для разрешения перегрузок, нам же интересно другое его немного нестандартное применение:auto lambda = [] {};Это работает, потому что лямбда с пустым захватом умеет неявно каститься в указатель на функцию, в итоге мы вызываем этот каст с помощью
auto func = +[] {};
using ptr = void(*)();
static_assert(std::is_same_v<ptr, decltype(func)> && !std::is_same_v<decltype(func), decltype(lambda)>);
operator+
.Мне недавно это пригодилось, чтобы написать код аккуратнее код, который работает с несколькими разными лямбдами без захвата, как с переменными одного типа.
А теперь резкий переход, cегодня вспоминал
io_uring
[1], по работе, и понял, что ни разу не писал в канал про эту абстракцию, которая мне очень нравится.Ниже речь пойдет только про Linux.
В Linux до относитель недавнего времени (5.1) существовало по сути два способа взаимодействия с файловой системой:
Способные блокировать поток, сисколы (
read
, write
, etc), простое, но неэффективное API прямиком из 70ых (в golang есть интересный хак, когда вы делаете блокирующий сисколл [2], поток тредпула (m
), исполняющий горутину, отдает свою очередь горутин (p
) шедулеру, и соотвественно другие потоки без очереди могут ее захватить). В плюсах же чаще для файлового IO просто делают отдельный тредпул. Главная проблема этого подхода он не масштабируется, так как мы добавляем порядок, синхронизацию, там где оно не нужно.Aсинхронное API (
aio_*
), оно крайне кривое (почему, отдельный разговор), и работает только с не буферизованными файлами. Так что, если вы хотели его использовать, вам нужно было реализовывать собственный кеш для файлов, как итог им пользуются только некоторые базы данных, насколько мне известно.Также на мой личный взгляд, если вы не считаете, что ваш процесс единственный нагруженный в юзерспейсе ОС, использовать его сомнительно.
В ядре 5.1 появилось новое API —
io_uring
.Некоторая предыстория моего знакомства с этим API:
Года так 3 назад, я задавался вопросом, а можно ли как-то сделать асинхронный
fsync
append-only файла. Задача была в том, чтобы по событию синхронизировать файл в который писались данные, при этом отсутствовал внешний наблюдатель (то есть смысла ожидать fsync
не было, хотелось как бы попросить OS: пожалуйста, если можешь синкани состояние этого файла как можно скорее).И тогда ответом было, что такого способа нет (может прийти идея создавать поток на каждый
fsync
, но даже не обращая внимания на то, что это дорого, в этом нет смысла, так как другие блокирующие операции, записи, блокируются и ждут когда мы доделаем fsync
), нашел я тогда только патч в ядро линукса, который вроде бы делал то что я хотел.Позже его приняли, и разобравшись в том, что это такое, я однозначно могу сказать, что на сегодняшний день эта задача прекрасно решается с помощью
io_uring
: