cuda中的count3非常慢

2024-04-08

我在 CUDA 中编写了一个小程序,用于计算 C 数组中有多少个 3 并打印它们。

#include <stdio.h>
#include <assert.h>
#include <cuda.h>
#include <cstdlib>

__global__ void incrementArrayOnDevice(int *a, int N, int *count)
{
    int id = blockIdx.x * blockDim.x + threadIdx.x;

    //__shared__ int s_a[512]; // one for each thread
    //s_a[threadIdx.x] = a[id];

    if( id < N )
    {
        //if( s_a[threadIdx.x] == 3 )
        if( a[id] == 3 )
        {
            atomicAdd(count, 1);
        }
    }
}

int main(void)
{
    int *a_h;   // host memory
    int *a_d;   // device memory

    int N = 16777216;

    // allocate array on host
    a_h = (int*)malloc(sizeof(int) * N);
    for(int i = 0; i < N; ++i)
        a_h[i] = (i % 3 == 0 ? 3 : 1);

    // allocate arrays on device
    cudaMalloc(&a_d, sizeof(int) * N);

    // copy data from host to device
    cudaMemcpy(a_d, a_h, sizeof(int) * N, cudaMemcpyHostToDevice);

    // do calculation on device
    int blockSize = 512;
    int nBlocks = N / blockSize + (N % blockSize == 0 ? 0 : 1);
    printf("number of blocks: %d\n", nBlocks);

    int count;
    int *devCount;
    cudaMalloc(&devCount, sizeof(int));
    cudaMemset(devCount, 0, sizeof(int));

    incrementArrayOnDevice<<<nBlocks, blockSize>>> (a_d, N, devCount);

    // retrieve result from device
    cudaMemcpy(&count, devCount, sizeof(int), cudaMemcpyDeviceToHost);

    printf("%d\n", count);

    free(a_h);
    cudaFree(a_d);
    cudaFree(devCount);
}

我得到的结果是: 真实0m3.025s 用户0m2.989s 系统0m0.029s

当我在 4 个线程的 CPU 上运行它时,我得到: 实际0m0.101s 用户0m0.100s 系统0m0.024s

请注意,GPU 是旧的 - 我不知道确切的型号,因为我没有 root 访问权限,但它运行的 OpenGL 版本是使用 MESA 驱动程序的 1.2。

难道我做错了什么?我该怎么做才能使它运行得更快?

注意:我尝试为每个块使用存储桶(因此每个块的atomicAdd() 都会减少),但我得到了完全相同的性能。 我还尝试将分配给该块的 512 个整数复制到共享内存块(您可以在注释中看到它),并且时间再次相同。


这是为了回答您的问题“我该怎么做才能让它运行得更快?”正如我在评论中提到的,计时方法(可能)存在问题,我对速度改进的主要建议是使用“经典并行缩减”算法。以下代码实现了更好的(在我看来)计时测量,并且还将您的内核转换为缩减风格的内核:

#include <stdio.h>
#include <assert.h>
#include <cstdlib>


#define N (1<<24)
#define nTPB 512
#define NBLOCKS 32

__global__ void incrementArrayOnDevice(int *a, int n, int *count)
{
  __shared__ int lcnt[nTPB];
  int id = blockIdx.x * blockDim.x + threadIdx.x;
  int lcount = 0;
  while (id < n) {
    if (a[id] == 3) lcount++;
    id += gridDim.x * blockDim.x;
    }
  lcnt[threadIdx.x] = lcount;
  __syncthreads();
  int stride = blockDim.x;
  while(stride > 1) {
    // assume blockDim.x is a power of 2
    stride >>= 1;
    if (threadIdx.x < stride) lcnt[threadIdx.x] += lcnt[threadIdx.x + stride];
    __syncthreads();
    }
  if (threadIdx.x == 0) atomicAdd(count, lcnt[0]);
}

int main(void)
{
    int *a_h;   // host memory
    int *a_d;   // device memory
    cudaEvent_t gstart1,gstart2,gstop1,gstop2,cstart,cstop;
    float etg1, etg2, etc;

    cudaEventCreate(&gstart1);
    cudaEventCreate(&gstart2);
    cudaEventCreate(&gstop1);
    cudaEventCreate(&gstop2);
    cudaEventCreate(&cstart);
    cudaEventCreate(&cstop);

    // allocate array on host
    a_h = (int*)malloc(sizeof(int) * N);
    for(int i = 0; i < N; ++i)
        a_h[i] = (i % 3 == 0 ? 3 : 1);

    // allocate arrays on device
    cudaMalloc(&a_d, sizeof(int) * N);

    int blockSize = nTPB;
    int nBlocks = NBLOCKS;
    printf("number of blocks: %d\n", nBlocks);

    int count;
    int *devCount;
    cudaMalloc(&devCount, sizeof(int));
    cudaMemset(devCount, 0, sizeof(int));

    // copy data from host to device
    cudaEventRecord(gstart1);
    cudaMemcpy(a_d, a_h, sizeof(int) * N, cudaMemcpyHostToDevice);
    cudaMemset(devCount, 0, sizeof(int));
    cudaEventRecord(gstart2);
    // do calculation on device

    incrementArrayOnDevice<<<nBlocks, blockSize>>> (a_d, N, devCount);
    cudaEventRecord(gstop2);

    // retrieve result from device
    cudaMemcpy(&count, devCount, sizeof(int), cudaMemcpyDeviceToHost);
    cudaEventRecord(gstop1);

    printf("GPU count = %d\n", count);
    int hostCount = 0;
    cudaEventRecord(cstart);
    for (int i=0; i < N; i++)
      if (a_h[i] == 3) hostCount++;
    cudaEventRecord(cstop);

    printf("CPU count = %d\n", hostCount);
    cudaEventSynchronize(cstop);
    cudaEventElapsedTime(&etg1, gstart1, gstop1);
    cudaEventElapsedTime(&etg2, gstart2, gstop2);
    cudaEventElapsedTime(&etc, cstart, cstop);

    printf("GPU total time   = %fs\n", (etg1/(float)1000) );
    printf("GPU compute time = %fs\n", (etg2/(float)1000));
    printf("CPU time         = %fs\n", (etc/(float)1000));
    free(a_h);
    cudaFree(a_d);
    cudaFree(devCount);
}

当我在相当快的 GPU(Quadro 5000,比 Tesla M2050 慢一点)上运行时,我得到以下结果:

number of blocks: 32
GPU count = 5592406
CPU count = 5592406
GPU total time   = 0.025714s
GPU compute time = 0.000793s
CPU time         = 0.017332s

我们发现 GPU 的计算部分比这种(简单的单线程)CPU 实现要快得多。当我们添加传输数据的成本时,GPU 版本会更慢,但不会慢 30 倍。

通过比较,当我对你的原始算法进行计时时,我得到了这样的数字:

GPU total time   = 0.118131s
GPU compute time = 0.093213s

我的系统配置是 Xeon X5560 CPU、RHEL 5.5、CUDA 5.0、Quadro5000 GPU。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

cuda中的count3非常慢 的相关文章

  • xamarin.forms 从 xaml 到属性的绑定

    我是一个 xaml 绑定的新手 有时我真的不明白 我的 xaml 中有这个
  • 为什么 XRecordDisableContext() 不起作用?

    void Callback XPointer XRecordInterceptData pRecord std cout lt lt my logs n int main if auto const pDisplay XOpenDispla
  • 这是我们可以强制 ObjectDataSource 的唯一方法吗?

    问候 1 我假设对象数据源仅在第一次请求时自动绑定到数据源 但不会在回发时自动绑定到数据源 否则ObjectDataSource 选择事件也会在回发时被触发 但事实并非如此 A 所以唯一的办法就是强迫对象数据源也可以通过手动调用来绑定回发数
  • C++ 相当于 C# 中的 new Random(seed)

    当我们在 C 中使用随机数生成器时 我们可以定义一个变量 例如 private Random rndGenerator 在课堂上然后打电话 rndGenerator new Random seed 正确地在类的构造函数中 我的问题是 这种定
  • 使用 cout 打印字符数组的全部内容

    我对 C 很陌生 只是 Java 的背景不太好 并且对如何打印 char 数组的全部内容感到困惑 我相信我需要使用循环 并将循环基于数组的长度 但我的编译尝试没有成功 这就是我现在所拥有的 在此先感谢您的帮助 include
  • 虚拟调用与类型检查的另一个例子

    Problem 我发誓 每次我脑子里都在想 我应该使用虚拟调用而不是类型检查 例如 if obj is Foo else if obj is Bar 我想出了另一个例子 我不知道如何实现前者 我正在通过串行端口实现分组协议 一些伪代码可以最
  • Promise.defer 的正确模式是什么?

    我正在使用 TypeScript 和async await来表示异步工作流程 该工作流程的一部分是调用 Web Worker 并在其回调结果时继续 在 C 中 我会创建一个TaskCompletionSource await its Tas
  • 用于打印的真实尺寸 WPF 控件

    我目前正在开发一个应用程序 用户可以在画布上动态创建 移动 TextBlock 一旦他们将文本块放置在他们想要的位置 他们就可以按下打印按钮 这将导致 ZPL 打印机打印当前显示在屏幕上的内容 ZPL 命令是通过从每个 TextBlock
  • 具有相反结合顺序的 C++ 重载运算符

    很难想出一个标题 我的母语不是英语 struct A int value A operator int i const A a a value value i return a int main A a a value 2 a a 2 re
  • 为什么检查 SynchronizationContext 是否为 null?

    InstallIfNeed方法 http referencesource microsoft com System Windows Forms winforms Managed System WinForms WindowsFormsSyn
  • C# 中 a+=1 和 a=a+1 的区别

    我发现在C 中a 1不等于a a 1 例如 以下代码编译时不会出现任何错误 字节 b 10 b 5 而下面的代码有编译错误 字节 b 10 b b 5 有人可以告诉我为什么吗 Because b 5变成整数 Int32 主要是因为有重载的可
  • 工厂模式:typedef Class *(createClassFunction)(void)

    什么是typedef Class createClassFunction void 或者另一种变化是typedef Class stdcall CreateClassFunction void 代表 这是什么意思 我该怎么解释呢 特别是在工
  • 如何在 .NET 中使 ComboBox 不可编辑?

    我想要一个 仅选择 ComboBox它提供了一个项目列表供用户选择 应在文本部分禁用打字ComboBox控制 我最初对此进行谷歌搜索 发现了一个过于复杂 误导性的建议来捕捉KeyPress event 要使 ComboBox 的文本部分不可
  • 如何将逗号分隔的列值与另一个表作为行连接

    我试图通过首先转换我正在成功执行的 SupplierId 列中的逗号分隔值来连接两个表 然而 当我尝试通过外键 DCLink 加入另一个带有供应商名称的表 Vendors 时 问题就出现了 这就是我的意思 原始表的 select 语句 SE
  • Pthread 创建为分离的

    我在创建分离线程时遇到问题 这是我写的代码 void testFunction pthread attr t attr int chk rc pthread attr init attr printf thread attr init d
  • 抽象类、构造函数和 Co

    嗯 我正在尝试重用 C 代码的一部分 它是一个带有UDP服务器的抽象类 可以在这里看到 http clutch inc com blog p 4 http clutch inc com blog p 4 我创建了一个像这样的派生类 publ
  • 从 C# 2.0 中的 dll 获取命名空间、类名

    我将动态获取dll 我需要加载 dll 并获取命名空间 类名来调用方法 方法名称是静态的 它将始终为 OnStart 基本上我需要通过加载 dll 来运行一个方法 有人可以帮忙吗 要加载程序集 您可以这样做 Assembly assembl
  • 如何检查c#代码中死锁的可能性

    我的应用程序有时会停止在下面的代码中 并非总是如此 但有时会停止 全部3种方法CalcQuarterlyFigures CalcWeeklyFigures CalcMonthlyFigures return Task
  • 从 Xcode 5.1 项目中删除所有调试表达式

    我在使用 C 和 XCode 5 1 时意外添加了一个调试表达式 现在每次我尝试查看添加此表达式的函数堆栈时 XCode 都会崩溃 我不知道如何在不单击该功能的情况下摆脱这个表达式 所以我有点迷失了 我找到了对 Expressions so
  • 在一个 Linq to Entities 查询中多次实现“like”运算符

    我们有一个字符串列表 我们需要通过该列表过滤结果 示例将查找所有 SSN 以 465 496 或 497 加上 x 更多 开头的学生 List

随机推荐