Синхронизирующий код - это искусство, и одна из частей искусства заключается в том, чтобы компилятор не оптимизировал ваш код. Для стандартных функций библиотеки компилятор может хорошо знать, что он делает и может вычислять константу во время компиляции. В вашем примере вызов cbrt(9999999);
дает две возможности для оптимизации. Значение из cbrt()
может быть оценено во время компиляции, поскольку аргумент является константой. Во-вторых, возвращаемое значение не используется, и стандартная функция не имеет побочных эффектов, поэтому компилятор может полностью его удалить. Вы можете избежать этих проблем, захватив результат (например, оценив сумму корней куба от 0 до одного миллиарда (минус один) и напечатав это значение после временного кода.
tm97.c
Когда я скомпилировал ваш код, без комментариев, я получил:
$ cat tm97.c
#include <time.h>
#include <stdio.h>
#include <math.h>
int main(void)
{
time_t begin, end;
time(&begin);
for (int i = 0; i < 1000000000; i++)
{
cbrt(9999999);
}
time(&end);
double difference = difftime(end, begin);
printf("time taken for function() %.2lf in Nanoseconds.\n", difference );
printf(" cube root is :%f \t", cbrt(9999999));
return 0;
}
$ make tm97
gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes tm97.c -o tm97 -L../lib -lsoq
tm97.c: In function ‘main’:
tm97.c:11:9: error: statement with no effect [-Werror=unused-value]
11 | cbrt(9999999);
| ^~~~
cc1: all warnings being treated as errors
rmk: error code 1
$
Я использую G CC 9.3.0 на MacBook Pro 2017 года, работающем под MacOS Mojave 10.14.6 с XCode 11.3.1 (11C504) и G CC 9.3.0 - XCode 11.4 требует Catalina 10.15.2, но пока не удалось организовать поддержку для этого. Интересно, что когда тот же код компилируется с помощью g++
, он компилируется без предупреждений (ошибок):
$ ln -s tm97.c tm89.cpp
make tm89 SXXFLAGS=-std=c++17 CXX=g++
g++ -O3 -g -I../inc -std=c++17 -Wall -Wextra -Werror -L../lib tm89.cpp -lsoq -o tm89
$
Я обычно использую некоторый временной код, который доступен в моем репозитории SOQ (вопросы переполнения стека) на GitHub в виде файлов timer.c
и timer.h
в подкаталоге src / libsoq . Код скомпилирован в моей библиотеке только как код C, поэтому я создал простой заголовок оболочки timer2.h
, чтобы нижеприведенные программы могли использовать #include "timer2.h"
и он будет работать нормально с обоими * Компиляции 1126 * и C ++:
#ifndef TIMER2_H_INCLUDED
#define TIMER2_H_INCLUDED
#ifdef __cplusplus
extern "C" {
#endif
#include "timer.h"
#ifdef __cplusplus
}
#endif
#endif /* TIMER2_H_INCLUDED */
tm29.cpp
и tm31.c
Этот код использует для тестирования функцию sqrt()
. Накапливается сумма квадратных корней. Он использует временной код от timer.h
/ timer.c
вокруг вашего временного кода - введите Clock
и функции clk_init()
, clk_start()
, clk_stop()
и clk_elapsed_us()
для оценки прошедшего времени в микросекундах между тем, когда часы были запущены и в последний раз остановились.
Исходный код может быть скомпилирован либо C компилятором, либо компилятором C ++.
#include <time.h>
#include <stdio.h>
#include <math.h>
#include "timer2.h"
int main(void)
{
time_t begin, end;
double sum = 0.0;
int i;
Clock clk;
clk_init(&clk);
clk_start(&clk);
time(&begin);
for (i = 0; i < 1000000000; i++)
{
sum += sqrt(i);
}
time(&end);
clk_stop(&clk);
double difference = difftime(end, begin);
char buffer[32];
printf("Time taken for sqrt() is %.2lf nanoseconds (%s ns).\n",
difference, clk_elapsed_us(&clk, buffer, sizeof(buffer)));
printf("Sum of square roots from 0 to %d is: %f\n", i, sum);
return 0;
}
tm41.c
и tm43.cpp
Этот код практически идентичен предыдущему коду, но проверенная функция - это функция cbrt()
(куб root).
#include <time.h>
#include <stdio.h>
#include <math.h>
#include "timer2.h"
int main(void)
{
time_t begin, end;
double sum = 0.0;
int i;
Clock clk;
clk_init(&clk);
clk_start(&clk);
time(&begin);
for (i = 0; i < 1000000000; i++)
{
sum += cbrt(i);
}
time(&end);
clk_stop(&clk);
double difference = difftime(end, begin);
char buffer[32];
printf("Time taken for cbrt() is %.2lf nanoseconds (%s ns).\n",
difference, clk_elapsed_us(&clk, buffer, sizeof(buffer)));
printf("Sum of cube roots from 0 to %d is: %f\n", i, sum);
return 0;
}
tm59.c
и tm61.c
Этот код использует fabs()
вместо sqrt()
или cbrt()
. Это все еще вызов функции, но он может быть встроенным. Он вызывает преобразование из int
в double
явно; без этого приведения G CC жалуется, что вместо него следует использовать целочисленную функцию abs()
.
#include <time.h>
#include <stdio.h>
#include <math.h>
#include "timer2.h"
int main(void)
{
time_t begin, end;
double sum = 0.0;
int i;
Clock clk;
clk_init(&clk);
clk_start(&clk);
time(&begin);
for (i = 0; i < 1000000000; i++)
{
sum += fabs((double)i);
}
time(&end);
clk_stop(&clk);
double difference = difftime(end, begin);
char buffer[32];
printf("Time taken for fabs() is %.2lf nanoseconds (%s ns).\n",
difference, clk_elapsed_us(&clk, buffer, sizeof(buffer)));
printf("Sum of absolute values from 0 to %d is: %f\n", i, sum);
return 0;
}
tm73.cpp
Этот файл использует исходный код с моей оболочкой синхронизации код тоже. Версия C не компилируется - версия C ++ делает:
#include <time.h>
#include <stdio.h>
#include <math.h>
#include "timer2.h"
int main(void)
{
time_t begin, end;
Clock clk;
clk_init(&clk);
clk_start(&clk);
time(&begin);
for (int i = 0; i < 1000000000; i++)
{
cbrt(9999999);
}
time(&end);
clk_stop(&clk);
double difference = difftime(end, begin);
char buffer[32];
printf("Time taken for cbrt() is %.2lf nanoseconds (%s ns).\n",
difference, clk_elapsed_us(&clk, buffer, sizeof(buffer)));
printf("Cube root is: %f\n", cbrt(9999999));
return 0;
}
Время
Используя команду timecmd
, которая сообщает время запуска и остановки, а также PID программ как Помимо временного кода, встроенного в различные команды (это вариант темы time
), я получил следующие результаты. (rmk
- это просто альтернативная реализация make
.)
$ for prog in tm29 tm31 tm41 tm43 tm59 tm61 tm73
> do rmk $prog && timecmd -ur -- $prog
> done
g++ -O3 -g -I../inc -std=c++11 -Wall -Wextra -Werror tm29.cpp -o tm29 -L../lib -lsoq
2020-03-28 08:47:50.040227 [PID 19076] tm29
Time taken for sqrt() is 1.00 nanoseconds (1.700296 ns).
Sum of square roots from 0 to 1000000000 is: 21081851051977.781250
2020-03-28 08:47:51.747494 [PID 19076; status 0x0000] - 1.707267s - tm29
gcc -O3 -g -I../inc -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes tm31.c -o tm31 -L../lib -lsoq
2020-03-28 08:47:52.056021 [PID 19088] tm31
Time taken for sqrt() is 1.00 nanoseconds (1.679867 ns).
Sum of square roots from 0 to 1000000000 is: 21081851051977.781250
2020-03-28 08:47:53.742383 [PID 19088; status 0x0000] - 1.686362s - tm31
gcc -O3 -g -I../inc -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes tm41.c -o tm41 -L../lib -lsoq
2020-03-28 08:47:53.908285 [PID 19099] tm41
Time taken for cbrt() is 7.00 nanoseconds (6.697999 ns).
Sum of cube roots from 0 to 1000000000 is: 749999999499.628418
2020-03-28 08:48:00.613357 [PID 19099; status 0x0000] - 6.705072s - tm41
g++ -O3 -g -I../inc -std=c++11 -Wall -Wextra -Werror tm43.cpp -o tm43 -L../lib -lsoq
2020-03-28 08:48:00.817975 [PID 19110] tm43
Time taken for cbrt() is 7.00 nanoseconds (6.614539 ns).
Sum of cube roots from 0 to 1000000000 is: 749999999499.628418
2020-03-28 08:48:07.438298 [PID 19110; status 0x0000] - 6.620323s - tm43
gcc -O3 -g -I../inc -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes tm59.c -o tm59 -L../lib -lsoq
2020-03-28 08:48:07.598344 [PID 19121] tm59
Time taken for fabs() is 1.00 nanoseconds (1.114822 ns).
Sum of absolute values from 0 to 1000000000 is: 499999999067108992.000000
2020-03-28 08:48:08.718672 [PID 19121; status 0x0000] - 1.120328s - tm59
g++ -O3 -g -I../inc -std=c++11 -Wall -Wextra -Werror tm61.cpp -o tm61 -L../lib -lsoq
2020-03-28 08:48:08.918745 [PID 19132] tm61
Time taken for fabs() is 2.00 nanoseconds (1.117780 ns).
Sum of absolute values from 0 to 1000000000 is: 499999999067108992.000000
2020-03-28 08:48:10.042134 [PID 19132; status 0x0000] - 1.123389s - tm61
g++ -O3 -g -I../inc -std=c++11 -Wall -Wextra -Werror tm73.cpp -o tm73 -L../lib -lsoq
2020-03-28 08:48:10.236899 [PID 19143] tm73
Time taken for cbrt() is 0.00 nanoseconds (0.000004 ns).
Cube root is: 215.443462
2020-03-28 08:48:10.242322 [PID 19143; status 0x0000] - 0.005423s - tm73
$
Я запускал программы много раз; Вышеуказанное время отражает то, что я получаю каждый раз Можно сделать ряд выводов:
sqrt()
(1,7 нс) быстрее, чем cbrt()
(6,7 нс). fabs()
(1,1 нс ) быстрее, чем sqrt()
(1,7 нс). - Однако
fabs()
дает умеренное приближение ко времени, затрачиваемому с накладными расходами l oop и преобразованием из int
в double
. - Когда результат
cbrt()
не используется, компилятор удаляет l oop. - При компиляции с помощью компилятора C ++ код с вопроса полностью удаляет l oop оставляя только звонки на
time()
для измерения. Результат, напечатанный clk_elapsed_us()
, представляет собой время, необходимое для выполнения кода в диапазоне от clk_start()
до clk_stop()
в секундах с разрешением в микросекундах - 0.000004
составляет 4 микросекунды. Это значение отмечено в ns
, потому что когда l oop выполняется один миллиард раз, истекшее время в секундах также представляет время в наносекундах для одного l oop - в секунду миллиард наносекунд. - Время, указанное
timecmd
, соответствует времени, сообщенному программами. Затраты на запуск процесса (fork()
и exec()
) и ввод-вывод в процессе включены в значения времени, сообщенные timecmd
. - Хотя это и не показано, время с
clang
и clang++
(вместо G CC 9.3.0) очень сопоставимы, хотя код cbrt()
занимает около 7,5 нс за итерацию вместо 6,7 нс. Временные различия для остальных в основном шумовые.
Числовые суффиксы - все 2-ди git простых чисел. Они не имеют никакого другого значения, кроме как разделять разные программы.