Guest User

Untitled

a guest
Dec 9th, 2025
31
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.83 KB | Source Code | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <random>
  5. #include <chrono>
  6. #include <cstring>
  7. #include <iomanip>
  8. #include <array>
  9. #include <intrin.h>
  10.  
  11. using T = int;
  12. const int NUM_ELEMENTS = 32;
  13. const int NUM_TRIALS = 10;
  14. const int NUM_REPEATS = 10'000'000;
  15.  
  16. #if defined(__INTEL_COMPILER) || defined(__INTEL_LLVM_COMPILER)
  17. #define COMPILER_INTEL
  18. #elif defined(__clang__)
  19. #define COMPILER_CLANG
  20. #elif defined(_MSC_VER)
  21. #define COMPILER_MSVC
  22. #elif defined(__GNUC__)
  23. #define COMPILER_GCC
  24. #endif
  25.  
  26. #if defined(COMPILER_GCC) || defined(COMPILER_CLANG)
  27. #define ALWAYS_INLINE inline __attribute__((__always_inline__))
  28. #else
  29. #define ALWAYS_INLINE __forceinline
  30. #endif
  31.  
  32. class CpuTimer {
  33.  
  34. #if defined(COMPILER_MSVC)
  35.     unsigned int dummyTscAuxMsvc;
  36.     uint64_t startCyclesMsvc = 0;
  37.     uint64_t endCyclesMsvc = 0;
  38. #else
  39.     uint32_t startCyclesLow = 0;
  40.     uint32_t startCyclesHigh = 0;
  41.     uint32_t endCyclesLow = 0;
  42.     uint32_t endCyclesHigh = 0;
  43. #endif
  44.  
  45. public:
  46.     uint64_t minMeasurementOverhead = 0;
  47.     uint64_t medianMeasurementOverhead = 0;
  48.  
  49.     CpuTimer() {
  50.         calculateMeasurementOverhead();
  51.     }
  52.  
  53.     ALWAYS_INLINE void start() {
  54.     #if defined(COMPILER_MSVC)
  55.         startCyclesMsvc = __rdtsc();
  56.     #else
  57.         asm volatile (
  58.             "CPUID\n\t"
  59.             "RDTSC\n\t"
  60.             "mov %%edx, %0\n\t"
  61.             "mov %%eax, %1\n\t"
  62.             : "=r" (startCyclesHigh), "=r" (startCyclesLow)
  63.             :: "%rax", "%rbx", "%rcx", "%rdx"
  64.         );
  65.     #endif
  66.     }
  67.     ALWAYS_INLINE void end() {
  68.     #if defined(COMPILER_MSVC)
  69.         endCyclesMsvc = __rdtscp(&dummyTscAuxMsvc);
  70.     #else
  71.         asm volatile (
  72.             "RDTSCP\n\t"
  73.             "mov %%edx, %0\n\t"
  74.             "mov %%eax, %1\n\t"
  75.             "CPUID\n\t"
  76.             : "=r" (endCyclesHigh), "=r" (endCyclesLow)
  77.             :: "%rax", "%rbx", "%rcx", "%rdx"
  78.         );
  79.     #endif
  80.     }
  81.     uint64_t getTime() {
  82.     #if defined(COMPILER_MSVC)
  83.         auto start = startCyclesMsvc;
  84.         auto end = endCyclesMsvc;
  85.     #else
  86.         auto start = ((uint64_t(startCyclesHigh) << 32) | startCyclesLow);
  87.         auto end = ((uint64_t(endCyclesHigh) << 32) | endCyclesLow);
  88.     #endif
  89.         return end - start - minMeasurementOverhead;
  90.     }
  91.     void calculateMeasurementOverhead(int64_t sampleCount = 1'000'000) {
  92.         std::vector<uint64_t> times;
  93.         for (int j = 0; j < sampleCount; ++j) {
  94.             start();
  95.             end();
  96.             times.push_back(getTime());
  97.         }
  98.         std::sort(times.begin(), times.end());
  99.         minMeasurementOverhead = times.front();
  100.         medianMeasurementOverhead = times[times.size() / 2];
  101.     }
  102. };
  103.  
  104. template<typename Function, typename T> int runBenchmark(CpuTimer& timer, Function testedFunction, const std::vector<T>& data, bool checkIfCorrectOutput) {
  105.     std::vector<int> executionTimes;
  106.     for (int i = 1; i <= NUM_REPEATS; ++i) {
  107.         auto copiedData = data;
  108.         timer.start();
  109.         testedFunction(copiedData, 0, NUM_ELEMENTS - 1);
  110.         timer.end();
  111.         executionTimes.push_back(timer.getTime());
  112.  
  113.         if (checkIfCorrectOutput) {
  114.             bool sorted = true;
  115.             for (size_t i = 0; i < copiedData.size() - 1; ++i) {
  116.                 if (copiedData[i] > copiedData[i + 1]) {
  117.                     sorted = false;
  118.                     break;
  119.                 }
  120.             }
  121.             if (!sorted) {
  122.                 std::cerr << "Error: Array not sorted on trial 1!" << std::endl;
  123.             }
  124.         }
  125.     }
  126.     std::sort(executionTimes.begin(), executionTimes.end());
  127.     return executionTimes.front();
  128. }
  129.  
  130.  
  131. /**
  132.  * Applies the specific rule requested for subarrays of size 3.
  133.  */
  134. void apply_three_element_rule(std::vector<T>& arr, int low, int high) {
  135.     // The check for size 3 (high - low == 2) is assumed to pass
  136.     // because the calling loop ensures it.
  137.  
  138.     T pivot = arr[low];
  139.     T third_num = arr[high];
  140.  
  141.     if (third_num <= pivot) {
  142.         // Swap all 3 to make pivot middle, third_num first
  143.         T temp_mid = arr[low + 1];
  144.  
  145.         arr[high] = temp_mid;
  146.         arr[low + 1] = pivot;
  147.         arr[low] = third_num;
  148.     } else {
  149.         // Swap all 3 to make pivot middle, third_num last
  150.         T temp_mid = arr[low + 1];
  151.  
  152.         arr[low] = temp_mid;
  153.         arr[low + 1] = pivot;
  154.         arr[high] = third_num;
  155.     }
  156. }
  157. void insertionSortMonty(std::vector<T>& arr, int low, int high) {
  158.     if (NUM_ELEMENTS >= 3) {
  159.         for (int i = 0; i <= NUM_ELEMENTS - 3; i += 3) {
  160.             apply_three_element_rule(arr, i, i + 2);
  161.         }
  162.     }
  163.  
  164.     for (int i = low + 1; i <= high; ++i) {
  165.         int key = arr[i];
  166.         int j = i - 1;
  167.  
  168.         while (j >= low && arr[j] > key) {
  169.             arr[j + 1] = arr[j];
  170.             j = j - 1;
  171.         }
  172.         arr[j + 1] = key;
  173.     }
  174. }
  175.  
  176. void insertionSort(std::vector<T>& arr, int low, int high) {
  177.     for (int i = low + 1; i <= high; ++i) {
  178.         int key = arr[i];
  179.         int j = i - 1;
  180.  
  181.         while (j >= low && arr[j] > key) {
  182.             arr[j + 1] = arr[j];
  183.             j = j - 1;
  184.         }
  185.         arr[j + 1] = key;
  186.     }
  187. }
  188.  
  189. int main() {
  190.     CpuTimer timer;
  191.  
  192.     std::cout << "Elements per array  : " << NUM_ELEMENTS << std::endl;
  193.     std::cout << "Total Trials        : " << NUM_TRIALS << std::endl;
  194.     std::cout << "Repeats per Trial   : " << NUM_REPEATS << std::endl;
  195.     std::cout << "minTimerOverhead    : " << timer.minMeasurementOverhead << std::endl;
  196.     std::cout << "medianTimerOverhead : " << timer.medianMeasurementOverhead << std::endl;
  197.  
  198.     std::mt19937 gen(0x1234567);
  199.     std::uniform_int_distribution<> distrib(1, 10000000);
  200.  
  201.     std::vector<T> data(NUM_ELEMENTS);
  202.  
  203.     std::cout << std::left;
  204.     std::cout << std::setw(10) << "Trial nr" << " | "
  205.         << std::setw(20) << "Normal [cycles]" << " | "
  206.         << std::setw(20) << "Monty [cycles]" << "\n";
  207.    
  208.     int sumOfMinTimesNormal = 0;
  209.     int sumOfMinTimesMonty = 0;
  210.  
  211.     for (int t = 1; t <= NUM_TRIALS; ++t) {
  212.         for (int i = 0; i < NUM_ELEMENTS; ++i) {
  213.             data[i] = distrib(gen);
  214.         }
  215.  
  216.         int minTimeNormal = runBenchmark(timer, insertionSort, data, true);
  217.         int minTimeMonty = runBenchmark(timer, insertionSortMonty, data, true);
  218.         std::cout << std::setw(10) << t << " | "
  219.             << std::setw(20) << minTimeNormal << " | "
  220.             << std::setw(20) << minTimeMonty << "\n";
  221.         sumOfMinTimesNormal += minTimeNormal;
  222.         sumOfMinTimesMonty += minTimeMonty;
  223.     }
  224.  
  225.     std::cout << std::setw(10) << "Total" << " | "
  226.         << std::setw(20) << sumOfMinTimesNormal << " | "
  227.         << std::setw(20) << sumOfMinTimesMonty << "\n";
  228.  
  229.     std::cout << std::setw(30) << "Monty / Normal " << " = " << double(sumOfMinTimesMonty) / sumOfMinTimesNormal << '\n';
  230. }
Advertisement
Add Comment
Please, Sign In to add comment