我正在为 C 和 x64 程序集中的二进制搜索开发低级例程,并尝试测量搜索未缓存数组(RAM 中的数据)的确切执行时间。根据分支预测的“幸运”程度,在同一个数组中搜索不同目标所需的时间差异很大。我可以准确地测量最小和中值执行时间,但我发现很难测量最大执行时间。
问题是分支预测的最坏情况在时间上与平均情况加上处理器中断相当。最坏的情况和中断都是罕见的,但我还没有想出一个好的方法来区分一个罕见的事件和另一个。标准方法只是过滤掉所有“异常”的高测量值,但这只有在两者之间有明确的界限时才有效。
所以问题变成了,“我如何区分被中断的测量和合法地比其他测量花费更长的时间? ”
或者更一般地说,“如何在不预先假设硬最大值的情况下测量执行时间的完整分布? ”
内核是否存储任何我可以查询的关于是否发生中断的信息?我可以在测量之前和之后查询的东西会告诉我测量是否被中断?理想情况下,它会告诉我中断需要多长时间,但只要知道测量受到影响将是一个很好的开始。
也许除了(或代替)RDTSC,我可以使用 RDPMC 读取一个计数器,该计数器测量在 Ring 0(内核)而不是 Ring 3(用户)中花费的周期数?是否可能已经设置了一个计数器来执行此操作,还是我需要自己设置?我需要创建自己的内核模块来执行此操作,还是可以使用现有的 ioctls?
一些背景:
我主要在 Intel Skylake i7-6700 上运行 Ubuntu 14.03 Linux 4.2.0,但也在 Intel Sandy Bridge 和 Haswell 上进行测试。我已经尽我所能尽可能地减少系统上的抖动。我用CONFIG_NOHZ_FULL重新编译了一个无滴答内核,没有强制抢占,透明的大页面支持关闭,定时器频率为 100 Hz。
我已经停止了大多数不必要的进程,并删除了大多数不必要的内核模块。我正在使用cpuset / cset shield为单个进程保留一个 NoHZ 内核,并使用内核/调试/跟踪来验证我收到的中断很少。但我仍然得到足够的精确测量是困难的。也许更重要的是,我可以设想未来的长尾情况(一个很少需要调整大小的哈希表),能够区分有效和无效的测量值将非常有帮助
我正在使用英特尔在其白皮书中建议的技术测量 RDTSC/RDTSCP 的执行时间,并且通常获得我期望的准确性。我的测试涉及搜索 16 位值,并且我重复和单独地对不同长度的随机数组的 65536 个可能搜索中的每一个进行计时。为了防止处理器学习正确的分支预测,每次都以不同的顺序重复搜索。每次使用“CLFLUSH”搜索后,搜索的数组都会从缓存中删除。
这是一个研究项目,我的目标是了解这些问题。因此,我愿意采用可能被认为是愚蠢和极端的方法。自定义内核模块、保护模式 x64 程序集、未经测试的内核修改和处理器特定功能都是公平的游戏。如果有办法摆脱少数剩余的中断,以便所有测量都是“真实的”,那也可能是一个可行的解决方案。感谢您的建议!