【问题标题】:Determining CPU time required to execute loop确定执行循环所需的 CPU 时间
【发布时间】:2023-03-22 22:24:02
【问题描述】:

我做了一些 SO 搜索,发现 thisthat 概述了计时方法。

我的问题是我需要确定执行以下循环所需的 CPU 时间(以毫秒为单位):

for (int i = 0, temp = 0; i < 10000; i++)
{
    if (i % 2 == 0)
    {
        temp = (i / 2) + 1;
    }
    else
    {
        temp = 2 * i;
    }
}

我研究了两种方法,clock()stead_clock::now()。根据docs,我知道clock() 返回“滴答声”,因此我可以通过使用CLOCKS_PER_SEC 将差值除以秒来得到它。 docs 还提到 steady_clock 是为间隔计时而设计的,但您必须调用 duration_cast&lt;milliseconds&gt; 来更改其单位。

我为这两者计时所做的事情(因为在同一运行中同时执行这两个操作可能会导致一个需要更长的时间,因为另一个是先调用的)是自己运行它们:

clock_t t = clock();
for (int i = 0, temp = 0; i < 10000; i++)
{
    if (i % 2 == 0)
    {
        temp = (i / 2) + 1;
    }
    else
    {
        temp = 2 * i;
    }
}
t = clock() - t;
cout << (float(t)/CLOCKS_PER_SEC) * 1000 << "ms taken" << endl;

chrono::steady_clock::time_point p1 = chrono::steady_clock::now();
for (int i = 0, temp = 0; i < 10000; i++)
{
    if (i % 2 == 0)
    {
        temp = (i / 2) + 1;
    }
    else
    {
        temp = 2 * i;
    }
}
chrono::steady_clock::time_point p2 = chrono::steady_clock::now();
cout << chrono::duration_cast<milliseconds>(p2-p1).count() << "ms taken" << endl;

输出:

0ms taken
0ms taken

这两种方法都会影响结果吗?肯定发生了一些毫秒的分形?

那么对于确定执行循环所需的 CPU 时间,哪个是理想的(或者更确切地说,更合适)?乍一看,我会支持clock(),因为文档明确告诉我它用于确定 CPU 时间。

就上下文而言,我的CLOCKS_PER_SEC 的值为1000

编辑/更新:

尝试了以下方法:

clock_t t = clock();
for (int j = 0; j < 1000000; j++) {
    volatile int temp = 0;
    for (int i = 0; i < 10000; i++)
    {
        if (i % 2 == 0)
        {
            temp = (i / 2) + 1;
        }
        else
        {
            temp = 2 * i;
        }
    }
}
t = clock() - t;
cout << (float(t) * 1000.0f / CLOCKS_PER_SEC / 1000000.0f) << "ms taken" << endl;

输出:0.019953 毫秒

clock_t start = clock();
volatile int temp = 0;
for (int i = 0; i < 10000; i++)
{
    if (i % 2 == 0)
    {
        temp = (i / 2) + 1;
    }
    else
    {
        temp = 2 * i;
    }
}
clock_t end = clock();
cout << fixed << setprecision(2) << 1000.0 * (end - start) / CLOCKS_PER_SEC << "ms taken" << endl;

输出:耗时 0.00 毫秒

chrono::high_resolution_clock::time_point p1 = chrono::high_resolution_clock::now();
volatile int temp = 0;
for (int i = 0; i < 10000; i++)
{
    if (i % 2 == 0)
    {
        temp = (i / 2) + 1;
    }
    else
    {
        temp = 2 * i;
    }
}
chrono::high_resolution_clock::time_point p2 = chrono::high_resolution_clock::now();
cout << (chrono::duration_cast<chrono::microseconds>(p2 - p1).count()) / 1000.0 << "ms taken" << endl;

输出:耗时 0.072 毫秒

chrono::steady_clock::time_point p1 = chrono::steady_clock::now();
volatile int temp = 0;
for (int i = 0; i < 10000; i++)
{
    if (i % 2 == 0)
    {
        temp = (i / 2) + 1;
    }
    else
    {
        temp = 2 * i;
    }
}
chrono::steady_clock::time_point p2 = chrono::steady_clock::now();
cout << (chrono::duration_cast<chrono::microseconds>(p2 - p1).count()) / 1000.0f << "ms taken" << endl;

输出:0.044ms

那么问题就变成了,哪个有效?第二种方法对我来说似乎无效,因为我认为循环完成的速度超过一毫秒。

我理解第一种方法(只是执行时间更长),但后两种方法产生的结果截然不同。

我注意到的一件事是,在编译程序后,我第一次运行它可能会得到 0.073 毫秒(high_resolution_clock)和 0.044 毫秒(steady_clock),但所有后续运行时间在 0.019 - 0.025ms 范围内。

【问题讨论】:

  • 旁白:由于这段代码很愚蠢/毫无意义(它不断覆盖temp 的值,最终被丢弃),编译器可能会选择消除其全部或部分输出。无论如何,对于这么简单的一段代码来说,10.000 次迭代并不算多 - 尝试将循环计数提高几个数量级。
  • 为什么你认为什么都不做需要时间?您的循环对程序的可观察行为没有影响
  • @500-InternalServerError 这样做了,他们确实产生了结果。我有同样的想法,但这些是我的限制。请参阅我对 Caleth 的回复。
  • @Caleth 执行此循环所需的时间稍后在对象程序中分配为 1 UT 的度量。所以我需要得到1 UT = x ms,其中x 是运行该循环的未知时间(以毫秒为单位)。
  • 即使编译器没有优化所有内容,0ms 也可能是正确的结果。例如,2 * ii + i 相同,在 PC 上只需几分之一纳秒。

标签: c++


【解决方案1】:

你可以循环一百万次,然后除法。您还可以添加 volatile 关键字以避免一些编译器优化。

clock_t t = clock();
for (int j = 0, j < 1000000; j++) {
    volatile int temp = 0;
    for (int i = 0; i < 10000; i++)
    {
        if (i % 2 == 0)
        {
            temp = (i / 2) + 1;
        }
        else
        {
            temp = 2 * i;
        }
    }
}
t = clock() - t;
cout << (float(t) * 1000.0f / CLOCKS_PER_SEC / 1000000.0f) << "ms taken" << endl;

【讨论】:

  • 此时我的问题变为:使用您的方法而不是 chrono::high_resolution_clock 来衡量这个有什么区别吗?我喜欢你使用专门测量 CPU 时间的clock(),而另一种方法实际上测量的是挂墙时间。除此之外,差异(输出方面)充其量是微不足道的。
  • 另外,事实证明,在 Windows 上 clock 测量挂壁时间,这将解释它和 chrono::high_resolution_clock 几乎相同的时间。所以我想什么是跨 Windows 和 Linux 的可移植变体?
  • 关于 windows 的有趣评论,我不知道。标准时钟被定义为返回进程使用的 CPU 时间,并且可能与挂钟时间不同,因此这将是最正确的(但在 Windows 上则不然)。 chrono 给出了 walltime,因此结果可能比您想知道的实际运行时间更长。您可以通过提高线程/进程优先级获得更准确的结果,但不能保证 CPU 不会用于其他进程。
  • 所以,总而言之,如果你想要一个“执行时间单位”,我会选择 walltime,并取多个循环和多次运行的平均值。
【解决方案2】:

我希望使用 GetTickCount() 似乎是解决方案

double start_s = GetTickCount();
for (int i = 0, temp = 0; i < 10000000; i++)
{
    if (i % 2 == 0)
    {
        temp = (i / 2) + 1;
    }
    else
    {
        temp = 2 * i;
    }
}
double stop_s = GetTickCount();
cout << (stop_s - start_s) / double(CLOCKS_PER_SEC) * 1000 << "ms taken" << endl;

对我来说,在 16-31 毫秒之间返回

【讨论】:

  • 这主要取决于GetTickCount的精度
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-31
  • 1970-01-01
相关资源
最近更新 更多