Warning: Undefined array key 0 in /var/www/tgoop/function.php on line 65

Warning: Trying to access array offset on value of type null in /var/www/tgoop/function.php on line 65
666 - Telegram Web
Telegram Web
Channel photo updated
на самом деле написал про блог, только чтобы поменять аву, а то просто так уведомление как-то не хорошо
А ещё мне кажется, что я злоупотребляю зачеркнутым текстом.
Вообще вместо того что выше, хотел написать пояснения к design доку tcmalloc, а так же по сути отсутвующую там часть про transfer cache и central free list, но со мной приключилась ужасная история.
Я закрыл браузер с вкладкой с текстом набранным в telegraph. Собственно полезный для всех вывод:
никогда не используйте telegraph при написании чего то, только при публикации
А так постараюсь к концу недели переписать, плюс появилась пара идей, как сделать лучше/полезнее. В идеале хотелось сделать серию постов об аллокаторах, но это я далеко загадываю.
У меня раньше в яндекс еде были отдельные кнопочки, а сейчас эта мерзкая панелька целая, просто зачем??
О класс в хроме добавили ридинг лист.
https://www.tgoop.com/experimentalchill/110
Хотел напомнить, что если x86 умрет и мы все станем счастливыми обладателями arm-а везде, то помимо снижения энергопотребления, более сложной архитектуры кешей => лучшей производительности хорошего конкуретного кода (и куче багов в плохом).
У нас ещё и везде будет load link (условно, атомарно загрузить значение и поставить флажок) store conditional (атомарно смотрит никто ли не тронул флажок и если никто, то устанавливает значение) вместо lock; cmpxchg.
Который фейлится, если кто-то потрогал кешлинию (еще иногда на самом деле, например, когда был switch context потоков ОС)
И как следствие из того как он работает, cas написанный с его помощью не подвержен ABA проблеме.

Собственно если кому то не очевидно как это реализовать, выглядит это например так:
https://elixir.bootlin.com/linux/latest/source/arch/arm/include/asm/cmpxchg.h#L254
ldr* это load link
str* это store conditional
Я по-моему уже где-то спрашивал, но зачем на работе всегда пишут приветствия с восклицательным знаком, я мб не грамотный, но я не могу придумать применения восклицательному знаку, кроме цитирования устной речи или чего-то вроде "?!??!?".
Ну и обычно если вы с кем-то здороваетесь устно, вы говорите это спокойно?
В общем странная фигня какая-то.
Ещё прочитал статьи:
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 структур данных/статистики
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 так, чтобы сломать ваш код, при этом не требуя изменения кода (то есть кейс, когда вы сменили версию компилятора, код скомпилировался, но перестал быть корректным)
Я тут подумал что хочу немного разобраться в том как можно сжимать данные, а то мои знания ограничиваются как написать jpeg encoder/decoder.
Может кто посоветует книжечку/курс?
Недавно начали писать с друзьями весьма интересную библиотеку, уже сейчас фьючи весьма хороши, и лучше большинства аналогов, а будут ещё лучше)
В общем, если у кого какие-то вопросы, или есть желание поконтрибутить, пишите
Как же мне надоел репозиторий llvm mirror который устарел.
Можно его как то убрать из поисковой выдачи?
Ждите доклад на cpp russia про фьючи и чутка про остальное в yaclib)0)
Супер рад
В общем надо и что-то полезное иногда писать:
Сегодня хочу рассказать о двух оптимизациях (они не связаны между собой, просто так совпало):

Начнем с чего попроще:
У вас есть такой код:

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 проект)

Кстати вышла забавная ситуация приехал курьер с документами и за оборудованием.
Сказал что не увезет монитор без коробки, у меня её естественно нет. В итоге он ничего не забрал и приедет только в понедельник(

Ну и минутка бесполезной инфы, чтобы включить дабл кас на гсс/кланге (если он есть офк), нужно использовать опцию -mcx16

Кст за что такие https://github.com/progschj/ThreadPool репозитории имеют 5к звёздочек?
В этой реализации ужасно все, там создаётся
std::function с std::shared_ptr внутри который внутри содержит ещё один shared ptr.
Все это обмазано мьютексами и ужасно неэффективной реализацией.

А вот у https://github.com/YACLib/YACLib меньше 100 звёздочек, несмотря на множество красивых идей и оптимизаций (хочу чтобы было 100+ до доклада, поставьте плз🥲)
Читал я тут блог автора перфбука

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
Но тут меня уже не хватило на чтение самих статьей, как-нибудь в другой раз.
Посоветуйте какой монитор купить
Блин почему гитхаб до сих пор не сделал страницы для истории коммитов, мб есть какой то лайфхак?
2025/07/13 23:02:07
Back to Top
HTML Embed Code: