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

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

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毫秒?


当前回答

c++ std::chrono具有跨平台的明显优势。 然而,与POSIX clock_gettime()相比,它也引入了显著的开销。 在我的Linux机器上,所有std::chrono::xxx_clock::now()味道的执行大致相同:

std::chrono::system_clock::now()
std::chrono::steady_clock::now()
std::chrono::high_resolution_clock::now()

虽然POSIX clock_gettime(CLOCK_MONOTONIC, &time)应该与steady_clock::now()相同,但它要快x3倍以上!

这是我的测试,为了完整性。

#include <stdio.h>
#include <chrono>
#include <ctime>

void print_timediff(const char* prefix, const struct timespec& start, const 
struct timespec& end)
{
    double milliseconds = end.tv_nsec >= start.tv_nsec
                        ? (end.tv_nsec - start.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec) * 1e3
                        : (start.tv_nsec - end.tv_nsec) / 1e6 + (end.tv_sec - start.tv_sec - 1) * 1e3;
    printf("%s: %lf milliseconds\n", prefix, milliseconds);
}

int main()
{
    int i, n = 1000000;
    struct timespec start, end;

    // Test stopwatch
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i) {
        struct timespec dummy;
        clock_gettime(CLOCK_MONOTONIC, &dummy);
    }
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("clock_gettime", start, end);

    // Test chrono system_clock
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i)
        auto dummy = std::chrono::system_clock::now();
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("chrono::system_clock::now", start, end);

    // Test chrono steady_clock
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i)
        auto dummy = std::chrono::steady_clock::now();
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("chrono::steady_clock::now", start, end);

    // Test chrono high_resolution_clock
    clock_gettime(CLOCK_MONOTONIC, &start);
    for (i = 0; i < n; ++i)
        auto dummy = std::chrono::high_resolution_clock::now();
    clock_gettime(CLOCK_MONOTONIC, &end);
    print_timediff("chrono::high_resolution_clock::now", start, end);

    return 0;
}

这是我用gcc7.2 -O3编译时得到的输出:

clock_gettime: 24.484926 milliseconds
chrono::system_clock::now: 85.142108 milliseconds
chrono::steady_clock::now: 87.295347 milliseconds
chrono::high_resolution_clock::now: 84.437838 milliseconds

其他回答

这两个值相同的原因是因为您的长过程不需要那么长时间—不到一秒。你可以试着添加一个长循环(for (int i = 0;I < 100000000;i++);)在函数的末尾确保这是问题所在,然后我们可以从那里…

如果上面的情况是正确的,你将需要找到一个不同的系统函数(我知道你在linux上工作,所以我不能帮助你知道函数名称)来更准确地测量时间。我相信在linux中有一个类似于GetTickCount()的函数,你只需要找到它。

正如其他人已经注意到的,C标准库中的time()函数的分辨率不超过1秒。唯一可以提供更好分辨率的完全可移植的C函数似乎是clock(),但它测量的是处理器时间而不是wallclock时间。如果一个人满足于将自己局限于POSIX平台(例如Linux),那么clock_gettime()函数是一个很好的选择。

从c++ 11开始,就有了更好的计时工具,以一种可以在不同编译器和操作系统间移植的形式提供了更好的分辨率。类似地,boost::datetime库提供了良好的高分辨率计时类,这些类应该是高度可移植的。

One challenge in using any of these facilities is the time-delay introduced by querying the system clock. From experimenting with clock_gettime(), boost::datetime and std::chrono, this delay can easily be a matter of microseconds. So, when measuring the duration of any part of your code, you need to allow for there being a measurement error of around this size, or try to correct for that zero-error in some way. Ideally, you may well want to gather multiple measurements of the time taken by your function, and compute the average, or maximum/minimum time taken across many runs.

为了帮助解决所有这些可移植性和统计数据收集问题,我一直在Github上开发cxx-rtimers库,它试图为c++代码的计时块提供一个简单的API,计算零错误,并从代码中嵌入的多个计时器报告统计数据。如果你有一个c++ 11编译器,你只需简单地#include <rtimers/cxx11.hpp>,并使用如下代码:

void expensiveFunction() {
    static rtimers::cxx11::DefaultTimer timer("expensiveFunc");
    auto scopedStartStop = timer.scopedStart();
    // Do something costly...
}

在程序退出时,你会得到一个写入std::cerr的时间统计摘要,例如:

Timer(expensiveFunc): <t> = 6.65289us, std = 3.91685us, 3.842us <= t <= 63.257us (n=731)

它显示了平均时间,它的标准偏差,上限和下限,以及这个函数被调用的次数。

如果你想使用特定于linux的计时函数,你可以#include <rtimers/posix.hpp>,或者如果你有Boost库但是一个旧的c++编译器,你可以#include <rtimers/ Boost .hpp>。这些计时器类也有不同版本,可以跨多个线程收集统计计时信息。还有一些方法允许您估计与两个立即连续的系统时钟查询相关的零错误。

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

通过这种方式,我可以测量一个代码块的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显式地启动和停止计时器,而不依赖于作用域。

从所看到的内容来看,tv_sec存储所经过的秒数,而tv_usec单独存储所经过的微秒数。它们不是彼此的转换。因此,必须将它们更改为适当的单位,并添加它们以获得所消耗的总时间。

struct timeval startTV, endTV;

gettimeofday(&startTV, NULL); 

doSomething();
doSomethingLong();

gettimeofday(&endTV, NULL); 

printf("**time taken in microseconds = %ld\n",
    (endTV.tv_sec * 1e6 + endTV.tv_usec - (startTV.tv_sec * 1e6 + startTV.tv_usec))
    );

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

#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