当前位置: 首页 > 知识库问答 >
问题:

扩展 std::chrono 功能以处理运行时(非编译时)常量周期

许淳
2023-03-14

我一直在Linux和OSX上试验各种计时器,并想尝试用std::chrono使用的相同接口包装其中一些计时器。

对于在编译时有明确定义的“周期”的定时器来说,这很容易做到,例如POSIX clock _ gettime()family、OSX上的clock_get_time() family或gettimeofday()。

然而,有些有用的计时器的“周期”(虽然是常量)只有在运行时才知道。例如:-POSIX表示时钟周期(CLOCKS_PER_SEC),在非XSI系统上可能是一个变量-在Linux上,时间周期(period of times)在运行时由sysconf(_SC_CLK_TCK)给出-在OSX上,mach_absolute_time()的周期在运行时通过mach_timebase_info()给定-在最近的Intel处理器上,DST寄存器以恒定速率计时,但这当然只能在运行时确定

要将这些计时器包装在std::chrono接口中,一种可能的方法是使用std::chrono::纳秒的周期,并将每个计时器的值转换为纳秒。另一种方法是使用浮点表示法。然而,这两种方法都会给now()函数带来(非常小的)开销,并(可能很小的)精度损失。

我试图寻求的html" target="_blank">解决方案是定义一组类来表示这样的“运行时常数”周期,按照与std::ratio类相同的方式构建。然而,我预计这将需要重写所有相关的模板类和函数(因为它们假设constexpr值)。

如何将这些计时器包装成la std: Chrono?

或者对时钟的时间段使用非连续值?

共有3个答案

漆雕嘉茂
2023-03-14

我为自己的目的做了一件类似的事情,不过只针对Linux。你可以在这里找到代码;你可以随意使用代码。

我的实现所解决的挑战与你问题中提到的挑战部分重叠。具体来说:

>

  • 在运行时检索刻度因子(需要将时钟刻度转换为基于秒的时间单位),但只使用第一次now()。如果您担心这会导致的小开销,您可以在启动时调用now()函数一次,然后再测量任何实际间隔。刻度因子存储在静态变量中,这意味着在最低级别上,每次调用now()函数都意味着检查静态变量是否已初始化。但是,在now()的每次调用中,此开销将是相同的,因此它不应该影响测量时间间隔。

    默认情况下,我不会转换为纳秒,因为当测量相对较长的时间段(例如几秒钟)时,这会导致溢出非常快。这实际上是我不使用 boost 实现的主要原因。我没有转换为纳秒,而是将基本单位实现为模板参数(在代码中称为 Precision)。我使用C 11中的std::比率作为模板参数。所以我可以选择,例如,时钟

    我的时钟类型,称为combined_clock结合了用户时间、系统时间和挂钟时间。对此也有一个升压时钟类型,但它与std中的比率类型和单位不兼容,而我的是。

    使用您建议的::sysconf()调用来检索刻度因子,并且保证在进程的整个生命周期内返回一个相同的值。

    所以你使用它的方式如下:

    #include "util/proctime.hpp"
    
    #include <ratio>
    #include <chrono>
    #include <thread>
    #include <utility>
    #include <iostream>
    
    int main()
    {
      using std::chrono::duration_cast;
      using millisec   = std::chrono::milliseconds;
      using clock_type = rlxutil::combined_clock<std::micro>;
    
      auto tp1 = clock_type::now();
    
      /* Perform some random calculations. */
      unsigned long step1 = 1;
      unsigned long step2 = 1;
      for (int i = 0 ; i < 50000000 ; ++i) {
        unsigned long step3 = step1 + step2;
        std::swap(step1,step2);
        std::swap(step2,step3);
      }
    
      /* Sleep for a while (this adds to real time, but not CPU time). */
      std::this_thread::sleep_for(millisec(1000));
    
      auto tp2 = clock_type::now();
    
      std::cout << "Elapsed time: "
                << duration_cast<millisec>(tp2 - tp1)
                << std::endl;
    
      return 0;
    }
    

    上面的用法涉及一个漂亮的打印函数,它生成如下输出:

    Elapsed time: [user 40, system 0, real 1070 millisec]
    

  • 孙嘉
    2023-03-14

    [有没有人有任何经验]还是对时钟的时间段使用非连续值?

    通读标准(20.11.5,类模板持续时间)后,“期间”预计是“比率的专门化”:

    备注:如果Period不是比率的专门化,则程序格式不正确。

    所有Chrono模板都严重依赖Constexpr功能。

    有人有包装这种计时器的经验吗?

    我在这里发现了一个建议,使用period = 1的duration,boost::rational作为rep,尽管没有任何具体的例子。

    国仰岳
    2023-03-14

    有人有包装这种计时器的经验吗?

    实际上我知道。在OSX上,你感兴趣的平台之一。:-)

    你提到:

    在OSX上,mach_absolute_time()的周期在运行时由mach_timebase_info()给出

    绝对正确。同样在 OSX 上,high_resolution_clocksteady_clock的 libc 实现实际上是基于mach_absolute_time。我是这段代码的作者,它是开源的,拥有慷慨的许可证(只要你保留版权,就可以做任何你想做的事情)。

    以下是 libc steady_clock的来源::现在()。它几乎是按照你推测的方式建造的。在返回之前,运行时间段将转换为纳秒。在OS X上,转换因子通常为1,代码通过优化来利用这一事实。但是,代码足够通用,可以处理非 1 转换因子。

    在第一次调用< code>now()时,将运行时转换因子查询为纳秒会有少量开销。在一般情况下,计算浮点转换因子。在通常情况下(转换因子== 1),后续成本是通过函数指针调用。我发现开销真的很合理。

    在OS X上,转换因子虽然直到运行时才确定,但仍然是一个常数(即不会随着程序的执行而变化),因此只需要计算一次。

    如果你的月经实际上是动态变化的,你需要更多的基础设施来处理这个问题。本质上,你需要对周期和时间曲线进行积分,然后计算两个时间点之间的平均周期。这将需要持续监控随着时间变化的周期,并且< code >

     类似资料:
    • 我有以下Spring Boot类,用自定义注释注释: 注释定义如下: 我想要的是编写一个注释处理器,有效地使我的控制器像下面的代码一样工作。 我已经能够在运行时通过反射实现这一点,但这大大延长了启动时间。有没有办法只使用注释和自定义注释处理器来实现上述功能?换句话说,我想创建一个注释,将带注释的方法添加到类中,并将任意方法调用添加到现有方法中。 我知道注释处理并不真正支持修改源代码。我有兴趣知道任

    • 我想使用部分模板专门化,以便将数组(在编译时创建)“分解”为由其值组成的参数包(以便与我在代码中定义的其他结构接口)。以下内容(我的第一次尝试)不编译 因为模板参数不得涉及模板参数。正如我所理解的,在部分模板专门化中提供非类型参数是不可能的,如果它们不是非常依赖于模板参数的话。因此,我试图通过在类型中包含值来解决这个问题: 我使用并通过,因为我使用非类型模板参数,所以需要c++2a。 在我的实际代

    • 问题内容: 所以对于这个项目,我试图在运行时扩展一个类。我想知道,这有可能吗?如果是这样,我该怎么办?是否有用于这些目的的库? 问题答案: CGLib是您要查找的库。它在扩展类或在运行时实现接口方面非常强大,因此许多流行的框架(如Spring或Hibernate)都使用它。 您可以使用以下代码创建类扩展 尽管您可能会使用具有所需逻辑的有用的方法拦截器替换回调。

    • 问题内容: Java语言文档说: 如果将原始类型或字符串定义为常量,并且在编译时知道该值,则编译器会使用其值替换代码中各处的常量名称。这称为编译时常量。 我的理解是,如果我们有一段代码: 然后,编译器会将x代码中每次出现的内容替换为literal 10。 但假设常量在运行时初始化: 与编译时常量相比,性能是否会下降(无论可以忽略不计)? 另一个问题是下面的代码行: 被编译器以与编译时常量相同的方式

    • 例如如下代码: SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日"); Date date = sdf.parse("abcd"); 这段代码会抛出ParseException,而它是编译时异常,为什么编译阶段不报错,运行时报错?

    • SDK对外开放了一个可自定义的协议NtalkerChatDelegate,如果客户想进行自定义实现接口,必须遵守此协议,初始化小能类的时候设置其delagate为实现代理接口方法的类,然后实现相应的接口。其中提供了以下几个接口: 深度自定义控件接口,详细调用细节,请参照demo。 一、自定义消息发送 二、查询历史咨询列表 三、设置超媒体自定义参数 四、+号功能区的扩展功能 五、商品条自定义 六、设