Advertisement
dmkozyrev

quick_sort_asm.cpp

May 27th, 2016
309
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.08 KB | None | 0 0
  1. /*
  2.     Быстрая сортировка:    на C++ и на ассемблере.
  3.     Ассемблер:             masm.
  4.     Синтаксис:             AT&T.
  5.      
  6.     Набор настроек и флагов компилятора:
  7.         Version: TDM-GCC 4.9.2 32-bit Release
  8.         Compile with the following bit width (-mx): 32bit
  9.         Language standard (-std): ISO C++11
  10.    
  11.     В main создается массив из 10.000.000 случайных чисел в двух экземплярах.
  12.     Засекается время работы сортировки алгоритмом на C++
  13.     Засекается время работы сортировки ассемблерной вставкой
  14.     Проверяется правильность: получен ли неубывающий порядок?
  15.    
  16.     Вывод (то, ради чего работа и делалась):
  17.         Ассемблерная вставка работает в среднем в два раза быстрее аналога на C++.
  18.        
  19.     Если использовать оптимизацию -O3 high level'a по скорости, то необходимо закомментировать строку 49: "pop %ebp;".
  20.     При оптимизации компилятор добавит ее за нас, следовательно, нам это делать не нужно.
  21. */
  22.  
  23. #include <iostream>
  24. #include <cstdio>
  25. #include <cstdlib>
  26. #include <ctime>
  27. using namespace std;
  28.  
  29. void quick_sort(int * first, int * last){
  30.     int * f = first, * l = last;
  31.     int mid = f[(l-f)/2];
  32.     do {
  33.         while ( *f < mid ) f++;
  34.         while ( *l > mid ) l--;
  35.         if ( f <= l ) {
  36.             int temp = *f;
  37.             *f = *l;
  38.             *l = temp;
  39.             f++;
  40.             l--;
  41.         }
  42.     } while (f < l);
  43.     if ( first < l ) quick_sort(first, l);
  44.     if ( f < last )  quick_sort(f, last);
  45. }
  46.  
  47. void quick_sort_asm(int * first, int * last){
  48.     asm (
  49.             "pop %ebp;" // Уничтожаем последствия от вызова void quick_sort_asm(int * first, int * last).
  50.         "_quick_sort:;"
  51.             // Сохраняем используемые регистры, смещаем указатель на стек:
  52.             "push   %ebp; push   %edi; push   %esi; push   %ebx; sub    $0x1c,  %esp;"
  53.            
  54.             "mov    0x30(%esp),     %ebp;" // 48; ebp = first
  55.             "mov    0x34(%esp),     %esi;" // 52; esi = last
  56.            
  57.             // eax = (l-f)/2
  58.             "mov    %esi,           %eax;"
  59.             "sub    %ebp,           %eax;"
  60.             "sar    $0x2,           %eax;"
  61.             "mov    %eax,           %edx;"
  62.             "shr    $0x1f,          %edx;"
  63.             "add    %edx,           %eax;"
  64.             "sar    %eax;"
  65.            
  66.             "mov    (%ebp,%eax,4),  %ecx;"  //  mid = *(f + (l-f)/2)
  67.             "mov    %esi,           %eax;"  //  l = last
  68.             "mov    %ebp,           %ebx;"  //  f = first
  69.            
  70.             // цикл do {...} while (f < l)
  71.             "_before_do:;"
  72.            
  73.                 // цикл while ( *f < mid ) f++;
  74.                 "_left_while_condition:;"
  75.                     "mov    (%ebx),     %edi;"
  76.                     "cmp    %edi,       %ecx;"
  77.                     "jle     _after_left_while;"
  78.                 "_left_while_body:;"
  79.                     "add    $0x4,       %ebx;"  //  f++
  80.                     "jmp    _left_while_condition;"
  81.                 "_after_left_while:;"
  82.            
  83.                 // цикл while ( *l > mid ) l--;
  84.                 "_right_while_condition:;"
  85.                     "mov    (%eax),     %edx;"
  86.                     "cmp    %edx,       %ecx;"
  87.                     "jge    _after_right_while;"
  88.                 "_right_while_body:;"
  89.                     "sub    $0x4,       %eax;"  //  l--
  90.                     "jmp    _right_while_condition;"
  91.                 "_after_right_while:;"     
  92.            
  93.                 "_before_swapping:;"
  94.                     //  проверка условия if ( f <= l ):
  95.                     "cmp    %eax,       %ebx;"     
  96.                     "ja     _after_swapping;"
  97.                     //  обмен *f и *l:
  98.                     "mov    %edx,       (%ebx);"
  99.                     "mov    %edi,       (%eax);"
  100.                     //  смещение f вправо на sizeof(int) = 4 бита: 
  101.                     "add    $0x4,       %ebx;"      //  f++
  102.                     //  смещение l влево на sizeof(int) = 4 бита:
  103.                     "sub    $0x4,       %eax;"      //  l--
  104.                 "_after_swapping:;"
  105.                
  106.                 // Проверка условия цикла с постусловием do {...} while (f < l):
  107.                 "cmp    %eax,       %ebx;"
  108.                 "jb     _before_do;"
  109.             "_after_do:;"
  110.            
  111.             // Левая рекурсивная ветвь:
  112.             "_before_left_call:;"
  113.                 // Проверка условия if ( first < l ):
  114.                 "cmp    %eax,       %ebp;"
  115.                 "jae    _after_left_call;"
  116.                 // Размещение l на стеке:
  117.                 "mov    %eax,       0x4(%esp);"
  118.                 // Передача first перед l на стеке:
  119.                 "mov    %ebp,       (%esp);"
  120.                 // Вызов функции сортировки на отрезке [first, l]:
  121.                 "call   _quick_sort;"
  122.             "_after_left_call:;"
  123.            
  124.             // Правая рекурсивная ветвь:
  125.             "_before_right_call:;"
  126.                 // Проверка условия if ( f < last ):
  127.                 "cmp    %ebx,       %esi;"
  128.                 "jbe    _after_right_call;"
  129.                 // Размещение last на стеке:
  130.                 "mov    %esi,       0x4(%esp);"
  131.                 // Передача f перед last на стеке:
  132.                 "mov    %ebx,       (%esp);"
  133.                 // Вызов функции сортировки на отрезке [f, last]:
  134.                 "call   _quick_sort;"
  135.             "_after_right_call:;"
  136.            
  137.         "_end:;"   
  138.         // Возвращаем указатель на стек в его исходное состояние и восстанавливаем значения используемых регистров:
  139.             "add    $0x1c,  %esp; pop    %ebx; pop    %esi; pop    %edi; pop    %ebp;"
  140.         "ret;"        
  141.     ); 
  142. }
  143.  
  144. int main() {
  145. //  Создаем массив:
  146.     const int n = 10000000;
  147.     int * a = new int[n];
  148.     int * b = new int[n];
  149.     for (int i = 0; i < n; i++)
  150.         a[i] = b[i] = rand() % n;
  151.        
  152.     int t = clock();
  153.     quick_sort(b, b+n-1);
  154.     double time_sec = (clock() - t ) * 1.0 / CLOCKS_PER_SEC;
  155.     printf("standart quick sort time: %0.3fs\n", time_sec);
  156.    
  157. //  Сортируем в порядке неубывания и засекаем время:
  158.     t = clock();
  159.     quick_sort_asm(a, a+n-1);
  160.     time_sec = (clock() - t ) * 1.0 / CLOCKS_PER_SEC;
  161.     printf("assembly quick sort time: %0.3fs\n", time_sec);
  162.    
  163. //  Проверяем на правильность:
  164.     for (int i = 1; i < n; i++)
  165.         if ( a[i-1] > a[i] )
  166.             printf("ERROR: a[%d] > a[%d]\n", i-1, i);
  167.    
  168.     delete[] a;
  169.     delete[] b;
  170.     printf("Type something and press enter for exit...\n");
  171.     char c; cin >> c;
  172.     return 0;
  173. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement