4
#include <iostream>
#include <conio.h>
#include <ctime>



using namespace std;

double diffclock(clock_t clock1,clock_t clock2)
{
    double diffticks=clock1-clock2;
    double diffms=(diffticks)/(CLOCKS_PER_SEC/1000);
    return diffms;
}
int main()
{
    clock_t start = clock();
    for(int i=0;;i++)
    {

    if(i==10000)break;
    }
    clock_t end = clock();

    cout << diffclock(start,end)<<endl;

    getch();
return 0;
}

所以我的问题来了,它给我返回一个 0,好吧,直截了当,我想检查我的程序运行了多少时间......我在互联网上发现了大量的废话,大多数情况下它与获得 0 的点相同因为开始和结束是一样的

这个问题转到 C++ 记住:<

4

5 回答 5

12

这里有几个问题。首先是您在传递给diffclock()函数时显然切换了开始和停止时间。第二个问题是优化。任何启用优化的合理智能编译器都会简单地丢弃整个循环,因为它没有任何副作用。但即使你解决了上述问题,程序很可能仍会打印 0。如果你试图想象每秒执行数十亿次操作,抛出复杂的乱序执行、预测和现代 CPU 采用的大量其他技术,即使是 CPU 也可能优化你的循环。但即使没有,您也需要超过 10K 次迭代才能使其运行更长时间。您可能需要您的程序运行一两秒钟才能clock()反映任何内容。

但最重要的问题是clock()它本身。该功能不适用于任何时间的性能测量。它的作用是为您提供程序使用的处理器时间的近似值。除了任何给定实现可能使用的近似方法的模糊性质(因为标准不需要任何特定的东西),POSIX 标准还要求CLOCKS_PER_SEC等于1000000独立于实际分辨率。换句话说——时钟有多精确并不重要,你的 CPU 以什么频率运行并不重要。简而言之——它是一个完全无用的数字,因此是一个完全无用的功能。它仍然存在的唯一原因可能是出于历史原因。所以,请不要使用它。

为了实现您要查找的内容,人们习惯于通过用于读取它的相应 CPU 指令的名称来读取CPU 时间戳,也称为“RDTSC”。然而,这些天来,这也大多是无用的,因为:

  1. 现代操作系统可以轻松地将程序从一个 CPU 迁移到另一个 CPU。您可以想象在另一个 CPU 上运行一秒钟后读取另一个 CPU 上的时间戳没有多大意义。只有在最新的 Intel CPU 中,计数器才会跨 CPU 内核同步。总而言之,仍然可以这样做,但必须格外小心(即一旦可以设置进程的亲和力等)。
  2. 经常测量程序的 CPU 指令并不能准确地了解它实际使用了多少时间。这是因为在实际程序中可能存在一些系统调用,其中工作由操作系统内核代表进程执行。在这种情况下,该时间不包括在内。
  3. 操作系统也可能长时间暂停进程的执行。尽管执行只需要几条指令,但对用户来说似乎只是一秒钟。所以这样的性能测量可能是无用的。

那么该怎么办?

perf在进行分析时,必须使用类似的工具。它可以跟踪多个 CPU 时钟、缓存未命中、已采用的分支、未命中的分支、进程从一个 CPU 移动到另一个 CPU 的次数,等等。它可以用作工具,也可以嵌入到您的应用程序中(类似于PAPI)。

如果问题是关于实际花费的时间,人们会使用挂钟。最好是高精度的,也不受 NTP 调整(单调)的影响。无论发生什么,这都能准确显示过去了多少时间。clock_gettime()可用于此目的。它是 SUSv2、POSIX.1-2001 标准的一部分。鉴于使用您getch()保持终端打开,我假设您使用的是 Windows。不幸的是,你没有clock_gettime(),最接近的是性能计数器 API:

BOOL QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency);
BOOL QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount);

对于便携式解决方案,最好的选择是std::chrono::high_resolution_clock(). 它是在 C++11 中引入的,但受到大多数工业级编译器(GCC、Clang、MSVC)的支持。

下面是一个如何使用它的例子。请注意,由于我知道我的 CPU 将以比毫秒快的速度执行 10000 个整数增量,因此我将其更改为微秒。我还声明了计数器volatile,希望编译器不会优化它。

#include <ctime>
#include <chrono>
#include <iostream>

int main()
{
    volatile int i = 0; // "volatile" is to ask compiler not to optimize the loop away.
    auto start = std::chrono::steady_clock::now();
    while (i < 10000) {
        ++i;
    }
    auto end = std::chrono::steady_clock::now();
    auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
    std::cout << "It took me " << elapsed.count() << " microseconds." << std::endl;
}

当我编译并运行它时,它会打印:

$ g++ -std=c++11 -Wall -o test ./test.cpp && ./test
It took me 23 microseconds.

希望能帮助到你。祝你好运!

于 2013-03-05T23:09:03.880 回答
5

乍一看,您似乎是从较小的值中减去较大的值。你打电话:

diffclock( start, end );

但随后 diffclock 被定义为:

    double diffclock( clock_t clock1, clock_t clock2 ) {

        double diffticks = clock1 - clock2;
        double diffms    = diffticks / ( CLOCKS_PER_SEC / 1000 );

        return diffms;
    }

除此之外,它可能与您转换单位的方式有关。使用 1000 转换为毫秒在此页面上有所不同:

http://en.cppreference.com/w/cpp/chrono/c/clock

于 2013-03-05T22:31:50.827 回答
3

问题似乎是循环太短了。我在我的系统上尝试了它,它给出了 0 个滴答声。我检查了 diffticks 是什么,它是 0。将循环大小增加到 100000000,所以有一个明显的时间延迟,我得到 -290 作为输出(错误——我认为 diffticks 应该是 clock2-clock1 所以我们应该得到 290而不是-290)。我还尝试在部门中将“1000”更改为“1000.0”,但没有奏效。

使用优化进行编译确实会删除循环,因此您不必使用它,或者使循环“做某事”,例如在循环体中增加一个计数器而不是循环计数器。至少这就是 GCC 所做的。

于 2013-03-05T22:31:38.573 回答
2

注意:这在 c++11 之后可用。

您可以使用std::chrono库。std::chrono 有两个不同的对象。(时间点持续时间)。时间点代表时间点和持续时间,正如我们已经知道的那样,该术语代表时间间隔或时间跨度。这个 c++ 库允许我们减去两个时间点来获得在间隔中传递的持续时间。因此,您可以设置起点和终点。使用函数,您还可以将它们转换为适当的单位。

使用high_resolution_clock的示例(这是该库提供的三个时钟之一):

#include <chrono> 
using namespace std::chrono;

//在运行函数之前

auto start = high_resolution_clock::now();

//调用函数后

auto stop = high_resolution_clock::now();

减去停止和开始时间点,并使用 duration_cast() 函数将其转换为所需的单位。预定义的单位是纳秒、微秒、毫秒、秒、分钟和小时。

auto duration = duration_cast<microseconds>(stop - start);
cout << duration.count() << endl;
于 2020-08-19T16:39:34.230 回答
1

首先,您应该减去 end - start 反之亦然。
文档说如果值不可用clock()返回-1,你检查了吗?编译程序时使用什么优化级别?如果启用优化,编译器可以有效地完全消除您的循环。

于 2013-03-05T22:26:34.477 回答