Методы измерения времени работы программы

Данная статья посвящена обзору и описанию некоторых методов измерения времени работы программ. Произведено тестирование таймеров.
article placeholder

УДК 004.054

МЕТОДЫ ИЗМЕРЕНИЯ ВРЕМЕНИ РАБОТЫ ПРОГРАММЫ

Лохматов Степан Юрьевич1, Светлов Сергей Викторович2, Калач Геннадий Петрович3
1Московский технологический университет, студент 4 курса
2Московский технологический университет, студент 4 курса
3Московский технологический университет, кандидат военных наук, доцент военной кафедры

Аннотация
Данная статья посвящена обзору и описанию некоторых методов измерения времени работы программ. Произведено тестирование таймеров.

Ключевые слова: clock_get_time, rdtsc, методы измерения, программа


Рубрика: 05.00.00 ТЕХНИЧЕСКИЕ НАУКИ

Библиографическая ссылка на статью:
Лохматов С.Ю., Светлов С.В., Калач Г.П. Методы измерения времени работы программы // Современные научные исследования и инновации. 2017. № 5 [Электронный ресурс]. URL: https://web.snauka.ru/issues/2017/05/83188 (дата обращения: 25.02.2023).

Методология и способы измерений

Одним из главных способов проверки характеристик программного и аппаратного обеспечения касательно быстродействия является измерение времени прикладной программы или ее составных частей.

Подобная проверка целесообразна для нахождения мест в программе или ее алгоритме, которым необходима оптимизация, а также помогает судить о реальных производительных качествах компьютера. На время работы программы влияют различные факторы: характеристики программы, ОС компьютера, работающие процессы и пр.

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

Теперь подробно рассмотрим способы снижения влияния подобных нежелательных факторов.

  1. Многократное измерение. Время выполнения программы измеряется несколько раз. Обычно, из-за влияния сторонних факторов, измерения отличаются, а время работы самой программы не изменяется. Наиболее точным из всех полученных измерений будет являться минимальное значение.

  2. Исключение из измерения стадий инициализации и завершения. Если необходимо измерить время выполнения некоторой части кода, то будет рационально вынести весь код, предшествующий вызову этой части, за первый замер времени, а следующий замер провести сразу после завершения работы программы.

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

  4. Снижение влияния посторонних процессов. Часто процессор загружен другими процессами. В таких случаях рационально использовать таймер времени выполнения процесса.

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

1) Таймер системного времени – аппаратный счетчик, отражающий течение времени с позиции ВС. Совпадает с реальным временем. Системное время одинаково для всех работающих на компьютере программ. Значение временного интервала, который измерен таким таймером, включает в себя кроме времени выполнения процесса замера еще и другие процессы. Функции для получения системного времени:

  • ОС Windows: time(); GetTickCount(); GetSystemTime(); clock() (системное время, которое прошло с запуска процесса).

  • ОС Linux: clock_gettime(); time(); times(); gettimeofday().

2) Счетчик тактов процессора – аппаратный счетчик, величина которого возрастает на каждом такте процессора. Позволяет с наибольшей точностью замерять малые промежутки времени. Данный счетчик стоит использовать для измерения интервалов времени, которые меньше кванта времени, выделенного процессу ОС. Специальные команды процессора для получения значения счетчика тактов:

  • Alpha: rpcc;

  • PowerPC: mftbu, mftb;

  • x86/x86-64: rdtsc;

  • Itanium: ar.itc.

Библиотечная функция clock_gettime

Для получения значения системного таймера в ОС Linux/UNIX используется библиотечная функция clock_gettime. Данная функция с параметром CLOCK_MONOTONIC_RAW записывает значение системного таймера в структуру struct timespec, которая состоит из двух полей – tv_sec и tv_nsec, задающих значение секунд и наносекунд, прошедших с некоторого момента времени. В примере записывается значение таймера перед выполнением фрагмента кода и после него. Разница показаний в секундах выводится на экран. Кроме того, функция дает возможность получать значения и с других таймеров.

052917 0811 1

Листинг 1: clock_gettime

Точность: Обычно в ОС Windows составляет 55 мс (55 10−3 с), в ОС GNU Linux/UNIX – 1 нс (1 10−9 с).

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

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

Машинная команда rdtsc

Машинная команда rdtsc (Read Time Stamp Counter) берет показания счетчика тактов в виде 64-разрядного беззнакового целого числа, которое равно количеству тактов, прошедших с момента запуска процессора. Делением количества тактов на тактовую частоту процессора получается время в секундах. В этом примере используется ассемблерная вставка команды процессора rdtsc, результат выполнения который записывается в объединение (union) ticks.

Разница данных счётчика тактов преобразовывается в секунды в зависимости от тактовой частоты.

052917 0811 2

Листинг 2: rdtsc

Точность: один такт.

Достоинство: максимально точность измерения времени.

Недостатки: привязка к архитектуре x86. Затруднительно преобразование в секунды в процессорах с динамическим изменением частоты.

Тестирование

Тестирование данных таймеров было произведено на алгоритме, представляющим из себя сложение двух чисел, повторяющееся 1000000 раз. Для уменьшения влияния посторонних факторов на результаты, измерения будет проведены 100 раз.

Эксперименты проводились на персональной ЭВМ с процессором Intel Core i3-2625M CPU с тактовой частотой 1.3 ГГц. Полученные результаты изображены на графике.

052917 0811 3

Библиографический список

  1. Supercomputer Software Department, Institute of Computational Mathematics and Mathematics Geophysics “Определение времени работы прикладных программ” http://ssd.sscc.ru/sites/default/les/content/attach/310/computerlab1.pdf


Количество просмотров публикации: Please wait

Все статьи автора «Лохматов Степан Юрьевич»

В этом посте будет обсуждаться, как найти время выполнения программы C в средах Windows и Linux.

Существует четыре широко используемых метода определения времени выполнения программы на C:

1. Использование clock() функция

Мы можем использовать clock() функция, предоставляемая <time.h> заголовочный файл для расчета времени ЦП, потребляемого задачей в приложении C. Он возвращает clock_t type, в котором хранится общее количество тактов часов.

Чтобы вычислить общее количество прошедших секунд, нам нужно разделить общее количество прошедших тактов часов на CLOCKS_PER_SEC макрос (также присутствует в <time.h>) как показано ниже:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

#include <stdio.h>

#include <time.h>       // for clock_t, clock(), CLOCKS_PER_SEC

#include <unistd.h>     // for sleep()

// основная функция для определения времени выполнения программы на C

int main()

{

    // для хранения времени выполнения кода

    double time_spent = 0.0;

    clock_t begin = clock();

    // делаем здесь что-нибудь

    sleep(3);

    clock_t end = clock();

    // рассчитать прошедшее время, найдя разницу (end — begin) и

    // деление разницы на CLOCKS_PER_SEC для перевода в секунды

    time_spent += (double)(end begin) / CLOCKS_PER_SEC;

    printf(«The elapsed time is %f seconds», time_spent);

    return 0;

}

Скачать  Выполнить код

Выход (может варьироваться):

The elapsed time is 0.000014 seconds

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

2. Использование time() функция

The <time.h> заголовок также предоставляет time() функция, которая возвращает общее количество секунд, прошедших с начала Эпохи (00:00:00 UTC, 1 января 1970 г.). Он принимает указатель на time_t в качестве аргумента, который обычно передается как NULL и возвращает time_t тип. Если аргумент не NULL, то возвращаемое значение также сохраняется в памяти, на которую указывает аргумент.

Его использование аналогично clock() функцию, как показано ниже:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

#include <stdio.h>

#include <time.h>       // for time()

#include <unistd.h>     // for sleep()

// основная функция для определения времени выполнения программы на C

int main()

{

    time_t begin = time(NULL);

    // делаем здесь что-нибудь

    sleep(3);

    time_t end = time(NULL);

    // вычислить прошедшее время, найдя разницу (end — begin)

    printf(«The elapsed time is %d seconds», (end begin));

    return 0;

}

Скачать  Выполнить код

результат:

The elapsed time is 3 seconds

3. Использование gettimeofday() функция

The gettimeofday() Функция возвращает время настенных часов, прошедшее с начала эпохи, и сохраняет его в timeval структура, выраженная в секундах и микросекундах.

Он определен в <sys/time.h> заголовочный файл и принимает два аргумента — первый аргумент является ссылкой на timeval структура, а второй аргумент — нулевой указатель. timeval структура объявляется следующим образом: <time.h> заголовок:

struct timeval {
    long tv_sec;    /* seconds */
    long tv_usec;   /* microseconds */
};

 
Следующий код демонстрирует использование gettimeofday() путем измерения времени настенных часов:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

#include <stdio.h>

#include <sys/time.h>   // for gettimeofday()

#include <unistd.h>     // for sleep()

// основная функция для определения времени выполнения программы на C

int main()

{

    struct timeval start, end;

    gettimeofday(&start, NULL);

    // делаем здесь что-нибудь

    sleep(5);

    gettimeofday(&end, NULL);

    long seconds = (end.tv_sec start.tv_sec);

    long micros = ((seconds * 1000000) + end.tv_usec) (start.tv_usec);

    printf(«The elapsed time is %d seconds and %d microsn», seconds, micros);

    return 0;

}

Скачать  Выполнить код

Выход (может варьироваться):

The elapsed time is 5 seconds and 5000147 micros

 
Эта функция поддерживается компиляторами GCC и может не работать в Windows.

4. Использование clock_gettime() функция

Мы также можем использовать clock_gettime() функция, определенная в <time.h> заголовочный файл, который поддерживает точность до наносекунд. Он принимает два аргумента: первый аргумент — это тип часов, а второй аргумент — указатель на timespec структура. timespec структура обеспечивается <time.h> заголовок и объявляется как:

struct timespec {
    time_t tv_sec;   /* seconds */
    long tv_nsec;    /* nanoseconds */
};

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

#include <stdio.h>

#include <time.h>    // for clock_t, clock()

#include <unistd.h>    // for sleep()

#define BILLION  1000000000.0

// основная функция для определения времени выполнения программы на C

int main()

{

    struct timespec start, end;

    clock_gettime(CLOCK_REALTIME, &start);

    // делаем здесь что-нибудь

    sleep(3);

    clock_gettime(CLOCK_REALTIME, &end);

    // time_spent = конец — начало

    double time_spent = (end.tv_sec start.tv_sec) +

                        (end.tv_nsec start.tv_nsec) / BILLION;

    printf(«The elapsed time is %f seconds», time_spent);

    return 0;

}

Скачать код

 
Обратите внимание, что clock_gettime() будет работать только на очень немногих машинах UNIX.

Вот и все, что касается нахождения времени выполнения программы на C.

 
Связанный пост:

Измерьте прошедшее время программы C++ с помощью библиотеки Chrono

Спасибо за чтение.

Пожалуйста, используйте наш онлайн-компилятор размещать код в комментариях, используя C, C++, Java, Python, JavaScript, C#, PHP и многие другие популярные языки программирования.

Как мы? Порекомендуйте нас своим друзьям и помогите нам расти. Удачного кодирования 🙂

Зачастую требуется узнать, сколько времени выполняется тот или иной код. Иногда требуется замерить время выполнения метода или какой-то задачи. В данной статье мы расскажем вам принципы замера времени в Java и покажем лучшие практики для конкретных задач.

Замер времени с помощью currentTimeMills()

Это довольно простой способ измерить время. Метод System.currentTimeMillis() вернёт вам текущее время в миллисекундах. Его потребуется вызвать до выполнения нужной задачи и после, а затем вычислить разницу. В итоге мы узнаем время выполнения в миллисекундах:

long start = System.currentTimeMillis();

// выполнение какой-то логики
Thread.sleep(1000);

long finish = System.currentTimeMillis();
long elapsed = finish - start;

System.out.println("Прошло времени, мс: " + elapsed);

При работе с данным методом следует учитывать его специфику: System.currentTimeMillis() показывает текущее время, основываясь на системных часах и может выдавать некорректный результат.

Замер времени с помощью nanoTime()

Ещё один метод для получения текущего времени это System.nanoTime(). Как следует из названия, этот метод возвращает время с точностью до нансекунд. Также работа этого метода не зависит от системных часов.

Он используется аналогично:

long start = System.nanoTime();

// выполнение какой-то логики
Thread.sleep(1000);

long finish = System.nanoTime();
long elapsed = finish - start;

System.out.println("Прошло времени, нс: " + elapsed);

Для получения значения в миллисекундах результат можно разделить на 1000:

System.out.println("Прошло времени, мс: " + elapsed / 1000000);

Важно: Хотя метод nanoTime() может возвращать время в наносекундах, он не гарантирует, что значения между его вызовами будут обновляться с точностью до наносекунд.

Но всё же это более приемлемый вариант, чем System.currentTimeMillis().

Замер времени с помощью Instant и Duration

В Java 8 добавили новый java.time API. В частности, ля измерения времени подойдут два новых класса – Instant и Duration. Оба эти класса иммутабельны.

Instant обозначает момент времени с начала эпохи Unix (1970-01-01T00:00:00Z). Для создания момента мы используем метод Instant.now(). После того, как мы создали два момент, вычислим разницу в миллисекундах:

Instant start = Instant.now();

// выполнение какой-то логики
Thread.sleep(1000);

Instant finish = Instant.now();
long elapsed = Duration.between(start, finish).toMillis();
System.out.println("Прошло времени, мс: " + elapsed);

Рекомендуется использовать именно этот подход в Java 8 и выше.

Замер времени выполнения с помощью StopWatch

StopWatch – это класс из библиотеки Apache Commons Lang. Он работает как секундомер. Для его использования сначала требуется подключить библиотеку к проекту:

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.9</version>
</dependency>

Теперь создадим экземпляр StopWatch. Затем начнём отсчёт с помощью метода start() и окончим отсчёт с помощью метода stop():

public static void stopWatch() throws InterruptedException {
    StopWatch stopWatch = new StopWatch();

    stopWatch.start();

    // выполнение какой-то логики
    Thread.sleep(1000);

    stopWatch.stop();

    System.out.println("Прошло времени, мс: " + stopWatch.getTime());
}

StopWatch удобно использовать тогда, когда в проекте уже подключена данная библиотека.

Исходный код

package ru.javalessons.time;

import org.apache.commons.lang3.time.StopWatch;

import java.time.Duration;
import java.time.Instant;

public class MeasureElapsedTime {
    public static void main(String[] args) throws InterruptedException {
        currentTimeMillis();
        nanoTime();
        instant();
        stopWatch();
    }

    public static void currentTimeMillis() throws InterruptedException {
        long start = System.currentTimeMillis();

        // выполнение какой-то логики
        Thread.sleep(1000);

        long finish = System.currentTimeMillis();
        long elapsed = finish - start;

        System.out.println("Прошло времени, мс: " + elapsed);
    }

    public static void nanoTime() throws InterruptedException {
        long start = System.nanoTime();

        // выполнение какой-то логики
        Thread.sleep(1000);

        long finish = System.nanoTime();
        long elapsed = finish - start;

        System.out.println("Прошло времени, нс: " + elapsed);
    }

    public static void instant() throws InterruptedException {
        Instant start = Instant.now();

        // выполнение какой-то логики
        Thread.sleep(1000);

        Instant finish = Instant.now();
        long elapsed = Duration.between(start, finish).toMillis();
        System.out.println("Прошло времени, мс: " + elapsed);
    }

    public static void stopWatch() throws InterruptedException {
        StopWatch stopWatch = new StopWatch();

        stopWatch.start();

        // выполнение какой-то логики
        Thread.sleep(1000);

        stopWatch.stop();

        System.out.println("Прошло времени, мс: " + stopWatch.getTime());
    }
}

Заключение

В данной статье мы разобрали простые методы замера времени выполнения в Java. Для простых замеров можно использовать все вышеперечисленные методы, кроме currentTimeMillis (из-за того, что он зависит от системных часов).

Понравилась статья? Поделить с друзьями:
  • Как сделать успешный бизнес на ритуальных услугах
  • Выездной кейтеринг в России
  • Миграционная служба уфа гоголя 47 режим работы
  • Метро спб дыбенко режим работы
  • Миллион друзей ярославль лисицына режим работы