LINUX.ORG.RU

pictura-stainless 1.0.0 — легковесный аналог Pictura Noctis

 , , , ,

pictura-stainless 1.0.0 — легковесный аналог Pictura Noctis

1

2

Опубликован выпуск pictura-stainless 1.0.0 — утилиты для установки случайных обоев в Noctalia Shell (Quickshell). Проект создан как лёгкая и более быстрая альтернатива недавно вышедшей утилите Pictura Noctis, с добавлением поддержки других WM (автор использует sway).

Основные отличия

  • Скорость сборки и размер: программа не зависит от экосистемы крейтов и собирается Makefile слишком быстро.

  • Не все флаги совместимы.

  • Режим для скриптов: добавлен флаг -p, который печатает только путь к выбранному изображению, что упрощает использование утилиты c другими бэкендами обоев:

swaymsg output "*" bg "$(./pictura-stainless -p ~/Pictures/Wallpapers)" fill
Требования и сборка

Для сборки требуется GCC 13 или Clang 16 и выше:

git clone https://github.com/x6prl/pictura-stainless.git
cd pictura-stainless
make
make install PREFIX=$HOME/.local

GCC младше 14 и Clang младше 18:

make CSTD=gnu2x

Нестрипнутый исполняемый файл может показаться великоват

$./pictura-stainless -v
pictura-stainless 1.0.0
$du -h pictura-stainless
24K	pictura-stainless

Но strip позволит сократить его размер ещё на 4KБ.

Исходный код написан на языке Си и распространяется под лицензией GPLv3.

Автор отмечает, что альтернативная реализация не только значительно упрощает поддержку кода, но и положительно сказывается на производительности за счет использования современных подходов к управлению памятью. При этом сравнительных замеров не производилось, а оригинальный код Pictura Noctris не был даже скачан.

Инструкции по интеграции с вашим любимым WM

Собранные бинарники для x86_64 и aarch64

>>> Репозиторий проекта на GitHub

★★★★★

Проверено: hobbit ()
Последнее исправление: hobbit (всего исправлений: 3)
Ответ на: комментарий от BruteForce

Попробуй make CSTD=gnu2x

Так собирается и работает, да.

$ gcc --version
x86_64-alt-linux-gcc (GCC) 13.2.1 20240128 (ALT Sisyphus 13.2.1-alt3)
Copyright (C) 2023 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$

saahriktu ★★★★★
()
Ответ на: комментарий от thesis

Вот бы кто-то устроил нормальное сравнение разных вариантов установки случайных обоев в Noctalia Shell, а то выбора много, а что выбирать непонятно. У меня вот слишком маленькая коллекция фотографий, find + shuf отрабатывают за 18мс и едят 8-8.5 метров(

BruteForce ★★★★★
() автор топика
Ответ на: комментарий от BruteForce

что выбирать непонятно

Нужно попросить иишку налабать нормальный нестыдный комбайн по типу музыкального плейера. С библиотекой, превьюхами, историей, тегами, рейтингами, чтоб в инет лазало и т.д. А поверх этого раскатать соцсеть случайных любителей пощекотать обои в нокталия шелл.

thesis ★★★★★
()

Ну и лапшекод.

Алсо, почему -O2, а не -O3?

Нужны многопоточность, нормальные хэш-таблицы (ладно, там open addressing). И io_uring.

shdown ★★
()
Последнее исправление: shdown (всего исправлений: 1)
Ответ на: комментарий от BruteForce

Потестил на 1579 обоев. Это также слишком мало чтобы увидеть между ними ощутимую разницу.

Из неощутимой разницы - моя Pictura Noctis, по ходу, тщательнее синхронизируется с системными событиями и за счёт этого теряет ~10 мс времени.

Однако, диапазон времени выполнения у pictura-stainless и find | shuf значительно больше - до ±2,2 мс. У моей Pictura Noctis он ±0,3 мс.

saahriktu ★★★★★
()
Последнее исправление: saahriktu (всего исправлений: 1)
Ответ на: комментарий от saahriktu

О, вариант на Python самый тормозной. В 2 раза медленнее чем bash-версия.

saahriktu ★★★★★
()
Ответ на: комментарий от saahriktu

Ваше в 5.7 раз медленнее сабжа, в 3 раза медленнее find | shuf. Синтаксис repeat и time специфичен для zsh, переписывайте на bash сами.

[~/repo/pictura-noctis]-[%] repeat 5 time ./target/release/pictura_noctis --recursive --dry-run ~ 2>/dev/null >/dev/null 

real    5.27s
user    0.69s
sys 4.57s

real    5.40s
user    0.72s
sys 4.68s

real    5.24s
user    0.77s
sys 4.46s

real    5.25s
user    0.69s
sys 4.55s

real    5.24s
user    0.63s
sys 4.61s
[~/repo/pictura-noctis]-[%]
[~/repo/pictura-stainless]-[%] repeat 5 {time ./pictura-stainless --recursive --dry-run ~ 2>/dev/null} | sed 's/^chosen image path: .*$/REDACTED/'
found 1573853 files in 110388 checked directories
total images found: 154306
REDACTED

real    0.93s
user    0.10s
sys 0.83s
found 1573309 files in 110388 checked directories
total images found: 154306
REDACTED

real    0.91s
user    0.10s
sys 0.80s
found 1573354 files in 110388 checked directories
total images found: 154306
REDACTED

real    0.91s
user    0.06s
sys 0.84s
found 1573324 files in 110388 checked directories
total images found: 154306
REDACTED

real    0.91s
user    0.07s
sys 0.84s
found 1573324 files in 110388 checked directories
total images found: 154306
REDACTED

real    0.91s
user    0.08s
sys 0.83s
[~/repo/pictura-stainless]-[%] 
[~/repo]-[%] repeat 5 { { time find ~ -type f -regextype posix-extended -iregex '.*\.(png|jpg|gif|bmp|tif|jxl|jpeg|webp|tiff|avif|heic)' 2>/dev/null } | shuf -n1 | sha1sum }                                                                                                                                                                                      

real    1.67s
user    1.23s
sys 0.44s
e4c4bde8147d6a99bef96716efa8efc19cef779d  -

real    1.68s
user    1.33s
sys 0.35s
d4b8564316dfe7b291c24b949f525f0647176773  -

real    1.69s
user    1.29s
sys 0.40s
24f1934282a22dccc0f2ca94edf954f30c7f9809  -

real    1.71s
user    1.37s
sys 0.34s
4c7a3ef0b04c29e1c4c7a0237089ec9ca718933c  -

real    1.71s
user    1.40s
sys 0.31s
cf5d8acd6ac2302bac508b1306df889e5a6a8d01  -
[~/repo]-[%] 
shdown ★★
()
Ответ на: комментарий от shdown

Ваше в 5.7 раз медленнее сабжа, в 3 раза медленнее find | shuf.

Это, очевидно, из-за обхода большого кол-ва вложенных директорий. Можно, конечно, оптимизировать кол-во системных вызовов, однако если не натравливать её на файлопомойки целиком, то она в целом и так работает довольно быстро.

saahriktu ★★★★★
()
Ответ на: комментарий от saahriktu

Rust:

— 47 лефтпадов от васянов

— 2.2 Мб на диске

— медленнее

Си:

— зависит только от libc

— 22 Кб на диске

— быстрее в 5.7 раз

$ grep -c -E '^\[\[package' Cargo.lock
47
$ du --apparent-size -h target/release/pictura_noctis
2.2M	target/release/pictura_noctis
shdown ★★
()
Последнее исправление: shdown (всего исправлений: 1)
Ответ на: комментарий от shdown

медленнее

Я уже написал почему. Дело и не в языке и не в библиотеках. На Си тоже можно написать код, который будет ещё медленнее. Чем больше системных вызовов - тем медленнее.

Моя версия делает минимум в 3–4 раза больше syscall'ов на каждую директорию.

В общем, тут разница в алгоритмах.

saahriktu ★★★★★
()
Последнее исправление: saahriktu (всего исправлений: 1)
Ответ на: комментарий от shdown

Основной источник - функция, которая «Возвращает каноническую абсолютную форму пути, в которой все промежуточные компоненты нормализованы, а символические ссылки разрешены.».

Плюс, дополнительная обработка симлинков: lstat по полному пути, stat по полному пути, heap-аллокация на каждую запись, аллокация на каждую ошибку.

Всё как у серьёзных людей.

saahriktu ★★★★★
()
Ответ на: комментарий от saahriktu

Основной источник - функция, которая «Возвращает каноническую абсолютную форму пути, в которой все промежуточные компоненты нормализованы, а символические ссылки разрешены.».

Это делается за один вызов realpath(3). А твоя программа делает O(N^2) количество системных вызовов readlink(). Т.е. если у меня 100 вложенных каталогов, она сделает 100*(100+1)/2 = 5050 системных вызовов:

[~/repo/pictura-noctis]-[%] ( repeat 100 { mkdir bench && cd bench } )
[~/repo/pictura-noctis]-[%] strace -e readlink ./target/release/pictura_noctis --recursive --dry-run ./bench |& grep -c -E '^readlink\('
5050
[~/repo/pictura-noctis]-[%] 

А сабж делает O(N) системных вызовов:

[~/repo/pictura-stainless]-[%] ( repeat 100 { mkdir bench && cd bench } )
[~/repo/pictura-stainless]-[%] strace -e file -o strace.log ./pictura-stainless --recursive --dry-run ./bench
no supported images found in ./bench
[~/repo/pictura-stainless]-[%] wc -l strace.log
106 strace.log
[~/repo/pictura-stainless]-[%] 

Аллокации вообще побоку, тут bottleneck в дисковом I/O.

Плюс, дополнительная обработка симлинков: lstat по полному пути, stat по полному пути

Всё как у серьёзных людей.

Ты вообще понимаешь, о чём ты говоришь? Какой lstat по полному пути? Сабж гораздо больше «как у серьёзных людей», там хоть зачаточная поддержка *at() вызовов (хотя и opendir() вместо openat() + fdopendir()).

АААААА, всё, добавляю в свой список «почему не нужно использовать Rust».

shdown ★★
()
Последнее исправление: shdown (всего исправлений: 2)
Ответ на: комментарий от shdown

Т.е., мне кажется, суть даже не в «не пишите на Rust, пишите на Си». Суть в «выучите матчасть, а потом пишите хоть на Visual Basic, но Rust будет вас активно отвлекать от учения матчасти своими абстракциями и лефтпадами от васянов».

shdown ★★
()
Ответ на: комментарий от saahriktu

Какие 1579 обоев?..

может быть важно, если в вашей коллекции десятки тысяч обоев.

Я думал у тебя там тысяч 200хоть, и 500 директроий, и симлинки друг на друга((

Однако, диапазон времени выполнения у pictura-stainless и find | shuf значительно больше - до ±2,2 мс. У моей Pictura Noctis он ±0,3 мс.

Нормально меряй, нормально будет. У меня, как видно на скриншоте, отклонение практически отсутствует, при скорости в 1,4мс.

тщательнее синхронизируется с системными событиями

Что это такое — я не понимаю

BruteForce ★★★★★
() автор топика
Ответ на: комментарий от saahriktu

очевидно, из-за обхода большого кол-ва вложенных директорий

Я думал у тебя поинт в колве директорий, в т.ч. вложенных, да с симлинками! Тебе зачем хэшмапа тогда вообще?

У тебя там хоть один симлинк вообще есть?

не натравливать её на файлопомойки целиком

Зачем выбор обоины с резервуарной выборкой, если нельзя натравливать на файлопомойку? На моих 7к фотках find+shuf ест не более 9мб, то есть тысяч до 100 можно вообще не париться, согласен?

то она в целом и так работает довольно быстро.

В целом и так довольно быстро работает find+shuf, а ты компилируемый яп приплёл для скорости, у тебя в новости это буквально первым пунктом:

Программа на компилируемом языке, работает

А теперь оказывается, что оно тебе самому ненадо, и ни вложенных директорий, ни десятков тысяч обоин у тебя нет. Симлинки, симлинки есть?

BruteForce ★★★★★
() автор топика
Ответ на: комментарий от shdown

Ну и лапшекод.

-O2, а не -O3

Не думаю, что в данном случае будет разница! На раннем этапе я сравнивал O0 и O2, её не было или типа того)

хэш-таблицы

Я думаю, что массива с полным проходом здесь достаточно, но решил что (1) не хочу сраться об этом на ЛОР, (2) не хотел ситуации, когда у @ saahriktu оказалось бы 100500 директорий. Оказалось, у него их нет вообще( аналогично не хотел добавлять closedir())))))))))

хотя и opendir()

Я покорчился на opendir(), а потом решил — да и ладно…. Очень удобно зато…………….

BruteForce ★★★★★
() автор топика
Ответ на: комментарий от shdown

Это делается за один вызов realpath(3).

Это функция glibc, а не syscall. И под капотом она делает ровно тоже, что и std::fs::canonicalize(), о которой речь.

Да, моя программа в итоге делает O(N^2) количество системных вызовов readlink(), но это не потому, что std::fs::canonicalize() плохая, а потому, что она вызывается в моей программе на каждом уровне рекурсии.

Т.е., как я и говорил, всё дело в алгоритмах. Да, есть более быстрые варианты, но все они не про «один вызов realpath(3)».

saahriktu ★★★★★
()
Ответ на: комментарий от BruteForce

Мне самому симлинки посреди обоев не нужны. Но мало ли кому нужны. Во все юниксовые утилиты добавляют их поддержку просто чтобы не зациклиться внезапно в случае чего.

saahriktu ★★★★★
()

Исходный код распространяется под лицензией GPLv3, в то время как Pictura Noctis распространяется под фашистской GPLv3.

Это последствия среды (которая, как известно, маленькая пятница) или проверка, читают ли модераторы новости перед подтверждением? Да, читают. И @Shaman007, вопреки известному заблуждению, тоже читал. Периодически промахиваемся, да.

Новость интересная, пусть будет битва реализаций. После доведения до вменяемого вида с удовольствие подтвержу.

hobbit ★★★★★
()
Последнее исправление: hobbit (всего исправлений: 2)
Ответ на: комментарий от hobbit

Это последствия среды

или проверка

Первое, рассчитано на то, что будет читаться людьми, но это задуманная часть НОВОСТИ (что лицензия не была изменена; впрочем, прямого переписывания тоже небыло, я код смотрел чтобы понять что за «нормальные коды возврата» и что такое резервуарная выборка у автора (оказалось очень просто и прикольно!).

После доведения до вменяемого вида

Я мог и сам, немного протестуя!

BruteForce ★★★★★
() автор топика
Последнее исправление: BruteForce (всего исправлений: 1)
Ответ на: комментарий от hobbit

Ещё сыграла инерция: я надеялся и верил, что у @saahriktu была MIT, и сильно расстроился, уже когда писал новость, увидав GPLv3! Полстрочки у меня было уже написано…

BruteForce ★★★★★
() автор топика

Ну что, обновил Pictura Noctis до версии 1.2.0, в которой оптимизированы syscall'ы. Теперь она должна быть не медленнее сабжевой версии на Си.

saahriktu ★★★★★
()
Ответ на: комментарий от saahriktu

Извини, Pictura Noctis всё ещё примерно в 5 раз медленнее pictura-stainless. Я думаю надо сменить модель управления памятью на более современную (pictura-stainless тоже не идеал, конечно).

$ taskset -c 6 hyperfine \                                                                                                             main
                               -N \
                               --warmup 20 \
                               --min-runs 1000 \
                               "../pictura-stainless/pictura-stainless -rp $HOME/pictures" \
                               "./target/release/pictura_noctis --recursive --dry-run $HOME/pictures/"
Benchmark 1: ../pictura-stainless/pictura-stainless -rp /home/QWERTY
  Time (mean ± σ):       1.4 ms ±   0.0 ms    [User: 0.2 ms, System: 1.2 ms]
  Range (min … max):     1.3 ms …   1.5 ms    2067 runs
 
Benchmark 2: ./target/release/pictura_noctis --recursive --dry-run /home/QWERTY
  Time (mean ± σ):       2.1 ms ±   0.0 ms    [User: 0.9 ms, System: 1.2 ms]
  Range (min … max):     2.0 ms …   2.3 ms    1407 runs
 
  Warning: Statistical outliers were detected. Consider re-running this benchmark on a quiet system without any interferences from other programs. It might help to use the '--warmup' or '--prepare' options.
 
Summary
  ../pictura-stainless/pictura-stainless -rp /home/QWERTY ran
    1.51 ± 0.02 times faster than ./target/release/pictura_noctis --recursive --dry-run /home/QWERTY
$ taskset -c 30 hyperfine \                                                                                                            main
                               -N \
                               --warmup 20 \
                               --min-runs 1000 \
                               "../pictura-stainless/pictura-stainless -rp $HOME/pictures" \
                               "./target/release/pictura_noctis --recursive --dry-run $HOME/pictures/"
Benchmark 1: ../pictura-stainless/pictura-stainless -rp /home/QWERTY
  Time (mean ± σ):       2.6 ms ±   0.0 ms    [User: 0.3 ms, System: 2.3 ms]
  Range (min … max):     2.6 ms …   2.7 ms    1126 runs
 
Benchmark 2: ./target/release/pictura_noctis --recursive --dry-run /home/QWERTY
  Time (mean ± σ):       3.8 ms ±   0.0 ms    [User: 1.4 ms, System: 2.3 ms]
  Range (min … max):     3.7 ms …   4.0 ms    1000 runs
 
Summary
  ../pictura-stainless/pictura-stainless -rp /home/QWERTY ran
1.46 ± 0.01 times faster than ./target/release/pictura_noctis --recursive --dry-run /home/QWERTY

ЗЫ. Сборка за 37 секунд — это мощно!

BruteForce ★★★★★
() автор топика
Последнее исправление: BruteForce (всего исправлений: 1)
Ответ на: комментарий от firkax

*если выкинуть sys по которому теперь паритет

BruteForce ★★★★★
() автор топика
Ответ на: комментарий от hobbit

А я думал это авторский художественный оборот. Типа у конкурента лицензия плохая, а у меня хорошая, и не важно что они одинаково называются.

firkax ★★★★★
()

за С конечно плюсик в карму, а за прочее обратно вдвое :-)

это не UNIX-way. Если каждая портянка будет сама внутри себя перебирать файлы и каталоги, это ппц.

Всё что разумного делает программа выражено в функции int set_wallpaper(const char *image_path, unsigned long timeout_ms). Порядка 100 строк

Остальное вредный мусор.

MKuznetsov ★★★★★
()

@saahriktu

Я же с --dry-run запускаю. Зачем вообще это в сабж пихать? Чем тебе -p не нравится, кстати?


Скормил твой код БЯМ, БЯМ нашла регрессию в v1.2.0: Symlinked images are ignored (v1.2.0 regression)

И ещё куча вот такого вот:

  • Pipe Buffer Deadlock in run_qs (Critical Bug)
  • Loss of Cross-Platform Portability (Windows Build Broken) (лол)
  • File-Level Errors Dropped from walk_errors
  • Broken Cycle Detection for Symlinked Directories

Я ничего не понимаю и ничего не смотрел-не проверял, но вдруг будет полезно.

BruteForce ★★★★★
() автор топика
Последнее исправление: BruteForce (всего исправлений: 1)
Ответ на: комментарий от BruteForce

@firkax нет-нет-нет, не надо здесь, Линус Торвальдс лично разрешил, а @saahriktu теперь должен идти и разбираться!!

BruteForce ★★★★★
() автор топика
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.