标准C ++ 11是否保证high_resolution_clock测量实时(非CPU周期)? [英] Does standard C++11 guarantee that high_resolution_clock measure real time (non CPU-cycles)?

查看:113
本文介绍了标准C ++ 11是否保证high_resolution_clock测量实时(非CPU周期)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

众所周知,clock()可能显示小于或大于实时值-在下面的示例1和2中都显示了这两种情况.

As known clock() may show less than or greater than the value of the real time - both cases are shown in the following examples 1 and 2.

对于C ++ 11中时间的高精度测量,我们可以使用:

For high-precision measurements of the time in C++11 we can use:

  • std::chrono::high_resolution_clock::now();-保证高精度
  • std::chrono::steady_clock::now();-确保实时测量
  • clock();-保证高精度,但测量CPU周期而不是时间
  • time(&t_start);-不是高精度,而是实时测量
  • std::chrono::high_resolution_clock::now(); - guarantee high-precision
  • std::chrono::steady_clock::now(); - guarantee that measure real time
  • clock(); - guarantee high-precision, but measure CPU-cycles instead of time
  • time(&t_start); - isn't high-precision, but measure real time

1-例如: http://ideone.com/SudWTM

#include <stdio.h>
#include <time.h>
#include <thread>
#include <iostream>
#include <chrono>

int main(void) {

    std::cout << "sleep(3) took: \n\n";

    clock_t c_start, c_end;
    time_t t_start, t_end;
    std::chrono::high_resolution_clock::time_point h_start, h_end;
    std::chrono::steady_clock::time_point steady_start, steady_end;

    time(&t_start);  // less precise than clock() but always get the real actual time
    c_start = clock(); // clock() get only CPU-time, it can be more than real or less - sleep(3); took 0.00 seconds 
    h_start = std::chrono::high_resolution_clock::now();
    steady_start = std::chrono::steady_clock::now(); 

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

    steady_end = std::chrono::steady_clock::now();
    h_end = std::chrono::high_resolution_clock::now();
    c_end = clock();
    time(&t_end);

    std::cout << "highres = " << std::chrono::duration<double>(h_end - h_start).count() << " s \n";
    std::cout << "steady = " << std::chrono::duration<double>(steady_end - steady_start).count() << " s \n";

    printf("clock() = %.2lf seconds \n", (c_end - c_start) / (double)CLOCKS_PER_SEC);
    printf("time() = %.2lf seconds \n", difftime(t_end, t_start));

    return 0;
}

在g ++(Debian 4.9.2-10)4.9.2上的结果: clock()= 0.00秒

Result on g++ (Debian 4.9.2-10) 4.9.2: clock() = 0.00 seconds

sleep(3) took: 

highres = 3.00098 s 
steady = 3.00098 s 
clock() = 0.00 seconds 
time() = 3.00 seconds 

在C ++ MSVS 2013 v120(Windows 7x64)上的结果:

Result on C++ MSVS 2013 v120 (Windows 7x64):

sleep(3) took:

highres = 3.00017 s
steady = 3.00017 s
clock() = 3.00 seconds
time() = 3.00 seconds

2-第二个示例OpenMP或<thread>: http://coliru.stacked- crooked.com/a/2922c85385d197e1

2- Second example OpenMP or <thread>: http://coliru.stacked-crooked.com/a/2922c85385d197e1

#include <stdio.h>
#include <time.h>
#include <thread>
#include <iostream>
#include <chrono>
#include <vector>

int main(void) {

    std::cout << "for-loop took: \n\n";

    clock_t c_start, c_end;
    time_t t_start, t_end;
    std::chrono::high_resolution_clock::time_point h_start, h_end;
    std::chrono::steady_clock::time_point steady_start, steady_end;

    time(&t_start);  // less precise than clock() but always get the real actual time
    c_start = clock(); // clock() get only CPU-time, it can be more than real or less - sleep(3); took 0.00 seconds 
    h_start = std::chrono::high_resolution_clock::now();
    steady_start = std::chrono::steady_clock::now();

    #pragma omp parallel num_threads(10)
    {
        for (volatile int i = 0; i < 200000000; ++i);
    }

    steady_end = std::chrono::steady_clock::now();
    h_end = std::chrono::high_resolution_clock::now();
    c_end = clock();
    time(&t_end);

    std::cout << "highres = " << std::chrono::duration<double>(h_end - h_start).count() << " s \n";
    std::cout << "steady = " << std::chrono::duration<double>(steady_end - steady_start).count() << " s \n";

    printf("clock() = %.2lf seconds \n", (c_end - c_start) / (double)CLOCKS_PER_SEC);
    printf("time() = %.2lf seconds \n", difftime(t_end, t_start));

    int b = getchar();

    return 0;
}

在g ++(Debian 4.9.2-10)4.9.2上的结果: clock()= 1.35秒

Result on g++ (Debian 4.9.2-10) 4.9.2: clock() = 1.35 seconds

for-loop took: 

highres = 0.213906 s 
steady = 0.213905 s 
clock() = 1.35 seconds 
time() = 0.00 seconds 

在C ++ MSVS 2013 v120(Windows 7x64)上的结果:

Result on C++ MSVS 2013 v120 (Windows 7x64):

for-loop took:

highres = 1.49109 s
steady = 1.49109 s
clock() = 1.49 seconds
time() = 2.00 seconds

恢复:

  1. 当线程休眠时,g ++ 4.9.2上的clock()不会像其他函数那样测量时间.

  1. When thread sleeps then clock() on g++ 4.9.2 doesn't measure time unlike other functions.

当我们通过OpenMP或<thread>(链接)使用多线程时,则在g ++ 4.9.2上的clock()测量所有线程的CPU周期.

When we use multithreading by using OpenMP or by using <thread> (link), then clock() on g++ 4.9.2 measures CPU-cycles of all threads.

在Windows MSVS 2013上,clock()也在两种情况下实时测量所需的时间,但这不能保证clock()在其他平台上也可以测量相同的时间(在Linux上,g ++的睡眠状态为0,x折叠的状态为x-fold.多线程).

Also on Windows MSVS 2013 clock() measures required real time in both cases, but this doesn't guarantee that clock() measures the same on other platforms (on linux g++ is 0 for the sleep and x-fold for the multithreading).

基于此,如果std::chrono::high_resolution_clock::now();在Windows MSVS 2013和g ++ 4.9.2上均在两种情况下均测量所需的实时性,是否保证它会在所有其他平台上测量实际的高分辨率时间,并且是否保证标准C ++ 11/14?

Based on this, if std::chrono::high_resolution_clock::now(); measures required real time in both cases on both Windows MSVS 2013 and g++ 4.9.2, does this guarantee that it will measure real high resolution time on all other platforms and does whether it guarantee standard C++11/14?

推荐答案

简短的回答:从C ++ 14标准开始,high_resolution_clock并未明确提供您要寻找的保证.

就目前而言,steady_clocksystem_clock提供了更好,更明确的保证.但是,大多数实现可能将确保HRC在其线程处于休眠状态时继续运行.尽管如此,最好还是自己进行类型别名.请参阅下面的编辑"部分,并在评论中进行讨论.

Short answer: as of the C++14 standard, high_resolution_clock does NOT explicitly provide the guarantee you're looking for.

For now, steady_clock and system_clock provide better and more explicit guarantees. However, most implementations probably will ensure that HRC advances while its thread is sleeping. It may nevertheless be preferable to do your own type-aliasing. See 'EDIT' sections below and discussion in comments.

草稿标准实际上,隐式地承认(在注释30.2.4定时规范",注释5中),在关联线程处于休眠状态时,不需要推进Clock对象.就上下文而言,本节说明标准库计时器对象如何工作.计时器的行为取决于用于设置计时器的时钟的行为.

The draft standard does in fact implicitly acknowledge (in note 30.2.4 "Timing Specifications", note 5) that Clock objects are not required to advance while their associated thread is sleeping. For context, this section is explaining how the standard-library timer objects work; the behavior of a timer is based on the behavior of the clock used to set it.

[注意:如果时钟未与稳定时钟同步,例如 CPU时间时钟,这些超时可能不提供有用的功能. — 尾注]

[ Note: If the clock is not synchronized with a steady clock, e.g., a CPU time clock, these timeouts might not provide useful functionality. — end note ]

请注意,在这种情况下,超时可能无法提供有用的功能"意味着,如果您使用计时器使用非同步(非实时)时钟sleep_until特定时钟时间 ,则您的线程不会唤醒.因此,上面的注释有些轻描淡写.

Note that in this case, "timeouts might not provide useful functionality" means that if you use a timer to sleep_until a particular clock time using an unsynchronized (non-realtime) clock, your thread will not wake up. So the note above is a bit of an understatement.

而且,实际上,时钟"规范(20.13.3)中没有任何内容需要与稳定时钟进行同步.

And, indeed, there is nothing in the Clock specification (20.13.3) that actually requires synchronization with a steady clock.

但是,该标准似乎隐含地宽恕了20.13.7.3中定义中high_resolution_clock的两个可能的别名:

However, the standard appears to implicitly condone two potential aliases for high_resolution_clock in the definition in 20.13.7.3:

high_resolution_clock可以是system_clock的同义词,或者 steady_clock.

high_resolution_clock may be a synonym for system_clock or steady_clock.

steady_clock当然是稳定的. system_clock不是 ,因为程序运行时系统时间可能会更改(例如,由于NTP更新).

steady_clock is, of course, steady. system_clock is not, because the system time could change (e.g. as the result of an NTP update) while the program is running.

但是,system_clock(20.13.7.1)仍然是实时"时钟:

However, system_clock (20.13.7.1) is still a "realtime" clock:

system_clock的对象表示从 系统范围的实时时钟.

Objects of class system_clock represent wall clock time from the system-wide realtime clock.

因此,当线程休眠时,system_clock 不会停止前进. 这证实了Nicol Bolas的观点,即is_steady对于high_resolution_clock可能是 false ,即使时钟的行为符合您的预期(即,时钟前进,而不管其关联线程的状态如何).

So system_clock will not stop advancing when your thread sleeps. This confirms Nicol Bolas's point that a is_steady may be false for high_resolution_clock even if the clock behaves as you expect (i.e. it advances regardless of the state of its associated thread).

基于此,可以预期大多数主流实现对high_resolution_clock使用某种实时(即同步)时钟.毕竟,实现被设计为有用的,并且如果时钟不是实时的,则时钟通常没有那么有用,尤其是按照上面有用的功能"的注释,如果它与计时器一起使用,则是不可用的.

Based on this, it seems reasonable to expect most mainstream implementations to use a realtime (i.e. synchronized) clock of some sort for high_resolution_clock. Implementations are designed to be useful, after all, and a clock is generally less useful if it's not realtime, especially if it's used with timers as per the note on "useful functionality" above.

但是,由于它没有得到保证,因此,您应检查要使用的每个实现的行为和/或文档.

Since it's not guaranteed, however, you should check the behavior and/or documentation of each implementation you want to use.

编辑:我已经开始了

I've started a discussion on the ISO C++ Standards group on the issue, suggesting that this is a bug in the standard. The first reply, from Howard Hinnant, who takes credit for putting it in the standard, is worth quoting:

我不会反对弃用high_resolution_clock,目的是在适当的弃用期后将其删除.现实情况是,它始终是steady_clocksystem_clock的typedef,并且与选择high_resolution_clock并逐一获得其他时钟相比,程序员最好选择这两个中的一个并知道他要得到什么.骰子.

I would not be opposed to deprecating high_resolution_clock, with the intent to remove it after a suitable period of deprecation. The reality is that it is always a typedef to either steady_clock or system_clock, and the programmer is better off choosing one of those two and know what he’s getting, than choose high_resolution_clock and get some other clock by a roll of the dice.

...根据Hinnant所说,道德是不要使用high_resolution_clock.

...So the moral, according to Hinnant, is don't use high_resolution_clock.

根据Hinnant的说法,high_resolution_clock的问题并不多,以至您可能会遇到HRC的问题(尽管根据参数,即使使用兼容的编译器, 也可能以上),但是由于通常您实际上未获得比其他两个时钟之一更低的分辨率(尽管您需要手动将它们的分辨率用type-alias或typedef进行比较以获得最大"分辨率"(非睡眠时钟),则没有具体好处.因此,您需要权衡使线程在符合规范的实现中永久睡眠的风险与名称high_resolution_clock的语义优势以及避免仅制作自己的typedef或type-alias的简单性/简洁性优势的权衡.

The problem with high_resolution_clock according to Hinnant is not so much that you're likely to run into a problem with HRC (although that is possible even with a conforming compiler, as per the argument above), but that since you're typically not actually getting a lower resolution than you could with the one of the other two clocks (though you'll need to manually compare their resolutions in a type-alias or typedef to get a "maximum resolution" non-sleeping clock), there's no concrete benefit. So you need to weigh the risk of having threads sleep forever on conforming implementations versus the semantic benefit of the name high_resolution_clock and the simplicity/brevity benefit of avoiding just making your own typedef or type-alias.

以下是一些用于各种方法的实际代码:

Here's some actual code for various approaches:

  • 使用static_assert检查 high_resolution_clock是否实际上是真实时钟的别名.这将可能永远不会触发,这意味着您将自动获得最高分辨率的实时"时钟,而不会弄乱您自己的typedef:

  • Use static_assert to check whether high_resolution_clock is actually aliased to a real clock. This will probably never fire, which means that you're automatically getting the highest-resolution "realtime" clock without messing with your own typedefs:

 static_assert(
      std::is_same<high_resolution_clock, steady_clock>::value
   || std::is_same<high_resolution_clock, system_clock>::value,
   "high_resolution_clock IS NOT aliased to one of the other standard clocks!");

  • 如果high_resolution_clock::is_steady为true,则使用HRC;否则,请使用HRC.否则,最好使用system_clocksteady_clock之间的高分辨率时钟. 注意,如果high_resolution_clock::is_steady为假,则此可能仅表示HRC的别名为system_clock,在这种情况下,您最终将得到新的类型-alias实际上与high_resolution_clock相同的类型.但是,创建自己的类型别名使这一点很明确,并保证即使是恶意但合规的实现也不会出现上述问题.

  • Use the HRC if high_resolution_clock::is_steady is true; otherwise prefer the higher-resolution clock between system_clock and steady_clock. NOTE that if high_resolution_clock::is_steady is false, this probably just means that the HRC is aliased to system_clock, in which case you'll ultimately end up with a new type-alias that is actually the same type as high_resolution_clock. However, creating your own type-alias makes this explicit and guarantees that even a malicious-but-conforming implementation won't have the issue outlined above.

    using maxres_sys_or_steady =
        std::conditional<
            system_clock::period::den <= steady_clock::period::den,
            system_clock, steady_clock
          >::type;
    using maxres_nonsleeping_clock =
        std::conditional<
            high_resolution_clock::is_steady,
            high_resolution_clock, maxres_sys_or_steady
          >::type;
    

  • 这篇关于标准C ++ 11是否保证high_resolution_clock测量实时(非CPU周期)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    相关文章
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆