Advertisement
Guest User

Untitled

a guest
Oct 22nd, 2017
123
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.83 KB | None | 0 0
  1. /*
  2.  * This program compares performance of
  3.  * cpp random, c random and intel rdrand random generator functions.
  4.  *
  5.  * Compile with GCC or clang with -DNDEBUG -O2 -m64 -mrdrand
  6.  */
  7.  
  8. #include <stdlib.h>
  9. #include <random>
  10. #include <iostream>
  11. #include <immintrin.h>
  12. #include <thread>
  13. #include <cpuid.h>
  14. #include <x86intrin.h>
  15. #include <cinttypes>
  16.  
  17. /* Performance benchmark taken from here
  18.  * https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/ia-32-ia-64-benchmark-code-execution-paper.pdf
  19.  * page 17-18
  20.  */
  21.  
  22. #if defined(__unix__)
  23. #define USE_ASM_RDTSC
  24. #endif
  25.  
  26. static const uint64_t N_RUNS = 10000000;
  27.  
  28. #if defined(USE_ASM_RDTSC)
  29. struct perf_timer {
  30.         __attribute__((always_inline))
  31.         void sample_start() {
  32.                 asm volatile(
  33.                 "CPUID\n\t"
  34.                         "RDTSC\n\t"
  35.                         "mov %%edx, %0\n\t"
  36.                         "mov %%eax, %1\n\t": "=r" (high0), "=r" (low0)::
  37.                 "%rax", "%rbx", "%rcx", "%rdx");
  38.         }
  39.  
  40.         __attribute__((always_inline))
  41.         void sample_stop() {
  42.                 asm volatile(
  43.                 "RDTSCP\n\t"
  44.                         "mov %%edx, %0\n\t"
  45.                         "mov %%eax, %1\n\t"
  46.                         "CPUID\n\t": "=r" (high1), "=r"
  47.                 (low1)::"%rax", "%rbx", "%rcx", "%rdx");
  48.         }
  49.  
  50.         uint64_t cycles() const {
  51.                 unsigned int low  = low1 - low0;
  52.                 unsigned int high = high1 - high0;
  53.                 return (uint64_t) high << 32 | low;
  54.         }
  55.  
  56. private:
  57.         unsigned int low0, high0, low1, high1;
  58. };
  59. #else
  60. struct perf_timer {
  61.         __attribute__((always_inline))
  62.         void sample_start() {
  63.                 unsigned int a = 0, b = 0, c = 0, d = 0;
  64.                 __cpuid(0, a, b, c, d);
  65.                 start = __rdtsc();
  66.         }
  67.  
  68.         __attribute__((always_inline))
  69.         void sample_stop() {
  70.                 unsigned int a = 0, b = 0, c = 0, d = 0;
  71.  
  72.                 stop = __rdtscp(&a);
  73.  
  74.                 a = 0;
  75.                 __cpuid(0, a, b, c, d);
  76.         }
  77.  
  78.         uint64_t cycles() const {
  79.                 return stop - start;
  80.         }
  81.  
  82. private:
  83.         uint64_t start, stop;
  84. };
  85. #endif
  86.  
  87. void warup_cache()
  88. {
  89.         perf_timer tm;
  90.         tm.sample_start();
  91.         tm.sample_stop();
  92.         tm.sample_start();
  93.         tm.sample_stop();
  94.         tm.sample_start();
  95.         tm.sample_stop();
  96.         tm.sample_start();
  97.         tm.sample_stop();
  98. }
  99.  
  100. __attribute__((used))
  101. int rand_cpp(std::uniform_int_distribution<int>& dis, std::mt19937& gen)
  102. {
  103.         return dis(gen);
  104. }
  105.  
  106. __attribute__((noinline))
  107. void test_cpprand()
  108. {
  109.         std::random_device rd;
  110.         std::mt19937 gen(rd());
  111.         std::uniform_int_distribution<int> dis(0, INT32_MAX);
  112.  
  113.         perf_timer tm;
  114.  
  115.         warup_cache();
  116.  
  117.         tm.sample_start();
  118.         for (uint64_t n = 0; n < N_RUNS; ++n)
  119.                 rand_cpp(dis, gen);
  120.  
  121.  
  122.         tm.sample_stop();
  123.  
  124.         uint64_t cycles = tm.cycles();
  125.  
  126.         printf("C++ uniform distribution %" PRIu64 " runs\n"
  127.                "Total exec cycles: %" PRIu64 "\n"
  128.                "Avg cycles/run   : %" PRIu64 "\n",
  129.                N_RUNS,
  130.                cycles,
  131.                (cycles / N_RUNS));
  132.  
  133. }
  134.  
  135. __attribute__((used))
  136. int rand_rdrand_fair()
  137. {
  138.         unsigned int r;
  139.         while(!_rdrand32_step(&r));
  140.  
  141.         return r;
  142. }
  143.  
  144. __attribute__((used))
  145. int rand_rdrand_unfair()
  146. {
  147.         unsigned int r;
  148.         _rdrand32_step(&r);
  149.  
  150.         return r;
  151. }
  152.  
  153. __attribute__((noinline))
  154. void test_rdrand_fair()
  155. {
  156.         perf_timer tm;
  157.  
  158.         warup_cache();
  159.  
  160.         tm.sample_start();
  161.         for (uint64_t n = 0; n < N_RUNS; ++n)
  162.                 rand_rdrand_fair();
  163.  
  164.  
  165.         tm.sample_stop();
  166.  
  167.         uint64_t cycles = tm.cycles();
  168.  
  169.         printf("RDRAND fair rand %" PRIu64 " runs\n"
  170.                "Total exec cycles: %" PRIu64 "\n"
  171.                "Avg cycles/run   : %" PRIu64 "\n",
  172.                N_RUNS,
  173.                cycles,
  174.                (cycles / N_RUNS));
  175.  
  176. }
  177.  
  178. __attribute__((noinline))
  179. void test_rdrand_unfair()
  180. {
  181.         perf_timer tm;
  182.  
  183.         warup_cache();
  184.  
  185.         tm.sample_start();
  186.         for (uint64_t n = 0; n < N_RUNS; ++n)
  187.                 rand_rdrand_unfair();
  188.  
  189.  
  190.         tm.sample_stop();
  191.  
  192.         uint64_t cycles = tm.cycles();
  193.  
  194.         printf("RDRAND unfair rand %" PRIu64 " runs\n"
  195.                "Total exec cycles: %" PRIu64 "\n"
  196.                "Avg cycles/run   : %" PRIu64 "\n",
  197.                N_RUNS,
  198.                cycles,
  199.                (cycles / N_RUNS));
  200.  
  201. }
  202.  
  203. __attribute__((used))
  204. int rand_c()
  205. {
  206.         return rand();
  207. }
  208.  
  209. __attribute__((noinline))
  210. void test_crand()
  211. {
  212.         perf_timer tm;
  213.  
  214.         warup_cache();
  215.  
  216.         tm.sample_start();
  217.         for (uint64_t n = 0; n < N_RUNS; ++n)
  218.                 rand_c();
  219.  
  220.  
  221.         tm.sample_stop();
  222.  
  223.         uint64_t cycles = tm.cycles();
  224.  
  225.         printf("C rand %" PRIu64 " runs\n"
  226.                "Total exec cycles: %" PRIu64 "\n"
  227.                "Avg cycles/run   : %" PRIu64 "\n",
  228.                N_RUNS,
  229.                cycles,
  230.                (cycles / N_RUNS));
  231.  
  232. }
  233.  
  234. /* Should return number of clocks
  235.  * approximately equal to the CPU frequency.
  236.  */
  237. __attribute__((noinline))
  238. void trace_timer_resulution()
  239. {
  240.  
  241.         perf_timer tm;
  242.  
  243.         warup_cache();
  244.  
  245.         tm.sample_start();
  246.  
  247.         std::this_thread::sleep_for(std::chrono::seconds(1));
  248.  
  249.         tm.sample_stop();
  250.  
  251.         printf("[Trace timer]: Clocks per second %'" PRIu64 "\n", tm.cycles() );
  252. }
  253.  
  254. int main()
  255. {
  256.         // locale for thousands separator
  257.         setlocale(LC_ALL, "");
  258.  
  259.         trace_timer_resulution();
  260.  
  261.         test_cpprand();
  262.         test_crand();
  263.         test_rdrand_fair();
  264.         test_rdrand_unfair();
  265. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement