Interstellar12312

Modified AVX2 Quicksort with three element rule versus Standard AVX2 Quicksort

Jul 17th, 2026
54
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.82 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>
  4. #include <random>
  5. #include <chrono>
  6. #include <immintrin.h> // Required for AVX2 Intrinsics
  7.  
  8. // Modified AVX2 Quicksort with three element rule versus Standard AVX2 Quicksort
  9. // Contact Email [email protected]
  10. // Created by I.A
  11.  
  12. const int NUM_ELEMENTS = 100000;
  13. const int NUM_TRIALS = 10000;
  14.  
  15. // ---------------------------------------------------------
  16. // 1. Core AVX2 Partition Logic
  17. // ---------------------------------------------------------
  18. int avx2_partition(std::vector<int>& arr, int low, int high) {
  19.     int pivot_val = arr[low];
  20.     __m256i pivot = _mm256_set1_epi32(pivot_val);
  21.     int size = high - low;
  22.  
  23.     alignas(32) std::vector<int> left_buf(size);
  24.     alignas(32) std::vector<int> right_buf(size);
  25.  
  26.     int left_count = 0;
  27.     int right_count = 0;
  28.  
  29.     int i = low + 1;
  30.     for (; i <= high - 7; i += 8) {
  31.         __m256i data = _mm256_loadu_si256((__m256i*)&arr[i]);
  32.         __m256i cmp = _mm256_cmpgt_epi32(data, pivot);
  33.  
  34.         alignas(32) int data_extracted[8];
  35.         alignas(32) int mask_extracted[8];
  36.         _mm256_storeu_si256((__m256i*)data_extracted, data);
  37.         _mm256_storeu_si256((__m256i*)mask_extracted, cmp);
  38.  
  39.         for (int k = 0; k < 8; ++k) {
  40.             if (mask_extracted[k] == 0) {
  41.                 left_buf[left_count++] = data_extracted[k];
  42.             } else {
  43.                 right_buf[right_count++] = data_extracted[k];
  44.             }
  45.         }
  46.     }
  47.  
  48.     // Scalar fallback for remaining elements
  49.     for (; i <= high; ++i) {
  50.         if (arr[i] <= pivot_val) {
  51.             left_buf[left_count++] = arr[i];
  52.         } else {
  53.             right_buf[right_count++] = arr[i];
  54.         }
  55.     }
  56.  
  57.     std::copy(left_buf.begin(), left_buf.begin() + left_count, arr.begin() + low);
  58.  
  59.     int pivot_idx = low + left_count;
  60.     arr[pivot_idx] = pivot_val;
  61.  
  62.     std::copy(right_buf.begin(), right_buf.begin() + right_count, arr.begin() + pivot_idx + 1);
  63.  
  64.     return pivot_idx;
  65. }
  66.  
  67. // ---------------------------------------------------------
  68. // 2. Modified AVX2 Quicksort (With Three-Element Rule)
  69. // ---------------------------------------------------------
  70. void apply_three_element_rule(std::vector<int>& arr, int low, int high) {
  71.     if (high - low == 2) {
  72.         int pivot = arr[low];
  73.         int third_num = arr[high];
  74.  
  75.         if (third_num <= pivot) {
  76.             int temp_mid = arr[low + 1];
  77.             arr[high] = temp_mid;
  78.             arr[low + 1] = pivot;
  79.             arr[low] = third_num;
  80.         } else {
  81.             int temp_mid = arr[low + 1];
  82.             arr[low] = temp_mid;
  83.             arr[low + 1] = pivot;
  84.             arr[high] = third_num;
  85.         }
  86.     }
  87. }
  88.  
  89. void quickSortModified(std::vector<int>& arr, int low, int high) {
  90.     if (low < high) {
  91.         if (high - low == 2) {
  92.             apply_three_element_rule(arr, low, high);
  93.         }
  94.  
  95.         int p;
  96.         if (high - low >= 16) {
  97.             p = avx2_partition(arr, low, high);
  98.             quickSortModified(arr, low, p - 1);
  99.             quickSortModified(arr, p + 1, high);
  100.         } else {
  101.             int pivot = arr[low];
  102.             int i = low - 1;
  103.             int j = high + 1;
  104.             while (true) {
  105.                 do { i++; } while (arr[i] < pivot);
  106.                 do { j--; } while (arr[j] > pivot);
  107.                 if (i >= j) {
  108.                     p = j;
  109.                     break;
  110.                 }
  111.                 std::swap(arr[i], arr[j]);
  112.             }
  113.             quickSortModified(arr, low, p);
  114.             quickSortModified(arr, p + 1, high);
  115.         }
  116.     }
  117. }
  118.  
  119. // ---------------------------------------------------------
  120. // 3. Standard AVX2 Quicksort (Without Modifications)
  121. // ---------------------------------------------------------
  122. void quickSortStandard(std::vector<int>& arr, int low, int high) {
  123.     if (low < high) {
  124.         int p;
  125.         if (high - low >= 16) {
  126.             p = avx2_partition(arr, low, high);
  127.             quickSortStandard(arr, low, p - 1);
  128.             quickSortStandard(arr, p + 1, high);
  129.         } else {
  130.             int pivot = arr[low];
  131.             int i = low - 1;
  132.             int j = high + 1;
  133.             while (true) {
  134.                 do { i++; } while (arr[i] < pivot);
  135.                 do { j--; } while (arr[j] > pivot);
  136.                 if (i >= j) {
  137.                     p = j;
  138.                     break;
  139.                 }
  140.                 std::swap(arr[i], arr[j]);
  141.             }
  142.             quickSortStandard(arr, low, p);
  143.             quickSortStandard(arr, p + 1, high);
  144.         }
  145.     }
  146. }
  147.  
  148.  
  149. // ---------------------------------------------------------
  150. // 4. Benchmark Runner
  151. // ---------------------------------------------------------
  152. int main() {
  153.     std::cout << "Starting AVX2 Benchmark (Standard vs Modified)..." << std::endl;
  154.     std::cout << "Elements per array: " << NUM_ELEMENTS << std::endl;
  155.     std::cout << "Total Trials: " << NUM_TRIALS << "\n" << std::endl;
  156.  
  157.     std::random_device rd;
  158.     std::mt19937 gen(rd());
  159.     std::uniform_int_distribution<> distrib(1, 10000000);
  160.  
  161.     std::chrono::duration<double> total_duration_mod(0);
  162.     std::chrono::duration<double> total_duration_std(0);
  163.  
  164.     for (int t = 1; t <= NUM_TRIALS; ++t) {
  165.         // Generate base data once per trial
  166.         std::vector<int> base_data(NUM_ELEMENTS);
  167.         for (int i = 0; i < NUM_ELEMENTS; ++i) {
  168.             base_data[i] = distrib(gen);
  169.         }
  170.  
  171.         // Copy data so both algorithms sort the exact same numbers
  172.         std::vector<int> data_mod = base_data;
  173.         std::vector<int> data_std = base_data;
  174.  
  175.         if (t % 2 == 0) {
  176.             // --- EVEN TRIALS: STANDARD RUNS FIRST ---
  177.  
  178.             // 1. Standard
  179.  
  180.             auto start_std = std::chrono::high_resolution_clock::now();
  181.             quickSortStandard(data_std, 0, NUM_ELEMENTS - 1);
  182.             auto end_std = std::chrono::high_resolution_clock::now();
  183.             total_duration_std += (end_std - start_std);
  184.  
  185.             // 2. Modified
  186.  
  187.             auto start_mod = std::chrono::high_resolution_clock::now();
  188.             quickSortModified(data_mod, 0, NUM_ELEMENTS - 1);
  189.             auto end_mod = std::chrono::high_resolution_clock::now();
  190.             total_duration_mod += (end_mod - start_mod);
  191.  
  192.         } else {
  193.             // --- ODD TRIALS: MODIFIED RUNS FIRST ---
  194.  
  195.             // 1. Modified
  196.  
  197.             auto start_mod = std::chrono::high_resolution_clock::now();
  198.             quickSortModified(data_mod, 0, NUM_ELEMENTS - 1);
  199.             auto end_mod = std::chrono::high_resolution_clock::now();
  200.             total_duration_mod += (end_mod - start_mod);
  201.  
  202.             // 2. Standard
  203.  
  204.             auto start_std = std::chrono::high_resolution_clock::now();
  205.             quickSortStandard(data_std, 0, NUM_ELEMENTS - 1);
  206.             auto end_std = std::chrono::high_resolution_clock::now();
  207.             total_duration_std += (end_std - start_std);
  208.         }
  209.  
  210.         // Verification Checks (Kept identical)
  211.         if (!std::is_sorted(data_mod.begin(), data_mod.end())) {
  212.             std::cerr << "Error: Modified Array not sorted on trial " << t << "!" << std::endl;
  213.             return 1;
  214.         }
  215.         if (!std::is_sorted(data_std.begin(), data_std.end())) {
  216.             std::cerr << "Error: Standard Array not sorted on trial " << t << "!" << std::endl;
  217.             return 1;
  218.         }
  219.  
  220.         std::cout << "Completed Trial " << t << "/" << NUM_TRIALS << "\r" << std::flush;
  221.     }
  222.  
  223.     std::cout << "\n\n--- Benchmark Complete ---" << std::endl;
  224.  
  225.     double avg_mod = total_duration_mod.count() / NUM_TRIALS;
  226.     double avg_std = total_duration_std.count() / NUM_TRIALS;
  227.  
  228.     std::cout << "**Modified Version (With 3-Element Rule):**" << std::endl;
  229.     std::cout << "Total Time:   " << total_duration_mod.count() << " seconds" << std::endl;
  230.     std::cout << "Average Time: " << avg_mod << " seconds\n" << std::endl;
  231.  
  232.     std::cout << "**Standard Version (Without Modifications):**" << std::endl;
  233.     std::cout << "Total Time:   " << total_duration_std.count() << " seconds" << std::endl;
  234.     std::cout << "Average Time: " << avg_std << " seconds\n" << std::endl;
  235.  
  236.     // Calculate percent difference relative to the standard baseline
  237.     double percent_diff = ((avg_std - avg_mod) / avg_std) * 100.0;
  238.  
  239.     std::cout << "--------------------------------------" << std::endl;
  240.     if (percent_diff > 0) {
  241.         std::cout << "Result: Modified version is " << percent_diff << "% FASTER than Standard." << std::endl;
  242.     } else if (percent_diff < 0) {
  243.         std::cout << "Result: Modified version is " << -percent_diff << "% SLOWER than Standard." << std::endl;
  244.     } else {
  245.         std::cout << "Result: Both versions performed identically." << std::endl;
  246.     }
  247.     std::cout << "--------------------------------------" << std::endl;
  248.  
  249.     return 0;
  250. }
Advertisement
Add Comment
Please, Sign In to add comment