Добавил:
Кафедра ВТ Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
2 лаба / lab2.docx
Скачиваний:
5
Добавлен:
07.04.2023
Размер:
749.33 Кб
Скачать

4. Оптимизация кода с помощью ассемблерной вставки

Как было сказано в пункте с intrinsic компилятор не будет задействовать все регистры при выключенной автоматической оптимизацией. Попробовать исправить это можно с помощью ассемблерных вставок.

Перепишем функцию calc_pi:

float calc_pi(unsigned N_iters) { const float N_f = (float)N_iters; float pi = 0.0; #pragma omp parallel { unsigned th_n = omp_get_num_threads(); unsigned th_i = omp_get_thread_num(); unsigned iter_per_th = N_iters / th_n; unsigned lb = iter_per_th*th_i; unsigned ub = 5051; if(th_i == th_n-1) ub = N_iters-1; else ub = lb + iter_per_th-1; float pi_local = 0.0; ALIGNED_(32) float vres[8]; ALIGNED_(32) float v8[8]; ALIGNED_(32) float onev[8]; ALIGNED_(32) float Nm[8]; onev[0] = 1.0; onev[1] = 1.0; onev[2] = 1.0; onev[3] = 1.0; onev[4] = 1.0; onev[5] = 1.0; onev[6] = 1.0; onev[7] = 1.0; Nm[0] = N_f; Nm[1] = N_f; Nm[2] = N_f; Nm[3] = N_f; Nm[4] = N_f; Nm[5] = N_f; Nm[6] = N_f; Nm[7] = N_f; for(unsigned i = lb; i <= ub; i+=8) { float j = (float)i + 0.5; v8[0] = j ; v8[1] = j+1.0; v8[2] = j+2.0; v8[3] = j+3.0; v8[4] = j + 4.0; v8[5] = j+5.0; v8[6] = j+6.0; v8[7] = j+7.0; __asm__ __volatile__( "vmovaps (%[v8]), %%ymm0 \n\t" "vmovaps (%[Nm]), %%ymm1 \n\t" "vmovaps (%[onev]), %%ymm2 \n\t" "vdivps %%ymm1, %%ymm0, %%ymm0 \n\t" "vmulps %%ymm0, %%ymm0, %%ymm0 \n\t" "vaddps %%ymm0, %%ymm2, %%ymm0 \n\t" "vdivps %%ymm0, %%ymm2, %%ymm0 \n\t" "vhaddps %%ymm0, %%ymm0, %%ymm0 \n\t" "vhaddps %%ymm0, %%ymm0, %%ymm0 \n\t" "vmovaps %%ymm0, %[res] \n\t" : [res] "=m"(*vres) : [v8] "r"(v8), [Nm] "r"(Nm), [onev] "r"(onev) : "%ymm0", "%ymm1", "%ymm2" ); pi_local += vres[0] + vres[7]; } #pragma omp atomic pi += pi_local; } pi *= 4.0; pi /= N_iters; return pi; }

Компилируем:

> CC lab1_4.c -o lab1_4 -O0 -Wall -fopenmp

Исходный код программы lab1_4.c представлен в приложении.

Сделаем замеры:

> ./lab1_4 # CLANG: # CPU time spent: 70.223842 sec (70223842 us) # Real time spent: 11.750158 sec (11750158 us) # GCC: # CPU time spent: 41.517682 sec (41517682 us) # Real time spent: 6.941952 sec (6941952 us)

Вот что perf говорит:

> perf stat -B -e task-clock,context-switches,cpu-migrations,cycles,instructions,cache-references,cache-misses,branches,branch-misses,migrations,page-faults ./lab1_4 # Performance counter stats for './lab1_4': CLANG # 70 366,40 msec task-clock:u # 5,967 CPUs utilized # 0 context-switches:u # 0,000 /sec # 0 cpu-migrations:u # 0,000 /sec # 272 702 829 419 cycles:u # 3,875 GHz # 95 982 680 986 instructions:u # 0,41 insn per cycle # 5 318 969 cache-references:u # 75,590 K/sec # 100 485 cache-misses:u # 1,889 % of all cache refs # 2 814 020 274 branches:u # 39,991 M/sec # 223 127 branch-misses:u # 0,01% of all branches # 0 migrations:u # 0,000 /sec # 228 page-faults:u # 3,240 /sec # Performance counter stats for './lab1_4': GCC # 41 703,38 msec task-clock:u # 5,967 CPUs utilized # 0 context-switches:u # 0,000 /sec # 0 cpu-migrations:u # 0,000 /sec # 161 701 029 546 cycles:u # 3,877 GHz # 78 869 553 297 instructions:u # 0,49 insn per cycle # 1 880 643 cache-references:u # 45,096 K/sec # 29 077 cache-misses:u # 1,546 % of all cache refs # 5 032 042 739 branches:u # 120,663 M/sec # 62 215 branch-misses:u # 0,00% of all branches # 0 migrations:u # 0,000 /sec # 83 page-faults:u # 1,990 /sec

Также стоит сказать, что при одном потоке получаются следующие результаты:

> ./lab1_4 # 1 thread # CLANG: # CPU time spent: 57.284885 sec (57284885 us) # Real time spent: 57.352539 sec (57352539 us) # GCC: # CPU time spent: 28.499533 sec (28499533 us) # Real time spent: 28.532705 sec (28532705 us) > perf stat -B -e task-clock,context-switches,cpu-migrations,cycles,instructions,cache-references,cache-misses,branches,branch-misses,migrations,page-faults ./lab1_4 # 1 thread # Performance counter stats for './lab1_4': CLANG # 69 645,23 msec task-clock:u # 0,998 CPUs utilized # 0 context-switches:u # 0,000 /sec # 0 cpu-migrations:u # 0,000 /sec # 270 103 347 662 cycles:u # 3,878 GHz # 95 015 639 694 instructions:u # 0,35 insn per cycle # 1 793 502 cache-references:u # 25,752 K/sec # 586 341 cache-misses:u # 32,693 % of all cache refs # 2 501 445 503 branches:u # 35,917 M/sec # 42 326 branch-misses:u # 0,00% of all branches # 0 migrations:u # 0,000 /sec # 188 page-faults:u # 2,699 /sec # Performance counter stats for './lab1_4': GCC # 40 993,49 msec task-clock:u # 0,998 CPUs utilized # 0 context-switches:u # 0,000 /sec # 0 cpu-migrations:u # 0,000 /sec # 158 984 307 961 cycles:u # 3,878 GHz # 78 759 458 673 instructions:u # 0,50 insn per cycle # 760 046 cache-references:u # 18,541 K/sec # 231 869 cache-misses:u # 30,507 % of all cache refs # 5 000 830 457 branches:u # 121,991 M/sec # 14 567 branch-misses:u # 0,00% of all branches # 0 migrations:u # 0,000 /sec # 74 page-faults:u # 1,805 /sec

Получается, если сравнивать вариант с intrinsic и ассемблерными вставками при компиляторе gcc, то ускорение почти в 56.3/28.5 = 1.98 раза.

Сведём в таблицу:

время

IPC

cache-misses

gcc

6.9

0,49

1,5

clang

11.8

0,41

1,9

Соседние файлы в папке 2 лаба