Векторизованно вычислить [евклидово расстояние]

Тема в разделе "WASM.BEGINNERS", создана пользователем Research, 25 фев 2026.

  1. Research

    Research Active Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    455
    Код (Pascal):
    1.  
    2. function EuclidDist(const arr1, arr2: array of Double): Double;
    3. var
    4.   i: Integer;
    5. begin
    6.   Result := 0;
    7.   if Length(arr1) = Length(arr2) then
    8.   begin
    9.     for i := 0 to Length(arr1) - 1 do
    10.     begin
    11.       Result := Result + Sqr(arr1 - arr2);
    12.     end;
    13.     Result := Sqrt(Result);
    14.   end;
    15. end; //EuclidDist
    16.  
    ---

    Delphi 7/win 32.
    Код (ASM):
    1. function EuclidDist(const V1, V2: TDouble): Double; assembler;
    2. asm
    3.   // EAX = V1 data ptr (or nil)
    4.   // EDX = V2 data ptr (or nil)
    5.   test  eax, eax
    6.   jz    @@Zero
    7.   test  edx, edx
    8.   jz    @@Zero
    9.   mov   ecx, [eax-4]      // len1
    10.   test  ecx, ecx
    11.   jz    @@Zero
    12.   cmp   ecx, [edx-4]      // len2
    13.   jne   @@Zero
    14.   // ---- теперь можно сохранять callee-saved, т.к. точно работаем дальше
    15.   push  ebx
    16.   push  esi
    17.   push  edi
    18.   mov   esi, eax          // p1
    19.   mov   edi, edx          // p2
    20.   // ebx = blocks of 8 doubles, edx = remainder (0..7)
    21.   mov   ebx, ecx
    22.   shr   ebx, 3
    23.   and   ecx, 7            // остаток оставим в ECX
    24.   xorps xmm0, xmm0
    25.   xorps xmm1, xmm1
    26.   xorps xmm2, xmm2
    27.   xorps xmm3, xmm3
    28.   // ---- optional aligned fast-path
    29.   mov   eax, esi
    30.   or    eax, edi
    31.   test  eax, 15
    32.   jnz   @@Unaligned
    33. @@Aligned:
    34.   test  ebx, ebx
    35.   jz    @@Tail
    36. @@LoopA:
    37.   movapd xmm4, [esi]
    38.   movapd xmm5, [edi]
    39.   subpd  xmm4, xmm5
    40.   mulpd  xmm4, xmm4
    41.   addpd  xmm0, xmm4
    42.   movapd xmm4, [esi+16]
    43.   movapd xmm5, [edi+16]
    44.   subpd  xmm4, xmm5
    45.   mulpd  xmm4, xmm4
    46.   addpd  xmm1, xmm4
    47.   movapd xmm4, [esi+32]
    48.   movapd xmm5, [edi+32]
    49.   subpd  xmm4, xmm5
    50.   mulpd  xmm4, xmm4
    51.   addpd  xmm2, xmm4
    52.   movapd xmm4, [esi+48]
    53.   movapd xmm5, [edi+48]
    54.   subpd  xmm4, xmm5
    55.   mulpd  xmm4, xmm4
    56.   addpd  xmm3, xmm4
    57.   add   esi, 64
    58.   add   edi, 64
    59.   dec   ebx
    60.   jnz   @@LoopA
    61.   jmp   @@AfterMain
    62. @@Unaligned:
    63.   test  ebx, ebx
    64.   jz    @@Tail
    65. @@LoopU:
    66.   movupd xmm4, [esi]
    67.   movupd xmm5, [edi]
    68.   subpd  xmm4, xmm5
    69.   mulpd  xmm4, xmm4
    70.   addpd  xmm0, xmm4
    71.   movupd xmm4, [esi+16]
    72.   movupd xmm5, [edi+16]
    73.   subpd  xmm4, xmm5
    74.   mulpd  xmm4, xmm4
    75.   addpd  xmm1, xmm4
    76.   movupd xmm4, [esi+32]
    77.   movupd xmm5, [edi+32]
    78.   subpd  xmm4, xmm5
    79.   mulpd  xmm4, xmm4
    80.   addpd  xmm2, xmm4
    81.   movupd xmm4, [esi+48]
    82.   movupd xmm5, [edi+48]
    83.   subpd  xmm4, xmm5
    84.   mulpd  xmm4, xmm4
    85.   addpd  xmm3, xmm4
    86.   add   esi, 64
    87.   add   edi, 64
    88.   dec   ebx
    89.   jnz   @@LoopU
    90. @@AfterMain:
    91.   addpd xmm0, xmm1
    92.   addpd xmm2, xmm3
    93.   addpd xmm0, xmm2
    94. @@Tail:
    95.   test  ecx, ecx
    96.   jz    @@Finish
    97. @@TailLoop:
    98.   movsd xmm4, [esi]
    99.   movsd xmm5, [edi]
    100.   subsd xmm4, xmm5
    101.   mulsd xmm4, xmm4
    102.   addsd xmm0, xmm4
    103.   add   esi, 8
    104.   add   edi, 8
    105.   dec   ecx
    106.   jnz   @@TailLoop
    107. @@Finish:
    108.   movhlps xmm1, xmm0
    109.   addsd   xmm0, xmm1
    110.   sqrtsd  xmm0, xmm0
    111.   // return Double via x87 ST(0)
    112.   sub   esp, 8
    113.   movsd qword ptr [esp], xmm0
    114.   fld   qword ptr [esp]
    115.   add   esp, 8
    116.   pop   edi
    117.   pop   esi
    118.   pop   ebx
    119.   ret
    120. @@Zero:
    121.   fldz
    122.   ret
    123. end;
    ---
     
    Последнее редактирование: 26 фев 2026
  2. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    595
    В скрипте наверно ошибка, должны быть индексы i в массивах,

    sqr это умножение.

    - deepseek

    Можно несколько потоков создать, уменьшить планировочные простои.
     
  3. Research

    Research Active Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    455
    ---
    Код (Text):
    1. Правильный вариант:
    2. def euclidean_distance(x, y):
    3.     return np.sqrt(np.sum((x - y) ** 2))
    4.  
    ---
    Типо такого?
    ---
    --- Сообщение объединено, 26 фев 2026 ---
    Дипсику про многопоточность не зашло
     
    Последнее редактирование: 26 фев 2026
  4. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    595
    Это абмолютная чепуха, ботов нужно вначале обучить, только затем они годное генерят.

    Это все нужно проверять, prefetch тоже.
     
  5. Research

    Research Active Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    455
    Screenshot_20260226_121214_com_android_chrome_ChromeTabbedActivity.jpg

    Формула евклидового расстояния абсолютно правильная, это вообще не трогаем.
    Да это понятно. Вручную надо писать, отлаживать в отладчике. Боты в такое вряд ли могут.

    ---

    Самое забористое.

    Код (ASM):
    1.  
    2. function EuclidDist(const V1, V2: TVector): Double; assembler;
    3. asm
    4.   // ----------------------------------------
    5.   // Максимально оптимизированная версия
    6.   // Вход: EAX = V1, EDX = V2
    7.   // Выход: ST(0) = евклидово расстояние
    8.   // ----------------------------------------
    9.   push  esi
    10.   push  edi
    11.   mov   esi, eax            // ESI = V1
    12.   mov   edi, edx            // EDI = V2
    13.   // ---------- Быстрая проверка на nil ----------
    14.   test  esi, esi
    15.   jz    @ret_zero
    16.   test  edi, edi
    17.   jz    @ret_zero
    18.   // ---------- Получение и сравнение длин ----------
    19.   mov   eax, [esi-4]        // EAX = Length(V1)
    20.   cmp   eax, [edi-4]        // сравниваем с Length(V2)
    21.   jne   @ret_zero
    22.   test  eax, eax
    23.   jz    @ret_zero
    24.   // ---------- Основной алгоритм ----------
    25.   mov   ecx, eax            // ECX = длина (счётчик для остатка)
    26.   shr   eax, 2              // EAX = количество четверок
    27.   xorps xmm0, xmm0          // xmm0 = 0
    28.   // ---------- Цикл по 4 элемента ----------
    29.   test  eax, eax
    30.   jz    @single
    31.   push  ebx                 // сохраняем EBX только если нужен цикл
    32.   mov   ebx, eax
    33. @quad_loop:
    34.     movupd xmm1, [esi]
    35.     movupd xmm2, [edi]
    36.     movupd xmm3, [esi+16]
    37.     movupd xmm4, [edi+16]
    38.     subpd xmm1, xmm2
    39.     subpd xmm3, xmm4
    40.     mulpd xmm1, xmm1
    41.     mulpd xmm3, xmm3
    42.     addpd xmm0, xmm1
    43.     addpd xmm0, xmm3
    44.     add   esi, 32
    45.     add   edi, 32
    46.     dec   ebx
    47.     jnz   @quad_loop
    48.   pop   ebx
    49. @single:
    50.   // ---------- Обработка оставшихся элементов ----------
    51.   and   ecx, 3
    52.   jz    @combine
    53. @single_loop:
    54.     movsd  xmm1, [esi]
    55.     movsd  xmm2, [edi]
    56.     subsd  xmm1, xmm2
    57.     mulsd  xmm1, xmm1
    58.     addsd  xmm0, xmm1
    59.     add   esi, 8
    60.     add   edi, 8
    61.     dec   ecx
    62.     jnz   @single_loop
    63. @combine:
    64.   movhlps xmm1, xmm0
    65.   addsd   xmm0, xmm1
    66.   sqrtsd  xmm0, xmm0
    67.   sub   esp, 8
    68.   movlpd [esp], xmm0
    69.   fld   qword ptr [esp]
    70.   add   esp, 8
    71.   pop   edi
    72.   pop   esi
    73.   ret
    74. @ret_zero:
    75.   fldz
    76.   pop   edi
    77.   pop   esi
    78.   ret
    79. end;
    80. ---
    81.  
    82. С проверками выравнивания:
    83.  
    84. Код (ASM):
    85. function EuclidDist_SSE(const V1, V2: TVector): Double; assembler;
    86. asm
    87.   // ----------------------------------------
    88.   // 1. ПРОЛОГ
    89.   // ----------------------------------------
    90.   push  ebx
    91.   push  esi
    92.   push  edi
    93.   push  ebp
    94.   // ----------------------------------------
    95.   // 2. ПРОВЕРКА ДАННЫХ
    96.   // ----------------------------------------
    97.   @validate:
    98.     test  eax, eax
    99.     jz    @error_exit
    100.     test  edx, edx
    101.     jz    @error_exit
    102.     mov   esi, [eax + TVector.FData]  // получаем данные
    103.     mov   edi, [edx + TVector.FData]
    104.     test  esi, esi
    105.     jz    @error_exit
    106.     test  edi, edi
    107.     jz    @error_exit
    108.     mov   ebx, [eax + TVector.FLength]  // длина
    109.     cmp   ebx, [edx + TVector.FLength]
    110.     jne   @error_exit
    111.     test  ebx, ebx
    112.     jz    @error_exit
    113.   // ----------------------------------------
    114.   // 3. ВЫЧИСЛЕНИЯ (КРАСИВО И ЭФФЕКТИВНО)
    115.   // ----------------------------------------
    116.   @compute:
    117.     // Сохраняем длину
    118.     mov   ebp, ebx              // EBP = общая длина
    119.     // Инициализация аккумуляторов (4 независимых для конвейера)
    120.     xorps  xmm0, xmm0
    121.     xorps  xmm1, xmm1
    122.     xorps  xmm2, xmm2
    123.     xorps  xmm3, xmm3
    124.     // Проверка выравнивания для выбора оптимального пути
    125.     mov   eax, esi
    126.     or    eax, edi
    127.     and   eax, 15
    128.     jnz   @use_unaligned        // невыровненные -> unaligned путь
    129.     // ---------- ВЫРОВНЕННЫЙ ПУТЬ (ОПТИМАЛЬНЫЙ) ----------
    130.     mov   ecx, ebp
    131.     shr   ecx, 2                // количество четверок
    132.     jz    @aligned_remainder
    133.   @aligned_quad_loop:
    134.     // Загружаем 4 элемента из V1 (выровненно!)
    135.     movapd xmm4, [esi]          // элементы 0-1
    136.     movapd xmm5, [esi+16]       // элементы 2-3
    137.     // Загружаем 4 элемента из V2 (выровненно!)
    138.     movapd xmm6, [edi]
    139.     movapd xmm7, [edi+16]
    140.     // Вычисления с минимальными зависимостями
    141.     subpd  xmm4, xmm6
    142.     subpd  xmm5, xmm7
    143.     mulpd  xmm4, xmm4
    144.     mulpd  xmm5, xmm5
    145.     // Накопление в разные регистры (конвейер!)
    146.     addpd  xmm0, xmm4
    147.     addpd  xmm1, xmm5
    148.     add    esi, 32
    149.     add    edi, 32
    150.     dec    ecx
    151.     jnz    @aligned_quad_loop
    152.   @aligned_remainder:
    153.     // Суммируем аккумуляторы
    154.     addpd  xmm0, xmm1
    155.     addpd  xmm2, xmm3
    156.     addpd  xmm0, xmm2
    157.     // Обработка остатка (0-3 элемента)
    158.     mov    ecx, ebp
    159.     and    ecx, 3
    160.     jz     @aligned_sum
    161.   @aligned_rem_loop:
    162.     movsd  xmm4, [esi]
    163.     movsd  xmm5, [edi]
    164.     subsd  xmm4, xmm5
    165.     mulsd  xmm4, xmm4
    166.     addsd  xmm0, xmm4
    167.     add    esi, 8
    168.     add    edi, 8
    169.     dec    ecx
    170.     jnz    @aligned_rem_loop
    171.   @aligned_sum:
    172.     jmp   @combine_and_sqrt
    173.   @use_unaligned:
    174.     // ---------- НЕВЫРОВНЕННЫЙ ПУТЬ (универсальный) ----------
    175.     mov   ecx, ebp
    176.     shr   ecx, 2
    177.     jz    @unaligned_remainder
    178.   @unaligned_quad_loop:
    179.     // Невыровненная загрузка (медленнее, но работает везде)
    180.     movupd xmm4, [esi]
    181.     movupd xmm5, [esi+16]
    182.     movupd xmm6, [edi]
    183.     movupd xmm7, [edi+16]
    184.     subpd  xmm4, xmm6
    185.     subpd  xmm5, xmm7
    186.     mulpd  xmm4, xmm4
    187.     mulpd  xmm5, xmm5
    188.     addpd  xmm0, xmm4
    189.     addpd  xmm1, xmm5
    190.     add    esi, 32
    191.     add    edi, 32
    192.     dec    ecx
    193.     jnz    @unaligned_quad_loop
    194.   @unaligned_remainder:
    195.     addpd  xmm0, xmm1
    196.     addpd  xmm2, xmm3
    197.     addpd  xmm0, xmm2
    198.     mov    ecx, ebp
    199.     and    ecx, 3
    200.     jz     @combine_and_sqrt
    201.   @unaligned_rem_loop:
    202.     movsd  xmm4, [esi]
    203.     movsd  xmm5, [edi]
    204.     subsd  xmm4, xmm5
    205.     mulsd  xmm4, xmm4
    206.     addsd  xmm0, xmm4
    207.     add    esi, 8
    208.     add    edi, 8
    209.     dec    ecx
    210.     jnz    @unaligned_rem_loop
    211.   @combine_and_sqrt:
    212.     // ---------- ФИНАЛЬНАЯ ОБРАБОТКА ----------
    213.     // Горизонтальное суммирование (красиво!)
    214.     movhlps xmm1, xmm0
    215.     addsd   xmm0, xmm1
    216.     // Квадратный корень
    217.     sqrtsd  xmm0, xmm0
    218.     // Перенос в FPU для возврата
    219.     sub     esp, 8
    220.     movlpd  [esp], xmm0
    221.     fld     qword ptr [esp]
    222.     add     esp, 8
    223.     jmp   @success_exit
    224.   // ----------------------------------------
    225.   // 4. УСПЕШНЫЙ ВЫХОД
    226.   // ----------------------------------------
    227.   @success_exit:
    228.     jmp   @epilog
    229.   // ----------------------------------------
    230.   // 5. ОШИБОЧНЫЙ ВЫХОД
    231.   // ----------------------------------------
    232.   @error_exit:
    233.     fldz                      // возвращаем 0
    234.   // ----------------------------------------
    235.   // 6. ЭПИЛОГ
    236.   // ----------------------------------------
    237.   @epilog:
    238.     pop   ebp
    239.     pop   edi
    240.     pop   esi
    241.     pop   ebx
    242.     ret
    243. end;
    244. ---
    245.  
    Что-то типа такого, без avx, с xmm0-xmm7 с prefetch, без багов. Не обмазываясь выравниванием.

    ---

    Здесь боты вообще не нужны.
    На васме люди шахматные движки в уме пишут под разные инструкции и разные процессоры. Может кто-то из местной элиты ранее писал чтото подобное.

    ---
    --- Сообщение объединено, 26 фев 2026 ---
    Даже без prefetch. prefetch тоже не нужон.
    --- Сообщение объединено, 26 фев 2026 ---
    --- Сообщение объединено, 26 фев 2026 ---
    Код (ASM):
    1. function EuclidDist(...): Double; assembler;
    2. asm
    3.   // ----------------------------------------
    4.   // 1. ПРОЛОГ - сохранение регистров
    5.   // ----------------------------------------
    6.  
    7.   // ----------------------------------------
    8.   // 2. ИНИЦИАЛИЗАЦИЯ
    9.   // - получить длину массива
    10.   // - установить указатели
    11.   // - обнулить аккумуляторы
    12.   // ----------------------------------------
    13.  
    14.   // ----------------------------------------
    15.   // 3. ОСНОВНОЙ ЦИКЛ
    16.   // - обрабатывать по 8 элементов за итерацию
    17.   // - использовать предвыборку
    18.   // - накапливать в 6 аккумуляторов
    19.   // ----------------------------------------
    20.  
    21.   // ----------------------------------------
    22.   // 4. ОБРАБОТКА ОСТАТКА
    23.   // - 0-7 оставшихся элементов
    24.   // - скалярная обработка
    25.   // ----------------------------------------
    26.  
    27.   // ----------------------------------------
    28.   // 5. СУММИРОВАНИЕ АККУМУЛЯТОРОВ
    29.   // - сложить все частичные суммы
    30.   // - вычислить x² +- 2xy
    31.   // ----------------------------------------
    32.  
    33.   // ----------------------------------------
    34.   // 6. КВАДРАТНЫЙ КОРЕНЬ
    35.   // ----------------------------------------
    36.  
    37.   // ----------------------------------------
    38.   // 7. ВОЗВРАТ РЕЗУЛЬТАТА
    39.   // - перенести из XMM в FPU
    40.   // ----------------------------------------
    41.  
    42.   // ----------------------------------------
    43.   // 8. ЭПИЛОГ - восстановление регистров
    44.   // ----------------------------------------
    45. end;
    --- Сообщение объединено, 26 фев 2026 ---
    Формула вычислений
    Код (Text):
    1. sum = 0
    2. for i = 0 to n-1
    3.     diff = a[i] - b[i]
    4.     sum = sum + diff * diff
    5. result = sqrt(sum)
    --- Сообщение объединено, 26 фев 2026 ---
    Примерная структура:
    Код (ASM):
    1. function EuclidDist(const V1, V2: TVector): Double; assembler;
    2. asm
    3.   // ----------------------------------------
    4.   // СТРУКТУРА ФУНКЦИИ
    5.   // ----------------------------------------
    6.  
    7.   // ========================================
    8.   // 1. ПРОЛОГ - сохранение регистров
    9.   // ========================================
    10.   push  ebx
    11.   push  esi
    12.   push  edi
    13.   push  ebp
    14.  
    15.   // ========================================
    16.   // 2. ПРОВЕРКА ДАННЫХ
    17.   // ========================================
    18.   @check_data:
    19.     // Проверка на nil
    20.     test  eax, eax
    21.     jz    @error_exit
    22.    
    23.     test  edx, edx
    24.     jz    @error_exit
    25.    
    26.     // Получение длины
    27.     mov   ecx, [eax - 4]        // длина V1
    28.     test  ecx, ecx
    29.     jz    @error_exit
    30.    
    31.     // Проверка совпадения длин
    32.     cmp   ecx, [edx - 4]
    33.     jne   @error_exit
    34.    
    35.     // ========================================
    36.     // 3. ЗАГРУЗКА ДАННЫХ
    37.     // ========================================
    38.     mov   esi, eax               // указатель на V1
    39.     mov   edi, edx               // указатель на V2
    40.     mov   ebx, ecx               // сохраняем длину в ebx
    41.     mov   ebp, ecx               // также сохраняем в ebp (для остатка)
    42.  
    43.   // ========================================
    44.   // 4. ВЫЧИСЛЕНИЯ (ОСНОВНОЙ БЛОК)
    45.   // ========================================
    46.   @compute:
    47.     // Инициализация аккумуляторов
    48.     xorps  xmm0, xmm0
    49.     xorps  xmm1, xmm1
    50.     xorps  xmm2, xmm2
    51.     xorps  xmm3, xmm3
    52.    
    53.     // Обработка четверками (4 Double = 32 байта)
    54.     mov   eax, ebx
    55.     shr   eax, 2                 // количество четверок
    56.     jz    @process_remainder
    57.    
    58.     xor   edx, edx               // смещение
    59.    
    60.   @loop_quad:
    61.       // Загрузка 4 элементов из V1
    62.       movupd  xmm4, [esi + edx]      // элементы 0-1
    63.       movupd  xmm5, [esi + edx + 16] // элементы 2-3
    64.      
    65.       // Загрузка 4 элементов из V2
    66.       movupd  xmm6, [edi + edx]      // элементы 0-1
    67.       movupd  xmm7, [edi + edx + 16] // элементы 2-3
    68.      
    69.       // Вычисления для первой пары
    70.       subpd   xmm4, xmm6
    71.       mulpd   xmm4, xmm4
    72.       addpd   xmm0, xmm4
    73.      
    74.       // Вычисления для второй пары
    75.       subpd   xmm5, xmm7
    76.       mulpd   xmm5, xmm5
    77.       addpd   xmm1, xmm5
    78.      
    79.       // Переход к следующим 4 элементам
    80.       add     edx, 32
    81.       dec     eax
    82.       jnz     @loop_quad
    83.    
    84.     // Суммирование аккумуляторов
    85.     addpd   xmm0, xmm1
    86.     addpd   xmm2, xmm3
    87.     addpd   xmm0, xmm2
    88.  
    89.   @process_remainder:
    90.     // Обработка остатка (0-3 элемента)
    91.     mov     eax, ebp
    92.     and     eax, 3                // остаток
    93.     jz      @combine_results
    94.    
    95.     mov     ecx, eax
    96.     mov     edx, ebp
    97.     sub     edx, ecx              // индекс начала остатка
    98.     shl     edx, 3                // пересчет в байты
    99.    
    100.   @rem_loop:
    101.       movsd   xmm4, [esi + edx]
    102.       movsd   xmm5, [edi + edx]
    103.       subsd   xmm4, xmm5
    104.       mulsd   xmm4, xmm4
    105.       addsd   xmm0, xmm4
    106.      
    107.       add     edx, 8
    108.       dec     ecx
    109.       jnz     @rem_loop
    110.  
    111.   @combine_results:
    112.     // Горизонтальное суммирование
    113.     movhlps xmm1, xmm0
    114.     addsd   xmm0, xmm1
    115.    
    116.     // Квадратный корень
    117.     sqrtsd  xmm0, xmm0
    118.  
    119.   // ========================================
    120.   // 5. ВЫХОД ПРИ НОРМАЛЬНОМ ЗАВЕРШЕНИИ
    121.   // ========================================
    122.   @success_exit:
    123.     // Перенос результата в FPU
    124.     sub     esp, 8
    125.     movlpd  [esp], xmm0
    126.     fld     qword [esp]
    127.     add     esp, 8
    128.     jmp     @epilog
    129.  
    130.   // ========================================
    131.   // 6. ВЫХОД ПРИ ОШИБКЕ
    132.   // ========================================
    133.   @error_exit:
    134.     fldz                          // возвращаем 0.0
    135.  
    136.   // ========================================
    137.   // 7. ЭПИЛОГ - восстановление регистров
    138.   // ========================================
    139.   @epilog:
    140.     pop   ebp
    141.     pop   edi
    142.     pop   esi
    143.     pop   ebx
    144.     ret
    145. end;
     
    Последнее редактирование: 26 фев 2026
  6. Application

    Application Active Member

    Публикаций:
    1
    Регистрация:
    15 окт 2022
    Сообщения:
    160
    Код (ASM):
    1. function EuclidDist(const V1, V2: TVector): Double; assembler;
    2. asm
    3.   // -----------------------------------------------------------------
    4.   // 1. Пролог – сохраняем регистры, которые обязаны сохранять
    5.   // -----------------------------------------------------------------
    6.   push  esi
    7.   push  edi
    8.  
    9.   // -----------------------------------------------------------------
    10.   // 2. Проверка корректности входных данных
    11.   // -----------------------------------------------------------------
    12.   test  eax, eax
    13.   jz    @ret_zero
    14.   test  edx, edx
    15.   jz    @ret_zero
    16.   mov   ecx, [eax - 4]        // длина V1
    17.   test  ecx, ecx
    18.   jz    @ret_zero
    19.   cmp   ecx, [edx - 4]        // сравниваем с длиной V2
    20.   jne   @ret_zero
    21.  
    22.   // -----------------------------------------------------------------
    23.   // 3. Получаем указатели на данные (длина уже в ECX)
    24.   // -----------------------------------------------------------------
    25.   mov   esi, eax               // esi = указатель на V1[0]
    26.   mov   edi, edx               // edi = указатель на V2[0]
    27.  
    28.   // -----------------------------------------------------------------
    29.   // 4. Инициализация аккумуляторов
    30.   // -----------------------------------------------------------------
    31.   xorps  xmm0, xmm0
    32.   xorps  xmm1, xmm1
    33.   xorps  xmm2, xmm2
    34.   xorps  xmm3, xmm3
    35.  
    36.   // -----------------------------------------------------------------
    37.   // 5. Основной цикл – обрабатываем по 8 элементов (4 пары Double) за итерацию
    38.   // -----------------------------------------------------------------
    39.   mov   eax, ecx
    40.   shr   eax, 3                  // eax = количество полных восьмёрок (n div 8)
    41.   jz    @@HandleRemainder
    42.  
    43.   xor   edx, edx                 // edx = смещение в байтах
    44.  
    45. @@MainLoop:
    46.     // Загружаем первые 4 элемента (2 пары) из V1 и V2
    47.     movupd  xmm4, [esi + edx]       // xmm4 = V1[i+1], V1[i]
    48.     movupd  xmm5, [edi + edx]       // xmm5 = V2[i+1], V2[i]
    49.     movupd  xmm6, [esi + edx + 16]  // xmm6 = V1[i+3], V1[i+2]
    50.     movupd  xmm7, [edi + edx + 16]  // xmm7 = V2[i+3], V2[i+2]
    51.  
    52.     // Вычисляем для первой пары
    53.     subpd   xmm4, xmm5
    54.     mulpd   xmm4, xmm4
    55.     addpd   xmm0, xmm4
    56.  
    57.     // Вычисляем для второй пары
    58.     subpd   xmm6, xmm7
    59.     mulpd   xmm6, xmm6
    60.     addpd   xmm1, xmm6
    61.  
    62.     // Загружаем следующие 4 элемента (3-ю и 4-ю пары)
    63.     movupd  xmm4, [esi + edx + 32]   // xmm4 = V1[i+5], V1[i+4]
    64.     movupd  xmm5, [edi + edx + 32]   // xmm5 = V2[i+5], V2[i+4]
    65.     movupd  xmm6, [esi + edx + 48]   // xmm6 = V1[i+7], V1[i+6]
    66.     movupd  xmm7, [edi + edx + 48]   // xmm7 = V2[i+7], V2[i+6]
    67.  
    68.     subpd   xmm4, xmm5
    69.     mulpd   xmm4, xmm4
    70.     addpd   xmm2, xmm4
    71.  
    72.     subpd   xmm6, xmm7
    73.     mulpd   xmm6, xmm6
    74.     addpd   xmm3, xmm6
    75.  
    76.     // ---------- Предварительная выборка следующих данных ----------
    77.     prefetcht0 [esi + edx + 64]   // загружаем в кэш следующие 64 байта из V1
    78.     prefetcht0 [edi + edx + 64]   // загружаем в кэш следующие 64 байта из V2
    79.     // --------------------------------------------------------------
    80.  
    81.     // Переходим к следующим 8 элементам (64 байта)
    82.     add     edx, 64
    83.     dec     eax
    84.     jnz     @@MainLoop
    85.  
    86.   // -----------------------------------------------------------------
    87.   // 6. Суммируем аккумуляторы
    88.   // -----------------------------------------------------------------
    89.   addpd   xmm0, xmm1
    90.   addpd   xmm2, xmm3
    91.   addpd   xmm0, xmm2
    92.  
    93.   // -----------------------------------------------------------------
    94.   // 7. Обработка остатка (0..7 элементов)
    95.   // -----------------------------------------------------------------
    96. @@HandleRemainder:
    97.   mov   eax, ecx
    98.   and   eax, 7                       // остаток от деления на 8
    99.   jz    @@Combine
    100.  
    101.   mov   edx, ecx
    102.   sub   edx, eax                     // edx = индекс первого остаточного элемента
    103.   shl   edx, 3                       // переводим в байты
    104.  
    105. @@RemLoop:
    106.     movsd  xmm4, [esi + edx]
    107.     movsd  xmm5, [edi + edx]
    108.     subsd  xmm4, xmm5
    109.     mulsd  xmm4, xmm4
    110.     addsd  xmm0, xmm4                 // добавляем к младшей половине xmm0
    111.     add    edx, 8
    112.     dec    eax
    113.     jnz    @@RemLoop
    114.  
    115.   // -----------------------------------------------------------------
    116.   // 8. Горизонтальное сложение (получаем одно число в xmm0)
    117.   // -----------------------------------------------------------------
    118. @@Combine:
    119.   movhlps xmm1, xmm0                // xmm1 = старшая половина xmm0
    120.   addsd   xmm0, xmm1                // xmm0[0] = сумма всех квадратов
    121.  
    122.   // -----------------------------------------------------------------
    123.   // 9. Квадратный корень
    124.   // -----------------------------------------------------------------
    125.   sqrtsd  xmm0, xmm0
    126.  
    127.   // -----------------------------------------------------------------
    128.   // 10. Возврат результата в FPU
    129.   // -----------------------------------------------------------------
    130.   sub     esp, 8
    131.   movlpd  [esp], xmm0
    132.   fld     qword ptr [esp]
    133.   add     esp, 8
    134.  
    135.   // -----------------------------------------------------------------
    136.   // 11. Эпилог – восстановление регистров
    137.   // -----------------------------------------------------------------
    138.   pop   edi
    139.   pop   esi
    140.   ret
    141.  
    142. @ret_zero:
    143.   fldz
    144.   pop   edi
    145.   pop   esi
    146.   ret
    147. end; //EuclidDist
    --- Сообщение объединено, 26 фев 2026 ---
    Вместо
    Код (ASM):
    1. test  eax, eax        // проверка V1 на nil
    2. jz    @ret_zero
    3. test  edx, edx        // проверка V2 на nil
    4. jz    @ret_zero
    5. mov   ecx, [eax - 4]  // длина V1
    6. test  ecx, ecx        // проверка длины V1
    7. jz    @ret_zero
    8. cmp   ecx, [edx - 4]  // сравнение длин
    9. jne   @ret_zero
    Код (ASM):
    1. mov   ecx, [eax - 4]  // сразу берем длину V1
    2. test  ecx, ecx        // проверка длины V1 = 0?
    3. jz    @@ZeroResult
    4. cmp   ecx, [edx - 4]  // сравнение длин
    5. jne   @@ZeroResult
    --- Сообщение объединено, 26 фев 2026 ---
    Зря убрал ebx в самом начале.
    Код (ASM):
    1. function EuclidDist(const V1, V2: TVector): Double; assembler;
    2. asm
    3.   // EAX = V1 ptr, EDX = V2 ptr
    4.  
    5.   push  ebx
    6.   push  esi
    7.   push  edi
    8.  
    9.   // --- nil checks (âàæíî äëÿ íà䏿íîñòè)
    10.   test  eax, eax
    11.   jz    @@Zero
    12.   test  edx, edx
    13.   jz    @@Zero
    14.  
    15.   // --- lengths
    16.   mov   ecx, [eax-4]          // len1
    17.   test  ecx, ecx
    18.   jz    @@Zero
    19.   cmp   ecx, [edx-4]          // len2
    20.   jne   @@Zero
    21.  
    22.   mov   esi, eax              // p1
    23.   mov   edi, edx              // p2
    24.  
    25.   // ebx = blocks of 8 doubles, eax = remainder
    26.   mov   ebx, ecx
    27.   shr   ebx, 3                // /8
    28.   mov   eax, ecx
    29.   and   eax, 7                // %8
    30.  
    31.   // accumulators
    32.   xorps xmm0, xmm0
    33.   xorps xmm1, xmm1
    34.   xorps xmm2, xmm2
    35.   xorps xmm3, xmm3
    36.  
    37.   test  ebx, ebx
    38.   jz    @@Tail
    39.  
    40. @@Loop:
    41.   // 8 doubles (64 bytes) per iteration, 4 independent accumulators
    42.   movupd xmm4, [esi]
    43.   movupd xmm5, [edi]
    44.   subpd  xmm4, xmm5
    45.   mulpd  xmm4, xmm4
    46.   addpd  xmm0, xmm4
    47.  
    48.   movupd xmm4, [esi+16]
    49.   movupd xmm5, [edi+16]
    50.   subpd  xmm4, xmm5
    51.   mulpd  xmm4, xmm4
    52.   addpd  xmm1, xmm4
    53.  
    54.   movupd xmm4, [esi+32]
    55.   movupd xmm5, [edi+32]
    56.   subpd  xmm4, xmm5
    57.   mulpd  xmm4, xmm4
    58.   addpd  xmm2, xmm4
    59.  
    60.   movupd xmm4, [esi+48]
    61.   movupd xmm5, [edi+48]
    62.   subpd  xmm4, xmm5
    63.   mulpd  xmm4, xmm4
    64.   addpd  xmm3, xmm4
    65.  
    66.   add   esi, 64
    67.   add   edi, 64
    68.   dec   ebx
    69.   jnz   @@Loop
    70.  
    71.   // combine accumulators
    72.   addpd xmm0, xmm1
    73.   addpd xmm2, xmm3
    74.   addpd xmm0, xmm2
    75.  
    76. @@Tail:
    77.   test  eax, eax
    78.   jz    @@Finish
    79.  
    80. @@TailLoop:
    81.   movsd xmm4, [esi]
    82.   movsd xmm5, [edi]
    83.   subsd xmm4, xmm5
    84.   mulsd xmm4, xmm4
    85.   addsd xmm0, xmm4
    86.   add   esi, 8
    87.   add   edi, 8
    88.   dec   eax
    89.   jnz   @@TailLoop
    90.  
    91. @@Finish:
    92.   // ãîðèçîíòàëüíàÿ ñóììà äâóõ lane
    93.   movhlps xmm1, xmm0
    94.   addsd   xmm0, xmm1
    95.   sqrtsd  xmm0, xmm0
    96.  
    97.   // âåðíóòü Double â ST(0) (Delphi Win32)
    98.   sub   esp, 8
    99.   movlpd [esp], xmm0
    100.   fld   qword ptr [esp]
    101.   add   esp, 8
    102.  
    103.   pop   edi
    104.   pop   esi
    105.   pop   ebx
    106.   ret
    107.  
    108. @@Zero:
    109.   fldz
    110.   pop   edi
    111.   pop   esi
    112.   pop   ebx
    113.   ret
    114. end; //EuclidDist
    --- Сообщение объединено, 26 фев 2026 ---
    Код (ASM):
    1. EuclidDist(const V1, V2: TVector): Double; assembler;
    2. asm
    3.   // EAX = V1 data ptr (or nil)
    4.   // EDX = V2 data ptr (or nil)
    5.  
    6.   test  eax, eax
    7.   jz    @@Zero
    8.   test  edx, edx
    9.   jz    @@Zero
    10.  
    11.   mov   ecx, [eax-4]      // len1
    12.   test  ecx, ecx
    13.   jz    @@Zero
    14.   cmp   ecx, [edx-4]      // len2
    15.   jne   @@Zero
    16.  
    17.   // ---- теперь можно сохранять callee-saved, т.к. точно работаем дальше
    18.   push  ebx
    19.   push  esi
    20.   push  edi
    21.  
    22.   mov   esi, eax          // p1
    23.   mov   edi, edx          // p2
    24.  
    25.   // ebx = blocks of 8 doubles, edx = remainder (0..7)
    26.   mov   ebx, ecx
    27.   shr   ebx, 3
    28.   and   ecx, 7            // остаток оставим в ECX
    29.  
    30.   xorps xmm0, xmm0
    31.   xorps xmm1, xmm1
    32.   xorps xmm2, xmm2
    33.   xorps xmm3, xmm3
    34.  
    35.   // ---- optional aligned fast-path
    36.   mov   eax, esi
    37.   or    eax, edi
    38.   test  eax, 15
    39.   jnz   @@Unaligned
    40.  
    41. @@Aligned:
    42.   test  ebx, ebx
    43.   jz    @@Tail
    44.  
    45. @@LoopA:
    46.   movapd xmm4, [esi]
    47.   movapd xmm5, [edi]
    48.   subpd  xmm4, xmm5
    49.   mulpd  xmm4, xmm4
    50.   addpd  xmm0, xmm4
    51.  
    52.   movapd xmm4, [esi+16]
    53.   movapd xmm5, [edi+16]
    54.   subpd  xmm4, xmm5
    55.   mulpd  xmm4, xmm4
    56.   addpd  xmm1, xmm4
    57.  
    58.   movapd xmm4, [esi+32]
    59.   movapd xmm5, [edi+32]
    60.   subpd  xmm4, xmm5
    61.   mulpd  xmm4, xmm4
    62.   addpd  xmm2, xmm4
    63.  
    64.   movapd xmm4, [esi+48]
    65.   movapd xmm5, [edi+48]
    66.   subpd  xmm4, xmm5
    67.   mulpd  xmm4, xmm4
    68.   addpd  xmm3, xmm4
    69.  
    70.   add   esi, 64
    71.   add   edi, 64
    72.   dec   ebx
    73.   jnz   @@LoopA
    74.   jmp   @@AfterMain
    75.  
    76. @@Unaligned:
    77.   test  ebx, ebx
    78.   jz    @@Tail
    79.  
    80. @@LoopU:
    81.   movupd xmm4, [esi]
    82.   movupd xmm5, [edi]
    83.   subpd  xmm4, xmm5
    84.   mulpd  xmm4, xmm4
    85.   addpd  xmm0, xmm4
    86.  
    87.   movupd xmm4, [esi+16]
    88.   movupd xmm5, [edi+16]
    89.   subpd  xmm4, xmm5
    90.   mulpd  xmm4, xmm4
    91.   addpd  xmm1, xmm4
    92.  
    93.   movupd xmm4, [esi+32]
    94.   movupd xmm5, [edi+32]
    95.   subpd  xmm4, xmm5
    96.   mulpd  xmm4, xmm4
    97.   addpd  xmm2, xmm4
    98.  
    99.   movupd xmm4, [esi+48]
    100.   movupd xmm5, [edi+48]
    101.   subpd  xmm4, xmm5
    102.   mulpd  xmm4, xmm4
    103.   addpd  xmm3, xmm4
    104.  
    105.   add   esi, 64
    106.   add   edi, 64
    107.   dec   ebx
    108.   jnz   @@LoopU
    109.  
    110. @@AfterMain:
    111.   addpd xmm0, xmm1
    112.   addpd xmm2, xmm3
    113.   addpd xmm0, xmm2
    114.  
    115. @@Tail:
    116.   test  ecx, ecx
    117.   jz    @@Finish
    118.  
    119. @@TailLoop:
    120.   movsd xmm4, [esi]
    121.   movsd xmm5, [edi]
    122.   subsd xmm4, xmm5
    123.   mulsd xmm4, xmm4
    124.   addsd xmm0, xmm4
    125.   add   esi, 8
    126.   add   edi, 8
    127.   dec   ecx
    128.   jnz   @@TailLoop
    129.  
    130. @@Finish:
    131.   movhlps xmm1, xmm0
    132.   addsd   xmm0, xmm1
    133.   sqrtsd  xmm0, xmm0
    134.  
    135.   // return Double via x87 ST(0)
    136.   sub   esp, 8
    137.   movsd qword ptr [esp], xmm0
    138.   fld   qword ptr [esp]
    139.   add   esp, 8
    140.  
    141.   pop   edi
    142.   pop   esi
    143.   pop   ebx
    144.   ret
    145.  
    146. @@Zero:
    147.   fldz
    148.   ret
    149. end;
     
  7. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    595
    Есть такое:
    Код (Text):
    1. function FastInvSqrt(x: Double): Double;
    2. var
    3.   i: Int64 absolute x;
    4.   y: Double;
    5. begin
    6.   y := x;
    7.   i := $5FE6EB50C7B537A9 - (i shr 1);  // магическая константа для Double
    8.   Result := y * (1.5 - (x * 0.5 * y * y));  // одна итерация Ньютона
    9. end;
    Смысл такой - вообще не использовать блок математики, что бы шедулер его не сохранял(~fxsave).

    --- Сообщение объединено, 27 фев 2026 ---
    Посмотрел разницу, за 8s отношение числа итераций simd/fpu = 8. Тоесть sse быстрее почти на порядок. Это не много, если вычисления за короткий интервал времени.
     

    Вложения:

    • test.7z
      Размер файла:
      783 байт
      Просмотров:
      65
    Research нравится это.
  8. Ahimov

    Ahimov Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2024
    Сообщения:
    595
    6, но не суть. prefetch смысла вообще наверно нет проверять.

    Норм вариант - распараллелить вычисления в потоках.
     
  9. Research

    Research Active Member

    Публикаций:
    1
    Регистрация:
    6 янв 2024
    Сообщения:
    455
    Если несложно, можешь написать пример? Самый луший способ обмена мыслями это исходник.
    Программа тоже мысль. Говорят если она весит немного, килобайта 3(как test.exe) то безопасна.

    Брат. Я нуб. И мне лучше исходник.
    --- Сообщение объединено, 27 фев 2026 ---
    Современным процессорам это будет только мешать.
    Современным процессорам в моем нубском исполнении это будет как х*уй в спину.
     
    Последнее редактирование: 27 фев 2026
  10. Application

    Application Active Member

    Публикаций:
    1
    Регистрация:
    15 окт 2022
    Сообщения:
    160
    Последнее редактирование: 27 фев 2026