Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.
Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support
Last updated 1 month ago
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 1 month, 3 weeks ago
Нет, я знал, что boost частично разрабатывают не иначе как no-life аутсайдеры, но это уже вопиющее ЧСВ. Морозить PR 2 недели от 2х людей, чтобы потом скопировать изменения, которые были предложены и залить их ПОД СВОИМ именем, да еще и НЕПРАВИЛЬНО, это конченый…
🫣 Как посчитать биты?
🤗 Это же тривиально!
В жизни каждого программиста наступает момент, когда встречаешься с задачей, эффективное решение которой нужно в 1% случаев, но решить которую всё равно интересно. Об одной из таких сегодня и пойдет речь.
Задача: посчитать количество возведенных битов в 64 битном значении. Просто? Тривиально? Быстрое решение - да.
```
#include
#include
#include
#include
int calc_set_bits(const uint64_t i64v) {
uint8_t bits_set = 0;
for (int i = 0; i < 64; i++) {
if (i64v >> i & 1) {
bits\_set++;
}
}
return bits\_set;
}
int main(int argc, char **argv) {
uint64_t i64v;
std::cin >> i64v;
std::cout << "Bits set: " << calc_set_bits(i64v) << std::endl;
}
```
Получаем вот такой ассемблерный выход (порезан до нужного):
calc\_set\_bits(unsigned long):
push rbp
mov rbp, rsp
mov qword ptr [rbp \- 8], rdi
mov byte ptr [rbp \- 9], 0
mov dword ptr [rbp \- 16], 0
.LBB0\_1:
cmp dword ptr [rbp \- 16], 64
jge .LBB0\_6
mov rax, qword ptr [rbp \- 8]
mov ecx, dword ptr [rbp \- 16]
shr rax, cl
and rax, 1
cmp rax, 0
je .LBB0\_4
mov al, byte ptr [rbp \- 9]
add al, 1
mov byte ptr [rbp \- 9], al
.LBB0\_4:
jmp .LBB0\_5
.LBB0\_5:
mov eax, dword ptr [rbp \- 16]
add eax, 1
mov dword ptr [rbp \- 16], eax
jmp .LBB0\_1
.LBB0\_6:
movzx eax, byte ptr [rbp \- 9]
pop rbp
ret
Видим тут простой цикл, и, в принципе, ровно то, что мы написали: смещение значения вправо на n битов и проверка младшего бита в цикле.
shr rax, cl
and rax, 1
cmp rax, 0
Но что будет, если мы воспользуемся функцией из стандартной библиотеки?
int calc\_set\_bits(const uint64\_t i64v) {
return std::popcount(i64v);
}
Соберем это дело командой clang++ ./main.cpp \-o bcnt.elf \-std=c++2a \-O0 \-g \-ggdb
и отладим внутрь.
```
lldb ./bcnt.elf
(lldb) b calc_set_bits(unsigned long)
(lldb) si ... # проваливаемся до std::__popcount
```
Вот тут-то мы и увидим нечто непонятное, но очень интересное, что работает очевидно быстрее, чем цикл. Давайте разбираться.
std::\_\_popcount<unsigned long>:
push rbp
mov rbp, rsp
mov qword ptr [rbp \- 0x8], rdi
\-> mov dword ptr [rbp \- 0xc], 0x40
mov dword ptr [rbp \- 0x10], 0x40
mov dword ptr [rbp \- 0x14], 0x40
mov dword ptr [rbp \- 0x18], 0x20
mov rcx, qword ptr [rbp \- 0x8]
mov rax, rcx
shr rax
movabs rdx, 0x5555555555555555
and rax, rdx
sub rcx, rax
movabs rdx, 0x3333333333333333
mov rax, rcx
and rax, rdx
shr rcx, 0x2
and rcx, rdx
add rax, rcx
mov rcx, rax
shr rcx, 0x4
add rax, rcx
movabs rcx, 0xf0f0f0f0f0f0f0f
and rax, rcx
movabs rcx, 0x101010101010101
imul rax, rcx
shr rax, 0x38
pop rbp
ret
🤗HAKMEM Item 169
☀️Как это работает?
С чего начать? Мы собирались clang, так что смотреть будем с него. Вот issue на GitHub, где эта оптимизация появилась для 8и битных чисел, интересно почитать, но интересует другое - понять, откуда этот алгоритм взялся и как он работает.
Вот тут чувак дает ссылки на статьи, но мне они не нравятся, зато дают наводку, куда читать (нормальные ссылку дам позже). Быстрым гуглежом констант с "HAKMEM" выясняем, что это HAKMEM Item 169, остается только изучить, как он работает.
Сам алгоритм выглядит так: ПРОДОЛЖЕНИЕ В КОММЕНТАРИЯХ
Для тех разработчиков и админов, кто столкнулся с проблемой ~~тепловой~~ смерти CentOS 7, но которым до сих пор нужно активно использовать ее в контейнерах/VM.
Скорее всего, просто пересобрать контейнер на CentOS 7 уже не получится, но есть варианты "оживить" ОС и обезопасить себя, отзеркалив некоторые репозитории и перенастроив mirror'ы.
Шаг 1 - Подключаем архивы
На этапе сборки образа переключаем апстрим репозитории на vault archive, который RH любезно держат поднятым (пока что).
```
#!/bin/bash
sed -i 's/mirrorlist/#mirrorlist/g' /etc/yum.repos.d/CentOS-;
sed -i 's|#baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-;
sed -i 's|# baseurl=http://mirror.centos.org|baseurl=http://vault.centos.org|g' /etc/yum.repos.d/CentOS-*;
```
Шаг 2 - Настраиваем дополнительные репозитории
Апстрим репозитории epel
и sclo
так же были перенесены в архив, но в архивных репозиториях при установке пакета epel\-release
устанавливаемые .repo
файлы будут продолжать смотреть на мертвый апстрим, так что ручками кладем файлы по пути /etc/yum.repos.d/
.
```
[epel7]
name=Extra Packages for Enterprise Linux 7 - $basearch
baseurl=https://archives.fedoraproject.org/pub/archive/epel/7/$basearch
enabled=1
gpgcheck=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
metadata_expire=never
[epel7-debuginfo]
name=Extra Packages for Enterprise Linux 7 - $basearch - Debug
baseurl=https://archives.fedoraproject.org/pub/archive/epel/7/$basearch/debug
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=0
metadata_expire=never
[epel7-source]
name=Extra Packages for Enterprise Linux 7 - $basearch - Source
baseurl=https://archives.fedoraproject.org/pub/archive/epel/7/SRPMS
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=0
metadata_expire=never
```
```
[centos-sclo-rh]
name=CentOS-7.9 - SCLo rh
baseurl=https://vault.centos.org/centos/7.9.2009/sclo/$basearch/rh/
gpgcheck=0
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo
[centos-sclo-sclo]
name=CentOS-7.9 - SCLo sclo
baseurl=https://vault.centos.org/centos/7.9.2009/sclo/$basearch/sclo/
gpgcheck=0
enabled=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-SIG-SCLo
```
* ПРОДОЛЖЕНИЕ В КОММЕНТАРИЯХ ***
Вот мы все любим шутейки про "сделано 90% работы, осталось сделать оставшиеся 90%", "последние 10% качества стоят нам 90% усилий", и так далее.
Я сейчас скажу довольно очевидную вещь, которая мне довольно долго не давалась.
Вот это вот умение вовремя остановиться, и сказать, что "от нас никто не ждет идеального результата, но ждут определенного качества за определенные деньги/ресурсы", пресловутое "и так сойдет" - это очень важно, и нужно иногда бить себя по рукам, и игнорировать свое чувство прекрасного, которое требует "еще немножечко better".
Нет, я знал, что boost частично разрабатывают не иначе как no-life аутсайдеры, но это уже вопиющее ЧСВ.
Морозить PR 2 недели от 2х людей, чтобы потом скопировать изменения, которые были предложены и залить их ПОД СВОИМ именем, да еще и НЕПРАВИЛЬНО, это конченый аутизм.
Сегодняшний герой залил патч в boost/process/v2
, который добавляет проверку версии glibc и MUSL при сборке проекта, чтобы понимать, можно использовать close_range()
или нет. НО! Во-первых, проверка наличия syscall'a опираясь на версию ядра хоть и имеет место быть, но ненадежна, лучше проверять SYS_close_range
. Во-вторых, если сборка будет проходить на новом ядре, НО со старым glibc
(а это частый кейс, чтобы расширить совместимость), вся программа сломается к херам и удачи это отладить. Почему так? А потому что он fallback'ается на сырой системный вызов. Нужно добавлять возможность явно отключать такие вещи. Типичный программист "на моей машине работает".
В-третьих, сука, еще и ЧСВ своё тешит тем, что копирует предложенные изменения под своим именем, типа это всё он подумал.
Для тех, кто пишет на C++ и использует vcpkg
. Я тут закинул пару системных библиотек, чтобы без боли можно было линковаться статически.
- libcgroup (v3.1.0) https://github.com/microsoft/vcpkg/pull/39647
- libaudit (v4.0.1) https://github.com/microsoft/vcpkg/pull/39587
Обе сильно порезаны при сборке, а libcgroup вообще нужно чинить в апстриме, так как при отключении интеграции с systemd
ломается umbrella include
, поэтому придется определять _LIBCGROUP_H_INSIDE
и писать свой мегаинклуд при использовании.
Architec.Ton is a ecosystem on the TON chain with non-custodial wallet, swap, apps catalog and launchpad.
Main app: @architec_ton_bot
Our Chat: @architec_ton
EU Channel: @architecton_eu
Twitter: x.com/architec_ton
Support: @architecton_support
Last updated 1 month ago
Канал для поиска исполнителей для разных задач и организации мини конкурсов
Last updated 1 month, 3 weeks ago