Распространенный совет, который дают новичкам: подключить библиотеку time.h
и, с помощью функции получения времени clock()
, определить время перед выполнением блока кода и после него. Время выполнения блока будет разницей полученных времен. То есть, что-то вроде
#include <stdio.h>
#include <time.h> /* clock_t, clock(), CLOCKS_PER_SEC */
int main ()
{
clock_t t;
t = clock();
/* Блок кода */
t = clock() - t;
printf ("It took me %d clicks (%f seconds).\n",
(int)t, ((double)t)/CLOCKS_PER_SEC);
return 0;
}
Здесь clock_t
— арифметический тип для представления времени; clock()
возвращает время, фиксируемое процессором от начала выполнения программы, или -1
, если оно не известно. Для выражения этого времени в секундах применяется формула clock()/CLOCKS_PER_SEC
.
Однако такой способ плохо подходит для измерения коротких интервалов времени. Рассмотрим следующий код
#include <stdio.h>
#include <time.h> /* clock_t, clock, CLOCKS_PER_SEC */
#include <math.h> /* sqrt */
int frequency_of_primes (int n) {
int i,j;
int freq = n-1;
for (i=2; i<=n; ++i) for (j=sqrt(i);j>1;--j) if (i%j==0) {--freq; break;}
return freq;
}
int main ()
{
clock_t t;
const int maxnum = 100000;
int f;
printf ("Calculating...\n");
t = clock();
f = frequency_of_primes(maxnum);
t = clock() - t;
printf ("The number of primes lower than %d is: %d\n",maxnum,f);
printf ("It took me %d clicks (%f seconds).\n",
(int)t,((double)t)/CLOCKS_PER_SEC);
return 0;
}
Он (взят отсюда) составлен по приведенной выше схеме и подсчитывает количество простых чисел на интервале от 0 до maxnum
. Сущность вычислений сейчас не важна -- они просто занимают некоторое время, которое мы пытаемся подсчитать. Выполнив, получим
Calculating...
The number of primes lower than 100000 is: 9592
It took me 140000 clicks (0.140000 seconds).
Теперь уменьшим maxnum
в 10 раз
Calculating...
The number of primes lower than 10000 is: 1229
It took me 0 clicks (0.000000 seconds).
Количество простых чисел сократилось даже менее, чем в 10 раз. Казалось бы, мы вправе ожидать ненулевого результата, но... Недаром пишут в руководстве по clock():
The clock() function returns an approximation of processor time used by the program.
Видимо, все дело в этом "approximation".
Обращает на себя внимание то, что следующая за выводом программы строка
Process returned 0 (0x0) execution time : 0.007 s
показывала ненулевое время. То есть системные средства считают все, что нужно, и пора ими воспользоваться.
Сначала приведем решения для Linux, хотя они работают и в Windows при использовании компилятора MinGW. Итак, альтернативами clock()
являются gettimeofday()
и clock_gettime()
.
Функция gettimeofday
int gettimeofday(struct timeval *tv, struct timezone *tz);
позволяет получить время в виде структуры timeval
(вторая структура -- timezone
считается устаревшей и при вызове заменяется NULL'ом):
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
которая содержит число секунд и микросекунд, прошедших с 1-го января 1970 г. 00:00:00 Всемирного времени. Имеется в виду, что с начального момента прошло tv_sec
секунд и еще tv_usec
микросекунд.
Микросекунды представляются мне слишком кратким интервалом. Напишем функцию, возвращающую число миллисекунд с начального момента времени
#include <sys/time.h> /* gettimeofday, timeval */
long mtime()
{
struct timeval t;
gettimeofday(&t, NULL);
long mt = (long)t.tv_sec * 1000 + t.tv_usec / 1000;
return mt;
}
Тестовую программу переделаем следующим образом:
#include <stdio.h>
#include <sys/time.h> /* gettimeofday, timeval */
#include <math.h> /* sqrt */
int frequency_of_primes (int n) {...}
long mtime() {...}
int main ()
{
long t;
const int maxnum = 100000;
int f;
printf ("Calculating...\n");
t = mtime();
f = frequency_of_primes(maxnum);
t = mtime() - t;
printf ("The number of primes lower than %d is: %d\n",maxnum,f);
printf ("It took me %ld milliseconds.\n",t);
return 0;
}
В результате получим
Calculating... The number of primes lower than 100000 is: 9592 It took me 144 milliseconds.
и
Calculating... The number of primes lower than 10000 is: 1229 It took me 7 milliseconds.
соответственно.
Конечно, по хорошему, нужно было бы испытать код несколько раз и выдать среднее значение. Мы этого не делаем, поскольку нас интересует не столько конкретная цифра, сколько сама возможность подсчитать время выполнения.
Функция clock_gettime()
из time.h
обеспечивает доступ к нескольким видам системных таймеров и имеет наносекундное разрешение. Прототип функции имеет вид:
int clock_gettime(clockid_t clk_id, struct timespect *tp);
clk_id
позволяет выбрать вид таймера, например (приведу фрагмент из руководства, там есть и другие таймеры):
CLOCK_REALTIME
, a system-wide realtime clock.CLOCK_PROCESS_CPUTIME_ID
, high-resolution timer provided by the CPU for each process.CLOCK_THREAD_CPUTIME_ID
, high-resolution timer provided by the CPU for each of the threads.
Время сохраняется в структуре timespec
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
по тому же принципу, что и в timeval
: с начального момента прошло tv_sec
секунд и еще tv_nsec
наносекунд.
Запишем функцию, возвращающую время в миллисекундах, основываясь на clock_gettime()
#include <time.h> /* clock_gettime, timespec */
long mtime()
{
struct timespec t;
clock_gettime(CLOCK_REALTIME, &t);
long mt = (long)t.tv_sec * 1000 + t.tv_nsec / 1000000;
return mt;
}
Теперь -- Windows-решение, работающее в Visual Studio. Это функция GetTickCount()
, возвращающая время в миллисекундах с момента старта операционной системы и в течение 49.7 дней:
DWORD WINAPI GetTickCount(void);
Поскольку GetTickCount()
возвращает DWORD
, счетчик времени сбрасывается в ноль через 49.7 дней. Эта проблема решается использованием GetTickCount64()
ULONGLONG WINAPI GetTickCount64(void);
переполнение в которой вряд ли возможно.
Тестовая программа с использованием GetTickCount()
:
#include <stdio.h>
#include <Windows.h> /* GetTickCount */
#include <math.h> /* sqrt */
int frequency_of_primes (int n) {
int i,j;
int freq = n-1;
for (i=2; i<=n; ++i) for (j=(int)sqrt((double)i);j>1;--j) if (i%j==0) {--freq; break;}
return freq;
}
int main ()
{
long t;
const int maxnum = 100000;
int f;
printf ("Calculating...\n");
t = GetTickCount();
f = frequency_of_primes(maxnum);
t = GetTickCount() - t;
printf ("The number of primes lower than %d is: %d\n",maxnum,f);
printf ("It took me %ld milliseconds.\n",t);
return 0;
}
Комментарии
comments powered by Disqus