我试图使用时间()来测量我的程序的各个点。

我不明白的是为什么前后的值是一样的?我知道这不是分析我的程序的最佳方式,我只是想看看需要多长时间。

printf("**MyProgram::before time= %ld\n", time(NULL));

doSomthing();
doSomthingLong();

printf("**MyProgram::after time= %ld\n", time(NULL));

我试过:

struct timeval diff, startTV, endTV;

gettimeofday(&startTV, NULL); 

doSomething();
doSomethingLong();

gettimeofday(&endTV, NULL); 

timersub(&endTV, &startTV, &diff);

printf("**time taken = %ld %ld\n", diff.tv_sec, diff.tv_usec);

我如何读取**时间花费= 0 26339的结果?这是否意味着26339纳秒= 26.3毫秒?

**时间= 4 45025,这是否意味着4秒25毫秒?


当前回答

我需要测量库中各个函数的执行时间。我不希望每个函数的每次调用都用一个时间度量函数来包装,因为这样做很难看,而且会加深调用堆栈。我也不想把定时器代码放在每个函数的顶部和底部,因为当函数可能提前退出或抛出异常时,这会造成混乱。所以我最终做了一个计时器,用它自己的生命周期来测量时间。

通过这种方式,我可以测量一个代码块的wallall时间,方法是在有问题的代码块(函数或任何作用域)的开头实例化这些对象之一,然后允许实例析构函数测量实例超出作用域时自构造以来所花费的时间。你可以在这里找到完整的例子,但结构体非常简单:

template <typename clock_t = std::chrono::steady_clock>
struct scoped_timer {
  using duration_t = typename clock_t::duration;
  const std::function<void(const duration_t&)> callback;
  const std::chrono::time_point<clock_t> start;

  scoped_timer(const std::function<void(const duration_t&)>& finished_callback) :
      callback(finished_callback), start(clock_t::now()) { }
  scoped_timer(std::function<void(const duration_t&)>&& finished_callback) :
      callback(finished_callback), start(clock_t::now()) { }
  ~scoped_timer() { callback(clock_t::now() - start); }
};

当函数超出作用域时,该结构体将回调所提供的函数,这样您就可以对计时信息做一些事情(打印它或存储它或其他什么)。如果你需要做一些更复杂的事情,你甚至可以使用std::bind和std::占位符来回调函数。

下面是一个快速使用它的例子:

void test(bool should_throw) {
  scoped_timer<> t([](const scoped_timer<>::duration_t& elapsed) {
    auto e = std::chrono::duration_cast<std::chrono::duration<double, std::milli>>(elapsed).count();
    std::cout << "took " << e << "ms" << std::endl;
  });

  std::this_thread::sleep_for(std::chrono::seconds(1));

  if (should_throw)
    throw nullptr;

  std::this_thread::sleep_for(std::chrono::seconds(1));
}

如果您希望更加谨慎,还可以使用new和delete显式地启动和停止计时器,而不依赖于作用域。

其他回答

0 -

使用delta函数计算时间差:

auto start = std::chrono::steady_clock::now();
std::cout << "Elapsed(ms)=" << since(start).count() << std::endl;

Since接受任何时间点并产生任何持续时间(毫秒为默认值)。它的定义为:

template <
    class result_t   = std::chrono::milliseconds,
    class clock_t    = std::chrono::steady_clock,
    class duration_t = std::chrono::milliseconds
>
auto since(std::chrono::time_point<clock_t, duration_t> const& start)
{
    return std::chrono::duration_cast<result_t>(clock_t::now() - start);
}

Demo

1 - 小时

使用基于std::chrono的计时器:

Timer clock; // Timer<milliseconds, steady_clock>

clock.tick();
/* code you want to measure */
clock.tock();

cout << "Run time = " << clock.duration().count() << " ms\n";

Demo

定时器定义为:

template <class DT = std::chrono::milliseconds,
          class ClockT = std::chrono::steady_clock>
class Timer
{
    using timep_t = typename ClockT::time_point;
    timep_t _start = ClockT::now(), _end = {};

public:
    void tick() { 
        _end = timep_t{}; 
        _start = ClockT::now(); 
    }
    
    void tock() { _end = ClockT::now(); }
    
    template <class T = DT> 
    auto duration() const { 
        gsl_Expects(_end != timep_t{} && "toc before reporting"); 
        return std::chrono::duration_cast<T>(_end - _start); 
    }
};

正如Howard Hinnant指出的那样,我们使用一个持续时间来保持在chrono类型系统中,并执行诸如平均或比较之类的操作(例如,这里这意味着使用std::chrono::milliseconds)。当我们只是执行IO时,我们使用持续时间的count()或tick(例如这里的毫秒数)。

2 -仪器仪表

任何可调用对象(函数、函数对象、lambda等)都可以用于基准测试。假设你有一个函数F调用参数arg1,arg2,这个技术会导致:

cout << "F runtime=" << measure<>::duration(F, arg1, arg2).count() << "ms";

Demo

度量定义为:

template <class TimeT  = std::chrono::milliseconds
          class ClockT = std::chrono::steady_clock>
struct measure
{
    template<class F, class ...Args>
    static auto duration(F&& func, Args&&... args)
    {
        auto start = ClockT::now();
        std::invoke(std::forward<F>(func), std::forward<Args>(args)...);
        return std::chrono::duration_cast<TimeT>(ClockT::now()-start);
    }
};

正如在(1)中提到的,使用持续时间w/o .count()对于那些希望在I/ o之前对一堆持续时间进行后处理的客户端是最有用的,例如average:

auto avg = (measure<>::duration(func) + measure<>::duration(func)) / 2;
std::cout << "Average run time " << avg.count() << " ms\n";

+这就是为什么被转发的函数调用。

完整的代码可以在这里找到

我试图建立一个基于chrono的基准测试框架的尝试记录在这里

+ Old演示

它们是一样的,因为doSomething函数发生得比计时器的粒度快。试一试:

printf ("**MyProgram::before time= %ld\n", time(NULL));

for(i = 0; i < 1000; ++i) {
    doSomthing();
    doSomthingLong();
}

printf ("**MyProgram::after time= %ld\n", time(NULL));

仅限Windows:(Linux标签是在我发布这个答案后添加的)

您可以使用GetTickCount()来获取自系统启动以来所经过的毫秒数。

long int before = GetTickCount();

// Perform time-consuming operation

long int after = GetTickCount();
#include <ctime>
#include <functional>

using namespace std;

void f() {
  clock_t begin = clock();

  // ...code to measure time...

  clock_t end = clock();

  function<double(double, double)> convtime = [](clock_t begin, clock_t end)
  {
     return double(end - begin) / CLOCKS_PER_SEC;
  };

  printf("Elapsed time: %.2g sec\n", convtime(begin, end));

}

类似的例子,一个可用在这里,只有额外的转换功能+打印出来。

下面是一个简单的类,它将在指定的持续时间单位内打印它进入和离开作用域之间的持续时间:

#include <chrono>
#include <iostream> 

template <typename T>
class Benchmark
{
   public:
    Benchmark(std::string name) : start(std::chrono::steady_clock::now()), name(name) {}
    ~Benchmark()
    {
        auto end = std::chrono::steady_clock::now();
        T duration = std::chrono::duration_cast<T>(end - start);
        std::cout << "Bench \"" << name << "\" took: " << duration.count() << " units" << std::endl;
    }

   private:
    std::string name;
    std::chrono::time_point<std::chrono::steady_clock> start;

};
int main()
{
  Benchmark<std::chrono::nanoseconds> bench("for loop");
  for(int i = 0; i < 1001000; i++){}
}

使用示例:

int main()
{
  Benchmark<std::chrono::nanoseconds> bench("for loop");
  for(int i = 0; i < 100000; i++){}
}

输出:

Bench "for loop" took: 230656 units