Від перекладача:
Більшість моїх знайомих для вимірювання часу в різного виду бенчмарках в С ++ використовують chrono або, в особливо запущених випадках, ctime. Але для бенчмаркінгу набагато корисніше заміряти процесорний час. Нещодавно я натрапив на статтю про кроссплатформенную вимірі процесорного часу і вирішив поділитися нею тут, можливо дещо збільшивши якість місцевих бенчмарков.
Як отримати процесорний час
Процесорний час збільшується, коли процес працює і споживає цикли CPU. Під час операцій введення-виведення, блокувань потоків та інших операцій, які припиняють роботу процесора, процесорний час не збільшується поки процес знову не почне використовувати CPU.
Різні інструменти, такі як ps в POSIX, Activity Monitor в OSX і Task Manager в Windows показують процесорний час, що використовується процесами, але часто буває корисним відстежувати його прямо з самого процесу. Це особливо корисно під час бенчмаркінгу алгоритмів або маленької частини складної програми. Незважаючи на те, що все ОС надають API для отримання процесорного часу, в кожній з них є свої тонкощі.
Функція getCPUTime (). представлена нижче, працює на більшості ОС (просто скопіюйте код або скачайте файл getCPUTime.c). Там, де це потрібно, Слінко з librt. щоб отримати POSIX-таймери (наприклад, AIX, BSD, Cygwin, HP-UX, Linux і Solaris, але не OSX). В іншому випадку, досить стандартних бібліотек.
Далі ми докладно обговоримо всі функції, тонкощі і причини, за якими в коді стільки #ifdef 'ов.
Використання
Щоб заміряти процесорний час алгоритму, викличте getCPUTime () до і після запуску алгоритму, і виведіть різницю. Не варто припускати, що значення, повернене при одиничному виконанні функції, несе якийсь сенс.
Обговорення
Кожна ОС надає один або кілька способів отримати процесорний час. Однак деякі способи точніше інших.
Кожен з цих способів докладно висвітлено нижче.
GetProcessTimes ()
На Windows і Cygwin (UNIX-подібна середовище та інтерфейс командного рядка для Windows), функція GetProcessTimes () заповнює структуру FILETIME процесорним часом, використаним процесом, а функція FileTimeToSystemTime () перетворює структуру FILETIME в структуру SYSTEMTIME. містить придатне для використання значення часу.
Доступність GetProcessTimes (): Cygwin, Windows XP і більш пізні версії.
Отримання процесорного часу:
clock_gettme ()
На більшості POSIX-сумісних ОС, clock_gettime () (дивись мануали до AIX. BSD. HP-UX. Linux і Solaris) надає найточніше значення процесорного часу. Перший аргумент функції вибирає "clock id", а другий це структура timespec. заповнюється використаним процесорним часом в секундах і наносекундах. Для більшості ОС, програма повинна бути слінкована з librt.
Однак, є кілька тонкощів, що ускладнюють використання цієї функції в крос-платформенном коді:
- Функція є опціональною частиною стандарту POSIX і доступна тільки якщо _POSIX_TIMERS визначено в
значенням більше 0. На сьогоднішній день, AIX, BSD, HP-UX, Linux і Solaris підтримують цю функцію, але OSX не підтримує. - Структура timespec. заповнюється функцією clock_gettime () може зберігати час в наносекундах, але точність годин відрізняється в різних ОС і на різних системах. Функція clock_getres () повертає точність годин, якщо вона вам потрібна. Ця функція, знову-таки, є опціональною частиною стандарту POSIX, доступною тільки якщо _POSIX_TIMERS більше нуля. На даний момент, AIX, BSD, HP-UX, Linux і Solaris надають цю функцію, але в Solaris вона не працює.
- стандарт POSIX визначає імена кількох стандартних значень "clock id", включаючи CLOCK_PROCESS_CPUTIME_ID. щоб отримати процесорний час процесу. Проте, сьогодні BSD і HP-UX не мають цього id, і натомість визначають власний id CLOCK_VIRTUAL для процесорного часу. Щоб заплутати все ще більше, Solaris визначає обидва цих, але використовує CLOCK_VIRTUAL для процесорного часу потоку. а не процесу.
Який id використовувати
- Замість того, щоб використовувати одну з констант, оголошених вище, функція clock_getcpuclockid () повертає таймер для обраного процесу. Використання процесу 0 дозволяє отримати процесорний час поточного процесу. Однак, це ще одна опциональная частина стандарту POSIX і доступна тільки якщо _POSIX_CPUTIME більше 0. На сьогоднішній день, тільки AIX і Linux надають цю функцію, але лінуксовскіе include-файли не визначають _POSIX_CPUTIME і функція повертає ненадійні і несумісні з POSIX результати.
- Функція clock_gettime () може бути реалізована за допомогою регістра часу процесора. На багатопроцесорних системах, у окремих процесорів може бути дещо різне сприйняття часу, через що функція може повертати невірні значення, якщо процес передавався від процесора процесору. На Linux, і тільки на Linux, це може бути виявлено, якщо clock_getcpuclockid () повертає Ні-POSIX помилку і встановлює errno в ENOENT. Однак, як зазначалося вище, на Linux clock_getcpuclockid () ненадійний.
На практиці через всіх цих тонкощів, використання clock_gettime () вимагає багато перевірок за допомогою #ifdef і можливість переключитися на іншу функцію, якщо вона не спрацьовує.
Доступність clock_gettime (): AIX, BSD, Cygwin, HP-UX, Linux і Solaris. Але clock id на BSD і HP-UX нестандартні.
Доступність clock_getres (): AIX, BSD, Cygwin, HP-UX та Linux, але не працює Solaris.
Доступність clock_getcpuclockid (): AIX і Cygwin, що не недостовірна на Linux.
Отримання процесорного часу:
getrusage ()
На всіх UNIX-подібних ОС, функція getrusage () це найнадійніший спосіб отримати процесорний час, використане поточним процесом. Функція заповнює структуру rusage часом в секундах і мікросекундах. Поле ru_utime містить час проведений в user mode, а поле ru_stime - в system mode від імені процесу.
Увага: Деякі ОС, до широкого поширення підтримки 64-біт, визначали функцію getrusage (). повертає 32-бітове значення, і функцію getrusage64 (). повертає 64-бітове значення. Сьогодні, getrusage () повертає 64-бітове значення, а getrusage64 () застаріло.
Доступність getrusage (): AIX, BSD, Cygwin, HP-UX, Linux, OSX, and Solaris.
Отримання процесорного часу:
На всіх UNIX-подібних ОС, застаріла функція times () заповнює структуру tms з процесорним часом в тиках, а функція sysconf () повертає кількість тиків в секунду. Поле tms_utime містить час, проведений в user mode, а поле tms_stime - в system mode від імені процесу.
Увага: Більш старий аргумент функції sysconf () CLK_TCK застарів і може не підтримуватися в деяких ОС. Якщо він доступний, функція sysconf () зазвичай не працює при його використанні. Використовуйте _SC_CLK_TCK замість нього.
Доступність times (): AIX, BSD, Cygwin, HP-UX, Linux, OSX і Solaris.
Отримання процесорного часу:
На всіх UNIX-подібних ОС, дуже стара функція clock () повертає процесорний час процесу в тиках, а макрос CLOCKS_PER_SEC кількість тиків в секунду.
Замітка: Повернене процесорний час включає в себе час проведений в user mode І в system mode від імені процесу.
Увага: Хоча спочатку CLOCKS_PER_SEC повинен був повертати значення, залежне від процесора, стандарти C ISO C89 і C99, Single UNIX Specification і стандарт POSIX вимагають, щоб CLOCKS_PER_SEC мав фіксоване значення 1,000,000, що обмежує точність функції мікросекундами. Більшість ОС відповідає цим стандартам, але FreeBSD, Cygwin і старі версії OSX використовують нестандартні значення.
Увага: На AIX і Solaris, функція clock () включає процесорний час поточного процесу І і будь-якого завершеного дочірнього процесу для якого батько виконав одну з функцій wait (). system () або pclose ().
Увага: У Windows, функція clock () підтримується, але повертатися не процесорний, а реальний час.
Доступність clock (): AIX, BSD, Cygwin, HP-UX, Linux, OSX і Solaris.
Отримання процесорного часу:
інші підходи
Існують і інші ОС-специфічні способи отримати процесорний час. На Linux, Solarisі деяких BSD, можна парсити / proc / [pid] / stat. щоб отримати статистику процесу. На OSX, приватна функція API proc_pidtaskinfo () в libproc повертає інформацію про процес. Також існують відкриті бібліотеки, такі як libproc, procps і Sigar.
На UNIX існує кілька утиліт дозволяють відобразити процесорний час процесу, включаючи ps. top. mpstat і інші. Можна також використовувати утиліту time. щоб відобразити час, витрачений на команду.
На Windows, можна використовувати диспетчер задач. щоб моніторити використання CPU.
На OSX, можна використовувати Activity Monitor. щоб моніторити використання CPU. Утиліта для профайлінга Instruments поставляється в комплекті з Xcode може моніторити використання CPU, а також багато інших речей.
- getCPUTime.c реалізує вище зазначену вище функцію на C. Скомпілюйте її будь-яким компілятором C і Слінко з librt. на системах де вона доступна. Код ліцензований під Creative Commons Attribution 3.0 Unported License.
Дивись також
Пов'язані статті на NadeauSoftware.com
- C / C ++ tip: How to measure elapsed real time for benchmarking пояснює як отримати реальний час, щоб виміряти минулий час для шматка коду, включаючи час, витрачений на I / O або призначений для користувача введення.
- C / C ++ tip: How to use compiler predefined macros to detect the operating system пояснює як використовувати макроси #ifdef для ОС-специфічного коду. Частина з цих методів використано в цій статті, щоб визначити Windows, OSX і варіанти UNIX.
Статті в інтернеті
- Процесорний час на вікіпедії пояснює, що таке процесорний час.
- CPU Time Inquiry на GNU.org пояснює як використовувати давню функцію clock ().
- Determine CPU usage of current process (C ++ and C #) надає код і пояснення для отримання процесорного часу та іншої статистики на Windows.
- Posix Options на Kernel.org пояснює опціональні фичи і константи POSIX, включаючи _POSIX_TIMERS і _POSIX_CPUTIME.