Как контролировать загрузку процессора с помощью функции POSIX clock () во время выполнения? - PullRequest
4 голосов
/ 10 мая 2011

Есть ли надежный способ, как программа может измерить загрузку своего ЦП во время выполнения?

Мне, вероятно, придется использовать функцию POSIX clock () из time.h.Идея состоит в том, чтобы сначала использовать несколько миллисекунд для установки нагрузки на процессор (шаг A), затем на полную загрузку процессора (шаг B), затем для запуска программы и постоянного вызова clock ().Таким образом, я могу рассчитать загрузку ЦП относительно вычисленных на шаге А и шаге Б, чтобы отслеживать загрузку ЦП в процентах.Я предполагаю, что все другие фоновые процессы игнорируются.

Однако я не уверен, как правильно реализовать эти шаги A и B, скажем, функции idle () и full_load (), используя только C89 и POSIX?

Ответы [ 3 ]

5 голосов
/ 10 мая 2011

Когда вы говорите «full_load», и вам нужен только один процессор или виртуальное ядро ​​под нагрузкой, простой тугой цикл поможет вам.Конечно, он не будет использовать все транзисторы в чипе (т. Е. Мы не говорим о тесте прожига для «полной нагрузки»), но он будет использовать для запланированного промежутка времени, который получает процессориспользуйте все доступные тактовые циклы без системных вызовов, которые бы передавали управление ядру и, возможно, приводили к перепланированию исполняющего потока на более позднее время.Также вы можете использовать сигнализацию с обработчиком сигнала для выхода из цикла.Так что это позволило бы вам запустить цикл примерно на секунду времени выполнения (сигналы тревоги не являются точно точными по времени ... они близки, но не до такта).

В дополнениедля «пустой» части нагрузки вы могли бы сделать то же самое, но с использованием sigsuspend() вместо замкнутого цикла, который ожидал бы срабатывания будильника.

Таким образом, ваш код мог бы что-то выглядетьнапример:

#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <stdio.h>

static sig_atomic_t alarm_flag = 1;

void alarm_handler(int arg)
{
    alarm_flag = 0;
}

clock_t idle()
{
    //setup the alarm flag
    alarm_flag = 1;

    //setup the signal masks
    sigset_t old_signal_set;
    sigset_t new_signal_set;

    sigemptyset(&old_signal_set);
    sigemptyset(&new_signal_set);

    //block the alarm signal
    sigaddset(&new_signal_set, SIGALRM);
    sigprocmask(SIG_BLOCK, &new_signal_set, &old_signal_set);

    //setup the alarm
    alarm(1);

    clock_t time_before = clock();

    //sit idle while we wait for the alarm to go off
    while(alarm_flag)
        sigsuspend(&old_signal_set);

    clock_t time_after = clock();

    //restore the old signal mask
    sigprocmask(SIG_SETMASK, &old_signal_set, NULL);

    return time_after - time_before;
}

clock_t full_load()
{
    //set the alarm signal
    alarm_flag = 1;

    //set the 1-second alarm
    alarm(1);

    clock_t time_before = clock();

    //loop until the alarm goes off
    while(alarm_flag);

    clock_t time_after = clock();

    return time_after - time_before;
}

int main()
{
    //setup the signal handler for the alarm
    sigset(SIGALRM, alarm_handler);

    //call the functions
    clock_t idle_time = idle();
    clock_t load_time = full_load();

    //... do whatever else you need to-do with this info
    printf("Idle Time: %d\n", (int)idle_time);
    printf("Load Time: %d\n", (int)load_time);

    return 0;
}

Имейте в виду, что в соответствии со стандартом POSIX должно быть 1 миллион часов в секунду в качестве временной базы для значения clock_t, поэтому вы должны увидеть числовозвращается для "full_load", который близок к этому числу, так как мы собираемся "полная загрузка" в течение примерно секунды.Холостая нагрузка должна быть очень маленькой (конечно).Вот числа, которые я сгенерировал на своем Mac Pro:

Idle Time: 31
Load Time: 1000099

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

2 голосов
/ 10 мая 2011

Я думал, что это покрыто CLOCK_VIRTUAL (BSD / HP-UX) или CLOCK_PROCESS_CPUTIME_ID в Linux для clock_gettime (2).

0 голосов
/ 11 мая 2011

Вы не указываете версию POSIX, но если вы используете C89, она должна быть довольно старой.POSIX.1-2001 aka SUSv3 требует C99, а также POSIX.1-2008.

Калибровка кажется ненужной;Просто сравните значения, возвращенные к монотонному (лучше, но не доступному) или настенному времени.Для clock() используйте определение CLOCKS_PER_SEC (гарантированно будет один миллион, если система поддерживает опцию XSI, но не если это просто POSIX).

Рассмотрим getrusage() вместо clock() для большей точности и гибкости.

Функция getrusage() находилась под опцией XSI в более ранних версиях POSIX;История изменений говорит, что она была введена в Выпуске 4 Версии 2 (SUSv1) и была перемещена на базу в Выпуске 5 (SUSv2), но на ней все еще есть маркировки XSI.В любом случае это довольно распространенное явление, поскольку это функция 4.2BSD.

Другой вариант - функция times().

...