并行执行共享特斯拉K20的两个进程

时间:2015-10-01 13:39:33

标签: concurrency cuda tesla

当我启动2个内核实例以便在共享GPU资源的同时运行时,我遇到了一种奇怪的行为。

我开发了一个CUDA内核,旨在在单个SM(多处理器)中运行,其中线程执行多次操作(使用循环)。

内核准备只创建一个块,因此只使用一个SM。

  

simple.cu

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

__global__ void increment(float *in, float *out)
{
    int it=0, i = blockIdx.x * blockDim.x + threadIdx.x;
    float a=0.8525852f;

    for(it=0; it<99999999; it++)
             out[i] += (in[i]+a)*a-(in[i]+a);
}

int main( int argc, char* argv[])
{
    int i;
    int nBlocks = 1;
    int threadsPerBlock = 1024;
    float *A, *d_A, *d_B, *B;
    size_t size=1024*13;

    A = (float *) malloc(size * sizeof(float));
    B = (float *) malloc(size * sizeof(float));

    for(i=0;i<size;i++){
            A[i]=0.74;
            B[i]=0.36;
    }

    cudaMalloc((void **) &d_A, size * sizeof(float));
    cudaMalloc((void **) &d_B, size * sizeof(float));

    cudaMemcpy(d_A, A, size, cudaMemcpyHostToDevice);
    cudaMemcpy(d_B, B, size, cudaMemcpyHostToDevice);

    increment<<<nBlocks,threadsPerBlock>>>(d_A, d_B);

    cudaDeviceSynchronize();

    cudaMemcpy(B, d_B, size, cudaMemcpyDeviceToHost);

    free(A);
    free(B);

    cudaFree(d_A);
    cudaFree(d_B);

    cudaDeviceReset();

    return (0);
}

所以如果我执行内核:

time ./simple

我得到了

real 0m36.659s user 0m4.033s sys 0m1.124s

否则,如果我执行两个实例:

time ./simple & time ./simple

我得到了每个流程:

real 1m12.417s user 0m29.494s sys 0m42.721s

real 1m12.440s user 0m36.387s sys 0m8.820s

据我所知,执行应同时持续一个(约36秒)。但是,它们的基准时间是两倍。我们知道GPU有13个SM,每个SM应该执行一个块,因此内核只创建1个块。

它们是否在同一个SM中执行?

它们不应该在不同的SM中同时运行吗?

EDITED

为了让我更清楚,我将附上从nvprof获得的并发执行的配置文件:

个人资料,第一个实例 simple.cu profile, first instance

个人资料,第二个实例 simple.cu profile, second instance

现在,我想向您展示同一场景的行为,但同时执行matrixMul示例的两个实例:

个人资料,第一个实例 enter image description here

个人资料,第二个实例 enter image description here

正如您所看到的,在第一个场景中,内核等待另一个内核完成。而在第二种情况(matrixMul)中,来自两个上下文的内核同时运行。

谢谢。

1 个答案:

答案 0 :(得分:3)

当您使用相同的GPU运行两个单独的进程时,它们每个都有自己的上下文。 CUDA不支持同时在同一设备上拥有多个上下文。相反,每个上下文以未定义的方式竞争设备,具有驱动程序级上下文切换。这就是为什么执行的行为就像进程被序列化一样 - 实际上它们是,但是在驱动程序而不是GPU级别。

有可用的技术(MPS,Hyper-Q)可以做你想要的,但你尝试这样做的方式是行不通的。

编辑以回复您问题中的更新

使用MatrixMul示例添加的示例未显示您的想法。该应用程序运行300个短内核,并计算这300个运行的平均值的性能数。您的性能分析显示已设置为非常粗略的时间分辨率,因此看起来只有一个长时间运行的内核启动,而实际上它是一系列非常短的运行时内核。

为了说明这一点,请考虑以下事项:

这是在Kepler设备上运行的单个MatrixMul进程的常规性能分析运行。请注意,有许多单独的内核直接相互运行。 enter image description here

这些是在同一个Kepler设备上运行的两个同步MatrixMul进程的分析跟踪: enter image description here enter image description here

请注意,每个进程的配置文件跟踪中都存在间隙,这是两个进程之间发生上下文切换的位置。行为与原始示例相同,只是在更精细的时间粒度。正如本讨论过程中由几个不同的人重复多次--CUDA不支持使用标准运行时API同时在示例设备上使用多个上下文。 MPS服务器 允许这样做,方法是添加一个守护程序,该守护程序使用大型共享内部Hyper-Q管道重新实现API,但您没有使用它,它与您在此中显示的结果无关问题