当前位置: 首页 > news >正文

全面获取TSC频率:提升性能分析与基准测试精度

TSC Frequency For All: Better Profiling and Benchmarking

Artem Dinaburg
October 03, 2019
containers, linux, research-practice

你是否曾尝试使用LLVM的X-Ray性能分析工具生成火焰图,却遇到如下晦涩错误?

==65892==Unable to determine CPU frequency for TSC accounting.
==65892==Unable to determine CPU frequency.

更糟糕的是,是否曾遇到分析应用程序中所有函数运行时,发现20分钟的运行时长中函数运行时间总和仅约15分钟?那丢失的5分钟去哪了?

我们遇到过这两种情况,因此开发了名为tsc_freq_khz的Linux内核模块作为解决方案。我们将快速但深入地探讨x86计时器来解释这个问题,但首先让我们了解核心方案。

核心方案

tsc_freq_khz模块增强了虚拟化环境中性能分析和基准测试工具(如X-Ray)的性能。不再出现“无法确定CPU频率”错误!该模块还提高了这些工具在新款Intel处理器上的准确性。

X-Ray使用x86时间戳计数器(TSC)——一种低延迟单调递增时钟——来测量事件持续时间,并假设TSC频率等同于最大时钟速度。这个假设在新款CPU上是错误的,会导致时间测量不准确。tsc_freq_khz模块提供了读取实际TSC频率的方法。分析数据中不再丢失分钟数!

该模块通过sysfs将Linux内核内部x86时间戳计数器频率值tsc_khz导出到用户空间。程序可以通过读取/sys/devices/system/cpu/cpu0/tsc_freq_khz来查询该值。

多个开源项目(如X-Ray和Abseil)已支持检查tsc_freq_khz的存在,但此前该文件仅存在于Google的生产内核中。tsc_freq_khz模块为所有用户启用了TSC频率导出功能。

时间戳的问题

在解释我们的工作和方案原理前,先快速介绍x86架构上的时间戳测量。

x86机器至少有六种不同的时间测量方式:

  • 实时时钟(RTC)
  • 可编程间隔定时器(PIT)
  • 高性能事件定时器(HPET)
  • ACPI电源管理定时器(ACPI PM)
  • 高级可编程中断控制器(APIC)定时器
  • 时间戳计数器(TSC)

每种方法都有独特且微妙的缺陷,使其在某些应用中完全不可用。这种计时器的丰富性是维护30年向后兼容性且从不删除功能的后果——因为总有人依赖它。

尽管存在诸多缺陷,TSC对于基准测试和分析非常有用。它具有极低的延迟,因为电路直接位于CPU上,并且可直接从用户模式应用程序访问。像X-Ray这样非常有用的性能分析工具依赖TSC进行精确测量。

然而,TSC以滴答数测量时间,这些滴答在不同处理器之间不可比较,因此基本上没有意义。对于性能分析和基准测试,我们需要以可比较的单位(如纳秒)测量时间。

从滴答到纳秒

那么一个滴答有多少纳秒?将滴答持续时间转换为纳秒的基本公式很简单:

time_in_nanoseconds = (tsc_count_end - tsc_count_start) * tsc_frequency

不幸的是,确定TSC频率很困难,在某些情况下(例如基于云或其他虚拟化环境)甚至不可能。直到现在。

核心问题是Linux内核没有提供应用程序了解TSC频率的方法,尽管Linux perf实用程序确实尝试通过Intel PT计算TSC频率。不直接暴露该值有合理理由,因为TSC频率相当晦涩,并且在某些情况下该值完全无意义。直到最近,处理器的最大时钟速度也是TSC频率的准确近似值。

然而,这不再成立。使用最大时钟速度作为TSC频率会在新款Intel CPU上给出错误结果。这是性能分析中丢失分钟数的原因。

此外,在基于云或其他虚拟化环境中无法通过/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq访问最大时钟速度。这是“无法确定CPU频率”错误的原因。

cpuinfo_max_freq由用于频率调节的cpufreq驱动程序填充——即根据节能设置使CPU运行更快或更慢。自然,虚拟化环境中通常不允许频率调节,因为每个物理CPU与多个虚拟租户共享。因此,该值不存在。

Google的提示

X-Ray中的时间戳测量代码引用了一个神秘的sysfs条目/sys/devices/system/cpu/cpu0/tsc_freq_khz,这听起来正好提供了我们需要的:以千赫兹为单位的TSC频率。不幸的是,Linux内核源代码中完全没有对该文件的引用。这是怎么回事?

更多搜索在Abseil源代码中揭示了以下提示:

// Google's production kernel has a patch to export the TSC
// frequency through sysfs. If the kernel is exporting the TSC// cannot be relied on because the BIOS may be exporting an invalid
// p-state (on x86) or p-states may be used to put the processor in
// a new mode (turbo mode). Essentially, those frequencies cannot
// always be relied upon. The same reasons apply to /proc/cpuinfo as
// well.
if (ReadLongFromFile("/sys/devices/system/cpu/cpu0/tsc_freq_khz", &freq)) {return freq * 1e3;  // Value is kHz.
}

中奖了!注释告诉我们:

  • Google在生产环境中运行自定义Linux内核
  • Google知道cpuinfo_max_freq不应用于基准测试
  • 内核的TSC频率计算是合理的
  • Google的内部内核有一个通过sysfs导出TSC频率的补丁,但该补丁尚未上游化到主内核树

全民TSC频率!

为什么只有Google内核可以访问TSC频率?由于Linux内核是开源的,我们可以编写自己的内核模块来做同样的事情。幸运的是,Linux内核在启动期间已经计算了TSC频率并将其存储在tsc_khz变量中。我们所要做的就是通过sysfs导出该变量。

我们的内核模块tsc_freq_khz正是这样做的。它创建了一个sysfs条目,读取内核定义的tsc_khz变量,并通过/sys/devices/system/cpu/cpu0/tsc_freq_khz导出。该模块极其简单但非常有用。

按照Github上的构建说明,通过将模块插入内核来测试:

$ sudo insmod ./tsc_freq_khz.ko
$ dmesg | grep tsc_freq_khz
[14045.345025] tsc_freq_khz: starting driver
[14045.345026] tsc_freq_khz: registering with sysfs
[14045.345028] tsc_freq_khz: successfully registered

现在应填充/sys/devices/system/cpu/cpu0/tsc_freq_khz文件。(您系统上的值会不同。)

$ cat /sys/devices/system/cpu/cpu0/tsc_freq_khz
2712020

警告:请不要在真实生产系统中使用此代码。虽然它不应该引起问题,但它确实做了一些假设,例如CPU0存在。也没有健全性检查来警告TSC值是否不合理或不可靠。

结论

像这样看似简单的问题可能让我们深入一个迷人的兔子洞。随着时间的推移,Google的内部补丁可能会进入Linux内核,或者内核开发人员可能会创建自己的官方补丁来将TSC频率导出到用户空间。同时,对于希望使用LLVM优秀的X-Ray性能分析工具进行精确测量的用户,tsc_freq_khz可以作为一个临时解决方案。

喜欢阅读这篇文章吗?我们在有趣的问题和具有挑战性的难题上茁壮成长。我们很乐意与您合作解决您的安全或软件工程挑战——请联系我们。

分享此文章
Twitter | LinkedIn | GitHub | Mastodon | Hacker News


页面内容导航

  • 时间戳的问题
  • 从滴答到纳秒
  • Google的提示
  • 全民TSC频率!
  • 结论

近期文章

  • 使用Deptective调查您的依赖项
  • 做好准备,Buttercup,AIxCC评分轮正在进行中!
  • 使您的智能合约超越私钥风险
  • Go解析器中意外的安全隐患
  • 我们审查首批DKLs23库的收获

©️ 2025 Trail of Bits.
使用Hugo和Mainroad主题生成。
更多精彩内容 请关注我的个人公众号 公众号(办公AI智能小助手)
公众号二维码

http://www.wxhsa.cn/company.asp?id=486

相关文章:

  • 【rdma】RoCE、IB和TCP等网络的基本知识及差异对比
  • WindTerm_2.7.0
  • VMWare Esxi防火墙添加白名单访问及ip异常无法登录解决办法
  • 鸿蒙,下一个iPhone时刻?
  • dw
  • 5%付费率背后,鸿蒙成独立开发者的“商业理想国”
  • HarmonyOS编写教师节贺卡
  • 3天赚2万!开发者的梦想也可以掷地有声!
  • 【IoTDB 线上小课 19】开源时序数据库 Apache IoTDB,四大优势解决企业选型难题!
  • java课前问题思考
  • nano快捷键指南
  • 个人开发者从0到1(BeeCount:一款开源的跨平台个人记账应用)
  • 网络通信中的死锁
  • 学生开发者经验|豆包大模型 + TRAE,让 AI 应用快速落地
  • java课前问题
  • CSP-S模拟19
  • union类型
  • PDE,广义特征问题,和神经特征函数法
  • 查看mysql具体使用那个glibc的版本的mysql
  • 【A】月半猫想吃麦当劳(待完坑)
  • 【A】宝宝肚肚打雷了(待完坑)
  • 01_TCP协议概念
  • 【A】杂题宣讲
  • 登录认证-上篇:基于 Session 的传统身份验证
  • 【A】chipi chipi chapa chapa
  • vLLM框架本地布署Qwen3-32B模型 - yi
  • 项目管理软件中有哪些不同的模块以及如何导出其报告?
  • 第十三届 TCCT 随机系统与控制专题研讨会 暨2025年智能控制与计算科学国际学术会议 (ICICCS 2025)
  • Kubernetes命名空间(Namespace)
  • linux安装python