Я не могу этим не поделиться
Недавно я делал внутреннюю тулзу, для которой хотелось запускать питон код
Я решил попробовать сделать это не с помощью процессов, а запускать питон прям в этом же процессе (язык для скриптов же все дела) (плюс можно было шерить память за очень быстро)
Для раста есть прекрасная либа под названием pyo3 (а еще там же есть биндинги numpy)
И мне надо было сделать
Ну я и пишу какой-то код аля
1. Компилятор(!) знал и понял, что
А именно, он мне сказал:
"PyDateTime" нельзя сувать в
И если я хочу быстро, то мне нужно использовать его.
И УЗНАЛ Я ОБ ЭТОМ НЕ ИЗ РАНТАЙМ ОШИБКИ, НЕ ИЗ ГУГЛА, А ОТ КОМПИЛЯТОРА
АААААААА
К слову, часто раст рекламируют как "memory safety", но на самом деле его система типов позволяет делать намного больше, как, например, тут, правильно описывать апи вообще другого языка.
Помимо этого, мой экспириенс с питоном в расте был мега приятный. Я не знал, можно ли в структурах, которые будут экспортироваться в питон, использовать обычные типы из раста (условно, нужно ли использовать
И такого рода вещей было очень много. Я глядел совсем чутка на то, как это делается в плюсах, и понял, что там просто UB на UB (C api все таки), и был в шоке, наскольно приятно это делается тут.
В общем, это довольно хороший пример большой библиотеки с кучей сложных вещей, которая при этом позволяет добиваться того самого волшебного момента "компилируется - значит работает"
Недавно я делал внутреннюю тулзу, для которой хотелось запускать питон код
Я решил попробовать сделать это не с помощью процессов, а запускать питон прям в этом же процессе (язык для скриптов же все дела) (плюс можно было шерить память за очень быстро)
Для раста есть прекрасная либа под названием pyo3 (а еще там же есть биндинги numpy)
И мне надо было сделать
datetime numpy array
(массив дат)Ну я и пишу какой-то код аля
PyArray1::<PyDateTime>::from_iter(dates...);И что бы вы думали
1. Компилятор(!) знал и понял, что
PyDateTime
нельзя пихать в numpy array
2. Но он не только сказал, что нельзя, но написал мне ошибку со скринаА именно, он мне сказал:
"PyDateTime" нельзя сувать в
numpy array
, но есть несколько других типов, которые можно, например numpy::DateTime
Оказывается, что у нампая свой тип дат (что логично, вместо всей структуры с полями типа year, month, day
и т.д., там просто хранится timestamp
)И если я хочу быстро, то мне нужно использовать его.
И УЗНАЛ Я ОБ ЭТОМ НЕ ИЗ РАНТАЙМ ОШИБКИ, НЕ ИЗ ГУГЛА, А ОТ КОМПИЛЯТОРА
АААААААА
К слову, часто раст рекламируют как "memory safety", но на самом деле его система типов позволяет делать намного больше, как, например, тут, правильно описывать апи вообще другого языка.
Помимо этого, мой экспириенс с питоном в расте был мега приятный. Я не знал, можно ли в структурах, которые будут экспортироваться в питон, использовать обычные типы из раста (условно, нужно ли использовать
PyString
, или можно String
), и вместо того, чтобы гуглить, безопасно ли это, можно ли так, я просто писал такой код, и он компилировался, и я был уверен, что так можно (и да, все ок)И такого рода вещей было очень много. Я глядел совсем чутка на то, как это делается в плюсах, и понял, что там просто UB на UB (C api все таки), и был в шоке, наскольно приятно это делается тут.
В общем, это довольно хороший пример большой библиотеки с кучей сложных вещей, которая при этом позволяет добиваться того самого волшебного момента "компилируется - значит работает"
👍10😁1🤔1
Очень хороший пост-статья про то, как работает
Крайне интересное чтиво
https://blog.burntsushi.net/regex-internals/
#статья
regex
изнутри, и какие проблемы встречаются при реализацииКрайне интересное чтиво
https://blog.burntsushi.net/regex-internals/
#статья
burntsushi.net
Regex engine internals as a library - Andrew Gallant's Blog
I blog mostly about my own programming projects.
👍3
https://world.hey.com/dhh/the-price-of-managed-cloud-services-4f33d67e
Хороший маленький пример сравнения cloud и bare metal с ценами (bare metal победил).
Одна из существенных проблем - очень тяжело оптимизировать стоимость клауда
Хороший маленький пример сравнения cloud и bare metal с ценами (bare metal победил).
Одна из существенных проблем - очень тяжело оптимизировать стоимость клауда
Hey
The price of managed cloud services
One of the common objections to our cloud exit has been that we shouldn't have expected good outcomes from a lift'n'shift operation. That the real value of the cloud is in managed services and new architectures, not just running the same software on rented…
👍2
Чем больше читаешь про hardware, тем меньше доверяешь компьютерам (с)
https://xuanwo.io/2023/04-rust-std-fs-slower-than-python/
https://xuanwo.io/2023/04-rust-std-fs-slower-than-python/
xuanwo.io
Rust std fs slower than Python!? No, it's hardware!
Achieving Data Freedom Through Open Source and Rust
Panic! At the 0xC0D3
Чем больше читаешь про hardware, тем меньше доверяешь компьютерам (с) https://xuanwo.io/2023/04-rust-std-fs-slower-than-python/
https://beza1e1.tuxen.de/lore/index.html?s=35
Детективные истории про баги в софте и хардвейре
Вкуснятина
Детективные истории про баги в софте и хардвейре
Вкуснятина
beza1e1.tuxen.de
Software Folklore
a blog post by @azwinkau
👍3
А вы знаете, как работает звук в линухе?
Наверное, не такой вопрос я ожидал себе задавать, когда взял гитару в руки за пару часов до этого. Я просто хотел спокойно поиграть на ней... Возможно записать себя пару раз, чтобы послушать "со стороны".
Ага, зараза подкралась незаметно.
Записывать звук? Любая микроволновка же так умеет
Профессиональная (чуть сложнее голосовухи в телеграме) запись звука вообще-то, блин, сложная (если ты хочешь слышать, что записывается), потому что твой звук должен пройти путь
И сделать это все с минимальной задержкой (<=1-10мс), иначе будет ощущение, что играешь в церкви (натуральный reverb так сказатб)
И не все стрелочки выше хотят/могут быть супер быстрыми:
Казалось бы, хуе мое, стримы данных, забудем даже про DAW и эффекты, просто сделаем пайп байтиков из инпута в аутпут, мы молодцы, готово.
Ан нет, основная проблема в том, что выход не может "подождать" данных. Если их сейчас нет, то ему нечего играть, он играет ничего, а мы слышим всякие щелчки-кряхтение (звуки дедов в общем). И это уже физика, кодом ее не решить. Отсюда идет требование, что на выход всегда должны быть данные. А что делать, если вход тупит, операционка или даже звуковая карта затупила и отдала данные чуть позже? Вот мы и попались.
ALSA, или первый круг ада
ALSA вообще это ваш бро. Это по сути самый низкий уровень "звука" в ядре линукса. Вот девайс, вот отсюда звук, сюда звук, все. Бро он, потому что простой (а значит работает!!): фигачим окно в 1мс на затупы (покупаем нормальную звуковую карту между делом), соединяем инпут с аутпутом, и живем. Ну и подсасываем инпут для записи, но это уже дело десятое.
Ну все, взяли ALSA, дело сделано, пошли гулять? Эээ, стой, а че хром с backing track перестал работать? Куда звук делся? А еще системная громкость не работает (но мы это мастером на -10дб пофиксим если что).
Ага, для всего остального нам нужен Audio Server, который будет микшировать звуки из разных приложений, управлять уровнями (громкостями) (не только системными, но и по приложениям), при этом отдавать эти стримы разным нуждающимся (напр. использование микрофона в двух приложениях одновременно)
PulseAudio, или швейцарский нож
Вот это имя скорее всего будет знакомо всем линуксоидам, которые когда-либо сидели в наушниках без звука на 5й странице гугла. Потому что с ALSA все просто: либо ваше устройство есть, либо его нет, и тогда обновляем кернел, а если не помогло, идем плакать на форум что дрова не завезли. А с PulseAudio тяжело, мда.
PulseAudio это такой мультитул, который пытается у всех программ звук забрать, замикшировать его в одну кучу, настроить громкость там все дела, и протолкнуть итоговый к.. результат в вывод вашей звуковой карты. И на самом деле делает это не совсем убого.
Основная его идея, это сделать все буферы ну капец большими, так что даже если вы запустили вс код, и вкладке со спотифай внезапно не хватает ядер процессора, у пульса будет немного буфера, чтобы это все замазать. Это хорошо работает, когда вы воспроизводите звук. Ютюбчик там, музяка, голосовухи в телеграмме. Это нормально работает, когда вы записываете звук без прослушивания: голосовухи там, дискорды и гугл миты.
Но это отвратительно работает, когда вы хотите записывать звук с мониторингом того, что вы вообще играете. Я не шучу, пока я услышу свою ноту на гитаре, я могу сходить себе чай заварить (ладно ладно, но задержка реально несколько СЕКУНД. UN-ACC-EPT-AB-LEEEEE)
Кстати, так (огромным буфером) работают аналогичные слои в других ОСях по умолчанию (никогда не пробовали на винде в системе включить "прослушивание микрофона" и офигеть от задержки? Даже с нормальной звуковой картой там все еще дофига)
Наверное, не такой вопрос я ожидал себе задавать, когда взял гитару в руки за пару часов до этого. Я просто хотел спокойно поиграть на ней... Возможно записать себя пару раз, чтобы послушать "со стороны".
Ага, зараза подкралась незаметно.
Записывать звук? Любая микроволновка же так умеет
Профессиональная (чуть сложнее голосовухи в телеграме) запись звука вообще-то, блин, сложная (если ты хочешь слышать, что записывается), потому что твой звук должен пройти путь
звуковая карта (вход) -> ось -> DAW (приложение для редактирования звука) -> спецэффекты и прибамбасы -> ось -> звуковая карта (выход)
И сделать это все с минимальной задержкой (<=1-10мс), иначе будет ощущение, что играешь в церкви (натуральный reverb так сказатб)
И не все стрелочки выше хотят/могут быть супер быстрыми:
Казалось бы, хуе мое, стримы данных, забудем даже про DAW и эффекты, просто сделаем пайп байтиков из инпута в аутпут, мы молодцы, готово.
Ан нет, основная проблема в том, что выход не может "подождать" данных. Если их сейчас нет, то ему нечего играть, он играет ничего, а мы слышим всякие щелчки-кряхтение (звуки дедов в общем). И это уже физика, кодом ее не решить. Отсюда идет требование, что на выход всегда должны быть данные. А что делать, если вход тупит, операционка или даже звуковая карта затупила и отдала данные чуть позже? Вот мы и попались.
ALSA, или первый круг ада
ALSA вообще это ваш бро. Это по сути самый низкий уровень "звука" в ядре линукса. Вот девайс, вот отсюда звук, сюда звук, все. Бро он, потому что простой (а значит работает!!): фигачим окно в 1мс на затупы (покупаем нормальную звуковую карту между делом), соединяем инпут с аутпутом, и живем. Ну и подсасываем инпут для записи, но это уже дело десятое.
Ну все, взяли ALSA, дело сделано, пошли гулять? Эээ, стой, а че хром с backing track перестал работать? Куда звук делся? А еще системная громкость не работает (но мы это мастером на -10дб пофиксим если что).
Ага, для всего остального нам нужен Audio Server, который будет микшировать звуки из разных приложений, управлять уровнями (громкостями) (не только системными, но и по приложениям), при этом отдавать эти стримы разным нуждающимся (напр. использование микрофона в двух приложениях одновременно)
PulseAudio, или швейцарский нож
Вот это имя скорее всего будет знакомо всем линуксоидам, которые когда-либо сидели в наушниках без звука на 5й странице гугла. Потому что с ALSA все просто: либо ваше устройство есть, либо его нет, и тогда обновляем кернел, а если не помогло, идем плакать на форум что дрова не завезли. А с PulseAudio тяжело, мда.
PulseAudio это такой мультитул, который пытается у всех программ звук забрать, замикшировать его в одну кучу, настроить громкость там все дела, и протолкнуть итоговый к.. результат в вывод вашей звуковой карты. И на самом деле делает это не совсем убого.
Основная его идея, это сделать все буферы ну капец большими, так что даже если вы запустили вс код, и вкладке со спотифай внезапно не хватает ядер процессора, у пульса будет немного буфера, чтобы это все замазать. Это хорошо работает, когда вы воспроизводите звук. Ютюбчик там, музяка, голосовухи в телеграмме. Это нормально работает, когда вы записываете звук без прослушивания: голосовухи там, дискорды и гугл миты.
Но это отвратительно работает, когда вы хотите записывать звук с мониторингом того, что вы вообще играете. Я не шучу, пока я услышу свою ноту на гитаре, я могу сходить себе чай заварить (ладно ладно, но задержка реально несколько СЕКУНД. UN-ACC-EPT-AB-LEEEEE)
Кстати, так (огромным буфером) работают аналогичные слои в других ОСях по умолчанию (никогда не пробовали на винде в системе включить "прослушивание микрофона" и офигеть от задержки? Даже с нормальной звуковой картой там все еще дофига)
👍6
JACK/PipeWire, или "а что если дать юзеру страдать с конфигами?"
Я, если честно, не уверен, что линукс где-то прям используется энтерпрайзом массивно для звука, но вообще не удивился бы. Потому что челы реально посмотрели этот видос и сказали "блин вот это тема, в которой никто никогда не разберется, но теоретически можно хоть ракету в космос запустить. А давайте так же сделаем?" И сделали.
Вообще идея прикольная, ну знаете так, чтобы услышать и никогда не трогать. Вместо того, чтобы полить все маслом под названием "задержка до луны и обратно", здесь решили дать возможность конфигурировать все и вся. Вот у тебя вход, можешь руками показать куда ему идти, вот тут в конфигах лично для него написать sample rate, bit depth, формат данных, длину окна периода, headroom и использовать ли mmap или нет (jokes on you но я в какой-то момент реально подумал, что для меня фикс был в этом).
Короче классический линукс, ничего удивительного.
А, нет, нет же! Удивительно то, что даже из коробки оно работает, работает намного лучше PulseAudio (по задержке), и одной строчкой в конфиге делается еще лучше! Жаль, что до задержки сырого ALSA так и не дошел.
(Нет, я не сделал это все за 5 минут, потому что выбрал не тот, сцука, тип инпута со звуковухи, он ТРЕЩАЛ, но просто сменой типа он ПЕРЕСТАВАЛ)
А в других системах то что?
А я и не знаю. Про мак вообще ничего не знаю, но на винде есть тоже свой "протокол" ASIO, который по сути ближе просто к сырому ALSA: вот устройство, у меня все; но при этом ASIO имеет какое-то микширование где-то, так что видимо ближе к JACK. Но вот что я знаю точно, что на ASIO нельзя записывать с одного устройства, и выводить звук на другой, даже с небольшой задержкой. Либо стандартные протоколы и секунды задержки, либо только 1 устройство. А на линуксе я могу спокойно записывать гитару со звуковой карты, а выводить на колонки ноутбука!
И зачем мне это все?
А я шо, я тоже не знаю. Я тоже знать этого не хотел 5 часов назад, я просто хотел записать гитару. А теперь вот тут сижу пост дописываю.
Как говорил мой дед, the more you know, the more you know.
Я, если честно, не уверен, что линукс где-то прям используется энтерпрайзом массивно для звука, но вообще не удивился бы. Потому что челы реально посмотрели этот видос и сказали "блин вот это тема, в которой никто никогда не разберется, но теоретически можно хоть ракету в космос запустить. А давайте так же сделаем?" И сделали.
Вообще идея прикольная, ну знаете так, чтобы услышать и никогда не трогать. Вместо того, чтобы полить все маслом под названием "задержка до луны и обратно", здесь решили дать возможность конфигурировать все и вся. Вот у тебя вход, можешь руками показать куда ему идти, вот тут в конфигах лично для него написать sample rate, bit depth, формат данных, длину окна периода, headroom и использовать ли mmap или нет (jokes on you но я в какой-то момент реально подумал, что для меня фикс был в этом).
Короче классический линукс, ничего удивительного.
А, нет, нет же! Удивительно то, что даже из коробки оно работает, работает намного лучше PulseAudio (по задержке), и одной строчкой в конфиге делается еще лучше! Жаль, что до задержки сырого ALSA так и не дошел.
(Нет, я не сделал это все за 5 минут, потому что выбрал не тот, сцука, тип инпута со звуковухи, он ТРЕЩАЛ, но просто сменой типа он ПЕРЕСТАВАЛ)
А в других системах то что?
А я и не знаю. Про мак вообще ничего не знаю, но на винде есть тоже свой "протокол" ASIO, который по сути ближе просто к сырому ALSA: вот устройство, у меня все; но при этом ASIO имеет какое-то микширование где-то, так что видимо ближе к JACK. Но вот что я знаю точно, что на ASIO нельзя записывать с одного устройства, и выводить звук на другой, даже с небольшой задержкой. Либо стандартные протоколы и секунды задержки, либо только 1 устройство. А на линуксе я могу спокойно записывать гитару со звуковой карты, а выводить на колонки ноутбука!
И зачем мне это все?
А я шо, я тоже не знаю. Я тоже знать этого не хотел 5 часов назад, я просто хотел записать гитару. А теперь вот тут сижу пост дописываю.
Как говорил мой дед, the more you know, the more you know.
👍6
Люди из гугла сделали "фронтэнд" вокруг гита, который по первым впечатлениям выглядит очень хорошо
https://github.com/martinvonz/jj
Я сам давно смотрел на https://pijul.org/, но меня отторгало то, что для него нужна полностью своя экосистема (система PRов, CI/CD, сайтик, где можно смотреть репу в браузере и т.д.)
А тут с одной стороны вдохновлялись лучшими дизайнами других VCS, а с другой в результате у тебя все та же гит репа, которую ты можешь пушнуть на гитхаб
Главная разница:
вместо того, чтобы работать "на текущем коммите, который находится внутри ветки", и добавлять "новый коммит на основе старого коммита, который находитсяв доме который построил Джек внутри ветки",
вы работаете с "изменениями", которые не привязаны к чему-то. Просто какой-то дифф. Эти изменения можно потом чейнить/мерджить между собой, и "тегать" в ветки
В итоге, у вас появляется огромная гибкость в том, как именно вы пишете историю. Знаете вот эти все проблемы с тем, чтобы замерджить один маленький фикс из одной ветки в другую, или походить по разным веткам с "грязным" working copy - с этим подходом такие проблемы должны решаться намного проще.
Ну и в добавок нормальный UI (The user interface is not only reasonable but actually really good: an idea borrowed from… literally every VCS other than Git) и quality of life фичи (тот же working copy автоматически коммитится, то есть никаких больше
Если хотите начать, есть довольно подробный гайд: https://v5.chriskrycho.com/essays/jj-init/
disclaimer: я пока только почитал про jj, и попробовать не успел, поэтому могу где-то врать
https://github.com/martinvonz/jj
Я сам давно смотрел на https://pijul.org/, но меня отторгало то, что для него нужна полностью своя экосистема (система PRов, CI/CD, сайтик, где можно смотреть репу в браузере и т.д.)
А тут с одной стороны вдохновлялись лучшими дизайнами других VCS, а с другой в результате у тебя все та же гит репа, которую ты можешь пушнуть на гитхаб
Главная разница:
вместо того, чтобы работать "на текущем коммите, который находится внутри ветки", и добавлять "новый коммит на основе старого коммита, который находится
вы работаете с "изменениями", которые не привязаны к чему-то. Просто какой-то дифф. Эти изменения можно потом чейнить/мерджить между собой, и "тегать" в ветки
В итоге, у вас появляется огромная гибкость в том, как именно вы пишете историю. Знаете вот эти все проблемы с тем, чтобы замерджить один маленький фикс из одной ветки в другую, или походить по разным веткам с "грязным" working copy - с этим подходом такие проблемы должны решаться намного проще.
Ну и в добавок нормальный UI (The user interface is not only reasonable but actually really good: an idea borrowed from… literally every VCS other than Git) и quality of life фичи (тот же working copy автоматически коммитится, то есть никаких больше
git stash && git checkout XXX && git pop
)Если хотите начать, есть довольно подробный гайд: https://v5.chriskrycho.com/essays/jj-init/
disclaimer: я пока только почитал про jj, и попробовать не успел, поэтому могу где-то врать
👍3
Blazingly 🔥 fast 🚀 memory vulnerabilities, written in 100% safe Rust. 🦀
https://github.com/Speykious/cve-rs
Нашли багу Красиво оформили старую багу в проверке лайфтаймов в компиляторе раста
TL;DR: в этом месте вся магия
https://github.com/Speykious/cve-rs/blob/main/src/lifetime_expansion.rs
И происходит там что-то такое:
Пусть есть два лайфтайма
Из этого следует, что в таком контексте конвертация
Это делает первая функция:
И, как написано в комментариях, сама по себе она ничего не нарушает.
А дальше мы просто засовываем вместо
Компилятор должен сделать две вещи:
Подставить вместо
Все, раст сломали, возвращаемся в плюсы?
Конечно же нет, с точки зрения математической модели тут очевидно есть ошибка, и по сути тут просто обычный баг в компиляторе, что он что-то не проверил/проверил неправильно.
Думаю, скоро пофиксят. UPD: Проблема эта старая и давно известная. К сожалению, комплиятор внутри довольно сложно устроен, и просто "закостылять" такую ошибку довольно сложно. Поэтому коммьюнити ждет, когда некоторые большие изменения во внутренней работе компилятора будут вмержены (основная - новый trait solver), и либо эти изменения сразу пофиксят эту проблему, либо на основе них будет намного проще
P.S. а еще там очень забавная лицензия
https://github.com/Speykious/cve-rs
TL;DR: в этом месте вся магия
https://github.com/Speykious/cve-rs/blob/main/src/lifetime_expansion.rs
Для незнающих: лайфтайм в расте это как бы время жизни переменной. Он существует только во время компиляции, и если очень грубо, то лайфтаймы можно описать на интуитивном уровне как "множество строчек между моментом, где переменная создалась, и где она закончила существовать".
И происходит там что-то такое:
Пусть есть два лайфтайма
'a, 'b
. Если в функцию передавать двойную ссылку &'a &'b
, то из этого следует, что 'b: 'a
, т.е. 'b
должен жить дольше, чем 'a
(иначе, существует момент, в котором верхняя ссылка жива, а внутренняя - нет). Это похоже на множественные операции: 'a
является подмножеством 'b
.Из этого следует, что в таком контексте конвертация
&'b -> &'a
является безопасной: как на множествах, 'a' является частью множества
'b`, и в расте (очевидно) можно конвертировать лайфтаймы в их "подмножества".Это делает первая функция:
// val_a тут только для создания ограничений на лайфтаймы
pub const fn lifetime_translator<'a, 'b, T>(_val_a: &'a &'b (), val_b: &'b T) -> &'a T {
val_b
}
И, как написано в комментариях, сама по себе она ничего не нарушает.
А дальше мы просто засовываем вместо
val_a
переменную с &'static &'static
лайфтаймами ('static
по сути значит, что переменная живет все время выполнения программы, например, такой лайфтайм у констант). И тут компилятор ломается, и почему-то не проверяет, что вызов функции lifetime_translator
невалидный. Это довольно важное замечение: сама функция валидна, но этот конкретный вызов - нет. У функции есть ограничения на лайфтаймы, и мы их по факту не прошли, но компилятор при этом не поругался.Компилятор должен сделать две вещи:
Подставить вместо
'b
минимальный лайфтайм из val_a
и val_b
, а потом проверить, что 'b: 'a
. Но из-за того, что ограничение на лайфтаймы написано не явно, а через двойную ссылку, то компилятор делает эти две вещи отдельно: сначала проверяет, что двойная ссылка валидна (условие 'b: 'a
), а потом подставляет лайфтайм, и на этом как раз и ломаетсяВсе, раст сломали, возвращаемся в плюсы?
Конечно же нет, с точки зрения математической модели тут очевидно есть ошибка, и по сути тут просто обычный баг в компиляторе, что он что-то не проверил/проверил неправильно.
P.S. а еще там очень забавная лицензия
👍5🤡1
Pointers Are Complicated
ого пост не про раст
Правда ли, что при компиляции корректно (и полезно) считать указатели на память просто "числами"?
Утверждается, что нет, а самое забавное - дополнительная информация может быть динамической в контексте компиляции (ци шо)
https://www.ralfj.de/blog/2020/12/14/provenance.html
Я не буду пересказывать статью, лучше сходите сами почитайте, но попробую добавить пару вещей:
Когда мы говорим о метадате для компиляции, мы обычно говорим о чем-то статическом, что зафиксированно в коде: типы переменных, какие-нибудь подсказки для компилятора аля
В статье приводится довольно сложный пример того, когда считать указатели "просто числами" является некорректным, но как будто идея раскрывается не совсем полностью. Pointer provenance это по сути идея добавлять для каждой переменной (не для типа!) с типом указателя метаданные аля "какой кусок памяти является валидным для этого указателя" и/или "откуда этот указатель появился".
Тогда, компилятор может не только запрещать невалидные оптимизации, но и разрешать делать дополнительные (опять же, эти оптимизации в контексте функции могут быть валидными, но индивидуально могут быть неправильными, если дополнительных ограничений на указатель нет)
1. Например, если мы знаем, что у нас есть указатель на 10 элементов, то мы не можем смотреть дальше него (т.к. это UB) (пример придумывать лень)
2. Помимо этого, если мы знаем, что два указателя появляются из двух разных мест (аля два разных вызова malloc), то мы знаем, что они не могут пересекаться по памяти (классический пример это оптимизации раста, которые он делает, т.к. у него этот инвариант всегда "включен")
3. Комбинации предыдущих: делаем указатель на кусок памяти, получаем другой указатель из первого - все еще знаем, что он не может указывать за пределы первого
Вот так считаешь всю жизнькомпьютеры детерменированными машинами все данные как битики и байтики, а потом на тебе...
Правда ли, что при компиляции корректно (и полезно) считать указатели на память просто "числами"?
Утверждается, что нет, а самое забавное - дополнительная информация может быть динамической в контексте компиляции (ци шо)
https://www.ralfj.de/blog/2020/12/14/provenance.html
Я не буду пересказывать статью, лучше сходите сами почитайте, но попробую добавить пару вещей:
Когда мы говорим о метадате для компиляции, мы обычно говорим о чем-то статическом, что зафиксированно в коде: типы переменных, какие-нибудь подсказки для компилятора аля
__builtin_expect
и т.п. Но pointer provenance это динамическая метадата, в том смысле, что ее нужно считать во время компиляции, она зависит не только от типа, но и от конкретной переменной, для который мы ее считаем.В статье приводится довольно сложный пример того, когда считать указатели "просто числами" является некорректным, но как будто идея раскрывается не совсем полностью. Pointer provenance это по сути идея добавлять для каждой переменной (не для типа!) с типом указателя метаданные аля "какой кусок памяти является валидным для этого указателя" и/или "откуда этот указатель появился".
Тогда, компилятор может не только запрещать невалидные оптимизации, но и разрешать делать дополнительные (опять же, эти оптимизации в контексте функции могут быть валидными, но индивидуально могут быть неправильными, если дополнительных ограничений на указатель нет)
1. Например, если мы знаем, что у нас есть указатель на 10 элементов, то мы не можем смотреть дальше него (т.к. это UB) (пример придумывать лень)
2. Помимо этого, если мы знаем, что два указателя появляются из двух разных мест (аля два разных вызова malloc), то мы знаем, что они не могут пересекаться по памяти (классический пример это оптимизации раста, которые он делает, т.к. у него этот инвариант всегда "включен")
3. Комбинации предыдущих: делаем указатель на кусок памяти, получаем другой указатель из первого - все еще знаем, что он не может указывать за пределы первого
Вот так считаешь всю жизнь
www.ralfj.de
Pointers Are Complicated II, or: We need better language specs
Some time ago, I wrote a blog post about how there’s more to a pointer than meets the eye. One key point I was trying to make is that just because two pointers point to the same address...
👍4🔥3
Моя главная боль с C++
Это сборка. Насрать на систему типов, насрать на "компилятор все проверяет". Изначально я пошел учить Rust только из-за того, что я попробовал Go, у которого прекрасная система сборки, и понял, что дальше так жить нельзя и я не хочу больше страдать со сборкой. Не из-за safety, из-за
Для меня всю мою жизнь стандартом было потратить несколько часов чтобы научиться собирать один файлик в плюсах. При этом с каждым годом я все больше и больше начинал разбираться в сборке, я даже могу сказать, что сейчас я что-то понимаю в cmake (sic!), но при этом я все еще трачу несколько часов на то, чтобы собрать один файлик
И вы не поверите, это случилось опять
Имеем две папки, содержимое файлов абсолютно одинаковое, хедер пустой, .cpp содержит элементарный hello world (он даже не инлюдит хедер).
Последняя команда генерировалась cmake'ом (тут она упрощена), я ее не из головы взял
Ошибка компиляции намекает на какую-то проблему со стандартной библиотекой, которая никак не гуглится
...
Вот так я в очередной раз не могу собрать один (ладно два) файлик в плюсах второй час
У меня уже нет слов, я просто устал, я просто хочу
Это сборка. Насрать на систему типов, насрать на "компилятор все проверяет". Изначально я пошел учить Rust только из-за того, что я попробовал Go, у которого прекрасная система сборки, и понял, что дальше так жить нельзя и я не хочу больше страдать со сборкой. Не из-за safety, из-за
cargo run
. Для меня всю мою жизнь стандартом было потратить несколько часов чтобы научиться собирать один файлик в плюсах. При этом с каждым годом я все больше и больше начинал разбираться в сборке, я даже могу сказать, что сейчас я что-то понимаю в cmake (sic!), но при этом я все еще трачу несколько часов на то, чтобы собрать один файлик
И вы не поверите, это случилось опять
Имеем две папки, содержимое файлов абсолютно одинаковое, хедер пустой, .cpp содержит элементарный hello world (он даже не инлюдит хедер).
.
├── features
│ ├── features.cpp
│ └── features.h
└── test
├── test.cpp
└── test.h
clang++ test/test.cpp # ok
clang++ -I/home/leviska/projects/personal/test/test test/test.cpp # ok
clang++ features/features.cpp # ok
clang++ -I/home/leviska/projects/personal/test/features features/features.cpp # fail
Последняя команда генерировалась cmake'ом (тут она упрощена), я ее не из головы взял
Ошибка компиляции намекает на какую-то проблему со стандартной библиотекой, которая никак не гуглится
...
Вот так я в очередной раз не могу собрать один (ладно два) файлик в плюсах второй час
У меня уже нет слов, я просто устал, я просто хочу
cargo run
, но для плюсов. И не говорите мне, что cmake
это тоже самое, как видите - нет.👍6🤔4
Panic! At the 0xC0D3
Моя главная боль с C++ Это сборка. Насрать на систему типов, насрать на "компилятор все проверяет". Изначально я пошел учить Rust только из-за того, что я попробовал Go, у которого прекрасная система сборки, и понял, что дальше так жить нельзя и я не хочу…
Люди про плюсы часто говорят, что "ну это просто инструмент, иногда плюсы для каких-то задач лучше подходят"
И я даже согласен с этим, я знаю примеры, когда C/C++ реально может быть удобнее Rust (да те же легаси кодовые базы)
Но меня никогда не покидает ощущение, что плюсы это "молоток", но то у него рукоятка сломается, то оголовье слетит
У меня после таких моментов просто пропадает все желание программировать
И я даже согласен с этим, я знаю примеры, когда C/C++ реально может быть удобнее Rust (да те же легаси кодовые базы)
Но меня никогда не покидает ощущение, что плюсы это "молоток", но то у него рукоятка сломается, то оголовье слетит
У меня после таких моментов просто пропадает все желание программировать
👍5🔥1🤔1
Use this simple trick to speedup catboost preparing dataset up to 210 times (21000%)
Я недавно оптимизировал пайплайн обучения катбуста, и наткнулся на странную вещь: инициализация
Гуглеж почему он может занимать много времени или как это ускорить не выдал абсолютно ничего, что сделало эту проблему еще веселее
Т.к. идей у меня больше не было, пришлось идти писать тестовый скрипт и pprofать его, и... ну я нашел проблему, больше сказать нечего
Оказывается, катбуст умеет копировать указатель только в одном очень аккуратном супер идеальном случае: это numpy массив(пока pyarrow), массив именно np.float32, и он непрерывный. В целом разумно, тут проблем нет.
Вопрос в том, что будет, если вы не дай бог передадите np.float64? Катбусту же много лет, над ним трудится кучастудентов людей, и все простые оптимизации уже были наверняка сделаны, подумаете вы
...
(буквально это но на cython)
Да, катбуст пойдет проверять тип каждого элемента. Да, это займет вечность.
Короче дамы и господа, передавайте катбусту только numpy массивы и только float32, и будет вам счастье.
А я сделал им ишьюи буду ждать когда они скажут, что это я дурак а они молодцы UPD: они согласились что это надо пофиксить!!!
Я недавно оптимизировал пайплайн обучения катбуста, и наткнулся на странную вещь: инициализация
catboost.Pool
занимает ну адски много времени (больше, чем обучение), хотя я ему передаю подготовленные нампай массивы в идеальном виде, и казалось бы ему надо просто указатель скопировать. Гуглеж почему он может занимать много времени или как это ускорить не выдал абсолютно ничего, что сделало эту проблему еще веселее
Т.к. идей у меня больше не было, пришлось идти писать тестовый скрипт и pprofать его, и... ну я нашел проблему, больше сказать нечего
Оказывается, катбуст умеет копировать указатель только в одном очень аккуратном супер идеальном случае: это numpy массив
Вопрос в том, что будет, если вы не дай бог передадите np.float64? Катбусту же много лет, над ним трудится куча
...
for i in range(len(x)):
if type(x[i]) == float:
res[i] = x[i]
(буквально это но на cython)
Да, катбуст пойдет проверять тип каждого элемента. Да, это займет вечность.
Короче дамы и господа, передавайте катбусту только numpy массивы и только float32, и будет вам счастье.
А я сделал им ишью
GitHub
Optimize catboost pool initialization for np.float64 case · Issue #2847 · catboost/catboost
I have a simple test code: import numpy as np import catboost from datetime import datetime print(catboost.version.VERSION) start = datetime.now() shape = (1024 * 1024 // 8, 1024) # 1 gig of floats...
🔥6😁5🤡1