【问题标题】:CUDA Performance - Always return different valuesCUDA 性能 - 总是返回不同的值
【发布时间】:2013-05-13 08:15:39
【问题描述】:

这是我的代码:

using namespace std;
#include <iostream>
#include <stdio.h>
#include <stdlib.h>

const int N = 8000;

void fillArray(int *data, int count) {
    for (int i = 0; i < count; i++)
        data[i] = rand() % 100;
}

__global__ void add(int* a, int *b, int *c) {

    int tid = threadIdx.x + blockIdx.x * blockDim.x;
    if (tid < N) {
        c[tid] = a[tid] + b[tid];
    }
}

__global__ void subtract(int* a, int *b, int *c) {

    int tid = threadIdx.x + blockIdx.x * blockDim.x;
    if (tid < N) {
        c[tid] = a[tid] - b[tid];
    }
}

__global__ void multiply(int* a, int *b, int *c) {

    int tid = threadIdx.x + blockIdx.x * blockDim.x;
    if (tid < N) {
        c[tid] = a[tid] * b[tid];
    }
}

__global__ void divide(int* a, int *b, int *c) {

    int tid = threadIdx.x + blockIdx.x * blockDim.x;
    if (tid < N) {
        c[tid] = a[tid] / b[tid];
    }
}

__global__ void modu(int* a, int *b, int *c) {

    int tid = threadIdx.x + blockIdx.x * blockDim.x;
    if (tid < N) {
        c[tid] = a[tid] % b[tid];
    }
}

__global__ void neg(int *data, int *c) {

    int tid = threadIdx.x + blockIdx.x * blockDim.x;
    if (tid < N) {
        c[tid] = -data[tid];
    }
}

float duration(int *devA, int *devB, int *devC, int blocksPerGrid, int threadsPerBlock) {

    cudaEvent_t start, stop;
    float elapsedTime;

    cudaEventCreate(&start);
    cudaEventCreate(&stop);
    cudaEventRecord(start, 0);

    int hArrayC[N];

    add<<<blocksPerGrid, threadsPerBlock>>>(devA, devB,devC);
    cudaMemcpy(hArrayC,devC,N*sizeof(int),cudaMemcpyDeviceToHost);

    subtract<<<blocksPerGrid, threadsPerBlock>>>(devA, devB,devC);
    cudaMemcpy(hArrayC,devC,N*sizeof(int),cudaMemcpyDeviceToHost);

    multiply<<<blocksPerGrid, threadsPerBlock>>>(devA, devB,devC);
    cudaMemcpy(hArrayC,devC,N*sizeof(int),cudaMemcpyDeviceToHost);

    divide<<<blocksPerGrid, threadsPerBlock>>>(devA, devB,devC);
    cudaMemcpy(hArrayC,devC,N*sizeof(int),cudaMemcpyDeviceToHost);

    modu<<<blocksPerGrid, threadsPerBlock>>>(devA, devB,devC);
    cudaMemcpy(hArrayC,devC,N*sizeof(int),cudaMemcpyDeviceToHost);

    neg<<<blocksPerGrid, threadsPerBlock>>>(devA,devC);
    cudaMemcpy(hArrayC,devC,N*sizeof(int),cudaMemcpyDeviceToHost);

    neg<<<blocksPerGrid, threadsPerBlock>>>(devB,devC);
    cudaMemcpy(hArrayC,devC,N*sizeof(int),cudaMemcpyDeviceToHost);

    cudaEventRecord(stop, 0);
    cudaEventSynchronize(stop);
    cudaEventElapsedTime(&elapsedTime, start, stop);

    cudaEventDestroy(start);
    cudaEventDestroy(stop);

    return elapsedTime;
}

int main(void) {

    int *a, *b;
    a = new int[N];
    b = new int [N];

    float dur = 0;

    int *devA, *devB,*devC;

    cudaMalloc((void**) &devA, N * sizeof(int));
    cudaMalloc((void**) &devB, N * sizeof(int));
    cudaMalloc((void**) &devC, N * sizeof(int));

    fillArray(a, N);
    fillArray(b, N);

    cudaMemcpy(devA, a, N * sizeof(int), cudaMemcpyHostToDevice);
    cudaMemcpy(devB, b, N * sizeof(int), cudaMemcpyHostToDevice);


    dur = duration(devA, devB, devC,N, 1);

    cout << "Global memory version:\n";
    cout << "Process completed in " << dur;
    cout << " for a data set of " << N << " integers.";



    cudaFree(devA);
    cudaFree(devB);
    delete [] a;
    delete [] b;

    return 0;
}

我想知道持续时间函数的总毫秒数。但是毫秒总是以不同的值返回。有时是 10 毫秒,有时是 0.78652,有时是 30 毫秒。为什么?我的代码有什么问题?

【问题讨论】:

  • 首先,如果您使用nvprof,就像我已经告诉您的那样,您的生活会更轻松。其次,你应该阅读这个问题的cmets:stackoverflow.com/questions/16500703/…。尝试将 GPU 设置为持久模式 (nvidia-smi -pm 1)。
  • 我知道,但我必须这样做。
  • 您可以尝试在您正在计时的内核之前调用一个虚拟内核,因此驱动程序加载的开销不应影响您的计时。
  • 我可以通过编程方式解决这个问题吗?
  • 你能给我们更多关于你系统的规格吗?哪个gpu在哪个操作系统上使用。您的代码唯一的问题是每个块只启动一个线程。有什么诀窍,但这是一个性能漏洞。尝试每个块启动更多线程,例如125 个块,每个块调用 64 个线程。最后免费的 devC 进行了很好的清理。

标签: cuda


【解决方案1】:

这可能是由加载/卸载 NVIDIA 驱动程序引起的。将其视为 GPU 的初始化步骤。

您可以将 GPU 设置为持久模式:

nvidia-smi -pm 1

或者您可以在计时您的 GPU 代码以触发加载驱动程序之前运行一个虚拟内核:

__global__ void dummy()
{
    // This kernel does nothing, this is just a "warm-up"
}

// Before your cudaEventRecord etc.
dummy<<<blocksPerGrid, threadsPerBlock>>>();

或者也许只是在为内核计时之前使用cudaThreadSynchronize()。

【讨论】:

  • nvprof 的结果如何?它们总是一致的吗?
  • 你的机器配置是什么?您使用的是哪种 GPU?这是windows还是linux? GPU 是否还托管显示器?您使用的是哪个驱动程序和 CUDA 版本?当我运行你的代码时,我得到 0.76 左右的结果相当一致。我从来没有看到 10、20 或 30。由于您在时序中运行多个内核,因此显示驱动程序可能会暂时将 GPU 带走以执行显示任务,这可能会出现在您的时序中。我认为,如果您分别使用开始和停止点对每个内核进行计时,并将经过的时间相加,您会看到更少的变化。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-10-22
  • 2019-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多