TGStat
TGStat
Введите текст для поиска
Расширенный поиск каналов
  • flag Russian
    Язык сайта
    flag Russian flag English flag Uzbek
  • Вход на сайт
  • Каталог
    Каталог каналов и чатов Региональные подборки Тематические подборки Платные каналы Поиск каналов
    Добавить канал/чат
  • Рейтинги
    Рейтинг каналов Рейтинг чатов Рейтинг публикаций
    Рейтинги брендов и персон
  • Аналитика
  • Поиск по публикациям
  • Мониторинг Telegram
  • Продвижение
    Реклама через Яндекс Бизнес Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
Грокаем C++

2 Aug, 19:00

Открыть в Telegram Поделиться Пожаловаться

​​Оверхэд системных вызовов
#опытным

Как измерить оверхэд системного вызова?

Задача ведь не самая тривиальная: сискол делает разную полезную работу, которая потенциально занимает сильно больше времени, чем переход в режим ядра и обратно.

И вставить свой измеряющий код в место начала и конца логики сискола мы тоже не можем - это часть скрыта от нас и вообще написана на ассемблере.

Что делать?

Брать самый легковесный сискол. Который делает минимальную работу.

Список сисколов можно найти в man'е. Изучив их поближе, я понял, что один и самых дешевых системных вызовов это getpid.

Все, что он делает - возвращает ID процесса. По сути одно чтение из памяти.

Однако библиотечная функция getpid() не всегда делает системный вызов. Айди процесса не меняется и это отличный кандидат для кэширования результата. И по сути эта библиотечная обертка делает сискол только в первый свой вызов. Дальше результат кэшируется в обертке и выдается из кэша.

Как обойти эту неприятность? Было бы круто уметь напрямую вызывать сискол без этих оберток со своей логикой.

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

#include
#include
#include
int main(int argc, char *argv[])
{
pid_t pid;
pid = syscall(SYS_getpid);
}

Таким образом мы избегаем кэширования и всегда делаем честный сискол. Который делает одно чтение из памяти и возвращает результат.

То есть фактически, измеряя затраты на вызов getpid, мы очень близко подбираемся к реальному оверхэду на переход в режим ядра и обратно.

Теперь обсудим несколько принципов, которые нужно учесть в измерениях, чтобы они были более точные:

✅ Большое количество прогонов - естественно. Флуктуации бывают везде, нужно их усреднять за счет большого количества экспериментов.

✅ Запрещаем компилятору оптимизировать результат. Компилятор хитрый: если он видит, что результат вызова не используется(а нафига нам нужны миллионы значений айди текущего процесса?) он пытается выкинуть весь вызов. Делаем ассемблерную вставку, запрещающую оптимизировать конкретно это место в коде.

✅ Прогрев. Первые вызовы всегда медленнее: кэши холодные, предсказатель ветвлений не обучен, процессор ещё не разогнался до турбо-частоты. Сделаем некоторое количество «холостых» вызовов до начала измерений, чтобы система вошла в стабильный «горячий» режим. Иначе первые тысячи медленных вызовов исказили бы результат.

✅ Вычесть стоимость самого измерения. Подсчет времени сам по себе требует времени на выполнение, поэтому это нужно учесть.

✅ Измерение с выборкой. Делаем 100 млн замеров для имитации бурной деятельности, но замеряем только небольшую часть, чтобы вывести подробную статистику с пенцентилями и меньше привносить эффекта наблюдателя в измерение.

Я навайбкодил программулину, которая учитывает эти штуки и делает измерение стоимости вызова чистого сискола getpid.

Результаты вышли вот такими:

getpid() syscall benchmark (macOS)
Method : syscall(SYS_getpid)
Iterations : 100,000,000

Total time : 9.536 s
Average time: 95.36 ns per call
Calls/sec : 10,486,821 calls/sec (approx)

Min : 18 ns
Median : 84 ns
P50 : 84 ns
P90 : 125 ns
P99 : 125 ns
Max : 28726 ns

CPU : Apple M4 Pro
Kernel : Darwin 24.6.0 (arm64)
Compiler : clang++ (Clang) 16.0.0
Flags : -O3 -Wall

Получилось, что медианное время - 84 нс. Что при частоте процессора около 4.5 Ггц дает около 380 клоков процессора.

Видел где-то в статье чувак тестил на интеле и у него вышло около 130 нс и примерно 350 циклов проца.

Если среди нас есть спецы по перф измерениям, подскажите, что можно было сделать, чтобы результаты были более приближены к реальности?

Measure your performance. Stay cool.

#performance #OS

3k 0 21 13 44
Каталог
Каталог каналов и чатов Подборки каналов Поиск каналов Добавить канал/чат
Рейтинги
Рейтинг каналов Telegram Рейтинг чатов Telegram Рейтинг публикаций Рейтинги брендов и персон
API
API статистики API поиска публикаций API Callback
Наши каналы
@TGStat @TGStat_Chat @telepulse @TGStatAPI
Почитать
Академия TGStat Исследование Telegram 2019 Исследование Telegram 2021 Исследование Telegram 2023
Контакты
Справочный центр Поддержка Почта Вакансии
Всякая всячина
Пользовательское соглашение Политика конфиденциальности Публичная оферта
Наши боты
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot