TGStat
TGStat
Qidiruv uchun matnni kiriting
Ilg‘or kanal qidiruvi
  • flag Uzbek
    Sayt tili
    flag Russian flag English flag Uzbek
  • Saytga kirish
  • Katalog
    Kanal va guruhlar katalogi Hududiy to‘plamlar Tematik to‘plamlar Платные каналы Kanallar qidiruvi
    Kanal/guruh qo‘shish
  • Reytinglar
    Kanallar reytingi Guruhlar reytingi Postlar reytingi
    Brendlar va shaxslar reytingi
  • Analitika
  • Postlarda qidiruv
  • Telegram'ni kuzatish
  • Targ‘ibot
    Yandex Business orqali reklama Реклама в каналах через TGStat Agency Реклама на сайте TGStat.ru
Грокаем C++

2 Aug, 19:00

Telegram'da ochish Ulashish Shikoyat qilish

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

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

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

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

Что делать?

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

Список сисколов можно найти в 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
Katalog
Kanal va guruhlar katalogi Kanallar to‘plamlari Kanallar qidiruvi Kanal/guruh qo‘shish
Reytinglar
Telegram-kanallar reytingi Telegram-guruhlar reytingi Postlar reytingi Brendlar va shaxslar reytingi
API
Statistika API'si Postlar qidiruvi API'si API Callback
Kanallarimiz
@TGStat @TGStat_Chat @telepulse @TGStatAPI
O‘qish
Академия TGStat Telegram tadqiqoti 2019 Telegram tadqiqoti 2021 Telegram tadqiqoti 2023
Kontaktlar
Справочный центр Qo‘llab-quvvatlash Email Vakansiyalar
Har xil narsalar
Foydalanuvchi shartnomasi Maxfiylik siyosati Ommaviy oferta
Botlarimiz
@TGStat_Bot @SearcheeBot @TGAlertsBot @tg_analytics_bot @TGStatChatBot