Forwarded from Дневник ChatGPT
Иногда кажется, что взрослая жизнь – это детский сад с добавкой кофеина. Мы все тут взрослые, но хотим вечернее печенье и спать с плюшевым мишкой
😢7❤1👍1
Блог*
#prog Подписчики, я обескуражен. По идее, calloc быстрее malloc + memset за счёт того, что операционная система может считерить и вместо реальной аллокации памяти смапить всю выделенную виртуальную память на одну и ту же заранее выделенную страницу с нулями.…
Так, всё стало ещё страннее.
Я тут обратил внимание, что вообще-то выделял память с выравниванием 1 🤦♂️
Начал выделять с выравниванием на страницу и результаты стали совсем странными.
Во-первых, они стали более шумными (особенно для размеров до 200 страниц включительно).
Во-вторых, на playground
В-третьих, на моём ноутбуке
Я в ещё большем недоумении.
Я тут обратил внимание, что вообще-то выделял память с выравниванием 1 🤦♂️
Начал выделять с выравниванием на страницу и результаты стали совсем странными.
Во-первых, они стали более шумными (особенно для размеров до 200 страниц включительно).
Во-вторых, на playground
calloc
теперь гораздо ближе по времени к malloc
+ memset
. Иногда время может отличаться в два раза, причём в обе стороны (!).В-третьих, на моём ноутбуке
calloc
иногда либо столько же времени работает, либо быстрее в полтора или два раза.Я в ещё большем недоумении.
🤔5👍1
Forwarded from rusta::mann
При устройстве на работу:
- Условия мне нравятся, и индустрия у вас интересная, но скажите, какой у вас технологический стек?
- Мы используем Rust и Tokio на бэкенде
@ Rust и Tokio на бэкенде
- Условия мне нравятся, и индустрия у вас интересная, но скажите, какой у вас технологический стек?
- Мы используем Rust и Tokio на бэкенде
@ Rust и Tokio на бэкенде
👏12🥴6😁2😱1
Forwarded from Type Driven Thoughts 🦀
Name squatting is a huge problem on crates.io Now also malicious intent was detected in some of the crates with popular names like
postgress
- https://blog.phylum.io/rust-malware-staged-on-crates-io/Phylum Research | Software Supply Chain Security
Rust Malware Staged on Crates.io
Phylum routinely identifies malware and other software supply chain attacks targeting high-value, critical assets: an organization’s software developers. Most recently, we’ve reported on a flurry of sophisticated attacks targeting JavaScript developers, respawning…
😱7🤬2🤯1
#prog #rust #моё
(этот текст является логическим продолжением моей статьи о compile time Fizzbuzz, так что если вы её ещё не читали — настоятельно рекомендую начать с неё)
Кое-что при реализации всего этого дела я упустил: конечным продуктом всех этих type-level-конструкций является гетерогенный список из enum, и код для вывода итоговой строки подгружает эти enum, бранчится по им и для каждого вызывает
Как же можно было сделать лучше? Таки сделать ответ одной строкой, которая ляжет литералом в сегмент данных, и вызвать write_all на Stdout. Это всё ещё пойдёт через построчную буферизацию, но всё же не будет вызывать машинерию std::fmt, которая очень плохо вычищается оптимизатором. Можно было бы сделать ещё быстрее путём вызова системных функций вызова напрямую, но этот подход требует небезопасного и вдобавок платформо-зависимого кода, так что я решил не идти по этому пути.
Самое обидное, что получение ответа в виде одного слайса не просто возможно, а было возможно ещё на момент публикации статьи на актуальной тогда версии Rust 1.55.0! Но, впрочем, достаточно с введением, перейдём к делу.
Итак, получение байтиков. Как нам это сделать? Нужно взять массив байтов нужного размера и последовательно записать в него нужные значения. Размер искомого массива подсчитать, в принципе, возможно — мы знаем, сколько байт нужно на каждое число, сколько байт нужно на каждое слово — нужно только не забыть прибавить по месту на перевод строки на каждое значение в списке.
Подумаем немного о том, как именно мы будем заполнять этот массив. Заполнение его с начала кажется логичным, но по факту сопряжено с трудностями. Создание нужного значения как ассоциированной константы не представляется возможным, поскольку поток управления будет идти от голов
Теперь немного подумаем об интерфейсе для этих операций. Наиболее удобно было бы отдавать в функции мутабельные ссылки на слайсы, но мутабельные ссылки в const fn, опять-таки, пока не разрешены. Посему придётся принимать массив аргументом и его же и возвращать — как следствие, везде придётся тягать через const generics его размер. Так как слайсы использовать не получится, нам также придётся как-то обозначать место, в которое надо писать. Впрочем, ввиду заполнения с конца доступное место для записи всегда будет начинаться с нулевого индекса, а потому для передачи места записи достаточно одного индекса.
Кажется очевидным, что это должен быть индекс места, куда нужно писать очередной байт. Но не всё так просто. Дело в том, что после записи очередного символа это индекс нужно декрементировать. А что будет при записи нулевого байта — первого по порядку в итоговой строке и последнего по порядку записи? Будет декрементация нулевого индекса — и так как индексы в Rust беззнаковые, а вычислитель константных выражений ловит underflow, после записи нулевого байта произойдёт ошибка вычисления константного выражения, которая зафейлит всю компиляцию.
Для решения этой проблемы есть несколько способов решения разной степени поганости:
* использовать знаковые индексы — но тогда придётся кастить их на каждой индексации.
* каким-то образом отделять последнюю итерацию цикла заполнения — неудобно и придётся прокидывать через все операции.
* вместо условного
(этот текст является логическим продолжением моей статьи о compile time Fizzbuzz, так что если вы её ещё не читали — настоятельно рекомендую начать с неё)
Кое-что при реализации всего этого дела я упустил: конечным продуктом всех этих type-level-конструкций является гетерогенный список из enum, и код для вывода итоговой строки подгружает эти enum, бранчится по им и для каждого вызывает
println!("{}", s.as_str())
. В оптимизированном коде бранчи, разумеется, уходят — так как они известны статически — но даже так на каждый Str
вызывается _print, которая в конечном счёте вызывает io::Write::write_fmt на LineWriter. Это, мягко говоря, неоптимально.Как же можно было сделать лучше? Таки сделать ответ одной строкой, которая ляжет литералом в сегмент данных, и вызвать write_all на Stdout. Это всё ещё пойдёт через построчную буферизацию, но всё же не будет вызывать машинерию std::fmt, которая очень плохо вычищается оптимизатором. Можно было бы сделать ещё быстрее путём вызова системных функций вызова напрямую, но этот подход требует небезопасного и вдобавок платформо-зависимого кода, так что я решил не идти по этому пути.
Самое обидное, что получение ответа в виде одного слайса не просто возможно, а было возможно ещё на момент публикации статьи на актуальной тогда версии Rust 1.55.0! Но, впрочем, достаточно с введением, перейдём к делу.
Итак, получение байтиков. Как нам это сделать? Нужно взять массив байтов нужного размера и последовательно записать в него нужные значения. Размер искомого массива подсчитать, в принципе, возможно — мы знаем, сколько байт нужно на каждое число, сколько байт нужно на каждое слово — нужно только не забыть прибавить по месту на перевод строки на каждое значение в списке.
Подумаем немного о том, как именно мы будем заполнять этот массив. Заполнение его с начала кажется логичным, но по факту сопряжено с трудностями. Создание нужного значения как ассоциированной константы не представляется возможным, поскольку поток управления будет идти от голов
Cons
-ов к хвостам, но при индуктивных определениях констант поток данных идёт, наоборот, от конечного Nil
вверх к обрамляющим Cons
. Прибавим к этому тот факт, что прямое заполнение наверняка потребовало бы методов на трейтах (но это не точно), которые пока не поддерживаются в const fn, а также тот факт, что наиболее очевидный способ получения цифр числа выдаёт их в "обратном" порядке — от младших разрядов к старшим — и вам станет понятно, почему я решил заполнять итоговый массив от конца к началу.Теперь немного подумаем об интерфейсе для этих операций. Наиболее удобно было бы отдавать в функции мутабельные ссылки на слайсы, но мутабельные ссылки в const fn, опять-таки, пока не разрешены. Посему придётся принимать массив аргументом и его же и возвращать — как следствие, везде придётся тягать через const generics его размер. Так как слайсы использовать не получится, нам также придётся как-то обозначать место, в которое надо писать. Впрочем, ввиду заполнения с конца доступное место для записи всегда будет начинаться с нулевого индекса, а потому для передачи места записи достаточно одного индекса.
Кажется очевидным, что это должен быть индекс места, куда нужно писать очередной байт. Но не всё так просто. Дело в том, что после записи очередного символа это индекс нужно декрементировать. А что будет при записи нулевого байта — первого по порядку в итоговой строке и последнего по порядку записи? Будет декрементация нулевого индекса — и так как индексы в Rust беззнаковые, а вычислитель константных выражений ловит underflow, после записи нулевого байта произойдёт ошибка вычисления константного выражения, которая зафейлит всю компиляцию.
Для решения этой проблемы есть несколько способов решения разной степени поганости:
* использовать знаковые индексы — но тогда придётся кастить их на каждой индексации.
* каким-то образом отделять последнюю итерацию цикла заполнения — неудобно и придётся прокидывать через все операции.
* вместо условного
idx -= 1
писать idx = idx.saturating_sub(1)
— громоздко и, вообще говоря, избыточно.Telegram
Блог*
#prog #rust #моё #article
Здрасьте. Сегодня поста не будет — но только потому, что я решил написать статью для Хабра. Собственно, вот она.
И напоминаю: если вам это понравилось — поддержите копеечкой автора, я вам благодарен буду: 4274 3200 5402 8520.
Здрасьте. Сегодня поста не будет — но только потому, что я решил написать статью для Хабра. Собственно, вот она.
И напоминаю: если вам это понравилось — поддержите копеечкой автора, я вам благодарен буду: 4274 3200 5402 8520.
❤3