1.98K subscribers
3.96K photos
157 videos
15 files
4.11K links
Блог со звёздочкой.

Много репостов, немножко программирования.

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
#prog #rust

Enabling the next-generation trait solver on nightly

И о том, что это значит для Rust
👍9🔥6
#prog #rust #rustreleasenotes

Вышел Rust 1.98.0! Как всегда, кусочки — тут, мясо — там.

▪️Обычно я пишу про новые вещи в порядке: фичи языка, добавления в std, изменения в cargo. В этот раз я напишу сначала про фичу, которая номинально является новым API в std, но которая даёт возможности, ранее невыразимые в языке (без использования интринсиков, по крайней мере).

Как известно, типы с плавающей точкой не обладают свойствами, которые имеются у действительных чисел в математике — в частности, у чисел с плавающей точкой сложение не является ассоциативной операцией. Это связывает руки оптимизатору, который обязан предохранять поведение. Например, если есть код типа

fn dot(a: &[f32], b: &[f32]) -> f32 {
let mut sum = 0.0;
for i in 0..a.len() {
sum += a[i] * b[i];
}
sum
}


, то компилятор обязан генерировать код, который считывает и суммирует произведения чисел из слайсов по одному. Он не может, скажем, векторизовать код, поскольку подобная трансформация неизбежно меняет порядок, в котором суммируются числа, и это может заметно повлиять на результаты (это, кстати, был мотивирующий пример для предложения добавить API, описанный ниже).

Типы f32 и f64 (а также f16 и f128, но их ещё не стабилизировали) обзавелись методами algebraic_{add, sub, mul, div, rem}. Они выполняют указанные арифметические операции, но, в отличие от обычных арифметических операций, оптимизатор может переупорядочивать их, используя тождества, справедливые для действительных чисел и, вообще говоря, неверные для чисел с плавающей точкой. Взамен компилятор в состоянии оптимизировать код значительно лучше — в частности, пример выше можно переписать в виде

fn dot(a: &[f32], b: &[f32]) -> f32 {
let mut sum = 0.0f32;
for i in 0..a.len() {
sum = sum.algebraic_add(a[i].algebraic_mul(b[i]));
}
sum
}


, и тогда генерируемый код теперь использует SIMD и на процессорах, поддерживающих набор инструкций AVX2, код может работать до восьми раз быстрее!

Данные операции идейно схожи с ключами -ffast-math, но обладают большей гранулярностью и, в отличие от них, не страдают от драконовских ограничений в виде UB на операциях с NaN.

▪️Компилятор теперь реагирует на #[no_mangle] функции, которые некорректно переопределяют функции, ожидаемые рантаймом (ошибка компиляции) и ожидаемые std (предупреждение).

▪️Компилятор теперь предупреждает, если функция возвращает core::ffi::c_void по значению. Тип void в C и C++ отображается на () в Rust, а c_void нужно использовать, только через указатель.

▪️Атрибут #[repr(transparent)] можно применить на структуру, где одно поле "значимо", а остальные имеют "тривиальные" типы. Ранее ими считались все типы нулевого размера с единичным выравниванием, но с этой версии из этого списка исключили #[repr(C)] типы, типы с приватными полями и #[non_exhaustive] типы.

▪️#[derive(PartialOrd)] в генерируемом коды теперь просто возвращает Some(self.cmp(rhs)), если используется одновременно с #[derive(Ord)]. Из-за ограничений инфраструктуры по раскрытию макросов есть забавная особенность: комбинации

#[derive(PartialOrd, Ord)]
struct A;

#[derive(Ord, PartialOrd)]
struct B;

#[derive(Ord)]
#[derive(PartialOrd)]
struct C;


получают упрощённый вариант кода, а вот

#[derive(PartialOrd)]
#[derive(Ord)]
struct D;


— нет.
14
#prog #rust

В Rust стабилизировали тип never. Да, опять. Но на этот раз вроде окончательно, все крейты, сломанные из-за смены фоллбека или получили апдейты, или дико старые. Если всё пройдёт гладко, дойдёт до stable в красивой версии 1.100.
🔥192
#prog #rust #article

Replacing a Rust Enum with a 64-bit Word Made My Interpreter 17% Faster

<...> That being said, sha256_unfixed is still running 12% faster with the new value representation than with the old version, even though it's allocating a total of 3,149,052 boxed integer values in a span of about 490 ms. That seemed a bit crazy to me, but having a copying GC with a bump allocator means that we can allocate objects really fast.
👍5🫡2
#prog #rust #article

How we saved 100 terabytes of memory by optimizing 1.1.1.1’s DNS cache

Big Pineapple, the platform behind 1.1.1.1, Gateway DNS, DNS Firewall, AS112, and several other Cloudflare DNS services, stores over 250 billion DNS cache entries at any given time. At that scale, wasting a single byte per entry costs more than 250 gigabytes of memory across our fleet.

Five successive changes to how cache entries are stored in memory cut the per-entry footprint by over 50%. Across our fleet, these changes freed up roughly 100 terabytes of memory, equivalent to the amount of RAM in 130 of our Gen 13 servers. The cache also got faster. Insert throughput rose 43% and lookup latency dropped 19%, as fewer allocations and better memory locality meant we did not trade speed for space.


Большая часть изменений довольно простая.
🎉7🔥2🤔2
#prog #rust #article

How I made Rustdoc 33% faster in one week

More than any technical detail, the learnings I most want you to take away are to trust your instincts and to question assumptions. Just because a piece of code (or anything, not just code!) has been a certain way for a long time doesn’t mean that it’s optimal or even correct.
👍71
#prog #js #abnormalprogramming #article

The Depths of JavaScript: Minesweeper in 247 Bytes

b=e=>document.body.innerHTML=m(73,e||[~9,..."1172711",~9].map(j=>m[i-=j]?++e:i).map(j=>b(b[i=j]^1|e),b[i]=!m[O--,i]*~e));b(m=t=>t--?`<a onmouseup=b(b[i=${t}]^=event.which)>${t%9?"*#F"[x=b[t]??=(O-=m[t]=Math.random()<.1,1)]??~x:"<p>"}`+m(t):O,O=64)
🔥13😱1
#prog #rust #article

iddqd, or the hardest kind of unsafe Rust

I’m the main author of iddqd, a Rust library for maps (named after the Doom cheat code) where keys are borrowed from values. <...>

iddqd consists of a fair amount of unsafe code underneath. There’s been some recent concern over the amount of unsafe code in Rust rewrites, so I thought I’d write about some of the unsafe code in iddqd and how we try to tame it.
🤔3
#prog #article

Implementing FMA and finding bugs in C and Rust standard libraries

This is a story of how I tried to compute a * b + c, and found that Rust and musl libc get it subtly wrong.
🤯8👍1
Блог*
#prog #rust #article Replacing a Rust Enum with a 64-bit Word Made My Interpreter 17% Faster <...> That being said, sha256_unfixed is still running 12% faster with the new value representation than with the old version, even though it's allocating a total…
#prog #rust #article

Plush's New Register-Based Interpreter Is Insanely Fast

I'll go into some detail on how the interpreter was rewritten to switch from a stack-based design like CPython, to a register-based design like Lua, and optimized to deliver some surprising, and I think pretty impressive results. One thing I'll say right away is that if you care about interpreter performance, you probably should not be writing stack-based bytecode interpreters in 2026.
🤔7👍1🔥1
#prog #rust #article

Could Cargo's scheduler be better?

Автор поста собрала записи того, сколько времени уходит на компиляцию каждого крейта во время сборки разных проектов, и решила проверить, можно ли было ускорить сборку за счёт использования порядка сборки, отличного от того, что используется в cargo. В качестве приоритета она использовала т. н. b-level — фактически критический путь в графе зависимостей в терминах длительности компиляции.

TL;DR: этот гипотетический вариант эффективнее cargo и переживает добавление нормально распределённого шума (с разбросом ±60%) и схлопывание информации о длительности до одного бита (долго/недолго).
5👍1
#prog #rust #rustlib #article

The Design Behind wincode, a Faster Rust Serializer

wincode is a fast, bincode-wire-compatible serializer and deserializer for Rust, built by Anza originally for the Agave validator. It is not a fork of bincode. It is a new implementation with its own traits and derive macros that produces the same bytes as bincode's default configuration


TL;DR: запись в предоставленный MaybeUninit буфер, батчинг валидаций для последовательностей "простых" значений, специализация по типам, использующая сгенерированную derive-макросами метаинформацию (facet на минималках)
🔥3🤔1
#prog #rust #article

Proving my Rust NVR doesn't leak memory (it did)

К сожалению, описанные методы диагностирования специфичны для MacOS
🤔2
#prog #article

Bespoke: A Programming Language for People Who Say Please

I therefore propose Bespoke, a statically typed and uncompromisingly civilised programming language for developers who believe that machine execution should never come at the expense of good manners. Informally it is known as The Queen’s Code: Victoria’s, naturally; the etiquette committee has yet to approve the twentieth century. Source files use the .charming extension, and the compiler reserves the right to be disappointed in you.
9😁2
🌚6🫡5🔥2😐2💯1
#prog #rust #article

Rust: When Empty Isn't Bottom

Или почему ! в Rust не является bottom типом. TL;DR: в Rust нет отношения подтипизации для типов, не включающих лайфтаймы.
4🤔2
#prog #java #article

JVM Anatomy Quark #23: Compressed References

Спека Java ничего не говорит о том, как представляются ссылки. Как следствие, реализации могут использовать представление ссылок, которые меньше указателя на машине. Статья описывает эти трюки.

Несколько неожиданное следствие: эти трюки работают только на достаточно маленьких кучах, поэтому выделение JVM большего количества памяти может привести к тому, что куча выйдет за этот предел, ссылки перестанут использовать компактное представление и потребление памяти многократно вырастет.
🥴4🤔3
#prog #haskell #article

Type-level programming is still programming

TL;DR: вычисление типов, в отличие от вычисления термов, не является ленивым, и изменения в логике вычисления типов, не меняющее поведение, могут поменять асимптотику времени компиляции с экспоненциальной на линейную.
7👍2🔥1💩1