1.9K subscribers
3.43K photos
134 videos
15 files
3.67K links
Блог со звёздочкой.

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

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

Quickly prototype procedural macros using JavaScript or TypeScript!

crates.io/crates/js-macros
👍5
Помнится, в первые дни после переезда я задавался вопросом, как армяне — местные — переносят жару: по идее, более привычные.

Оказалось, никак не переносят — точно так же сидят по домам с кондиционерами
😁12👍10🔥4🌚1
#prog #rust

У Linux есть чудесная технология eBPF. Если коротко, то это виртуальная машина с JIT-компиляцией, которая работает в контексте ядра и потому имеет доступ к его структурам и может вызываться на входе и выходе конкретных функций ядра, а также верификатор, который проверяет, что программы, исполняемые на этой виртуальной машине, всегда завершаются.

К сожалению, непосредственное взаимодействие со всем API, которое ядро для этого даёт, осуществляется через системный вызов bpf:

int bpf(int cmd, union bpf_attr *attr, unsigned int size);


Работать с этим интерфейсом не очень удобно, поэтому разработчики ядра также предоставляют библиотеку libbpf, которая даёт более внятный интерфейс — с отдельными функциями и внятными аргументами для того, что в системном вызове делается через комбинацию аргументов и заполнение bpf_attr. Ожидаемо, для этой библиотеки есть обёртка для использования из Rust: libbpf-rs. Она предоставляет более дружелюбный к Rust API и использует его систему типов для того, чтобы соблюдать инварианты, которые в сишном коде записаны лишь в документации.

В силу крайне высоких ограничений на размеры BPF-программ сколько-нибудь насыщенную логику непосредственно в них писать нереально — на практике в них, как правило, только собирают информацию и передают их в юзерспейс. Для (в том числе) поддержки этой задачи специально для BPF-кода есть мапы (maps). К ним можно осуществлять доступ как и из BPF-кода, так и из юзерспейса. Разновидностей мап несколько, с разными возможностями. Один из типов — кольцевой буфер (ringbuf), для асинхронной передачи произвольных данных и поддерживающий многопоточный доступ.

В юзерспейс-составляющей API этого кольцевого буфера есть несколько функций. Одна из них опрашивает кольцевой буфер на предмет наличия новых данных и вызывает на них пользовательские коллбеки. Эти коллбеки предварительно регистрируются функцией ring_buffer__add:

int ring_buffer__add(
struct ring_buffer *rb,
int map_fd,
ring_buffer_sample_fn sample_cb,
void *ctx
)


, где ring_buffer_sample_fn является typedef-ом на тип коллбека:

typedef int (*ring_buffer_sample_fn)(void *ctx, void *data, size_t size);


Как видите, разработчики libbpf избежали позорной ошибки дизайна qsort и предоставили возможность привязать к коллбеку произвольный контекст, который передаётся в него аргументом.

Библиотека libbpf-rs, хоть и не полностью покрывает API libbpf, всё же даёт возможность регистрировать пользовательские коллбеки со стороны Rust:

impl<'slf, 'cb> struct RingBufferBuilder<'slf, 'cb> {
pub fn add<NewF>(
&mut self,
map: &'slf MapHandle,
callback: NewF
) -> Result<&mut Self>
where
NewF: FnMut(&[u8]) -> i32 + 'cb;
}


Как видите, libbpf-rs даёт возможность прикреплять растовые замыкания. Но погодите-ка, как это работает, если сишное API работает только с указателями на функции, а растовые замыкания нельзя (по крайней мере, на стабильной версии) распилить на код и захваченные данные?

libbpf-rs использует этот контекстный параметр! Именно, метод RingBufferBuilder::add боксит замыкание и сохраняет его в векторе в виде Box<dyn FnMut(&[u8]) -> i32 + 'cb>, а в методе RingBufferBuilder::build итерируется по сохранённым коллбекам, переводит их в тонкие сырые указатели через Box::into_raw(Box::new(callback)) и передаёт его как параметр ctx в ring_buffer__new или ring_buffer__add. В обоих случаях в качестве сишного коллбека передаётся эта функция, которая просто распаковывает настоящий коллбек из контекста и вызывает его:

unsafe extern "C" fn call_sample_cb(
ctx: *mut c_void,
data: *mut c_void,
size: c_ulong
) -> i32 {
let callback_struct = ctx as *mut RingBufferCallback<'_>;
let callback = unsafe { (*callback_struct).cb.as_mut() };
let slice = unsafe {
slice::from_raw_parts(
data as *const u8,
size as usize,
)
};

callback(slice)
}


Так что вот неожиданный пример, как дальновидность со стороны изначальных разработчиков может быть использована так, как они и не думали.
19👍8🤯3🔥2😐1
Друг ищет специалиста, папищеки, помогите, пожалуйста.
Forwarded from Kim-Cat (Cosplay, Design, Model) (Ким-Кэт (ArkStranger))
Друзья, серьёзная просьба к вам.

Посоветуйте, пожалуйста, психолога или психотерапевта в Петербурге, который работает с мужчинами со следующими проблемами:

* Эмоциональная закрытость;
* Недоверие к людям и их отторжение;
* Тревожность;
* Стремление угодить другим, и при этом неспособность радовать себя;
* Низкая самооценка;
* Нарциссические черты характера;
* Вспыльчивость.

На этот раз я твёрдо намерен себе помочь. Писать сюда: @dakmmail

Заранее большое спасибо.
🤣17🫡12🤝3🎉2🤡2😢1
Блог* pinned a photo
Forwarded from Neural Machine
Боюсь, я из тех, кого нужно пинать несколько раз в день.
😢4👍3💯2😭1
😁26🔥4👍2🌚2
#prog #article

How single-iteration InstCombine improves LLVM compile time

Проход оптимизации InstCombine в LLVM является сборником peephole оптимизаций — то есть оптимизаций, которые ищут короткие конкретные паттерны в исходном коде и заменяют на эквивалентные, но более эффективные. Например, замена x / 2 на x >> 1, или замена x + y == y на x == 0.

Исторически InstCombine работал до достижения неподвижной точки — то есть прогонял всю пачку трансформаций снова и снова, пока трансформации не переставали вносить изменения в код. Однако InstCombine — довольно дорогой проход оптимизации, и на практике на этот цикл уходило довольно много времени компиляции. Более того, замеры показали, что этот цикл избыточен: в подавляющем большинстве случаев (>99,9%) одной итерации было достаточно.

Статья рассказывает о том, как InstCombine перевели на одну итерацию — вместе с информацией о технических деталях, которые пришлось поменять попутно. Это изменение в итоге привело к снижению времени компиляции на 4%.

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

(thanks @itpgchannel)
👍8
Forwarded from David Eritsyan
Кек.
😁21👎1
Ты исправляешь предупреждения компилятора, чтобы сделать свой код лучше.

Я исправляю предупреждения компилятора, чтобы избавиться от назойливых подчёркиваний в IDE.

Мы не одинаковы.
👍241
Ну, допустим, #meme про любовь
❤‍🔥17
#prog #c #shell #menacingopensource

🥜 Pnut: A Self-Compiling C Transpiler Targeting Human-Readable POSIX Shell

int sum(int* a, int len) {
int i, sum = 0;
for (i = 0; i < len; i += 1) {
sum += a[i];
}
return sum;
}

⬇️

#!/bin/sh
set -e -u

: $((sum = i = len = a = 0))
_sum() { let a $2; let len $3
let i; let sum
sum=0
i=0
while [ $i -lt $len ] ; do
: $((sum += _$((a + i))))
: $((i += 1))
done
: $(($1 = sum))
endlet $1 sum i len a
}

# Runtime library
# Local variables
__=0
__SP=0
let() { # $1: variable name, $2: value (optional)
: $((__SP += 1)) $((__$__SP=$1)) # Push
: $(($1=${2-0})) # Init
}
endlet() { # $1: return variable
# $2...: function local variables
__ret=$1 # Don't overwrite return value
: $((__tmp = $__ret))
while [ $# -ge 2 ]; do
: $(($2 = __$__SP)) $((__SP -= 1)); # Pop
shift;
done
: $(($__ret=__tmp)) # Restore return value
}
🤯14😁1
#science #meme про физику (и точно не про магию)
Forwarded from RWPS::Mirror
❤‍🔥10👍3