C++ Linux 最快的时间测量方法(比 std::chrono 更快)?包含基准

2023-12-26

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

class MyTimer {
 private:
  std::chrono::time_point<std::chrono::steady_clock> starter;
  std::chrono::time_point<std::chrono::steady_clock> ender;

 public:
  void startCounter() {
    starter = std::chrono::steady_clock::now();
  }

  double getCounter() {
    ender = std::chrono::steady_clock::now();
    return double(std::chrono::duration_cast<std::chrono::nanoseconds>(ender - starter).count()) /
           1000000;  // millisecond output
  }
  
  // timer need to have nanosecond precision
  int64_t getCounterNs() {
    return std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::steady_clock::now() - starter).count();
  }
};

MyTimer timer1, timer2, timerMain;
volatile int64_t dummy = 0, res1 = 0, res2 = 0;

// time run without any time measure
void func0() {
    dummy++;
}

// we're trying to measure the cost of startCounter() and getCounterNs(), not "dummy++"
void func1() {
    timer1.startCounter();  
    dummy++;
    res1 += timer1.getCounterNs();
}

void func2() {
    // start your counter here
    dummy++;
    // res2 += end your counter here
}

int main()
{
    int i, ntest = 1000 * 1000 * 100;
    int64_t runtime0, runtime1, runtime2;

    timerMain.startCounter();
    for (i=1; i<=ntest; i++) func0();
    runtime0 = timerMain.getCounter();
    cout << "Time0 = " << runtime0 << "ms\n";

    timerMain.startCounter();
    for (i=1; i<=ntest; i++) func1();
    runtime1 = timerMain.getCounter();
    cout << "Time1 = " << runtime1 << "ms\n";

    timerMain.startCounter();
    for (i=1; i<=ntest; i++) func2();
    runtime2 = timerMain.getCounter();
    cout << "Time2 = " << runtime2 << "ms\n";

    return 0;
}

我正在尝试分析一个程序,其中某些关键部分的执行时间小于 50 纳秒。我发现我的计时器类使用std::chrono太昂贵了(带计时的代码比不带计时的代码多花 40% 的时间)。如何制作更快的计时器类?

我认为一些特定于操作系统的系统调用将是最快的解决方案。平台是Linux Ubuntu。

Edit:所有代码均使用 -O3 编译。确保每个计时器仅初始化一次,因此测量的成本仅由 startMeasure/stopMeasure 函数引起。我不做任何文本打印。

Edit 2:接受的答案不包括实际将周期数转换为纳秒的方法。如果有人能做到这一点,那将非常有帮助。


你想要的就是所谓的“微基准测试”。它可能会变得非常复杂。我假设您在 x86_64 上使用 Ubuntu Linux。这对于 ARM、ARM64 或任何其他平台无效。

std::chrono 在 Linux 上的 libstdc++ (gcc) 和 libc++ (clang) 上实现,作为 GLIBC(C 库)的一个简单包装,它完成了所有繁重的工作。如果您查看 std::chrono::steady_clock::now() 您将看到对clock_gettime() 的调用。

Clock_gettime() 是一个VDSO,即它是在用户空间中运行的内核代码。它应该非常快,但有时它可能需要做一些内务处理,并且每次调用都需要很长时间。所以我不推荐进行微基准测试。

几乎每个平台都有一个周期计数器,x86 有汇编指令rdtsc。该指令可以通过制作插入到您的代码中asm调用或使用编译器特定的内置函数 __builtin_ia32_rdtsc() 或 __rdtsc()。

这些调用将返回一个 64 位整数,表示自机器加电以来的时钟数。 rdtsc 不是立即执行的,但速度很快,大约需要 15-40 个周期才能完成。

不能保证在所有平台上每个核心的该计数器都相同,因此当进程从一个核心移动到另一个核心时要小心。但在现代系统中这不应该是一个问题。

rdtsc 的另一个问题是,如果编译器发现指令没有副作用,它们通常会重新排序指令,不幸的是 rdtsc 就是其中之一。因此,如果您发现编译器在欺骗您,则必须在这些计数器读取周围使用假屏障 - 查看生成的程序集。

还有一个大问题是cpu本身乱序执行。不仅编译器可以改变执行顺序,CPU 也可以。由于 x86 486 英特尔 CPU 是流水线式的,因此可以同时执行多条指令 - 粗略地说。因此,您最终可能会测量虚假执行。

我建议您熟悉微基准测试的类似量子问题。这并不简单。

请注意,rdtsc() 将返回周期数。您必须使用时间戳计数器频率转换为纳秒。

这是一个例子:

#include <iostream>
#include <cstdio>

void dosomething() {
    // yada yada
}

int main() {
    double sum = 0;
    const uint32_t numloops = 100000000;
    for ( uint32_t j=0; j<numloops; ++j ) {
        uint64_t t0 = __builtin_ia32_rdtsc();
        dosomething();
        uint64_t t1 = __builtin_ia32_rdtsc();
        uint64_t elapsed = t1-t0;
        sum += elapsed;
    }
    std::cout << "Average:" << sum/numloops << std::endl;
}

这篇论文有点过时(2010 年),但它足够最新,可以为您提供有关微基准测试的良好介绍:

如何对英特尔® IA-32 和 IA-64 指令集架构上的代码执行时间进行基准测试 https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ Linux 最快的时间测量方法(比 std::chrono 更快)?包含基准 的相关文章

  • 解析 JWT 令牌以仅获取有效负载内容,无需 C# 或 Blazor 中的外部库

    我正在使用 Blazor 编写可以访问 JWT 的客户端应用程序 我想知道一种简单的方法来读取令牌有效负载内容而不添加额外的依赖项 因为我不需要其他信息 也不需要验证令牌 我认为解析有效负载内容应该足够简单 只需将其写入方法即可 JwtTo
  • 在 C# 中调用 C++ 库 [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有很多用 C 编写的库 我想从 C 调用这些库 但是 我遇到了很多问题 我想知道是否有书籍或指南告诉我如何做到这一点 Dll导入 htt
  • 在开关中使用“goto”?

    我看到了一个建议的编码标准 内容如下Never use goto unless in a switch statement fall through 我不跟 这个 例外 案例到底是什么样的 这证明了goto 此构造在 C 中是非法的 swi
  • 循环中的递归算法复杂度(运行时间)

    我想了解您对如何检测以下递归算法的 T n 运行时间 的意见 Charm 是一种用于发现事务数据库中频繁闭项集的算法 频繁闭项集列表是在一组交易 tids 中多次出现的频繁项 例如面包和牛奶是经常一起购买的物品 它们是通过将索引为 i 的当
  • 访问 ascx 文件中的母版页控件

    我有一个母版页文件 其中包含 2 个面板控件中的 2 个菜单 我还使用控件来检查用户是否登录并获取用户类型 根据我想要显示 隐藏面板的类型 控件本身不在母版页中引用 而是通过 CMS 系统动态引用 我想在用户控件中使用findcontrol
  • 增强精神、递归和堆栈溢出

    为什么下面的代码在运行时崩溃 它会给出堆栈溢出错误 include
  • 根据对象变量搜索对象列表

    我有一个对象列表 这些对象具有三个变量 ID 名称和值 这个列表中可能有很多对象 我需要根据ID或Name找到一个对象 并更改值 例子 class objec public string Name public int UID public
  • 使用 C# 和 wpf 创建类似 Dock 的应用程序

    我需要创建一个与我们购买笔记本电脑时获得的应用程序类似的应用程序 仅当鼠标指针到达窗口顶部时它才可见 那么我怎样才能使用 C 4 0 来做到这一点呢 http www notebookcheck net uploads pics win2
  • 如何在三个 IEnumerable 上使用 Zip [重复]

    这个问题在这里已经有答案了 可能的重复 使用 Linq 从 3 个集合创建项目 https stackoverflow com questions 5284315 create items from 3 collections using
  • 在 asp.net MVC 中使用活动目录进行身份验证

    我想使用活动目录对我的 asp net mvc 项目中的用户进行身份验证 在网上冲浪了几个小时后 我没有找到任何对我有用的东西 我已经看到了所有结果 但什么也没有 我尝试按照许多帖子的建议编辑我的 web config 如果有人可以帮助我提
  • 使用 GCC 生成可读的程序集?

    我想知道如何使用GCC http en wikipedia org wiki GNU Compiler Collection在我的 C 源文件中转储机器代码的助记符版本 这样我就可以看到我的代码被编译成什么 你可以使用 Java 来做到这一
  • 从浏览器访问本地文件?

    您好 我想从浏览器访问系统的本地文件 由于涉及大量安全检查 是否可以通过某种方式实现这一目标 或使用 ActiveX 或 Java Applet 的任何其他工作环境 请帮帮我 要通过浏览器访问本地文件 您可以使用签名的 Java Apple
  • VSCODE 在 Linux 上不适用于我

    刚刚了解 VSCODE 很高兴尝试一下 我下载 解压并运行可执行文件 我得到 Code 2183 0429 201254 ERROR browser main loop cc 170 Running without the SUID san
  • 如何停止无限循环?

    我正在编写一个程序 该程序将计算三角形或正方形的面积 然后提示用户是否希望计算另一个 我的代码已经运行到可以计算任一形状的面积的程度 但随后不再继续执行代码的其余部分 例如 如果选择了正方形 则计算面积 然后返回到正方形边长的提示 我假设这
  • 如何调试 .NET 运行时中的内部错误?

    我正在尝试调试一些处理大文件的工作 代码本身works 但 NET 运行时本身会报告零星错误 对于上下文 这里的处理是一个 1 5GB 文件 仅加载到内存中一次 在循环中处理和释放 故意尝试重现此否则不可预测的错误 我的测试片段基本上是 t
  • C++ 中 void(*)() 和 void(&)() 之间的区别[重复]

    这个问题在这里已经有答案了 在此示例代码中 func1是类型void int double and funky是类型void int double include
  • 如何得知客户端从服务器的下载速度?

    根据客户的下载速度 我想以低质量或高质量显示视频 任何 Javascript 或 C 解决方案都是可以接受的 Thanks 没有任何办法可以确定 您只能测量向客户端发送数据的速度 如果没有来自客户端的任何类型的输入来表明其获取信息的速度 您
  • 来自 3rd 方库的链接器错误 LNK2019

    我正在将旧的 vc 6 0 应用程序移植到 vs2005 我收到以下链接器错误 我花了几天时间试图找到解决方案 错误LNK2019 无法解析的外部符号 imp 创建AwnService 52 在函数 public int thiscall
  • INotifyPropertyChanged 和 propertyName

    我一直不确定它的含义propertyName实施时INotifyPropertyChanged 所以一般来说你实现INotifyPropertyChanged as public class Data INotifyPropertyChan
  • 使用 numpy 加速 for 循环

    下一个 for 循环如何使用 numpy 获得加速 我想这里可以使用一些奇特的索引技巧 但我不知道是哪一个 这里可以使用 einsum 吗 a 0 for i in range len b a numpy mean C d e f b i

随机推荐

  • 在银河系坐标中绘制热图

    EDIT 好吧 我想出了一个糟糕的方法来做到这一点 涉及scipy interpolate griddata 我有一些二维数组 130x360 形式的地图 数组中的每个值对应于该点的测量值 这些地图以赤经 ra 和赤纬 dec 形式提供 范
  • 如何获取字符串的第一个单词并将其转换为 int? jQuery

    我需要获取字符串中的第一个单词 并将其转换为整数 如何使用 jQuery 做到这一点 example 223 洛雷姆 伊普苏姆 多洛尔 I need 223 并且它必须转换为integer 任何帮助 将不胜感激 您可以根据任何字符 例如空格
  • iPad 上禁用嵌入式 Youtube 播放器中的全屏按钮

    在研究了 stackoverflow 上至少十个类似的问题后 我似乎偶然发现了一些新东西 最近 不确定具体什么时候停止工作 嵌入式 YouTube 视频上的全屏按钮在 iPad 上被禁用 如果我尝试单击它 则会弹出 您的浏览器不支持全屏 的
  • 使用 lerna 将自定义参数发送到 npm (yarn) 脚本

    我在尝试将参数传递给npm脚本与lerna 我有一个节点脚本 我想在工作区的每个包中运行它 lerna文档建议如下 scripts my script lerna exec node LERNA ROOT PATH scripts my s
  • Swift 一次删除多个对象 Parse 服务器

    我向服务器查询如下 let query PFQuery className posts query whereKey uuid equalTo Ncell uuidLbl text query findObjectsInBackground
  • 从远程 SQLite 数据库复制表?

    有没有办法将数据从一个远程 SQLite 数据库复制到另一个 我在两台服务器上完成了文件复制 但是 一些更改会记录在每个服务器本地的 SQLite 数据库中 为了使文件复制正常工作 我需要复制一个表的内容并将其输入到另一系统上的表中 我知道
  • 如何保护database.yml?

    在 Ruby on Rails 应用程序中 database yml 是一个存储数据库凭据的纯文本文件 当我部署 Rails 应用程序时 我的 Capistrano 中有一个部署后回调 在应用程序的 config 目录中创建到 databa
  • 如何在Ubuntu中生成核心转储文件[重复]

    这个问题在这里已经有答案了 我想知道如何在 Ubuntu 中生成核心转储文件 我使用的是 Ubuntu 8 04 1 和 gcc 编译器 4 2 3 我编写了一个简单的 C 程序来生成核心转储 我已经编译了该程序 如 gcc g badpo
  • 从 StructureMap 获取的 HttpContext 上的空用户

    好吧 我之前的问题 设置有太多变量 所以我将其精简为最基本的组件 给出使用 StructureMap3 的以下代码 IoC setup For
  • 回发或回调参数无效。为什么?

    所以我得到了例外 回发或回调参数无效 使用启用事件验证 在配置或 在 页 出于安全目的 这 功能验证参数 回发或回调事件发起 从服务器控制 最初渲染它们 如果数据 是有效且预期的 使用 ClientScriptManager Registe
  • libreoffice 大量文本颜色更改

    有没有办法更改 LibreOffice 或 Openoffice 中文本中所有出现的特定颜色 是 光标位于find box hit more options 在里面Search Replace对话 点击 Format select Font
  • 如何在Windows 7中设置Python路径[重复]

    这个问题在这里已经有答案了 我尝试在 Windows 7 中设置 python 的路径 但我不能这样做 我去 My Computer gt Properties gt Advanced gt Environment Variables 但我
  • 使用空格而不是制表符进行缩进的客观原因是什么?

    根据 PSR 2 标准使用空格而不是制表符来缩进文件是否有客观原因 有人可以提供 facts 参考 具体的专业知识 PSR 2 标准基于哪个 PSR 2 标准的作者考虑的不仅仅是 外观和感觉 不仅仅是基于意见的东西 而且很多人很难理解为什么
  • 将 Excel 导入 Rails 应用程序

    我正在创建一个供个人使用的小型 Rails 应用程序 并且希望能够上传 Excel 文件以便稍后进行验证并添加到数据库中 我之前曾对 csv 文件进行过此操作 但此后这已变得不切实际 有谁知道使用 roo 或电子表格 gem 上传文件 向用
  • 带颜色编码的 vb.net/C# 代码编辑器[关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 是否有任何带有颜色编码的 winforms 源代码编辑器控件 首选 开源 我好像记得以前遇到过类似的事情
  • PHP套接字服务器,检查客户端是否还活着

    我有一个 php 服务器正在监听 1 个 c 客户端 当连接建立后 它会一直保持活动状态 直到客户端发送 退出 命令来终止 PHP 服务器 但是 当 C 客户端在没有 退出 命令 即 单击 Windows 窗体中的关闭 x 按钮 的情况下断
  • 要包含或包含自动生成的依赖项?

    我喜欢用g MM自动构建我的依赖项的功能 我这样做的方法如下 include ALLOBJ o d d cxx echo making dependencies for lt g MM CXXFLAGS lt o sed i s o g 基
  • 分配时出现 JPEG 错误 #42

    为什么我不能直接将 MemoryStream 分配给图片 下面我发布了两种将 MemoryStream 分配给 TImage 的方法 方法 1 不起作用 方法 2 起作用 为什么 谢谢 山姆 方法 1 此方法返回 JPEG 错误 42 Va
  • jax-ws webservice 的端点始终是 localhost

    我真的需要你的帮助 我读到 jax ws web 服务的 wsdl 将为每个请求动态生成 这样 soap 端点等地址将被调整为请求 url 就我而言 无论是内部请求还是外部请求 地址始终引用 localhost 8080 某人知道我该如何处
  • C++ Linux 最快的时间测量方法(比 std::chrono 更快)?包含基准

    include