6IT Hare分类资讯
6IT Hare涵盖多种分类内容,包括书籍、系统架构、编程、硬件、安全、开发、其他、IT Hare学校以及关于Hare的杂谈等。在书籍分类中,有“MOGs的龙与地下城”相关,包含目录、第一至三卷、第四至六卷、第七至九卷的首次测试版;系统架构分类涉及需求分析、设计决策、分布式系统、(Re)Actors等;编程分类包含技巧与窍门、网络编程、编程语言、优化、调试、嵌入式等;硬件分类有MCU、Wi - Fi;安全分类包括最佳实践、欺诈预防、研究;开发分类包含开发理念、开发流程、团队结构、IT职业与IT招聘;其他分类有公告、报告;IT Hare学校分类有面向恐龙的IT Hare学校、外行写给外行;关于Hare的杂谈分类有Hare背后的真实人物、为我们撰稿、H.A.R.E.与兔子传说。
论CPU物理原理与CPU周期
2026年6月10日,“无Bug”兔子撰写了即将出版的《现代64位CPU的高效C++编程》第一卷第四章“论CPU物理原理与CPU周期”第一部分的草稿,翻译为Sherry Ignatchenko。
CPU核心相关
从一个“典型”主板示意图展开,上面有“典型”的CPU芯片及核心。电信号传输物理距离越远,访问速度越慢,电子信号特征时间受寄生电容限制,寄生电容通常与连接长度成正比。对于CPU核心,距离和速度的关系体现于此。
编写`a += b;`这样的代码是寄存器 - 寄存器(R - R)操作,64位CPU是流水线式的,多数情况可避免从寄存器到ALU再返回的延迟。简单操作如加法/减法和位运算需1个CPU周期,乘法约3 - 6个周期,除法最多20个周期,相比过去除法时间有显著改善。
L1缓存分为L1数据缓存(L1D)和L1指令缓存(L1I),ALU通常不止一个,CPU是超标量的,能同时处理多个ALU级操作,可能导致微基准测试中操作周期数非整数。现代超标量CPU每周期退休指令数(RIPC)最高可达10 - 12,但实际应用中达4有挑战,且通常限于ALU密集型算法。
访问CPU寄存器外信息需访问内存,先访问L1D缓存,读取需3个CPU周期,写入“几乎是即时的”。L1D缓存未命中,访问L2缓存需10 - 15个周期。
分支预测错误与`[[likely]]`/`[[unlikely]]`
CPU核心“指令”部分大多经完美优化,除非分支操作。现代CPU遇到分支指令会推测结果并继续执行,若结果不符,会丢弃基于猜测的内容并重新处理,分支预测错误代价约15 - 25个周期。开发者可影响分支选择可能性,从而影响分支预测错误数量。指令层面有启发式规则,C++中可通过`[[likely]]`/`[[unlikely]]`属性影响,但现代CPU使用“动态分支预测”,这些属性效率并非很高,不建议使用,除非有至少200%把握确定分支极不可能发生。
关于TLB
TLB分为用于指令的ITLB和用于数据的DTLB,主要功能是将虚拟地址转换为物理地址,是一种缓存,位于L1之上。TLB未命中代价理论上可能高,但实践中在应用层面未遇到问题。使用线性数据结构可减少DTLB压力,对于主要依赖向量的优化型C++程序,DTLB未命中影响较小。在使用大量RAM的应用程序中,DTLB未命中可能成问题,在虚拟化环境中,TLB成本会增加,可通过切换到“大页”解决。ITLB未命中通常适用于大应用程序,也可用大页解决。
芯片层面
芯片层面,每个核心旁有L3缓存,读取需30 - 70个CPU周期。离开芯片成本高,因为寄生电容难以控制且会急剧增加。虽然理论上带有片上RAM的SoC可能改善主RAM延迟,但实际上受标准化接口和功率限制,x64桌面电脑和M4苹果SoC的主内存访问延迟大致在200 - 300个CPU周期左右。
主板层面
主板层面,从主RAM读取数据需200 - 300个CPU周期,比从L1读取慢约100倍。持久存储设备速度更慢,NVMe SSD读取至少需30000 - 45000个CPU周期,SATA SSD需240000 - 300000个CPU周期,传统HDD需30000000 - 45000000个CPU周期。`fsync()`延迟方面,配备电池备份缓存的企业级RAID控制器约120000个CPU周期,企业级NVMe SSD为450000个周期,消费级SATA SSD为1500000 - 30000000个周期,HDD为50000000 - 200000000个周期。
从C/C++角度看内存存储方式
栈上存储对应C++标准中的“自动存储期”,是常见的局部函数变量和函数参数,栈内存按常规缓存规则缓存,活跃部分几乎保证被缓存,栈特定于当前线程且大小有限。
静态变量包括全局变量、静态变量、函数级静态变量和静态数据成员,地址编译时基本已知,通常映射到程序可执行文件的`.bss`和`.data`段,静态变量在无构造函数初始化时,会在程序第一行代码执行前获初始值,静态/全局变量缓存较好,但不如栈。
堆上数据通过`malloc()`或`new`分配,堆大小可任意大,但增长会导致过度分页,系统变慢,堆数据视为未缓存,除非知道最近访问过附近内容,对线性内存数据结构“线性扫描”时可依赖缓存。
线程局部变量由`thread_local`关键字指示,每个线程有自己的TLS,TLS是线程特定指针指向已分配内存。
外部世界的速度
超出计算机/手机范围,速度更慢。1Gbit有线局域网访问时间约100000 - 500000个CPU周期,本地Wi - Fi为3000000 - 30000000个周期,通过光纤连接到ISP需额外15000000 - 80000000个周期,电缆和DSL为60000000 - 150000000个周期,4G LTE/5G为100000000 - 200000000个周期。从多伦多到蒙特利尔往返需约24000000个周期,到都柏林需255000000个周期,到珀斯需745000000个CPU周期。多伦多家中通过Wi - Fi连接到本地路由器,再通过DSL连接到ISP的手机访问蒙特利尔服务器,预计总时间在100000000 - 200000000个CPU周期之间,网络时间“最佳”和“最坏”情况差异大,对网络故障进行FMEA超出本书范围。
参考文献
涉及[Fog]、[Fog04]、[Drepper]、[Bakhvalov]、[JiaEtAl]、[Trudeau]、[Ketron]、[Roy]、[Josuttis]、[Cordes]等参考文献。
评论
可发表评论,需填写评论、姓名、电子邮件,网站可选填,下次评论时可保存信息。本网站使用Akismet减少垃圾评论。