Advertisement
alexsetyaev

task_6_gather

Oct 1st, 2021
921
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.86 KB | None | 0 0
  1. #include <cfloat>
  2. #include <chrono>
  3. #include <cuda_profiler_api.h>
  4. #include <iostream>
  5.  
  6. using namespace std;
  7.  
  8. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  9.  
  10. #define SAFE_CALL( CallInstruction ) { \
  11.     cudaError_t cuerr = CallInstruction; \
  12.     if(cuerr != cudaSuccess) { \
  13.          printf("CUDA error: %s at call \"" #CallInstruction "\"\n", cudaGetErrorString(cuerr)); \
  14.          throw "error in CUDA API function, aborting..."; \
  15.     } \
  16. }
  17.  
  18. #define SAFE_KERNEL_CALL( KernelCallInstruction ){ \
  19.     KernelCallInstruction; \
  20.     cudaError_t cuerr = cudaGetLastError(); \
  21.     if(cuerr != cudaSuccess) { \
  22.         printf("CUDA error in kernel launch: %s at kernel \"" #KernelCallInstruction "\"\n", cudaGetErrorString(cuerr)); \
  23.         throw "error in CUDA kernel launch, aborting..."; \
  24.     } \
  25.     cuerr = cudaDeviceSynchronize(); \
  26.     if(cuerr != cudaSuccess) { \
  27.         printf("CUDA error in kernel execution: %s at kernel \"" #KernelCallInstruction "\"\n", cudaGetErrorString(cuerr)); \
  28.         throw "error in CUDA kernel execution, aborting..."; \
  29.     } \
  30. }
  31.  
  32. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  33.  
  34. void __global__ gather(int *ptrs, int *connections, int *outgoing_ids, int vertices_count, int *data, int *result)
  35. {
  36.     const long long src_id = (blockIdx.x * blockDim.x + threadIdx.x) / 32;
  37.    
  38.     if (src_id < vertices_count)
  39.     {
  40.         const int first_edge_ptr = ptrs[src_id];
  41.         const int connections_count = connections[src_id];
  42.         //connections_count = ptrs[src_id + 1] - ptrs[src_id];
  43.  
  44.         for(register int cur_edge = threadIdx.x % 32; cur_edge < connections_count; cur_edge += 32)
  45.         {
  46.             // first_edge_ptr + cur_edge - индекс текущего ребра в массивах
  47.             int dst_id = outgoing_ids[first_edge_ptr + cur_edge];
  48.             int val = data[dst_id];
  49.             result[first_edge_ptr + cur_edge] = val;
  50.  
  51.             // данную программу можно легко переделать во многие графовые алгоритмы, например:
  52.             /* BFS
  53.             int src_level = data[src_id];
  54.             int dst_level = data[dst_id];
  55.             if((src_level == current_level) && (dst_level == UNVISITED_VERTEX))
  56.             {
  57.                 data[dst_id] = current_level + 1;
  58.             }
  59.             */
  60.  
  61.             /* SSSP
  62.             float weight = outgoing_weights[first_edge_ptr + cur_edge];
  63.             float src_weight = data[src_id];
  64.             float dst_weight = data[dst_id];
  65.  
  66.             if(dst_weight > src_weight + weight)
  67.             {
  68.                 data[dst_id] = src_weight + weight;
  69.             }
  70.             */
  71.         }
  72.     }
  73. }
  74.  
  75.  
  76. ///////////////////////////////////////////////////////////////////////////////////////////////////////////
  77.  
  78. int main()
  79. {
  80.     int vertices_count = 1024*1024;
  81.  
  82.     int *ptrs = new int[vertices_count];
  83.     int *data = new int[vertices_count];
  84.     int *connections = new int[vertices_count];
  85.  
  86.     int pos = 0;
  87.     for(int i = 0; i < vertices_count; i++) // TODO (bonus) граф с несколькими "большими" вершинами
  88.     {
  89.         ptrs[i] = pos;
  90.         connections[i] = 16 + rand()%32;
  91.         pos += connections[i];
  92.  
  93.         data[i] = rand();
  94.     }
  95.  
  96.     int edges_count = pos;
  97.     int *outgoing_ids = new int[edges_count];
  98.     int *result = new int[edges_count];
  99.     for(int i = 0; i < edges_count; i++)
  100.     {
  101.         outgoing_ids[i] = rand()%vertices_count;
  102.     }
  103.  
  104.     int *dev_ptrs; int *dev_connections; int *dev_outgoing_ids; int *dev_data; int *dev_result;
  105.     cudaMalloc((void**)&dev_ptrs, vertices_count*sizeof(int));
  106.     cudaMalloc((void**)&dev_connections, vertices_count*sizeof(int));
  107.     cudaMalloc((void**)&dev_data, vertices_count*sizeof(int));
  108.  
  109.     cudaMalloc((void**)&dev_outgoing_ids, edges_count*sizeof(int));
  110.     cudaMalloc((void**)&dev_result, edges_count*sizeof(int));
  111.  
  112.     SAFE_CALL(cudaMemcpy(dev_ptrs, ptrs, vertices_count * sizeof(int), cudaMemcpyHostToDevice));
  113.     SAFE_CALL(cudaMemcpy(dev_connections, connections, vertices_count * sizeof(int), cudaMemcpyHostToDevice));
  114.     SAFE_CALL(cudaMemcpy(dev_data, data, vertices_count * sizeof(int), cudaMemcpyHostToDevice));
  115.     SAFE_CALL(cudaMemcpy(dev_outgoing_ids, outgoing_ids, edges_count * sizeof(int), cudaMemcpyHostToDevice));
  116.  
  117.     dim3 compute_threads(1024);
  118.     dim3 compute_blocks(32*((vertices_count - 1) / compute_threads.x + 1));
  119.  
  120.     for(int i = 0; i < 5; i++)
  121.     {
  122.         auto start = std::chrono::steady_clock::now();
  123.         SAFE_KERNEL_CALL((gather <<< compute_blocks, compute_threads >>> (dev_ptrs, dev_connections, dev_outgoing_ids, vertices_count, dev_data, dev_result)));
  124.         auto end = std::chrono::steady_clock::now(); // TODO почему работает данный замер веремени?
  125.         std::chrono::duration<double> elapsed_seconds = end-start;
  126.         cout << "time: " << (elapsed_seconds.count())*1000.0 << " ms" << endl;
  127.         cout << "bandwidth: " << 3.0*sizeof(int)*edges_count/((elapsed_seconds.count())*1e9) << " GB/s" << endl << endl;
  128.     }
  129.  
  130.     int *copy_device_result = new int[edges_count];
  131.  
  132.     SAFE_CALL(cudaMemcpy(copy_device_result, dev_result, edges_count * sizeof(int), cudaMemcpyDeviceToHost));
  133.  
  134.     for(int src_id = 0; src_id < vertices_count; src_id++)
  135.     {
  136.         const int first_edge_ptr = ptrs[src_id];
  137.         const int connections_count = connections[src_id];
  138.         for(register int cur_edge = 0; cur_edge < connections_count; cur_edge++)
  139.         {
  140.             int dst_id = outgoing_ids[first_edge_ptr + cur_edge];
  141.             int val = data[dst_id];
  142.             result[first_edge_ptr + cur_edge] = val;
  143.         }
  144.     }
  145.  
  146.  
  147.     // TODO check
  148.     int errors_count = 0;
  149.     for(int i = 0; i < edges_count; i++)
  150.     {
  151.         if(result[i] != copy_device_result[i])
  152.         {
  153.             errors_count++;
  154.         }
  155.     }
  156.     cout << errors_count << endl;
  157.  
  158.  
  159.     // TODO какие 3 недостатка у текущей версии ядра?
  160.  
  161.     // TODO отпрофилировать текущую версию, сделать выводы о её производитлеьности
  162.  
  163.     // TODO сделать оптимизированную версию ядра
  164.  
  165.     // TODO (bonus) реализовать базовую версию BFS алгоритма (выделить структуры данных и реализовать сам алгоритм)
  166.  
  167.     cudaFree(dev_data);
  168.     cudaFree(dev_ptrs);
  169.     cudaFree(dev_connections);
  170.     cudaFree(dev_result);
  171.     cudaFree(dev_outgoing_ids);
  172.  
  173.     delete[]result;
  174.     delete[]data;
  175.     delete[]ptrs;
  176.     delete[]outgoing_ids;
  177.     delete[]connections;
  178.    
  179.     return 0;
  180. }
  181.  
  182.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement