Я хочу выяснить, сколько времени занимает выполнение определенной функции в моей программе на C++ на Linux. После этого я хочу провести сравнение скорости. Я видел несколько функций времени, но в итоге остановился на этой из boost. Chrono:
process_user_cpu_clock, captures user-CPU time spent by the current process
Теперь, я не совсем понимаю, если я использую вышеуказанную функцию, получу ли я только время, которое CPU потратил на эту функцию?
Во-вторых, я не смог найти ни одного примера использования вышеуказанной функции. Может ли кто-нибудь помочь мне, как использовать вышеуказанную функцию?
P.S: Сейчас я использую std::chrono::system_clock::now()
для получения времени в секундах, но это дает мне разные результаты из-за разной загрузки процессора каждый раз.
Это очень простой в использовании метод в C++11. Вы должны использовать std::chrono::high_resolution_clock
из заголовка <chrono>
.
Используйте его следующим образом:
#include <iostream>
#include <chrono>
void function()
{
long long number = 0;
for( long long i = 0; i != 2000000; ++i )
{
number += 5;
}
}
int main()
{
auto t1 = std::chrono::high_resolution_clock::now();
function();
auto t2 = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>( t2 - t1 ).count();
std::cout << duration;
return 0;
}
Это позволит измерить длительность функции.
ПРИМЕЧАНИЕ: Вы не всегда будете получать одинаковое время для функции. Это связано с тем, что центральный процессор вашей машины может быть меньше или больше задействован другими процессами, запущенными на компьютере, точно так же, как ваш ум может быть более или менее сконцентрирован, когда вы решаете математическое упражнение. В человеческом уме мы можем запомнить решение математической задачи, но для компьютера тот же самый процесс всегда будет чем-то новым; поэтому, как я уже сказал, вы не всегда будете получать один и тот же результат!
Вот функция, которая будет измерять время выполнения любой функции, переданной в качестве аргумента:
#include <chrono>
#include <utility>
typedef std::chrono::high_resolution_clock::time_point TimeVar;
#define duration(a) std::chrono::duration_cast<std::chrono::nanoseconds>(a).count()
#define timeNow() std::chrono::high_resolution_clock::now()
template<typename F, typename... Args>
double funcTime(F func, Args&&... args){
TimeVar t1=timeNow();
func(std::forward<Args>(args)...);
return duration(timeNow()-t1);
}
Пример использования:
#include <iostream>
#include <algorithm>
typedef std::string String;
//first test function doing something
int countCharInString(String s, char delim){
int count=0;
String::size_type pos = s.find_first_of(delim);
while ((pos = s.find_first_of(delim, pos)) != String::npos){
count++;pos++;
}
return count;
}
//second test function doing the same thing in different way
int countWithAlgorithm(String s, char delim){
return std::count(s.begin(),s.end(),delim);
}
int main(){
std::cout<<"norm: "<<funcTime(countCharInString,"precision=10",'=')<<"\n";
std::cout<<"algo: "<<funcTime(countWithAlgorithm,"precision=10",'=');
return 0;
}
Выходные данные:
norm: 15555
algo: 2976
простая программа для нахождения времени выполнения функции.
#include <iostream>
#include <ctime> // time_t
#include <cstdio>
void function()
{
for(long int i=0;i<1000000000;i++)
{
// do nothing
}
}
int main()
{
time_t begin,end; // time_t is a datatype to store time values.
time (&begin); // note time before execution
function();
time (&end); // note time after execution
double difference = difftime (end,begin);
printf ("time taken for function() %.2lf seconds.\n", difference );
return 0;
}
В книгу Скотта Мейерса я нашел пример всеобщего универсального лямбда-выражение, которое может использоваться, чтобы измерить время выполнения функции. (С++14)
auto timeFuncInvocation =
[](auto&& func, auto&&... params) {
// get time before function invocation
const auto& start = high_resolution_clock::now();
// function invocation using perfect forwarding
std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...);
// get time after function invocation
const auto& stop = high_resolution_clock::now();
return stop - start;
};
Проблема в том, что вы не измеряете только одно исполнение, поэтому результаты могут сильно отличаться. Для получения достоверного результата вам необходимо измерить большое количество казни. По данным лекцию Андрея Александреску в код::конференция погружение 2015 - написание быстрого кода я:
Измеренное время: ТМ = Т + ТВ + ТН + с
где:
ТМ - измеренное (наблюдаемое) время
Т - фактическое время интерес
с TQ - время добавляется шум квантования
ТН - время, добавленные различных источников шума
к - издержки времени (измерения, циклы, вызовы функций)
По его словам, позднее в ходе лекции, вы должны принять как минимум это большое количество выполнения как ваш результат. Я призываю вас посмотреть на лекцию, в которой он объясняет, почему.
Также есть очень хорошая библиотека от Google - https://github.com/google/benchmark. Эта библиотека очень проста в использовании и мощный. Вы можете оформить заказ некоторые лекции Чендлер Carruth на YouTube, где он использует эту библиотеку на практике. Например CppCon 2017: Чендлер Carruth “в никуда быстрее”;
Пример использования:
#include <iostream>
#include <chrono>
#include <vector>
auto timeFuncInvocation =
[](auto&& func, auto&&... params) {
// get time before function invocation
const auto& start = high_resolution_clock::now();
// function invocation using perfect forwarding
for(auto i = 0; i < 100000/*largeNumber*/; ++i) {
std::forward<decltype(func)>(func)(std::forward<decltype(params)>(params)...);
}
// get time after function invocation
const auto& stop = high_resolution_clock::now();
return (stop - start)/100000/*largeNumber*/;
};
void f(std::vector<int>& vec) {
vec.push_back(1);
}
void f2(std::vector<int>& vec) {
vec.emplace_back(1);
}
int main()
{
std::vector<int> vec;
std::vector<int> vec2;
std::cout << timeFuncInvocation(f, vec).count() << std::endl;
std::cout << timeFuncInvocation(f2, vec2).count() << std::endl;
std::vector<int> vec3;
vec3.reserve(100000);
std::vector<int> vec4;
vec4.reserve(100000);
std::cout << timeFuncInvocation(f, vec3).count() << std::endl;
std::cout << timeFuncInvocation(f2, vec4).count() << std::endl;
return 0;
}
Редактировать: Конечно, вы всегда должны помнить, что ваш компилятор может оптимизировать что-то или нет. Инструменты, такие как перфорация может быть полезной в таких случаях.
Простой способ для старых C++ или C:
#include <time.h> // includes clock_t and CLOCKS_PER_SEC
int main() {
clock_t start, end;
start = clock();
// ...code to measure...
end = clock();
double duration_sec = double(end-start)/CLOCKS_PER_SEC;
return 0;
}
Точность синхронизации в секунд 1.0/CLOCKS_PER_SEC
- это очень простой в использовании метод в C++11.
- мы можем использовать std::хроно::high_resolution_clock от <хронометр> жатка
- мы можем написать метод для печати время выполнения метода в гораздо более читабельном виде.
Например, чтобы найти все простые числа между 1 и 100 миллионов, это занимает примерно 1 минуту и 40 секунд. Таким образом, время выполнения вам напечатать как:
Execution Time: 1 Minutes, 40 Seconds, 715 MicroSeconds, 715000 NanoSeconds
Код здесь:
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
typedef high_resolution_clock Clock;
typedef Clock::time_point ClockTime;
void findPrime(long n, string file);
void printExecutionTime(ClockTime start_time, ClockTime end_time);
int main()
{
long n = long(1E+8); // N = 100 million
ClockTime start_time = Clock::now();
// Write all the prime numbers from 1 to N to the file "prime.txt"
findPrime(n, "C:\\prime.txt");
ClockTime end_time = Clock::now();
printExecutionTime(start_time, end_time);
}
void printExecutionTime(ClockTime start_time, ClockTime end_time)
{
auto execution_time_ns = duration_cast<nanoseconds>(end_time - start_time).count();
auto execution_time_ms = duration_cast<microseconds>(end_time - start_time).count();
auto execution_time_sec = duration_cast<seconds>(end_time - start_time).count();
auto execution_time_min = duration_cast<minutes>(end_time - start_time).count();
auto execution_time_hour = duration_cast<hours>(end_time - start_time).count();
cout << "\nExecution Time: ";
if(execution_time_hour > 0)
cout << "" << execution_time_hour << " Hours, ";
if(execution_time_min > 0)
cout << "" << execution_time_min % 60 << " Minutes, ";
if(execution_time_sec > 0)
cout << "" << execution_time_sec % 60 << " Seconds, ";
if(execution_time_ms > 0)
cout << "" << execution_time_ms % long(1E+3) << " MicroSeconds, ";
if(execution_time_ns > 0)
cout << "" << execution_time_ns % long(1E+6) << " NanoSeconds, ";
}
Вот отличный заголовок только шаблон класса для измерения времени функции или какого-либо блока кода:
#ifndef EXECUTION_TIMER_H
#define EXECUTION_TIMER_H
template<class Resolution = std::chrono::milliseconds>
class ExecutionTimer {
public:
using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock,
std::chrono::steady_clock>;
private:
const Clock::time_point mStart = Clock::now();
public:
ExecutionTimer() = default;
~ExecutionTimer() {
const auto end = Clock::now();
std::ostringstream strStream;
strStream << "Destructor Elapsed: "
<< std::chrono::duration_cast<Resolution>( end - mStart ).count()
<< std::endl;
std::cout << strStream.str() << std::endl;
}
inline void stop() {
const auto end = Clock::now();
std::ostringstream strStream;
strStream << "Stop Elapsed: "
<< std::chrono::duration_cast<Resolution>(end - mStart).count()
<< std::endl;
std::cout << strStream.str() << std::endl;
}
}; // ExecutionTimer
#endif // EXECUTION_TIMER_H
Вот некоторые виды:
int main() {
{ // empty scope to display ExecutionTimer's destructor's message
// displayed in milliseconds
ExecutionTimer<std::chrono::milliseconds> timer;
// function or code block here
timer.stop();
}
{ // same as above
ExecutionTimer<std::chrono::microseconds> timer;
// code block here...
timer.stop();
}
{ // same as above
ExecutionTimer<std::chrono::nanoseconds> timer;
// code block here...
timer.stop();
}
{ // same as above
ExecutionTimer<std::chrono::seconds> timer;
// code block here...
timer.stop();
}
return 0;
}
Так как класс-это шаблон, мы можем указать реальный легко, как мы хотим, чтобы наши время измерения & отображается. Это очень удобный шаблон служебный класс для выполнения бенчмаркинга, а также очень проста в использовании.
Я рекомендую использовать steady_clock
, который guarunteed быть монотонным, в отличие от high_resolution_clock
.
#include <iostream>
#include <chrono>
using namespace std;
unsigned int stopwatch()
{
static auto start_time = chrono::steady_clock::now();
auto end_time = chrono::steady_clock::now();
auto delta = chrono::duration_cast<chrono::microseconds>(end_time - start_time);
start_time = end_time;
return delta.count();
}
int main() {
stopwatch(); //Start stopwatch
std::cout << "Hello World!\n";
cout << stopwatch() << endl; //Time to execute last line
for (int i=0; i<1000000; i++)
string s = "ASDFAD";
cout << stopwatch() << endl; //Time to execute for loop
}
Выход:
Hello World!
62
163514