日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Openacc多卡优化Floyd算法

發布時間:2024/1/18 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Openacc多卡优化Floyd算法 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

狀態轉移方程

常規的Floyd算法目的在于找最短路,狀態轉移方程為:dis[i,j]=min{dis[i,k]+dis[k,j],dis[i,j]},距離矩陣初始化為正無窮;本實驗目的在于找最長路,所以狀態轉移方程:dis[i,j]=max{dis[i,k]+dis[k,j],dis[i,j]},距離矩陣初始化為負無窮。

優化思路

眾所周知Floyd算法的最外層循環k存在dependence,是不能并行的,所以重點在于如何并行內層的兩重循環。在之前的實驗中我們把內層的i、j兩重循環交給了acc gang和vector,看起來似乎沒有優化空間了。

其實還有一個優化的方向,那就是將數據分塊,不同的顯卡負責不同塊數據的計算。雖然我們使用的是線性數組,但是你可以將它想象為方陣,方陣的寬高是SIZE,橫著把方陣切幾刀,這樣就有了若干個block,每一個block的高度就是blocksize。

優化的核心思路如下圖:

即每張卡并不是齊頭并進,而是有先后順序,通過async來控制異步。

寫代碼的過程中需要經常思考這樣幾個問題:

  • 我的數據傳到了哪里?
  • 顯卡上計算出了什么數據?
  • 顯卡上的數據是否回傳?
  • 計算完成之后哪張顯卡有全部計算好的數據?
  • ……

有幾個小細節需要注意:

  • copy的作用是在GPU上申請內存并將CPU數據拷貝到顯存,在退出data region的時候會從GPU拷貝數據到CPU。把copy分解便是create、copyin和copyout,copyout在多卡的時候會出現問題,如果最后一次copyout恰巧是從擁有完整計算結果的顯卡拷貝,那沒有問題,否則就錯了。所以在本次實驗中我們采用create與copyin的組合。
  • 數據不需要更新地太頻繁,計算完一個block更新一次就可以。
  • data[a:b]的第二個參數是步長而不是終止點。

代碼

floyd.cpp

#define INF 1e7 #include <omp.h> #include <openacc.h> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <assert.h> #include <algorithm> using namespace std;inline int index(const int i, const int j) {return i * SIZE + j; }// add your codes begin #define processor 2 // add your codes endint main() {const int size2 = SIZE * SIZE;float *data = new float[size2];for (int i = 0; i < size2; i++) data[i] = -INF;srand(SIZE);for (int i = 0; i < SIZE*20; i++) {int prev = rand() % SIZE;int next = rand() % SIZE;if ((prev == next) || (data[index(prev, next)] > -INF)) {i--;continue;}data[index(prev, next)] = log((rand() % 99 + 1.0) / 100);}double t = omp_get_wtime();// add your codes beginint blocksize=SIZE/processor;omp_set_num_threads(processor);#pragma omp parallel{int my_gpu=omp_get_thread_num();acc_set_device_num(my_gpu,acc_device_nvidia);#pragma acc data copyin(data[0:size2])//不能使用copy{#pragma omp for schedule(static,1)for(int block=0;block<processor;block++){int istart=block*blocksize;int iend=istart+blocksize;for(int k=0;k<SIZE;k++){#pragma acc parallel loop gang worker num_workers(4) vector_length(128) async(block)for(int i=istart;i<iend;i++){#pragma acc loop vectorfor(int j=0;j<SIZE;j++){if(data[index(i,j)]<data[index(i,k)]+data[index(k,j)]){data[index(i,j)]=data[index(i,k)]+data[index(k,j)];} }}}#pragma acc update self(data[istart*SIZE:SIZE*blocksize]) async(block)}#pragma acc wait}}// add your codes end t = omp_get_wtime() - t;printf("time %f %d\n", t, SIZE);for (int i = 0; i < 20; i++) {int prev = rand() % SIZE;int next = rand() % SIZE;if (prev == next) {i--;continue;}printf("test %d %d %f\n", prev, next, data[index(prev, next)]);} }

run.sh(2卡)

source device.sh 2 make clean # timeout 1m time make serial # timeout 1m time make multicore # timeout 1m time make managed # timeout 1m time make optimize timeout 1m time make multidevice

注釋掉了serial、multicore、managed、optimize,只編譯多卡,這樣縮短了等待時間。

運行結果

2卡2線程的話平均運行時間可以達到1.65~1.75左右。

4卡4線程的話平均運行時間可以達到1.45~1.75左右。

寫在最后

有問題歡迎在評論區討論

總結

以上是生活随笔為你收集整理的Openacc多卡优化Floyd算法的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。