<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      高性能計算-GPU單進程多卡(多流)并行計算編程模型示例(25)

      1. 簡介

      (1) 使用CPU對向量點乘進行串行計算
      (2) 對數據進行分塊,使用單進程多卡(多流)并行計算
      (3) 使用不同數據規模,比較加速比的變化

      2. 代碼

      #include <stdio.h>
      #include <sys/time.h>
      #include <stdlib.h>
      
      #define CUDA_ERROR_CHECK
      
      int nGpus = 1;                  //gpu數量
      int blockSize = 256;            //線程塊大小
      int leftBit = 10;               //數據規模左移位數
      unsigned long nSize = 1LL << leftBit;    //方陣維度
      float *hostA = NULL;            //向量 A
      float *hostB = NULL;            //向量 B
      float *hostResult = NULL;       //串行計算結果
      float *deviceResult = NULL;      //gpu計算結果
      
      
      //宏定義檢查API調用是否出錯
      #define CudaCall(err) __cudaSafeCall(err,__FILE__,__LINE__)
      inline void __cudaSafeCall(cudaError_t err,const char* file,const int line)
      {
          #ifdef CUDA_ERROR_CHECK
          if(err!=cudaSuccess)
          {
              fprintf(stderr,"cudaSafeCall failed at %s:%d :(%d) %s\n",file,line,err,cudaGetErrorString(err));
              exit(-1);
          }
          #endif
      }
      
      //宏定義檢查獲取流中的執行錯誤,主要是對核函數
      #define CudaCheck() _cudaCheckError(__FILE__,__LINE__)
      inline void _cudaCheckError(const char * file,const int line)
      {
          #ifdef CUDA_ERROR_CHECK
          cudaError_t err = cudaGetLastError();
          if(err != cudaSuccess)
          {
              fprintf(stderr,"cudaCheckError failed at %s:%d :(%d) %s\n",file,line,err,cudaGetErrorString(err));
              exit(-1);
          }
          #endif
      }
      
      //ms
      long getTime()
      {
          struct timeval cur;
          gettimeofday(&cur, NULL);
          // printf("sec %ld usec %ld,toal ms %ld\n",cur.tv_sec,cur.tv_usec,cur.tv_sec*1e3 + cur.tv_usec / 1e3);
          return cur.tv_sec*1e3 + cur.tv_usec / 1e3;
      }
      
      void initData(float *A,float *B,unsigned long len)
      {
          //設置隨機數種子
          srand(0);
          // len = 10;
          for(unsigned long i=0;i<len;i++)
          {
              A[i] = (float)rand()/RAND_MAX;
              B[i] = (float)rand()/RAND_MAX;
              // printf("%f %f\n",A[i],B[i]);
          }
      }
      
      //cpu 串行計算
      long serial(unsigned long len)
      {
          long start = getTime();
          for(unsigned long i=0;i<len;i++)
              hostResult[i] = hostA[i] * hostB[i];
          long end = getTime();
          // printf("cpu time %d\n",end-start);
          return end-start;
      }
      
      __global__ void kernel(float *A,float *B,float *result,unsigned long len)
      {
          unsigned long id = blockIdx.x * blockDim.x + threadIdx.x;
          if(id<len)
              result[id] = A[id] * B[id];
      }
      
      //gpu多卡并行
      float gpu_multi(float *result,unsigned long len,int ngpus)
      {
          float gpuTime = 0.0;
          //對數據分塊,每個gpu上開辟內存空間存儲數據,并創建一個流,每個GPU計算自己的數據
          //每個流GPU處理的數據個數
          unsigned long nPerGpu = len/ngpus;
          float **deviceA,**deviceB,**deviceResult;
          deviceA = (float**)calloc(ngpus,sizeof(float*));
          deviceB = (float**)calloc(ngpus,sizeof(float*));
          deviceResult = (float**)calloc(ngpus,sizeof(float*));
          cudaStream_t *streams = (cudaStream_t*)calloc(ngpus,sizeof(cudaStream_t));
          //在gpu上分配內存空間
          for(int i=0;i<ngpus;i++)
          {
              CudaCall(cudaSetDevice(i));
              CudaCall(cudaMalloc((void**)&deviceA[i],nPerGpu*sizeof(float)));
              CudaCall(cudaMalloc((void**)&deviceB[i],nPerGpu*sizeof(float)));
              CudaCall(cudaMalloc((void**)&deviceResult[i],nPerGpu*sizeof(float)));
              CudaCall(cudaStreamCreate(streams+i));
          }
          //事件記錄在默認流
          cudaEvent_t start,end;
          CudaCall(cudaSetDevice(0));
          CudaCall(cudaEventCreate(&start));
          CudaCall(cudaEventCreate(&end));
          CudaCall(cudaEventRecord(start,streams[0]));
          for(int i=0;i<ngpus;i++)
          {
              CudaCall(cudaSetDevice(i));
              //異步數據拷貝
              CudaCall(cudaMemcpyAsync(deviceA[i],hostA+i*nPerGpu,nPerGpu*sizeof(float),cudaMemcpyHostToDevice,streams[i]));
              CudaCall(cudaMemcpyAsync(deviceB[i],hostB+i*nPerGpu,nPerGpu*sizeof(float),cudaMemcpyHostToDevice,streams[i]));
              //計算
              int gridDim = (nPerGpu-1)/blockSize + 1;
              kernel<<<gridDim,blockSize,0,streams[i]>>>(deviceA[i],deviceB[i],deviceResult[i],nPerGpu);
              CudaCheck();
              //異步拷貝數據
              CudaCall(cudaMemcpyAsync(result+i*nPerGpu,deviceResult[i],nPerGpu*sizeof(float),cudaMemcpyDeviceToHost,streams[i]));
          }
          CudaCall(cudaSetDevice(0));
          CudaCall(cudaEventRecord(end,streams[0]));
          //流同步
          for(int i=0;i<ngpus;i++)
          {
              CudaCall(cudaSetDevice(i));
              CudaCall(cudaStreamSynchronize(streams[i]));
          }
          // CudaCall(cudaEventSynchronize(end));
          CudaCall(cudaEventElapsedTime(&gpuTime,start,end));
      
          //free
          CudaCall(cudaEventDestroy(start));
          CudaCall(cudaEventDestroy(end));
          for(int i=0;i<ngpus;i++)
          {
              CudaCall(cudaSetDevice(i));
              CudaCall(cudaFree(deviceA[i]));
              CudaCall(cudaFree(deviceB[i]));
              CudaCall(cudaFree(deviceResult[i]));
              CudaCall(cudaStreamDestroy(streams[i]));
          }
          
          cudaFree(deviceA);
          cudaFree(deviceB);
          cudaFree(deviceResult);
          free(streams);
          // printf("gpu time %f\n",gpuTime);
          return gpuTime;
      }
      
      int main(int argc, char* argv[])
      {
          cudaDeviceProp prop;
          int globalMemSize = 0;
          int memSize = 0;    //對單卡顯存需求大小
          CudaCall(cudaGetDeviceProperties(&prop ,0));
          globalMemSize = (float)prop.totalGlobalMem/1024/1024;
          // printf("compute capability %d.%d\n", prop.major,prop.minor);//k80 3.7
          // printf("Memory clock rate: %d\n",prop.memoryClockRate);
          // printf("global memory:%dMB\n",globalMemSize);
      
          //獲得 device 數量
          CudaCall(cudaGetDeviceCount(&nGpus));
          //限制參數設置的最大gpu數量
          if(argc==3)
          {
              leftBit = atoi(argv[2]);
              nSize = 1LL << leftBit;
              int n = atoi(argv[1]);
      	//當gpu數量設置為3時,nSize%n !=0,使用最大gpu數量計算
              nGpus = ((n > nGpus || nSize%n !=0)?nGpus:n);
              memSize = nSize*sizeof(float)*3/nGpus/1024/1024;
              //判斷顯存是否夠用,k80 單卡可用顯存為 11441MB
              if(memSize > globalMemSize)
              {
                  printf("one gpu memory not enough gater %dMB\n",globalMemSize);
                  exit(-1);
              }
          }
          else
          {
              printf("parameter 1:ngpus 2:matrix dim 2^(_)\n");
              exit(-1);
          }
      
          unsigned long nBytes = nSize * sizeof(float);   //單個向量字節數
          //數據初始化,開辟主機鎖頁內存
          // hostA = (float*)calloc(nSize,sizeof(float));
          // hostB = (float*)calloc(nSize,sizeof(float));
          // hostResult = (float*)calloc(nSize,sizeof(float));
          CudaCall(cudaMallocHost((void**)&hostA,nBytes));
          CudaCall(cudaMallocHost((void**)&hostB,nBytes));
          CudaCall(cudaMallocHost((void**)&hostResult,nBytes));
          CudaCall(cudaMallocHost((void**)&deviceResult,nBytes));
          initData(hostA,hostB,nSize);
      
          //串行計算
          long cpuTime = serial(nSize);
      
          //多GPU計算
          float gpuTime = gpu_multi(deviceResult,nSize,nGpus);
      
          printf("單個向量長度 2^%ld,單個顯卡三個數組需要顯存 %dMB,使用 %d個GPU,cpu串行耗時 %ldms,GPU并行數據傳輸和計算耗時 %fms,加速比: %f\n",\
          leftBit,memSize,nGpus,cpuTime,gpuTime,cpuTime/gpuTime);
      
          cudaFreeHost(hostA);
          cudaFreeHost(hostB);
          cudaFreeHost(hostResult);
          cudaFreeHost(deviceResult);
          return 0;
      }
      

      3. 測試腳本

      #!/bin/bash
      # 編譯
      nvcc pointMul.cu -o pointMul
      dir=out
      # 清空文件夾
      > "$dir"
      
      echo "start $(date)" >> out
      
      # 串行計算
      # for((i=0;i<4;i++)); do
      #     yhrun -N1 -n1 -pTH_GPU ./matrix_add2D 0 | tee -a "$dir"
      # done
      
      # 顯卡數量
      nGpus=(1 2 3 4)   
      # 數據規模 2^(S)
      S=(24 28 30 31)
      
      
      # gpu
      for n in "${nGpus[@]}"; do
          for s in "${S[@]}"; do
              for((i=0;i<3;i++)); do
                  yhrun -N1 -n1 -pTH_GPU ./pointMul "$n" "$s" | tee -a "$dir"
              done
          done
      done
      
      echo "end $(date)" >> out
      

      4. 測試數據

      由于測試腳本的限制,CPU串行計算在GPU單卡(K80 12G顯存)、雙卡、四卡測試中分別跑了一輪,數據如下:

      數據長度 gpu單卡(ms) gpu2個卡(ms) gpu4個卡(ms)
      2^24 44.3 44.7 44
      2^28 719.7 717.3 703.3
      2^30 - 2988.7 2951.7
      2^31 - - 5906.7

      GPU測試耗時及加速比數據:

      數據長度 gpu單卡(ms) gpu2個卡(ms) gpu4個卡(ms)
      2^24(耗時/加速比) 27.9/1.6 17.7/2.5 17.1/2.6
      2^28(耗時/加速比) 399.8/1.8 273.6/2.6 273.9/2.6
      2^30(耗時/加速比) 顯存不足 985/3.0 1056.3/2.8
      2^31(耗時/加速比) 顯存不足 顯存不足 1942.4/3.0

      5. 結果分析

      (1)GPU比CPU計算有明顯的性能提升,根據數據規模,數據量越大提升越明顯。
      (2)GPU數量越多,計算效率提升越高,數據規模越大,提升越明顯。

      posted @ 2025-02-19 16:56  安洛8  閱讀(136)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 日韩av一区二区精品不卡| 日本亚洲一区二区精品| av午夜久久蜜桃传媒软件| 国产综合久久久久鬼色| 日韩大尺度一区二区三区| 日本成熟少妇喷浆视频| 一区二区三区国产亚洲网站| 久久成人成狠狠爱综合网| 电影在线观看+伦理片| 2019国产精品青青草原| 自拍第一区视频在线观看| 亚洲中文字幕日产无码成人片| 亚洲人妻系列中文字幕| 精品一区二区三区女性色| 一 级做人爱全视频在线看| 久久夜色撩人精品国产av| 国产欧美日韩亚洲一区二区三区| 四虎影视库国产精品一区| 亚洲午夜精品国产电影在线观看| 亚洲无人区一区二区三区| 99久久精品国产一区二区蜜芽| 高清不卡一区二区三区| 亚洲人午夜射精精品日韩| 国产浮力第一页草草影院| 国产乱码日韩亚洲精品成人| 又色又污又爽又黄的网站| 安阳县| 亚洲av激情久久精品人| 中国CHINA体内裑精亚洲日本| 亚洲精品美女一区二区| 亚洲成人午夜排名成人午夜| 国产女人高潮视频在线观看| 河间市| 人人爽人人爽人人片a免费| 亚洲丰满熟女一区二区蜜桃| 少妇高潮喷水正在播放| 国内揄拍国内精品对久久| 国产免费久久精品44| 99久久无色码中文字幕| 亚洲精品一区二区口爆| 亚洲欧美一区二区三区在线|