Измерение количества процессорного времени, занятого фрагментом кода, в C на Unix / Linux - PullRequest
6 голосов
/ 11 января 2010

Можно ли использовать clock () как надежный API для измерения времени, затрачиваемого ЦП на выполнение фрагмента кода? При проверке usng times () / clock () оба, похоже, не измеряют время процессора точно.

Во-первых, можно ли использовать API-интерфейс clock () / times () для измерения времени выполнения функции / фрагмента кода, как показано в примере ниже? Есть ли лучшая и надежная альтернатива? Механизм заключается в том, чтобы работать в Linux, HP-UX, IBM-AIX и Sun Solaris, поскольку нам необходимо измерять (и сравнивать) производительность фрагмента кода на всех этих платформах.

Пожалуйста, предложите. Кроме того, пожалуйста, дайте мне знать, если что-то упущено.

bbb@m_001:/tmp/kk1$ ./perf_clock 102400
{clock(): S          0 E          0 D    0.0000000000}
bbb@m_001:/tmp/kk1$ ./perf_clock 204800
{clock(): S          0 E      10000 D    0.0100000000}
bbb@m_001:/tmp/kk1$ cat perf_clock.c

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

void test_clock(char* sbuf, int* len){
    clock_t start, end; int i=0;
    start = clock();
    while(i++ < 500) memset((char*)sbuf,0,*len);
    end = clock();
    printf("{clock(): S %10lu E %10lu D %15.10f}\n",
        start,end,(end-start)/(double) CLOCKS_PER_SEC);
}
int main(int argc,char* argv[])
{
        int len=atoi(argv[1]);
        char *sbuf=(char*)malloc(len);
        test_clock(sbuf,&len);
        free(sbuf); return 0;
}

Результаты, похоже, говорят о том, что memset () 100 КБ, 500 раз, не тратит время. Или это говорит о том, что это невозможно измерить в микросекундах?

На самом деле, это не memset (), а другая функция [которая подготавливает огромную структуру размером около 1 МБ, размещает копию этой структуры, выделяет в БД Oracle и заполняет эти структуры данными из БД], которая пытается измерения. Даже это показывает 0 тиков, и это сбило меня с толку.

Спасибо!

Ответы [ 6 ]

7 голосов
/ 11 января 2010

В последних версиях Linux (*). Вы можете получить эту информацию из файловой системы / proc. В файле /proc/PID/stat 14-я запись содержит количество jiffies, использованных в коде пользовательского пространства, а 15-я запись имеет количество jiffies, используемых в системном коде.

Если вы хотите просматривать данные по отдельным потокам, вам следует ссылаться на файл /proc/PID/task/TID/stat.

Чтобы преобразовать jiffies в микросекунды, вы можете использовать следующее:

define USEC_PER_SEC         1000000UL

long long jiffies_to_microsecond(long long jiffies)
{
    long hz = sysconf(_SC_CLK_TCK);
    if (hz <= USEC_PER_SEC && !(USEC_PER_SEC % hz))
    {
        return (USEC_PER_SEC / hz) * jiffies;
    }
    else if (hz > USEC_PER_SEC && !(hz % USEC_PER_SEC))
    {
        return (jiffies + (hz / USEC_PER_SEC) - 1) / (hz / USEC_PER_SEC);
    }
    else
    {
        return (jiffies * USEC_PER_SEC) / hz;
    }
}

Если все, что вас волнует, это статистика по процессам, то getrusage проще. Но если вы хотите быть готовы сделать это для каждого потока, этот метод лучше, чем имя файла, код будет идентичен для получения данных для процесса или потока.

* - Я не уверен точно, когда был представлен файл статистики. Вам нужно будет проверить, есть ли в вашей системе.

5 голосов
/ 11 января 2010

Я бы попробовал с getrusage и проверил бы системное и пользовательское время.

Также сверьтесь с gettimeofday, чтобы сравнить со временем настенных часов.

4 голосов
/ 11 января 2010

Я бы попытался соотнести время с командой оболочки time для проверки работоспособности.

Также следует учитывать, что компилятор может оптимизировать цикл. Так как memset не зависит от переменной цикла, у компилятора будет искушение применить оптимизацию, известную как движение инвариантного кода цикла .

Я бы также предупредил, что 10 МБ, возможно, очищенное в кеше, на самом деле будет 1,25 или 2,5 миллиона операций ЦП, поскольку memset, безусловно, записывает в 4-байтовых или 8-байтовых количествах. Хотя я, скорее, сомневаюсь, что это можно сделать менее чем за микросекунду, поскольку хранилища стоят немного дороже, а 100 Кбайт добавляет некоторое давление в кеше L1, вы говорите о не более чем одной операции в наносекунду, которую не так сложно выдержать для многогГц процессор.

Можно представить, что 600 нС округляется до 1 такта, но я бы тоже об этом беспокоился.

1 голос
/ 11 января 2010

вы можете использовать clock_t, чтобы получить количество тактов процессора с момента запуска программы.

Или вы можете использовать команду linux time. Например: время [программа] [аргументы]

0 голосов
/ 11 января 2010

Использование ресурсов процессом / потоком обновляется ОС только периодически. Вполне возможно, что фрагмент кода будет завершен до следующего обновления, что приведет к разнице в использовании ресурсов. Ничего не могу сказать о HP или AIX, отсылаю вас к книге Performance and Tools для Sun. Для Linux вы хотите посмотреть oprofile и более новый perf tool . С профилирующей стороны очень помог бы valgrind .

0 голосов
/ 11 января 2010

Некоторая информация здесь на странице HP о таймерах с высоким разрешением. Кроме того, тот же трюк _Asm_mov_from_ar (_AREG_ITC); используется в http://www.fftw.org/cycle.h тоже.

Необходимо подтвердить, действительно ли это может быть решением.

Пример программы, протестированный на HP-UX 11.31:

bbb@m_001/tmp/prof > ./perf_ticks 1024
ticks-memset {func [1401.000000] inline [30.000000]} noop [9.000000]
bbb@m_001/tmp/prof > cat perf_ticks.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "cycle.h" /* one from http://www.fftw.org/cycle.h */
void test_ticks(char* sbuf, int* len){
    memset((char*)sbuf,0,*len);
}
int main(int argc,char* argv[]){
        int len=atoi(argv[1]);
        char *sbuf=(char*)malloc(len);
        ticks t1,t2,t3,t4,t5,t6;
        t1 =getticks(); test_ticks(sbuf,&len); t2 =getticks();
        t3 =getticks(); memset((char*)sbuf,0,len); t4 =getticks();
        t5=getticks();;t6=getticks();
        printf("ticks-memset {func [%llf] inline [%llf]} noop [%llf]\n",
                          elapsed(t2,t1),elapsed(t4,t3),elapsed(t6,t5));
        free(sbuf); return 0;
}
bbb@m_001/tmp/prof >
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...