【问题标题】:Negligible difference in performance between RDSEED and RDRANDRDSEED 和 RDRAND 之间的性能差异可以忽略不计
【发布时间】:2017-07-26 19:56:09
【问题描述】:

最近的英特尔芯片(Ivy Bridge 及更高版本)具有生成(伪)随机位的指令。 RDSEED 输出从芯片上的传感器收集的熵生成的“真实”随机位。 RDRAND 输出由真随机数生成器种子从伪随机数生成器生成的位。根据Intel's documentationRDSEED 速度较慢,因为收集熵的成本很高。因此,RDRAND 作为一种更便宜的替代品提供,其输出对于大多数加密应用程序来说足够安全。 (这类似于 Unix 系统上的 /dev/random/dev/urandom。)

我很好奇这两条指令的性能差异,所以我写了一些代码来比较它们。令我惊讶的是,我发现在性能方面几乎没有区别。谁能提供解释?代码和系统详细信息如下。

基准测试

/* Compare the performance of RDSEED and RDRAND.
 *
 * Compute the CPU time used to fill a buffer with (pseudo) random bits 
 * using each instruction.
 *
 * Compile with: gcc -mdrnd -mdseed
 */
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <x86intrin.h>

#define BUFSIZE (1<<24)

int main() {

  unsigned int ok, i;
  unsigned long long *rand = malloc(BUFSIZE*sizeof(unsigned long long)), 
                     *seed = malloc(BUFSIZE*sizeof(unsigned long long)); 

  clock_t start, end, bm;

  // RDRAND (the benchmark)
  start = clock();
  for (i = 0; i < BUFSIZE; i++) {
    ok  = _rdrand64_step(&rand[i]);
  }
  bm = clock() - start;
  printf("RDRAND: %li\n", bm);

  // RDSEED
  start = clock();
  for (i = 0; i < BUFSIZE; i++) {
    ok = _rdseed64_step(&seed[i]);
  }
  end = clock();
  printf("RDSEED: %li, %.2lf\n", end - start, (double)(end-start)/bm);

  free(rand);
  free(seed);
  return 0;
}

系统详情

  • 英特尔酷睿 i7-6700 CPU @ 3.40GHz
  • Ubuntu 16.04
  • gcc 5.4.0

【问题讨论】:

    标签: gcc random cryptography x86-64


    【解决方案1】:

    您没有检查返回值,因此您没有生成多少实际随机数。重试,因为 Florian suggested RDSEED 版本慢了 3 倍以上:

    RDRAND: 1989817
    RDSEED: 6636792, 3.34 
    

    在幕后,硬件熵源可能仅以有限的速率生成,这会导致RDSEED 在以比熵再生速度更快的速率调用时失败。而RDRAND 只是基于周期性重新播种生成伪随机序列,因此不太可能失败。

    这里是修改后的代码摘录:

      // RDRAND (the benchmark)
      start = clock();
      for (i = 0; i < BUFSIZE; i++) {
        while (!_rdrand64_step(&rand[i]))
            ;
      }
      bm = clock() - start;
      printf("RDRAND: %li\n", bm);
    
      // RDSEED
      start = clock();
      for (i = 0; i < BUFSIZE; i++) {
        while (!_rdseed64_step(&seed[i]))
            ;
      }
      end = clock();
    

    【讨论】:

      【解决方案2】:

      对我来说,在 Core m7-6Y75 上,您的测试程序中的 RDSEED 偶尔会失败(我添加了两个 assert (ok);s,第二个偶尔会失败)。正确的代码会重试,从而导致有利于RDRAND 的性能差异。 (RDRAND 也需要重试,但在实践中似乎不会发生,所以RDRAND 更快。)

      【讨论】:

      • 有趣!我天真地假设_rdseed64_step() 会阻塞,直到有足够的熵可用。 (就像在熵可用之前从 /dev/random 块中读取一样。)谢谢!
      • @tweaksp 和 Florian:另见 What are the exhaustion characteristics of RDRAND on Ivy Bridge? David Johnston(英特尔 RNG 硬件设计师和 librdrand 作者)发布了一些有趣的东西。例如IvyBridge 中的实际实现永远不会下溢其缓冲区,但不能保证未来的 CPU 会这样。
      【解决方案3】:

      有趣 - 在我使用 3.6 GHz 10 核英特尔酷睿 i9(在 iMac 上)的情况下,使用上述程序(更正以在失败的情况下重复 RDRAND/RDSEED 调用)我观察到:

      $ ./rdseed-test 
      RDRAND: 1751837
      RDSEED: 1752472, 1.00
      

      更新

      我必须承认我很困惑 - 几天后尝试同样的可执行文件给了我 3 倍的差异,就像上面其他人报告的那样:

      $ ./rdseed-test 
      RDRAND: 1761312
      RDSEED: 5309609, 3.01
      

      不知道为什么有时 RDSEED 的运行速度与 RDRAND 一样快,而有时却慢了三倍。

      【讨论】:

      • 也许他们加强了硬件 RNG 和预处理逻辑,以便它可以再次完全跟上单个内核,因此您需要多个内核拉随机数来耗尽它。 i9是哪一代的? Ice Lake,还是 Skylake 衍生的 CPU?
      • @Peter,它已经快一岁了,所以一定是 Skylake 衍生产品。但是请参阅我的帖子的更新 - 现在我经常会获得 3 倍的性能差异。
      • 可能是 Comet Lake i9,然后像 i9-10910,因为它是唯一具有 10 核和 3.6GHz 非涡轮基础时钟的 Comet Lake。 en.wikipedia.org/wiki/… Ice Lake 已经推出一年多了,但只有移动版本,没有 i9 或 10 核。有 Tiger Lake i9 CPU,但没有 10 核。
      • IDK 为什么你会看到这样不同的结果,除非缓冲区与这个基准从中提取的熵量相比真的很大......
      • 不同芯片的RNG速度不同。通常,低功率 SoC 具有较慢的熵源(由较低的系统电压引起)。 10核I9更快。 RdRand 比 RdSeed 快,但在总线上没有拥塞,您可能会受到每个请求的往返时间的限制,因此看到相同的吞吐量,而在一组并行进程同时拉取时会看到差异。您可能正在使用操作系统或其他一些程序。在测试时序时,我们不会将其写入内存 - 我们将其与运行值异或以从结果中删除内存时序。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-21
      • 2012-05-26
      • 2013-09-02
      • 2014-03-15
      相关资源
      最近更新 更多