Cuda 如何让malloc出现在nvprof';s统计分析器?

Cuda 如何让malloc出现在nvprof';s统计分析器?,cuda,profiling,nvprof,Cuda,Profiling,Nvprof,有没有办法让CUDA的nvprof在其统计分析器中包含类似malloc的函数调用? 我一直在努力提高我的应用程序的性能。当然,我一直在使用nvprof作为这方面的工具 最近,为了减少我的应用程序的GPU内存占用,我编写的代码使其运行时间延长了一倍。然而,导致速度减慢的新代码只在探查器中少量出现(指令采样表明约10%的时间花在新代码中,但天真的想法表明50%的时间应该花在新代码中)。可能新代码导致了更多的缓存抖动,可能将实现放在头文件中,这样它就可以内联到分析器中,等等。但是,没有什么好的理由,我

有没有办法让CUDA的
nvprof
在其统计分析器中包含类似
malloc
的函数调用?

我一直在努力提高我的应用程序的性能。当然,我一直在使用
nvprof
作为这方面的工具

最近,为了减少我的应用程序的GPU内存占用,我编写的代码使其运行时间延长了一倍。然而,导致速度减慢的新代码只在探查器中少量出现(指令采样表明约10%的时间花在新代码中,但天真的想法表明50%的时间应该花在新代码中)。可能新代码导致了更多的缓存抖动,可能将实现放在头文件中,这样它就可以内联到分析器中,等等。但是,没有什么好的理由,我怀疑新代码调用了
malloc

事实上,在我减少了
malloc
调用的数量之后,我的性能提高了,几乎恢复到合并新代码之前的水平

这就引出了一个类似的问题,为什么
malloc
的调用没有出现在统计分析器中?
是不是
malloc
调用某种GPU系统调用无法观察到

下面,我提供了一个示例程序及其输出,展示了这个特定问题

#include <iostream>
#include <numeric>
#include <thread>
#include <stdlib.h>
#include <stdio.h>

static void CheckCudaErrorAux (const char *, unsigned, const char *, cudaError_t);
#define CUDA_CHECK_RETURN(value) CheckCudaErrorAux(__FILE__,__LINE__, #value, value)

__global__ void countup()
{
    long sum = 0;
    for (long i = 0; i < (1 << 23); ++i) {
        sum += i;
    }
    printf("sum is %li\n", sum);
}

__global__ void malloc_a_lot() {
    long sum = 0;
    for (int i = 0; i < (1 << 17) * 3; ++i) {
        int * v = (int *) malloc(sizeof(int));
        sum += (long) v;
        free(v);
    }
    printf("sum is %li\n", sum);
}

__global__ void both() {
    long sum = 0;
    for (long i = 0; i < (1 << 23); ++i) {
        sum += i;
    }
    printf("sum is %li\n", sum);

    sum = 0;
    for (int i = 0; i < (1 << 17) * 3; ++i) {
        int * v = (int *) malloc(sizeof(int));
        sum += (long) v;
        free(v);
    }
    printf("sum is %li\n", sum);
}


int main(void)
{

    CUDA_CHECK_RETURN(cudaDeviceSynchronize());
    std::chrono::time_point<std::chrono::system_clock> t1 = std::chrono::system_clock::now();
    countup<<<8,1>>>();
    CUDA_CHECK_RETURN(cudaDeviceSynchronize());
    std::chrono::time_point<std::chrono::system_clock> t2 = std::chrono::system_clock::now();
    malloc_a_lot<<<8,1>>>();
    CUDA_CHECK_RETURN(cudaDeviceSynchronize());
    std::chrono::time_point<std::chrono::system_clock> t3 = std::chrono::system_clock::now();
    both<<<8,1>>>();
    CUDA_CHECK_RETURN(cudaDeviceSynchronize());
    std::chrono::time_point<std::chrono::system_clock> t4 = std::chrono::system_clock::now();

    std::chrono::duration<double> duration_1_to_2 = t2 - t1;
    std::chrono::duration<double> duration_2_to_3 = t3 - t2;
    std::chrono::duration<double> duration_3_to_4 = t4 - t3;
    printf("timer for countup() took %.3lf\n", duration_1_to_2.count());
    printf("timer for malloc_a_lot() took %.3lf\n", duration_2_to_3.count());
    printf("timer for both() took %.3lf\n", duration_3_to_4.count());

    return 0;
}

static void CheckCudaErrorAux (const char *file, unsigned line, const char *statement, cudaError_t err)
{
    if (err == cudaSuccess)
        return;
    std::cerr << statement<<" returned " << cudaGetErrorString(err) << "("<<err<< ") at "<<file<<":"<<line << std::endl;
    exit (1);
}
分析结果如下图所示。将鼠标移到浅蓝色条上时显示的数字与条的大小一致。具体而言,第41行有16515077个与之相关的样本,但第47行只有633996个样本


顺便说一句,上面的程序是用调试信息编译的,可能没有优化——在Nsight Eclipse中编译的默认“调试”模式。如果我在“Release”模式下编译,将调用优化,并且调用的持续时间非常接近0秒。

当前的NVIDIA GPU PC采样器仅收集当前的warp程序计数器(不是调用堆栈)。PC取样器将在malloc内正确采集样本;但是,该工具不显示内部系统调用的SASS或高级源代码

  • 该工具没有显示syscall模块内样本聚合计数的UI
  • 该工具不知道malloc、free或其他系统调用的PC范围,无法将样本正确地归属于名为syscall的用户

  • 如果(1)或(2)是固定的,数据将显示在单独的一行上,简单地标记为“syscall”或“malloc”。硬件不收集调用堆栈,因此无法将样本归因于L48。

    当前的NVIDIA GPU PC采样器仅收集当前的warp程序计数器(不是调用堆栈)。PC取样器将在malloc内正确采集样本;但是,该工具不显示内部系统调用的SASS或高级源代码

  • 该工具没有显示syscall模块内样本聚合计数的UI
  • 该工具不知道malloc、free或其他系统调用的PC范围,无法将样本正确地归属于名为syscall的用户

  • 如果(1)或(2)是固定的,数据将显示在单独的一行上,简单地标记为“syscall”或“malloc”。硬件不收集调用堆栈,因此无法将样本归因于L48。

    有一个想法,可能我需要在程序末尾包含对
    cudaProfilerStop()
    的调用。所以,我试过了,但变化不大。我目前正在运行一个nvprof会话,其标志是
    ——跟踪
    上的内存分配。将报告调查结果。使用
    nvprof
    跟踪内存分配
    似乎无法做到这一点。下面是我发出的命令(然后将生成的两个文件导入Nsight Eclispse/nvp)
    nvprof-f-o~/cuda-workspace/malloc/timeline.out~/cuda-workspace/malloc/Debug/malloc;nvprof-f——跟踪--kernels::both:1——分析度量-o~/cuda-workspace/malloc/analysis-metrics.out~/cuda-workspace/malloc/Debug/malloc上的内存分配
    有一个想法,可能我需要在程序的末尾包含对
    cudaProfilerStop()
    的调用。所以,我试过了,但变化不大。我目前正在运行一个nvprof会话,其标志是
    ——跟踪
    上的内存分配。将报告调查结果。使用
    nvprof
    跟踪内存分配
    似乎无法做到这一点。下面是我发出的命令(然后将生成的两个文件导入Nsight Eclispse/nvp)
    nvprof-f-o~/cuda-workspace/malloc/timeline.out~/cuda-workspace/malloc/Debug/malloc;nvprof-f——跟踪--kernels::both:1——分析度量-o~/cuda-workspace/malloc/analysis-metrics.out~/cuda-workspace/malloc/Debug/malloc上的内存分配我猜你的意思是写“硬件不收集调用堆栈…”?我猜你的意思是写“硬件不收集调用堆栈…”?
    
    sum is 35184367894528...
    sum is -319453208467532096...
    sum is 35184367894528...
    sum is -319453208467332416...
    timer for countup() took 4.034
    timer for malloc_a_lot() took 4.306
    timer for both() took 8.343