SlideShare a Scribd company logo
1 of 8
Download to read offline
Вечный вопрос измерения времени
Автор: Андрей Карпов

Дата: 30.03.2011

Казалось, закончились долгие обсуждения в форумах, как измерить время работы алгоритма,
какие функции использовать, какую точность ожидать. Жаль, но опять придется вернуться к этому
вопросу. На повестке дня вопрос – как лучше измерить скорость работы параллельного
алгоритма.

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

Задача состоит в измерении времени работы участка пользовательского кода. Раньше для этой
задачи я использовал класс следующего вида:

class Timing {

public:

  void StartTiming();

  void StopTiming();

  double GetUserSeconds() const {

      return double(m_userTime) / 10000000.0;

  }

private:

  __int64 GetUserTime() const;

  __int64 m_userTime;

};



__int64 Timing::GetUserTime() const {

  FILETIME creationTime;

  FILETIME exitTime;

  FILETIME kernelTime;

  FILETIME userTime;

  GetThreadTimes(GetCurrentThread(),
&creationTime, &exitTime,

                      &kernelTime, &userTime);

    __int64 curTime;

    curTime = userTime.dwHighDateTime;

    curTime <<= 32;

    curTime += userTime.dwLowDateTime;

    return curTime;

}



void Timing::StartTiming() {

    m_userTime = GetUserTime();

}



void Timing::StopTiming() {

    __int64 curUserTime = GetUserTime();

    m_userTime = curUserTime - m_userTime;

}

Данный класс основан на использовании функции GetThreadTimes, которая позволяет разделить
время, затраченное на работу пользовательского кода, и время работы системных функций. Класс
предназначен для оценки времени работы потока в пользовательском режиме, и поэтому
используется только возвращаемый параметр lpUserTime.

Рассмотрим пример кода, вычисляющий некоторое число. Используем для измерения времени
работы класс Timing.

void UseTiming1()

{

    Timing t;

    t.StartTiming();

    unsigned sum = 0;



    for (int i = 0; i < 1000000; i++)

    {
char str[1000];

        for (int j = 0; j < 999; j++)

         str[j] = char(((i + j) % 254) + 1);

        str[999] = 0;

        for (char c = 'a'; c <= 'z'; c++)

         if (strchr(str, c) != NULL)

           sum += 1;

    }



    t.StopTiming();

    printf("sum = %un", sum);

    printf("%.3G seconds.n", t.GetUserSeconds());

}

В таком виде механизм измерения времени ведет себя как ожидалось и на моей рабочей машине
выдает, скажем, 7 секунд. Результат корректен даже для многоядерной машины, так как неважно
какие ядра будут использованы в процессе работы алгоритма (см. рисунок 1).




Рисунок 1 - Работа одного потока на многоядерной машине

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

#pragma omp parallel for reduction(+:sum)

for (int i = 0; i < 1000000; i++)
{

    char str[1000];

    for (int j = 0; j < 999; j++)

     str[j] = char(((i + j) % 254) + 1);

    str[999] = 0;

    for (char c = 'a'; c <= 'z'; c++)

     if (strchr(str, c) != NULL)

       sum += 1;

}

Теперь программа печатает на экран время работы 1.6 секунд. Поскольку используется машина с
4 ядрами, хочется сказать "Ура, мы получили ускорение в 4 раза и замер времени работы это
подтверждает".

Огорчу. Мы измеряем не время работы алгоритма, а время работы главного потока. В данном
случае измерение кажется достоверным, поскольку основной поток работал столько же, сколько и
дополнительные. Поставим простой эксперимент. Явно укажем использовать 10 потоков, а не 4:

#pragma omp parallel for reduction(+:sum) num_threads(10)

Логика подсказывает, что данный код должен работать приблизительно тоже время, что и код,
распараллеливаемый на 4 потока. У нас четырех ядерный процессор, а следовательно от
увеличения количества потоков можно ожидать только замедление. Однако на экране мы увидим
значение порядка 0.7 секунд.

Это ожидаемый результат, хотя мы хотели получить совсем иное. Было создано 10 потоков.
Каждый из которых отработал порядка 0.7 секунд. Именно это время работал и основной поток,
время которого мы замеряем, используя класс Timing. Как видите, такой способ неприменим для
измерения скорости программ с параллельными участками кода. Для наглядности отобразим это
на рисунке 2.
Рисунок 2 - Так может выглядеть работа 10 потоков, на машине с четырьмя ядрами

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



Любимой функцией многих разработчиков для измерения скорости является
QueryPerformanceCounter. Давайте построим измерение скорости с ее использованием. В простом
виде класс для измерения будет выглядеть следующим образом:

class Timing2 {

public:

    void StartTiming();

    void StopTiming();

    double GetUserSeconds() const {

        return value;

    }

private:

    double value;

    LARGE_INTEGER time1;

};



void Timing2::StartTiming()

{

    QueryPerformanceCounter(&time1);

}



void Timing2::StopTiming()

{

    LARGE_INTEGER performance_frequency, time2;

    QueryPerformanceFrequency(&performance_frequency);

    QueryPerformanceCounter(&time2);

    value = (double)(time2.QuadPart - time1.QuadPart);
value /= performance_frequency.QuadPart;

}

К сожалению, на многоядерной машине, так делать больше нельзя. :) Вот что сказано по поводу
этой функции в MSDN:

On a multiprocessor computer, it should not matter which processor is called. However, you can get
different results on different processors due to bugs in the basic input/output system (BIOS) or the
hardware abstraction layer (HAL). To specify processor affinity for a thread, use the
SetThreadAffinityMask function.

Произведем усовершенствования и привяжем главный поток к одному ядру:

class Timing2 {

public:

    void StartTiming();

    void StopTiming();

    double GetUserSeconds() const {

        return value;

    }

private:

    DWORD_PTR oldmask;

    double value;

    LARGE_INTEGER time1;

};



void Timing2::StartTiming()

{

    volatile int warmingUp = 1;

    #pragma omp parallel for

    for (int i=1; i<10000000; i++)

    {

        #pragma omp atomic

        warmingUp *= i;

    }
oldmask = SetThreadAffinityMask(::GetCurrentThread(), 1);



    QueryPerformanceCounter(&time1);

}



void Timing2::StopTiming()

{

    LARGE_INTEGER performance_frequency, time2;

    QueryPerformanceFrequency(&performance_frequency);

    QueryPerformanceCounter(&time2);

    SetThreadAffinityMask(::GetCurrentThread(), oldmask);



    value = (double)(time2.QuadPart - time1.QuadPart);

    value /= performance_frequency.QuadPart;

}

У читателей может возникнуть вопрос, зачем нужен странный, ничего не делающий цикл?
Современные процессоры уменьшают свою частоту, если не нагружены. Имеющийся цикл
заранее выводит процессор на максимальную скорость работы и тем самым несколько повышает
точность измерения скорости. При этом мы прогреваем все доступные ядра.

Показанный способ измерения по-прежнему подвержен тому же недостатку, что невозможно
отделить время работы системного и пользовательского кода. Если на ядре выполняются другие
задачи, то результат измерения также будет весьма неточен. Однако как мне кажется, такой
способ все же применим к параллельному алгоритму в отличии GetThreadTimes.

Измерим, что покажут классы Timing и Timing2 на различном количестве потоков. Для этого
используется OpenMP-директива num_threads(N). Сведем данные в таблицу, показанную на
третьем рисунке.
Рисунок 3 - Время работы алгоритма в секундах измеренное с помощью функций GetThreadTimes
и QueryPerformanceCounter на четырехядерной машине

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

К сожалению, от запуска к запуску, программа печатает отличающиеся значения. Я не знаю как
сделать измерение более правильным и точным. Жду ваших комментариев и описаний способов,
как лучше измерять время работы параллельных алгоритмов.

Текст программы для скачивания доступен здесь (проект для Visual Studio 2005).

More Related Content

What's hot

Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Mikhail Kurnosov
 
Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)Mikhail Kurnosov
 
Intel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибкамиIntel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибкамиTatyanazaxarova
 
Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPMikhail Kurnosov
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Yauheni Akhotnikau
 
разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2Eugeniy Tyumentcev
 
Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPMikhail Kurnosov
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3Eugeniy Tyumentcev
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловSergey Platonov
 
Статический анализ: ошибки в медиаплеере и безглючная аська
Статический анализ: ошибки в медиаплеере и безглючная аська Статический анализ: ошибки в медиаплеере и безглючная аська
Статический анализ: ошибки в медиаплеере и безглючная аська Tatyanazaxarova
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...Alexey Paznikov
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Mikhail Kurnosov
 
FreeRTOS
FreeRTOSFreeRTOS
FreeRTOSquakke
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...Alexey Paznikov
 
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...corehard_by
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиvictor-yastrebov
 
Применение фреймворка GStreamer в системе видеонаблюдения
Применение фреймворка GStreamer в системе видеонаблюденияПрименение фреймворка GStreamer в системе видеонаблюдения
Применение фреймворка GStreamer в системе видеонаблюденияcorehard_by
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1Michael Karpov
 
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX ThreadsПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX ThreadsAlexey Paznikov
 

What's hot (20)

Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
Лекция 7: Многопоточное программирование: часть 3 (OpenMP)
 
Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)Семинар 6. Многопоточное программирование на OpenMP (часть 6)
Семинар 6. Многопоточное программирование на OpenMP (часть 6)
 
Intel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибкамиIntel IPP Samples for Windows - работа над ошибками
Intel IPP Samples for Windows - работа над ошибками
 
Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMP
 
Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?Для чего мы делали свой акторный фреймворк и что из этого вышло?
Для чего мы делали свой акторный фреймворк и что из этого вышло?
 
разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2разработка серверов и серверных приложений лекция №2
разработка серверов и серверных приложений лекция №2
 
Parallel STL
Parallel STLParallel STL
Parallel STL
 
Лекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMPЛекция 6. Стандарт OpenMP
Лекция 6. Стандарт OpenMP
 
разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3разработка серверов и серверных приложений лекция №3
разработка серверов и серверных приложений лекция №3
 
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионаловПолухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
Полухин Антон, Как делать не надо: C++ велосипедостроение для профессионалов
 
Статический анализ: ошибки в медиаплеере и безглючная аська
Статический анализ: ошибки в медиаплеере и безглючная аська Статический анализ: ошибки в медиаплеере и безглючная аська
Статический анализ: ошибки в медиаплеере и безглючная аська
 
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
ПВТ - весна 2015 - Лекция 5. Многопоточное программирование в С++. Синхрониза...
 
Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)Семинар 9. Параллельное программирование на MPI (часть 2)
Семинар 9. Параллельное программирование на MPI (часть 2)
 
FreeRTOS
FreeRTOSFreeRTOS
FreeRTOS
 
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
ПВТ - весна 2015 - Лекция 1. Актуальность параллельных вычислений. Анализ пар...
 
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...
Модульность и управляемая многопоточность встраиваемых С++ приложений - трудн...
 
Использование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработкиИспользование юнит-тестов для повышения качества разработки
Использование юнит-тестов для повышения качества разработки
 
Применение фреймворка GStreamer в системе видеонаблюдения
Применение фреймворка GStreamer в системе видеонаблюденияПрименение фреймворка GStreamer в системе видеонаблюдения
Применение фреймворка GStreamer в системе видеонаблюдения
 
20090720 hpc exercise1
20090720 hpc exercise120090720 hpc exercise1
20090720 hpc exercise1
 
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX ThreadsПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
ПВТ - осень 2014 - Лекция 3 - Стандарт POSIX Threads
 

Viewers also liked

Presentacion de Fran Moreno para adwe
Presentacion de Fran Moreno para adwePresentacion de Fran Moreno para adwe
Presentacion de Fran Moreno para adweADWE Team
 
Normalizacion de la Tara
Normalizacion de la TaraNormalizacion de la Tara
Normalizacion de la TaraVLADEMIRSS
 
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...VLADEMIRSS
 
Formación Competencias Tecnológicas - Wilson Castaño
Formación Competencias Tecnológicas - Wilson CastañoFormación Competencias Tecnológicas - Wilson Castaño
Formación Competencias Tecnológicas - Wilson Castañocolfreepress
 
FormacióN Barcelona V2.00
FormacióN Barcelona V2.00FormacióN Barcelona V2.00
FormacióN Barcelona V2.00red.es
 
Novas da xustiza nº1036 Boletín de CCOO
Novas da xustiza nº1036 Boletín de CCOONovas da xustiza nº1036 Boletín de CCOO
Novas da xustiza nº1036 Boletín de CCOOCCOOXustiza
 
Software libre en_educacion_v2 (1)
Software libre en_educacion_v2 (1)Software libre en_educacion_v2 (1)
Software libre en_educacion_v2 (1)Carol de la Plaza
 
Bibliotic 2009 - Presentación BibloRed Taller de Búsqueda
Bibliotic 2009 - Presentación BibloRed Taller de BúsquedaBibliotic 2009 - Presentación BibloRed Taller de Búsqueda
Bibliotic 2009 - Presentación BibloRed Taller de Búsquedacolfreepress
 
Formación en gestión pública
Formación en gestión públicaFormación en gestión pública
Formación en gestión públicagatitasusan
 
Experiencia de indización colectiva y voluntaria
Experiencia de indización colectiva y voluntariaExperiencia de indización colectiva y voluntaria
Experiencia de indización colectiva y voluntariacolfreepress
 

Viewers also liked (20)

Presentacion de Fran Moreno para adwe
Presentacion de Fran Moreno para adwePresentacion de Fran Moreno para adwe
Presentacion de Fran Moreno para adwe
 
Redes2
Redes2Redes2
Redes2
 
Diapo04
Diapo04Diapo04
Diapo04
 
Normalizacion de la Tara
Normalizacion de la TaraNormalizacion de la Tara
Normalizacion de la Tara
 
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...
COORPORACION REGIONAL PARA EL DESARROLLO DE LA TAYA - PROCESO CONSTITUCION CO...
 
Formación Competencias Tecnológicas - Wilson Castaño
Formación Competencias Tecnológicas - Wilson CastañoFormación Competencias Tecnológicas - Wilson Castaño
Formación Competencias Tecnológicas - Wilson Castaño
 
PresentacióN Daniel Lequerica
PresentacióN Daniel LequericaPresentacióN Daniel Lequerica
PresentacióN Daniel Lequerica
 
Fotos Jornadas AVS 2013 Granada
Fotos Jornadas AVS 2013 GranadaFotos Jornadas AVS 2013 Granada
Fotos Jornadas AVS 2013 Granada
 
FormacióN Barcelona V2.00
FormacióN Barcelona V2.00FormacióN Barcelona V2.00
FormacióN Barcelona V2.00
 
Novas da xustiza nº1036 Boletín de CCOO
Novas da xustiza nº1036 Boletín de CCOONovas da xustiza nº1036 Boletín de CCOO
Novas da xustiza nº1036 Boletín de CCOO
 
Software libre en_educacion_v2 (1)
Software libre en_educacion_v2 (1)Software libre en_educacion_v2 (1)
Software libre en_educacion_v2 (1)
 
Mi blog de aprendizaje
Mi blog de aprendizajeMi blog de aprendizaje
Mi blog de aprendizaje
 
Informe actividad Gipuzkoa Aurrera ( 2008-2011)
Informe actividad Gipuzkoa Aurrera ( 2008-2011)Informe actividad Gipuzkoa Aurrera ( 2008-2011)
Informe actividad Gipuzkoa Aurrera ( 2008-2011)
 
Bip xullo 2013
Bip xullo 2013Bip xullo 2013
Bip xullo 2013
 
Prob Sol[1]
Prob Sol[1]Prob Sol[1]
Prob Sol[1]
 
Ebook mitosy realidades
Ebook mitosy realidadesEbook mitosy realidades
Ebook mitosy realidades
 
Bibliotic 2009 - Presentación BibloRed Taller de Búsqueda
Bibliotic 2009 - Presentación BibloRed Taller de BúsquedaBibliotic 2009 - Presentación BibloRed Taller de Búsqueda
Bibliotic 2009 - Presentación BibloRed Taller de Búsqueda
 
Guia De Usuario
Guia De UsuarioGuia De Usuario
Guia De Usuario
 
Formación en gestión pública
Formación en gestión públicaFormación en gestión pública
Formación en gestión pública
 
Experiencia de indización colectiva y voluntaria
Experiencia de indización colectiva y voluntariaExperiencia de indización colectiva y voluntaria
Experiencia de indización colectiva y voluntaria
 

Similar to Вечный вопрос измерения времени

Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Mikhail Kurnosov
 
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Yandex
 
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"Fwdays
 
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья СтусьПолный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья СтусьMail.ru Group
 
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Mikhail Kurnosov
 
Борзунов Александр, Cpmoptimize
Борзунов Александр, CpmoptimizeБорзунов Александр, Cpmoptimize
Борзунов Александр, CpmoptimizeDarya Zubova
 
Автоматическая оптимизация алгоритмов с помощью быстрого возведения матриц в ...
Автоматическая оптимизация алгоритмов с помощью быстрого возведения матриц в ...Автоматическая оптимизация алгоритмов с помощью быстрого возведения матриц в ...
Автоматическая оптимизация алгоритмов с помощью быстрого возведения матриц в ...Alexander Borzunov
 
практика 5
практика 5практика 5
практика 5student_kai
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаSergey Platonov
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioAndrey Karpov
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesPlatonov Sergey
 
Многопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметкиМногопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметкиDotNetConf
 
Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)Mikhail Kurnosov
 
Статический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMergeСтатический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMergeTatyanazaxarova
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Yandex
 
Опыт разработки статического анализатора кода
Опыт разработки статического анализатора кодаОпыт разработки статического анализатора кода
Опыт разработки статического анализатора кодаAndrey Karpov
 
Tomato Engine: Как мы создавали онлайн шутер с авторитарным сервером
Tomato Engine: Как мы создавали онлайн шутер с авторитарным серверомTomato Engine: Как мы создавали онлайн шутер с авторитарным сервером
Tomato Engine: Как мы создавали онлайн шутер с авторитарным серверомDevGAMM Conference
 

Similar to Вечный вопрос измерения времени (20)

Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
Лекция 7: Фибоначчиевы кучи (Fibonacci heaps)
 
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
Использование шаблонов и RTTI для конфигурации симулятора флеш-накопителя - Г...
 
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
Aleksei Milovidov "Let's optimize one aggregate function in ClickHouse"
 
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья СтусьПолный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
Полный цикл тестирования React-приложений, Алексей Андросов и Наталья Стусь
 
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
Лекция 6: Многопоточное программирование: часть 2 (Speedup, Amdahl's law, POS...
 
Борзунов Александр, Cpmoptimize
Борзунов Александр, CpmoptimizeБорзунов Александр, Cpmoptimize
Борзунов Александр, Cpmoptimize
 
Автоматическая оптимизация алгоритмов с помощью быстрого возведения матриц в ...
Автоматическая оптимизация алгоритмов с помощью быстрого возведения матриц в ...Автоматическая оптимизация алгоритмов с помощью быстрого возведения матриц в ...
Автоматическая оптимизация алгоритмов с помощью быстрого возведения матриц в ...
 
практика 5
практика 5практика 5
практика 5
 
лекция 4
лекция 4лекция 4
лекция 4
 
Павел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладкаПавел Довгалюк, Обратная отладка
Павел Довгалюк, Обратная отладка
 
Принципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-StudioПринципы работы статического анализатора кода PVS-Studio
Принципы работы статического анализатора кода PVS-Studio
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
 
Оптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templatesОптимизация трассирования с использованием Expression templates
Оптимизация трассирования с использованием Expression templates
 
Многопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметкиМногопоточное программирование на C#, путевые заметки
Многопоточное программирование на C#, путевые заметки
 
Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)Семинар 1. Многопоточное программирование на OpenMP (часть 1)
Семинар 1. Многопоточное программирование на OpenMP (часть 1)
 
Статический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMergeСтатический анализ исходного кода на примере WinMerge
Статический анализ исходного кода на примере WinMerge
 
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
Евгений Крутько — Опыт внедрения технологий параллельных вычислений для повыш...
 
Опыт разработки статического анализатора кода
Опыт разработки статического анализатора кодаОпыт разработки статического анализатора кода
Опыт разработки статического анализатора кода
 
Tomato Engine: Как мы создавали онлайн шутер с авторитарным сервером
Tomato Engine: Как мы создавали онлайн шутер с авторитарным серверомTomato Engine: Как мы создавали онлайн шутер с авторитарным сервером
Tomato Engine: Как мы создавали онлайн шутер с авторитарным сервером
 
информатика лекции 4
информатика лекции 4информатика лекции 4
информатика лекции 4
 

More from Tatyanazaxarova

Урок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияУрок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияTatyanazaxarova
 
Урок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программУрок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программTatyanazaxarova
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокTatyanazaxarova
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиTatyanazaxarova
 
Урок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структурУрок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структурTatyanazaxarova
 
Урок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данныхУрок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данныхTatyanazaxarova
 
Урок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияУрок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияTatyanazaxarova
 
Урок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен даннымиУрок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен даннымиTatyanazaxarova
 
Урок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаУрок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаTatyanazaxarova
 
Урок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхУрок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхTatyanazaxarova
 
Урок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателейУрок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателейTatyanazaxarova
 
Урок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметикаУрок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметикаTatyanazaxarova
 
Урок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаУрок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаTatyanazaxarova
 
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументовУрок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументовTatyanazaxarova
 
Урок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаУрок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаTatyanazaxarova
 
Урок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокУрок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокTatyanazaxarova
 
Урок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокУрок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокTatyanazaxarova
 
Урок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеУрок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеTatyanazaxarova
 
Урок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияУрок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияTatyanazaxarova
 
Урок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииУрок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииTatyanazaxarova
 

More from Tatyanazaxarova (20)

Урок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окруженияУрок 27. Особенности создания инсталляторов для 64-битного окружения
Урок 27. Особенности создания инсталляторов для 64-битного окружения
 
Урок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программУрок 26. Оптимизация 64-битных программ
Урок 26. Оптимизация 64-битных программ
 
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибокУрок 25. Практическое знакомство с паттернами 64-битных ошибок
Урок 25. Практическое знакомство с паттернами 64-битных ошибок
 
Урок 24. Фантомные ошибки
Урок 24. Фантомные ошибкиУрок 24. Фантомные ошибки
Урок 24. Фантомные ошибки
 
Урок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структурУрок 23. Паттерн 15. Рост размеров структур
Урок 23. Паттерн 15. Рост размеров структур
 
Урок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данныхУрок 21. Паттерн 13. Выравнивание данных
Урок 21. Паттерн 13. Выравнивание данных
 
Урок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. ИсключенияУрок 20. Паттерн 12. Исключения
Урок 20. Паттерн 12. Исключения
 
Урок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен даннымиУрок 19. Паттерн 11. Сериализация и обмен данными
Урок 19. Паттерн 11. Сериализация и обмен данными
 
Урок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметикаУрок 17. Паттерн 9. Смешанная арифметика
Урок 17. Паттерн 9. Смешанная арифметика
 
Урок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединенияхУрок 16. Паттерн 8. Memsize-типы в объединениях
Урок 16. Паттерн 8. Memsize-типы в объединениях
 
Урок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателейУрок 15. Паттерн 7. Упаковка указателей
Урок 15. Паттерн 7. Упаковка указателей
 
Урок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметикаУрок 13. Паттерн 5. Адресная арифметика
Урок 13. Паттерн 5. Адресная арифметика
 
Урок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвигаУрок 11. Паттерн 3. Операции сдвига
Урок 11. Паттерн 3. Операции сдвига
 
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументовУрок 10. Паттерн 2. Функции с переменным количеством аргументов
Урок 10. Паттерн 2. Функции с переменным количеством аргументов
 
Урок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числаУрок 9. Паттерн 1. Магические числа
Урок 9. Паттерн 1. Магические числа
 
Урок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибокУрок 8. Статический анализ для выявления 64-битных ошибок
Урок 8. Статический анализ для выявления 64-битных ошибок
 
Урок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибокУрок 7. Проблемы выявления 64-битных ошибок
Урок 7. Проблемы выявления 64-битных ошибок
 
Урок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном кодеУрок 6. Ошибки в 64-битном коде
Урок 6. Ошибки в 64-битном коде
 
Урок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложенияУрок 5. Сборка 64-битного приложения
Урок 5. Сборка 64-битного приложения
 
Урок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурацииУрок 4. Создание 64-битной конфигурации
Урок 4. Создание 64-битной конфигурации
 

Вечный вопрос измерения времени

  • 1. Вечный вопрос измерения времени Автор: Андрей Карпов Дата: 30.03.2011 Казалось, закончились долгие обсуждения в форумах, как измерить время работы алгоритма, какие функции использовать, какую точность ожидать. Жаль, но опять придется вернуться к этому вопросу. На повестке дня вопрос – как лучше измерить скорость работы параллельного алгоритма. Сразу скажу, что не дам точного рецепта. Я сам недавно столкнулся с проблемой измерения скорости работы параллельных алгоритмов и не являюсь экспертом в этом вопросе. Эта заметка носит скорее исследовательский характер. Я буду рад услышать ваше мнение и рекомендации. Думаю, вместе мы разберемся с проблемой и выработаем оптимальное решение. Задача состоит в измерении времени работы участка пользовательского кода. Раньше для этой задачи я использовал класс следующего вида: class Timing { public: void StartTiming(); void StopTiming(); double GetUserSeconds() const { return double(m_userTime) / 10000000.0; } private: __int64 GetUserTime() const; __int64 m_userTime; }; __int64 Timing::GetUserTime() const { FILETIME creationTime; FILETIME exitTime; FILETIME kernelTime; FILETIME userTime; GetThreadTimes(GetCurrentThread(),
  • 2. &creationTime, &exitTime, &kernelTime, &userTime); __int64 curTime; curTime = userTime.dwHighDateTime; curTime <<= 32; curTime += userTime.dwLowDateTime; return curTime; } void Timing::StartTiming() { m_userTime = GetUserTime(); } void Timing::StopTiming() { __int64 curUserTime = GetUserTime(); m_userTime = curUserTime - m_userTime; } Данный класс основан на использовании функции GetThreadTimes, которая позволяет разделить время, затраченное на работу пользовательского кода, и время работы системных функций. Класс предназначен для оценки времени работы потока в пользовательском режиме, и поэтому используется только возвращаемый параметр lpUserTime. Рассмотрим пример кода, вычисляющий некоторое число. Используем для измерения времени работы класс Timing. void UseTiming1() { Timing t; t.StartTiming(); unsigned sum = 0; for (int i = 0; i < 1000000; i++) {
  • 3. char str[1000]; for (int j = 0; j < 999; j++) str[j] = char(((i + j) % 254) + 1); str[999] = 0; for (char c = 'a'; c <= 'z'; c++) if (strchr(str, c) != NULL) sum += 1; } t.StopTiming(); printf("sum = %un", sum); printf("%.3G seconds.n", t.GetUserSeconds()); } В таком виде механизм измерения времени ведет себя как ожидалось и на моей рабочей машине выдает, скажем, 7 секунд. Результат корректен даже для многоядерной машины, так как неважно какие ядра будут использованы в процессе работы алгоритма (см. рисунок 1). Рисунок 1 - Работа одного потока на многоядерной машине Теперь представим, что мы хотим использовать в нашей программе возможности многоядерных процессоров и хотим оценить, что нам дает распараллеливание алгоритма на основе технологии OpenMP. Распараллелим наш код, добавив одну строчку: #pragma omp parallel for reduction(+:sum) for (int i = 0; i < 1000000; i++)
  • 4. { char str[1000]; for (int j = 0; j < 999; j++) str[j] = char(((i + j) % 254) + 1); str[999] = 0; for (char c = 'a'; c <= 'z'; c++) if (strchr(str, c) != NULL) sum += 1; } Теперь программа печатает на экран время работы 1.6 секунд. Поскольку используется машина с 4 ядрами, хочется сказать "Ура, мы получили ускорение в 4 раза и замер времени работы это подтверждает". Огорчу. Мы измеряем не время работы алгоритма, а время работы главного потока. В данном случае измерение кажется достоверным, поскольку основной поток работал столько же, сколько и дополнительные. Поставим простой эксперимент. Явно укажем использовать 10 потоков, а не 4: #pragma omp parallel for reduction(+:sum) num_threads(10) Логика подсказывает, что данный код должен работать приблизительно тоже время, что и код, распараллеливаемый на 4 потока. У нас четырех ядерный процессор, а следовательно от увеличения количества потоков можно ожидать только замедление. Однако на экране мы увидим значение порядка 0.7 секунд. Это ожидаемый результат, хотя мы хотели получить совсем иное. Было создано 10 потоков. Каждый из которых отработал порядка 0.7 секунд. Именно это время работал и основной поток, время которого мы замеряем, используя класс Timing. Как видите, такой способ неприменим для измерения скорости программ с параллельными участками кода. Для наглядности отобразим это на рисунке 2.
  • 5. Рисунок 2 - Так может выглядеть работа 10 потоков, на машине с четырьмя ядрами Конечно, всегда можно использовать функцию time(), но ее разрешающая способность низкая, она не позволяет разделить время работы пользовательского и системного кода. Дополнительно на время могут влиять другие процессы, что также может сильно искажать измерения времени. Любимой функцией многих разработчиков для измерения скорости является QueryPerformanceCounter. Давайте построим измерение скорости с ее использованием. В простом виде класс для измерения будет выглядеть следующим образом: class Timing2 { public: void StartTiming(); void StopTiming(); double GetUserSeconds() const { return value; } private: double value; LARGE_INTEGER time1; }; void Timing2::StartTiming() { QueryPerformanceCounter(&time1); } void Timing2::StopTiming() { LARGE_INTEGER performance_frequency, time2; QueryPerformanceFrequency(&performance_frequency); QueryPerformanceCounter(&time2); value = (double)(time2.QuadPart - time1.QuadPart);
  • 6. value /= performance_frequency.QuadPart; } К сожалению, на многоядерной машине, так делать больше нельзя. :) Вот что сказано по поводу этой функции в MSDN: On a multiprocessor computer, it should not matter which processor is called. However, you can get different results on different processors due to bugs in the basic input/output system (BIOS) or the hardware abstraction layer (HAL). To specify processor affinity for a thread, use the SetThreadAffinityMask function. Произведем усовершенствования и привяжем главный поток к одному ядру: class Timing2 { public: void StartTiming(); void StopTiming(); double GetUserSeconds() const { return value; } private: DWORD_PTR oldmask; double value; LARGE_INTEGER time1; }; void Timing2::StartTiming() { volatile int warmingUp = 1; #pragma omp parallel for for (int i=1; i<10000000; i++) { #pragma omp atomic warmingUp *= i; }
  • 7. oldmask = SetThreadAffinityMask(::GetCurrentThread(), 1); QueryPerformanceCounter(&time1); } void Timing2::StopTiming() { LARGE_INTEGER performance_frequency, time2; QueryPerformanceFrequency(&performance_frequency); QueryPerformanceCounter(&time2); SetThreadAffinityMask(::GetCurrentThread(), oldmask); value = (double)(time2.QuadPart - time1.QuadPart); value /= performance_frequency.QuadPart; } У читателей может возникнуть вопрос, зачем нужен странный, ничего не делающий цикл? Современные процессоры уменьшают свою частоту, если не нагружены. Имеющийся цикл заранее выводит процессор на максимальную скорость работы и тем самым несколько повышает точность измерения скорости. При этом мы прогреваем все доступные ядра. Показанный способ измерения по-прежнему подвержен тому же недостатку, что невозможно отделить время работы системного и пользовательского кода. Если на ядре выполняются другие задачи, то результат измерения также будет весьма неточен. Однако как мне кажется, такой способ все же применим к параллельному алгоритму в отличии GetThreadTimes. Измерим, что покажут классы Timing и Timing2 на различном количестве потоков. Для этого используется OpenMP-директива num_threads(N). Сведем данные в таблицу, показанную на третьем рисунке.
  • 8. Рисунок 3 - Время работы алгоритма в секундах измеренное с помощью функций GetThreadTimes и QueryPerformanceCounter на четырехядерной машине Как видно из таблицы, пока количество потоков не превышает количества ядер, функция GetThreadTimes дает результат схожий с QueryPerformanceCounter, что может приводить к ощущению, что производятся корректные измерения. Однако при большем количестве потоков на ее результат полагаться уже нельзя. К сожалению, от запуска к запуску, программа печатает отличающиеся значения. Я не знаю как сделать измерение более правильным и точным. Жду ваших комментариев и описаний способов, как лучше измерять время работы параллельных алгоритмов. Текст программы для скачивания доступен здесь (проект для Visual Studio 2005).