IT News: Digital Camera, OS, Laptop, Smartphone, Smart TV, Sound...

The Author's Project by Valeri N.Kravchuk
Сайт проверен Dr.Web
Меню сайта
  • Главная страница
  • Информация о сайте
  • Дневник
  • Каталог файлов
  • Обратная связь
  • Каталог сайтов
  • FAQ
  • Доска объявлений
  • Форум
  • Фотоальбом
  • Категории раздела
    Автомобильные гаджеты, ремонт... [220]
    Безопасность IT [484]
    Блоки питания, Power Banks, зарядки... [490]
    Видеорегистраторы [220]
    Гаджеты для спорта и здоровья... [190]
    Гаджеты, аксессуары... [625]
    Измерительная техника, инструменты [449]
    Накопители данных [226]
    Нетбуки, Ноутбуки, Ультрабуки [680]
    Мультиварки, блендеры и не только... [158]
    Планшеты [758]
    Радар-детекторы [26]
    Роботы-пылесосы [37]
    Своими руками [357]
    Сети, сетевые технологии, оборудование... [269]
    Смартфоны [4966]
    Фотокамеры, объективы, искусство фотографии.. [543]
    Умный дом [47]
    Электронные книги [96]
    CB, LPD, PMR- связь... [171]
    DECT, IP-телефоны [18]
    Drones, boats, cars... [108]
    electric cars [35]
    GPS-навигаторы, трекеры... [51]
    Linux и не только [4380]
    mini computers и не только... [409]
    News IT, Это интересно, ликбез... [1113]
    Smart TV, UltraHD, приставки, проекторы... [414]
    Smart Watch [263]
    Sound: наушники, плееры, усилители... [616]
    Windows 10... [298]
    Windows 11 [28]
    Погода

  • Метеорадар БРЕСТ
  • Погода в Бресте от www.yr.no

    Яндекс.Погода БРЕСТ

  • Интересные ссылки

    COMPIZOMANIA

    Наш опрос
    Оцените мой сайт
    Всего ответов: 1340
    Статистика
    Анализ веб сайтов

    Яндекс.Метрика

    Рейтинг@Mail.ru Яндекс цитирования

    Russian America Top. Рейтинг ресурсов Русской Америки.

    eXTReMe Tracker

    Правильный CSS!


    Онлайн всего: 1
    Гостей: 1
    Пользователей: 0
    Locations of visitors to this page
    Форма входа
    Главная » 2022 » Декабрь » 1 » Выжимаем все соки: PGO Оптимизация ядра Linux
    10:16
    Выжимаем все соки: PGO Оптимизация ядра Linux

    Выжимаем все соки: PGO Оптимизация ядра Linux

     

    Сложность вычислительных задач и систем растёт с каждым днём. Для бизнеса ускорение кода даже на пару процентов даёт улучшение производительности, заметное снижение издержек и уменьшение задержки(latency). В первую очередь это касается мобильных и встраиваемых систем, высоконагруженных серверов, научных вычислений и 3D-графики. Так был разработан относительно перспективный и молодой метод оптимизации — Profile-Guided Optimization, далее просто PGO-оптимизация. Данный метод эффективно используют такие известные компании, как Google, Mozilla Foundation, Intel, Oracle, IBM и другие. Практически ни один современный веб-браузер не обходится без PGO-оптимизации.

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

    Если вас заинтересовала эта тема, вам интересно развитие технологий и тренды крупных компаний, то добро пожаловать под кат.
     

    Теория


    При классической компиляции кода компилятор вынужден строить предположения об оптимальном методе оптимизации, а где-то вовсе отказаться от одного из методов, т. к. по простым подсчётам из теории сложностей оптимизация будет слишком трудоёмкая. При PGO-оптимизации сначала собирается реальная статистика об исполняемом коде, и далее эта статистика в обработанном виде передаётся компилятору. Теперь же при выборе метода оптимизации компилятор меньше полагается на предположения о коде, а руководствуется статисткой, что, в свою очередь, помогает оптимизировать некоторые участки кода более эффективно. Как можно понять, основным недостатком этого метода является двойная компиляция: сначала надо скомпилировать код, собрать статистику, и уже повторно скомпилировать код. Также недостатком является то, что для правильного сбора статистики надо использовать правильную нагрузку на реальных задачах. Если при сборе статистики будут в основном участвовать одни участки кода, а другие будут простаивать, то это негативно скажется на статистике, и приложение на практике может работать даже медленнее, чем до PGO-оптимизации. Поэтому правильному созданию нагрузочных тестов уделяется большое внимание. Основное, что вы должны запомнить, — мы должны собрать статистику, максимально приближённую к реальному использованию в дальнейшем. Если у нас есть высоконагруженный сервер, то мы создаём нагрузку, максимально приближённую к боевым условиям. Для этого используют тестовые стенды, пишутся программы-симуляторы нагрузки. Как правильно это сделать, подскажут ваши задачи и ваш реальный опыт. Что-то советовать тут, увы, сложно.
     

    По этой же причине в случае с ядром Linux данный метод оптимизации неприменим к тяжёлым ядрам с большим количеством модулей, т. е. он подходит только к hardware-dependent ядрам (кастомным ядрам, сконфигурированным под определённую конфигурацию железа), например, ядру для смартфона, из которого мы хотим выжать максимум производительности.

    В компиляторе clang для PGO-оптимизации существует два вида профилей:

    Инструментальный профиль (Instrumentation-based profiles). Такой вид профиля содержит более подробную информацию, но имеет более низкую скорость работы. Его ещё называют AST-based профилем или профилем, основанным на Абстрактном Синтаксическом Дереве (Abstract Syntax Tree, подробнее про AST можно прочитать в литературе по теории компиляторов). Чтобы собрать программу с таким видом профиля, надо передать компилятору параметр -fprofile-instr-generate. Во время линковки к исполняемому файлу будет прилинкована статическая библиотека libclang_rt.profile-arch.a из состава компилятора clang, в нашем случае это libclang_rt.profile-x64_86.a для 64-битных приложений, libclang_rt.profile-i386.a для 32-битных, для андроид это libclang_rt.profile-arch-android.a, где arch — архитектура процессора.

    Профиль на основе выборки (Sampling-based profile). Такой профиль обычно собирается аппаратными счётчиками процессора — hardware performance counters (HPC). Для такого вида профиля характерны более низкие накладные расходы на профилирование и он может быть собран без какого-либо инструментария, и сложной модификации бинарного файла. Также к данному виду профиля относят профиль основанный на байткоде LLVM(LLVM IR-based). Для создания LLVM IR-based профиля надо передать компилятору: -fprofile-generate. Такжe можно добавить параметр -gline-tables-only для уменьшения отладочной информации.

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

    ▍ Оптимизация с использованием инструментального профиля

     
    clang -O2 -fprofile-instr-generate myprog.c -o myprog
    LLVM_PROFILE_FILE=myprog.profraw ./myprog

    Командой выше мы компилируем файл myprog.c с инструментальным профилем и запускаем исполняемый файл. LLVM_PROFILE_FILE указывает на имя файла, в который будет сохраняться профиль. Далее необходимо обработать сырой профиль и очистить от ненужной информации.
     
    llvm-profdata merge --output=myprog.profdata myprog.profraw

    На выходе мы получим файл профиля myprog.profdata. Далее уже компилируем исходный код с нашим профилем:
     
    clang -O2 -fprofile-use=myprog.profdata myprog.c -o myprog
     

    ▍ Оптимизация с использованием профиля на основе выборки и LLVM IR

     
    clang -O2 -fprofile-generate myprog.c -o myprog
    LLVM_PROFILE_FILE=myprog.profraw ./myprog

    Компилируем файл myprog.c с профилем на основе выборки и запускаем исполняемый файл. Всё также обрабатываем и очищаем сырой профиль от ненужной информации.
     
    llvm-profdata merge --output=myprog.profdata myprog.profraw

    Снова получем файл профиля myprog.profdata и компилируем исходный код с нашим профилем:
     
    clang -O2 -fprofile-use=myprog.profdata myprog.c -o myprog
     

    ▍ Оптимизация с использованием профиля на основе выборки и стороннего инструментария perf и AutoFDO


    Компилируем нашу программу:
     
    clang -O2 -gline-tables-only myprog.c -o myprog

    Собираем статистику с помощью инструмента perf:
     
    perf record -b ./myprog

    Создаём профиль:
     
    create_llvm_prof --binary=./myprog --out=myprog.profdata

    Компилируем нашу программу с полученным ранее профилем:
     
    clang -O2 -fprofile-sample-use=myprog.profdata myprog.c -o myprog
     

    Инструментарий


    В своей работе мы будем использовать компилятор clang >= 12. К сожалению для clang 12 и llvm 12 необходим набор дополнительных патчей, т. к. для PGO оптимизации ядра нужен дополнительный атрибут для кода __attribute__((no_profile)), который появился только в clang 13 и запрещает профилирование функции и добавление в неё дополнительного служебного кода для создания профиля. Он нам нужен, так как в некоторых функциях может неправильно генерироваться код, что, в свою очередь, вызывает kernel panic. Изначально этот атрибут был в clang 13, как __attribute__((no_profile_instrument_function)), но в более поздних коммитах llvm 13 был переименован в __attribute__((no_profile)) для совместимости с GCC. На данный момент мною используется clang 14. Необходимый набор патчей и сборочный скрипт для llvm 12 вы можете найти здесь. Сборочный скрипт для llvm 14 вы можете найти здесь. Также рекомендую к ознакомлению мою предыдущую статью — LTO оптимизация ядра Linux.
     

    Практика


    Скачайте патч по ссылке Патч PGO Оптимизация.

    Скачаем и распакуем архив с исходным кодом ядра в /tmp:
     
    wget https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-6.0.9.tar.xz
    tar -xf linux-6.0.9.tar.xz -C /tmp

    Перейдём в рабочий каталог:
     
    cd /tmp/linux-6.0.9

    Применим патч с PGO оптимизацией:
     
    patch -p1 < путь к патчу/pgo.patch

    Копируем конфигурация ядра или создаём конфигурацию с нуля:
     
    zcat /proc/config.gz > .config

    или
     
    cp путь к вашему конфигу .config

    или создаём конфигурация с нуля
     
    make tinyconfig
     

    Запускаем конфигуратор ядра:
     
    make nconfig LLVM=1

    В конфигураторе нам важен параметр ядра CONFIG_PGO_CLANG=y, для этого переходим в General architecture-dependent options в самом низу будет пункт Profile Guided Optimization (PGO), заходим в него и выбираем Enable clang’s PGO-based kernel profiling.
     
     
     

    Обязательно необходимо отключить в конфигурации ядра AMD Secure Memory Encryption (SME), если этот параметр включён, то ядро зависает на самой ранней стадии загрузки ядра, и эту ошибку очень сложно понять и отловить, и её невозможно даже отловить дебагером. Для этого заходим Processor type and features и снимаем галочку с AMD Secure Memory Encryption (SME) support.
     
     

    Наши настройки ядра закончены, поэтому сохраняем конфигурацию ядра и выходим из конфигуратора.

    Собираем ядро:
     
    make -j $(nproc) LLVM=1

    Внимательно смотрим на предупреждения при сборке ядра! Если мы встретим, что-то типа этого:
     
    vmlinux.o: warning: objtool: can't decode instruction at .text.calc_rc_params:0x92
    
    arch/x86/tools/insn_decoder_test: warning: Found an x86 instruction decoder bug, please report this.
    arch/x86/tools/insn_decoder_test: warning: ffffffff81d68bb2: f2 0f 78 c0 08 08 insertq $0x8,$0x8,%xmm0,%xmm0
    arch/x86/tools/insn_decoder_test: warning: objdump says 6 bytes, but insn_get_length() says 0
    arch/x86/tools/insn_decoder_test: warning: Decoded and checked 7200326 instructions with 1 failures
    

    То это плохой знак, и наше ядро не загрузится после перезагрузки. Как мы можем понять из сообщения, варнинг возникает в функции calc_rc_params. Для этого делаем поиск по файлам в поисках нашей функции:
     
    grep -lR "calc_rc_params"

    Просматриваем все файлы, и в итоге находим, что наша функция находится в файле drivers/gpu/drm/amd/display/dc/dsc/rc_calc.c.

    Открываем файл, находим функцию void calc_rc_params (struct rc_params *rc, const struct drm_dsc_config *pps) и перед ней добавляем строку __attribute__((no_profile)), которая говорит, что мы запрещаем её профилировать и встраивать какой-либо необходимый компилятору служебный код. В итоге у нас получится:
     
    __attribute__((no_profile))
    void calc_rc_params(struct rc_params *rc, const struct drm_dsc_config *pps)

    Сохраняем наш файл. Очищаем сборку ядра:
     
    make clean

    Повторяем сборку:
     
    make -j $(nproc) LLVM=1

    Если всё впорядке, то после сборки переходим к установке ядра и модулей (mykernel необходимо заменить на имя вашего ядра):
     
    sudo make modules_install
    sudo cp -v arch/x86_64/boot/bzImage /boot/vmlinuz-mykernel

    Создаём cpio загрузочный образ с помощью dracut или mkinicpio. Прописываем ваше новое ядро в grub или systemd-boot и перезагружаемся в новое ядро.

    Загружаем новое ядро.

    Проверяем подмонтирован ли proc в системе:
     
    mount | grep proc

    Если всё в порядке — мы должны увидеть похожую строку:
     
    proc on /proc type proc (rw,nosuid,nodev,noexec,relatime)

    Если proc не подмонтирован, то это можно сделать под root командой:
     
    mount -t proc proc /proc

    В /proc/pgo находятся 2 файла. Файл reset используется для обнуления статистики, и чтобы начать её сбор по новой. Файл vmlinux.profraw содержит необходимый нам не обработанный PGO профиль.

    Чтобы обнулить статистику — необходимо c правами root выполнить:
     
    echo 1 > /proc/pgo/reset

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

    После того как система поработала, копируем наш профиль (нужны root права) в директорию доступную для чтения обычному пользователю:
     
    cp -a /proc/pgo/vmlinux.profraw vmlinux.profraw

    Даём пользователю права на чтения файла:
     
    chown ruvds:ruvds vmlinux.profraw

    С правами обычного пользователя конвертируем сырой профиль и генерируем конечный профиль для компилятора:
     
    llvm-profdata merge --output=vmlinux.profdata vmlinux.profraw

    Перейдём в рабочий каталог с исходниками ядро:
     
    cd /tmp/linux-6.0.9

    Очистим исходный код ядра:
     
    make distclean

    Копируем конфигурация текущего ядра:
     
    zcat /proc/config.gz > .config

    Запускаем конфигуратор ядра:
     
    make nconfig LLVM=1

    Переходим в General architecture-dependent options в самом низу будет пункт Profile Guided Optimization (PGO), заходим в него и снимаем галочку напротив Enable clang’s PGO-based kernel profiling. Выходим и сохраняем новый конфиг.

    Собираем наше ядро с профилем:
     
    make -j $(nproc) LLVM=1 KCFLAGS=-fprofile-use=полный путь к профилю/vmlinux.profdata

    Если компиляция прошла успешно, то устанавливаем наше новое ядро и модули:
     
    sudo make modules_install
    sudo cp -v arch/x86_64/boot/bzImage /boot/vmlinuz-mykernel

    Перезагружаем систему и наслаждаемся новым оптимизированным ядром.
     

    Итоги


    Если отбросить лень и предрассудки, то сборка ядра — несложная задача. А при определённом опыте, сборка ядра с PGO оптимизацией под силу многим. После несложных и понятных операций мы получили более быстрое и оптимизированное ядро Linux. Применить которое вы можете дома и в своей работе. Также не стоит бояться новых технологий, ведь «Только смелым покоряются моря!». Поэтому только вам под силу достичь новых высот, и продвигать технический прогресс!
     

    Комментарии


    После того как компания Google выпустила набор патчей для PGO оптимизации, мною была добавлена поддержка LLVM 13 и LLVM 14, т.к. в них менялся формат профиля и с оригинальными патчами clang его не понимает. Также файл профиля и сброса были перенесены из debugfs в proc для устранения проблем с включённым kernel_lockdown (man kernel_lockdown) в ядре Linux, который не даёт прочесть профиль. Данное изменение позволять профилировать ядро с включёнными системами безопасности ядра, без их отключения на этапе загрузки. Дополнительную информацию вы можете найти в файле Documentation/dev-tools/pgo.rst после применения патча ядра.
     

    Результаты бенчмарков


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

     

    RUVDS.com
    VDS/VPS-хостинг. Скидка 10% по коду HABR10
    @nullc0de

    Software developer

     

    https://habr.com/ru/company/ruvds/blog/696236/

    Категория: Linux и не только | Просмотров: 93 | Добавил: laptop | Рейтинг: 5.0/1
    Всего комментариев: 0
    Добавлять комментарии могут только зарегистрированные пользователи.
    [ Регистрация | Вход ]
    Волк слабее льва и тигра, но в цирке волк не выступает!
    Волк слабее льва и тигра, но в цирке волк не выступает!
    Волк - единственный из зверей, который может пойти в бой на более сильного противника.
    Если же он проиграл бой, то до последнего вздоха смотрит в глаза противника. После этого умирает...

    Праздники сегодня

    Поиск
    Календарь
    «  Декабрь 2022  »
    ПнВтСрЧтПтСбВс
       1234
    567891011
    12131415161718
    19202122232425
    262728293031
    Архив записей
    Друзья сайта
  • Официальный блог
  • JEEP - the best! Mercedes - the best! Автомобильный портал города Бреста: технические характеристики с фото, авторынок, автоспорт...
    Наша кнопка
    IT новости с моего лаптопа...

    Внимание!
    Администратор сайта laptop.ucoz.ru не несет ответственности за содержание рекламных объявлений. Все используемые на сайте зарегистрированные товарные знаки принадлежат своим законным владельцам! Используемая со сторонних источников информация публикуется с обязательными ссылками на эти источники.
    Copyright Valeri N.Kravchuk © 2007-2024