【问题标题】:Measuring cycles per byte for an algorithm测量算法的每字节周期
【发布时间】:2016-06-27 13:24:17
【问题描述】:

我已经在 C 中实现了在 http://primates.ae/ 中找到的 PRIMATE 密码的位切片实现。我使用 SIMD 编程实现了它,所以我在我的代码中使用了 AVX2 指令集。

我目前正在尝试准确衡量我的实施效果如何,但我并不真正相信当前的数字,我得到了。以我目前的数字,我每字节大约有 200 个周期,这似乎比密码得到的要好。

目前,我的代码如下所示

#typedef u64 unsigned long long

u64 start, finish;
u64 samples[1000000];
data = calloc(4000, sizeof(unsigned char));

//Performance test on a single core, as that is the standard when computing cycles/byte.
SetThreadAffinityMask(GetCurrentThread(), 0x00000008);

//Find CPU clock speed
start = _rdtsc();
sleep(1000);
finish = _rdtsc();
cpu_frequency = finish-start;

//Take a lot of samples and use median of these.
for (int i = 0; i < 1000000; i++){
   start = _rdtsc();
   encrypt(data);
   decrypt(data);
   finish = _rdtsc();
   samples[i] = finish - start;
}
qsort(samples);
u64 median = samples[500000];
double cycles_per_byte = 1 / (4000.00 / median);

我相信我的计算是正确的,所以我想知道......

  • 使用 _rdtsc() 测量每个字节的周期是否错误?
  • 可能是因为我没有测量专门用于我的代码的时钟周期,而是用于整个系统的时钟周期? (我不知道,如果我能看到在这种情况下我的代码独占了多少)
  • 我可以在 Windows 上运行它而不是例​​如在 Windows 上运行它吗? linux 有很大的不同吗?

我尝试使用 GCC 和 MSVC 编译代码,但没有区别(使用 /O2 或 /O3 时,GCC 的速度大约快 1%;不记得是哪个)。我只在一个内核上运行测试,并关闭了 Intel Turboboost 和超线程。

我的完整源代码在这里: https://github.com/opolo/Bitsliced-AEAD/tree/master/Primates/APE120_Bitsliced 我的测试套件在 Ref.c 中,而位切片排列在 Primate.c 中……代码现在不是很干净,我的错。这就是为什么我之前试图给出一个例子,而不是完全 c/p 我的代码。

【问题讨论】:

  • very easy 了解 _rdtsc 的措施。
  • 嗨。感谢你的回答。我不怀疑 _rdtsc 测量了什么。如果我读取 cpu_frequency 变量,我可以看到它的值与我的 CPU 时钟速度相匹配,所以它必须是循环计数。然而,与其他密码相比,我的周期/字节数确实很大,这一事实让我想知道,如果使用它是错误的。如果它可能在多核环境中出现问题,或者是因为我没有测量专门用于我的代码的 CPU 周期(以防其他人这样做..我无法找到其他的周期/字节代码测量) Windows API 调用(例如 _rdtsc())。
  • 进行快速的完整性检查很容易 - 使用您的密码处理大量数据 - 足够大,大约需要 10 秒的时间来处理。然后测量“挂钟”时间并除以数据中的字节数。这应该会给你一个数字,你可以依赖它作为在正确的球场 - 如果它与你的 _rdtsc 测量值有很大不同,那么你知道你做错了什么(反之亦然)。
  • 哦,现在我明白你的意思了。你知道你不只是测量你自己过程的周期,而是想知道这是否是大量数字的原因(对吗?)。对困惑感到抱歉。 (我会说确实是这个原因,但我对 Windows 的了解还不够,无法回答。)
  • sleep() 周围调用rdtsc 并不是在多处理器机器中找到时钟速度的明智方法。 sleep() 可能会导致程序被操作系统调度出去,你不知道它是否会被调度回同一个处理器(或处理器内核)。

标签: c++ c gcc benchmarking simd


【解决方案1】:

使用 _rdtsc() 测量每个字节的周期是错误的吗?

不,这是正确的做法。我更喜欢对rdtsc 指令使用内联汇编来保证内联。这是一个依赖于实现的函数,所以你并不真正知道发生了什么。特别是您不知道它是否正确地防止了乱序执行。见here for an inline asm solution。我不知道 x86 内部函数是做什么的。

原因可能是我没有测量专门用于我的代码的时钟周期,而是用于整个系统的时钟周期?

是的,函数调用有一些开销。在现代平台上通常有一个 O(100) 时钟滴答开销。如果您的数据集足够大,这并不重要。

我可以在 Windows 上运行它而不是例​​如在 Windows 上运行它吗? linux 有很大的不同吗?

没有


所以您没有从算法中获得您想要的性能?这一切都取决于你的实现方式,所以我不会责怪你的计时功能。完善算法实现有许多复杂性。如果您使用内联 asm 或内在函数显式矢量化了内容,请注意,与标准 C 和优化编译器相比,较差或过度抽象的实现可能会执行得更差。一个好的方法是首先编写算法的 C 实现作为基准和验证,然后开始手动优化。

加密/解密函数在哪里?

【讨论】:

  • 很晚的答案 - 抱歉。那几个月压力很大。长话短说,你的回答真的帮助了我,所以值得感谢:谢谢!!我的论文需要它,我最终得到了 A。可以说部分归功于答案。我最终使用 _rdtsc() 并按照您的建议使我的数据集足够大+多次执行相同的操作以使速度的微小差异可以忽略不计。效果很好!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-10-06
  • 2016-10-27
  • 1970-01-01
  • 1970-01-01
  • 2012-11-10
相关资源
最近更新 更多