Проблема измерения N раз времени выполнения кодового блока - PullRequest
0 голосов
/ 12 мая 2010

РЕДАКТИРОВАТЬ: Я только что нашел свою проблему после написания этого длинного поста, объясняющего каждую мелочь ... Если кто-то может дать мне хороший ответ о том, что я делаю неправильно, и как я могу получить исполнение время в секундах (используя число с 5 десятичными знаками или около того), я отмечу это как принятое. Подсказка: проблема заключалась в том, как я интерпретировал справочную страницу clock_getttime ().

Привет

Допустим, у меня есть функция с именем myOperation, для которой мне нужно измерить время выполнения. Чтобы измерить это, я использую clock_gettime(), как это было рекомендовано здесь в одном из комментариев.

Мой учитель рекомендует нам измерить его N раз, чтобы мы могли получить среднее, стандартное отклонение и медиану для окончательного отчета. Он также рекомендует нам выполнить myOperation M раз вместо одного. Если myOperation - очень быстрая операция, то ее измерение M раз позволит нам получить представление о «реальном времени», которое требуется; потому что используемые часы могут не иметь необходимой точности для измерения такой операции. Таким образом, выполнение myOperation только один раз или M раз действительно зависит, если сама операция занимает достаточно много времени для точности используемых нами часов.

У меня проблемы с этим M казнью. Увеличение M уменьшает (много) окончательное среднее значение. Что не имеет смысла для меня. Примерно так: в среднем у вас уходит от 3 до 5 секунд, чтобы добраться из точки А в В. Но затем вы переходите от А к В и обратно к А 5 раз (что составляет 10 раз, потому что от А до Б - то же самое, что и В). а) и вы измеряете это. Если вы разделите на 10, то среднее значение, которое вы получите, должно быть таким же, как и среднее, которое вы берете, путешествуя из пункта А в пункт Б, то есть от 3 до 5 секунд.

Это то, что я хочу, чтобы мой код делал, но он не работает. Если я продолжу увеличивать количество раз, когда я иду от А к В и обратно А, среднее будет с каждым разом все меньше и меньше, для меня это не имеет смысла.

Достаточно теории, вот мой код:

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

#define MEASUREMENTS 1
#define OPERATIONS   1

typedef struct timespec TimeClock;

TimeClock diffTimeClock(TimeClock start, TimeClock end) {
    TimeClock aux;

    if((end.tv_nsec - start.tv_nsec) < 0) {
        aux.tv_sec = end.tv_sec - start.tv_sec - 1;
        aux.tv_nsec = 1E9 + end.tv_nsec - start.tv_nsec;
    } else {
        aux.tv_sec = end.tv_sec - start.tv_sec;
        aux.tv_nsec = end.tv_nsec - start.tv_nsec;
    }

    return aux;
}

int main(void) {
    TimeClock sTime, eTime, dTime;
    int i, j;

    for(i = 0; i < MEASUREMENTS; i++) {
        printf(" » MEASURE %02d\n", i+1);

        clock_gettime(CLOCK_REALTIME, &sTime);

        for(j = 0; j < OPERATIONS; j++) {
            myOperation();
        }

        clock_gettime(CLOCK_REALTIME, &eTime);

        dTime = diffTimeClock(sTime, eTime);

        printf("   - NSEC (TOTAL): %ld\n", dTime.tv_nsec);
        printf("   - NSEC (OP): %ld\n\n", dTime.tv_nsec / OPERATIONS);
    }

    return 0;
}

Примечания: Вышеупомянутая diffTimeClock функция взята из этого сообщения в блоге . Я заменил свою реальную операцию на myOperation(), потому что публиковать мои реальные функции не имеет никакого смысла, так как мне пришлось бы публиковать длинные блоки кода, вы можете легко кодировать myOperation() с любым, что вам нравится для компиляции кода, если Вы хотите.

Как видите, OPERATIONS = 1 и результаты:

 » MEASURE 01
   - NSEC (TOTAL): 27456580
   - NSEC (OP): 27456580

Для OPERATIONS = 100 результаты:

 » MEASURE 01
   - NSEC (TOTAL): 218929736
   - NSEC (OP): 2189297

Для OPERATIONS = 1000 результаты:

 » MEASURE 01
   - NSEC (TOTAL): 862834890
   - NSEC (OP): 862834

Для OPERATIONS = 10000 результаты:

 » MEASURE 01
   - NSEC (TOTAL): 574133641
   - NSEC (OP): 57413

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

Вы могли бы сказать мне, что это на самом деле зависит от самой операции, читаемых данных и что некоторые данные уже могут быть в кеше и т. Д., Но я не думаю, что это проблема. В моем случае myOperation читает 5000 строк текста из файла CSV, разделяя значения на ; и вставляя эти значения в структуру данных. Для каждой итерации я уничтожаю структуру данных и заново ее инициализирую.

Теперь, когда я думаю об этом, я также думаю, что есть проблема измерения времени с clock_gettime(), возможно, я не правильно его использую. Я имею в виду, посмотрите на последний пример, где OPERATIONS = 10000. Общее время, которое потребовалось, составило 574133641 нс, что составляет примерно 0,5 с; это невозможно, это заняло пару минут, так как я не мог стоять и смотреть на экран в ожидании и пошел что-то есть.

Ответы [ 4 ]

1 голос
/ 13 мая 2010

Вам просто нужно изменить функцию diffTimeClock(), чтобы она возвращала разницу в количестве секунд, как double:

double diffTimeClock(TimeClock start, TimeClock end) {
    double diff;

    diff = (end.tv_nsec - start.tv_nsec) / 1E9;
    diff += (end.tv_sec - start.tv_sec);

    return diff;
}

и в основной процедуре измените dTime на double, а printfs подойдет:

printf("   - SEC (TOTAL): %f\n", dTime);
printf("   - SEC (OP): %f\n\n", dTime / OPERATIONS);
1 голос
/ 12 мая 2010

Похоже, что у типа TimeClock есть два поля, одно для секунд и одно для наносекунд. Не имеет смысла просто делить поле наносек с количеством операций. Вам нужно разделить общее время.

1 голос
/ 13 мая 2010

Если вы используете систему POSIX, где есть функция gettimeofday (), вы можете использовать что-то вроде этого, чтобы получить текущее время в микросекундах:

long long timeInMicroseconds(void) {
    struct timeval tv;

    gettimeofday(&tv,NULL);
    return (((long long)tv.tv_sec)*1000000)+tv.tv_usec;
}

Причина, по которой это очень удобно, состоит в том, что для того, чтобы вычислить, сколько потребовалось вашей функции, вам нужно сделать следующее:

long long start = timeInMicroseconds();
... do your task N times ...
printf("Total microseconds: %lld", timeInMicroseconds()-start);

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

0 голосов
/ 12 мая 2010

Я обычно использую функцию time () для этого. Он показывает время настенных часов, но в конце концов это то, что меня волнует.

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

...