全局内存重放开销来自哪里? 运行下面的代码在英伟达可视化剖析器中在全局内存中写入1 GB,我得到: -100%的存储效率 -69.4%(128.6 GB/s)的DRAM利用率 -18.3%的总重播开销 -18.3%的全局内存重播开销。 内存写入应该合并,内核中没有分歧,所以问题是全局内存重放开销从何而来?我在Ubuntu13.04上运行这个程序,nvidia cuda toolkit版本为5.0.35-4ubuntu1。 #include <cuda.h> #include <unistd.h> #include <getopt.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <stdint.h> #include <ctype.h> #include <sched.h> #include <assert.h> static void HandleError( cudaError_t err, const char *file, int line ) { if (err != cudaSuccess) { printf( "%s in %s at line %d\n", cudaGetErrorString(err), file, line); exit( EXIT_FAILURE ); } } #define HANDLE_ERROR(err) (HandleError(err, __FILE__, __LINE__)) // Global memory writes __global__ void kernel_write(uint32_t *start, uint32_t entries) { uint32_t tid = threadIdx.x + blockIdx.x*blockDim.x; while (tid < entries) { start[tid] = tid; tid += blockDim.x*gridDim.x; } } int main(int argc, char *argv[]) { uint32_t *gpu_mem; // Memory pointer uint32_t n_blocks = 256; // Blocks per grid uint32_t n_threads = 192; // Threads per block uint32_t n_bytes = 1073741824; // Transfer size (1 GB) float elapsedTime; // Elapsed write time // Allocate 1 GB of memory on the device HANDLE_ERROR( cudaMalloc((void **)&gpu_mem, n_bytes) ); // Create events cudaEvent_t start, stop; HANDLE_ERROR( cudaEventCreate(&start) ); HANDLE_ERROR( cudaEventCreate(&stop) ); // Write to global memory HANDLE_ERROR( cudaEventRecord(start, 0) ); kernel_write<<<n_blocks, n_threads>>>(gpu_mem, n_bytes/4); HANDLE_ERROR( cudaGetLastError() ); HANDLE_ERROR( cudaEventRecord(stop, 0) ); HANDLE_ERROR( cudaEventSynchronize(stop) ); HANDLE_ERROR( cudaEventElapsedTime(&elapsedTime, start, stop) ); // Report exchange time printf("#Delay(ms) BW(GB/s)\n"); printf("%10.6f %10.6f\n", elapsedTime, 1e-6*n_bytes/elapsedTime); // Destroy events HANDLE_ERROR( cudaEventDestroy(start) ); HANDLE_ERROR( cudaEventDestroy(stop) ); // Free memory HANDLE_ERROR( cudaFree(gpu_mem) ); return 0; } #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 静态空隙 HandleError(cudaError\u t err,const char*文件,int行) { if(err!=cudaSuccess){ printf(“%s在%s中的%d行\n”,cudaGetErrorString(err),文件,行); 退出(退出失败); } } #定义句柄错误(err)(句柄错误(err,文件,行) //全局内存写入 __全局无效 内核写入(uint32\u t*start,uint32\u t条目) { uint32_t tid=线程idx.x+块idx.x*块dim.x; 而(tid请求的原因。@GregSmith非常感谢您对分析工具的详细解释。您有什么建议吗dea关于为什么第一篇文章中的内核具有高重放率(特别是高全局内存重放开销)?类似的情况已经被证明是对常量内存()的非一致访问()或高TLB未命中率(),这两种情况在这里都不会发生。如果您没有回答问题,请不要回答。您可以改为编辑您的问题(并明确在需要时添加新信息)@coder指令重放的原因有很多。全局、本地、共享和常量的地址差异是最常见的,开发人员可以采取行动。这些工具不会为具有地址差异的常量请求公开计数器。其他原因包括l1未命中和l1缓冲区已满,如写入缓冲区和请求缓冲区r、 我在费米和开普勒上分析了您的代码。开普勒GPU可以在一次过程中从所有单元收集计数器。没有全局地址差异。所谓地址差异,我的意思是扭曲中的线程访问不同缓存线中的地址,需要多次重放。对于大于32位。例如,64位存储需要2个问题,128位存储需要4个存储。

全局内存重放开销来自哪里? 运行下面的代码在英伟达可视化剖析器中在全局内存中写入1 GB,我得到: -100%的存储效率 -69.4%(128.6 GB/s)的DRAM利用率 -18.3%的总重播开销 -18.3%的全局内存重播开销。 内存写入应该合并,内核中没有分歧,所以问题是全局内存重放开销从何而来?我在Ubuntu13.04上运行这个程序,nvidia cuda toolkit版本为5.0.35-4ubuntu1。 #include <cuda.h> #include <unistd.h> #include <getopt.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <time.h> #include <stdint.h> #include <ctype.h> #include <sched.h> #include <assert.h> static void HandleError( cudaError_t err, const char *file, int line ) { if (err != cudaSuccess) { printf( "%s in %s at line %d\n", cudaGetErrorString(err), file, line); exit( EXIT_FAILURE ); } } #define HANDLE_ERROR(err) (HandleError(err, __FILE__, __LINE__)) // Global memory writes __global__ void kernel_write(uint32_t *start, uint32_t entries) { uint32_t tid = threadIdx.x + blockIdx.x*blockDim.x; while (tid < entries) { start[tid] = tid; tid += blockDim.x*gridDim.x; } } int main(int argc, char *argv[]) { uint32_t *gpu_mem; // Memory pointer uint32_t n_blocks = 256; // Blocks per grid uint32_t n_threads = 192; // Threads per block uint32_t n_bytes = 1073741824; // Transfer size (1 GB) float elapsedTime; // Elapsed write time // Allocate 1 GB of memory on the device HANDLE_ERROR( cudaMalloc((void **)&gpu_mem, n_bytes) ); // Create events cudaEvent_t start, stop; HANDLE_ERROR( cudaEventCreate(&start) ); HANDLE_ERROR( cudaEventCreate(&stop) ); // Write to global memory HANDLE_ERROR( cudaEventRecord(start, 0) ); kernel_write<<<n_blocks, n_threads>>>(gpu_mem, n_bytes/4); HANDLE_ERROR( cudaGetLastError() ); HANDLE_ERROR( cudaEventRecord(stop, 0) ); HANDLE_ERROR( cudaEventSynchronize(stop) ); HANDLE_ERROR( cudaEventElapsedTime(&elapsedTime, start, stop) ); // Report exchange time printf("#Delay(ms) BW(GB/s)\n"); printf("%10.6f %10.6f\n", elapsedTime, 1e-6*n_bytes/elapsedTime); // Destroy events HANDLE_ERROR( cudaEventDestroy(start) ); HANDLE_ERROR( cudaEventDestroy(stop) ); // Free memory HANDLE_ERROR( cudaFree(gpu_mem) ); return 0; } #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 #包括 静态空隙 HandleError(cudaError\u t err,const char*文件,int行) { if(err!=cudaSuccess){ printf(“%s在%s中的%d行\n”,cudaGetErrorString(err),文件,行); 退出(退出失败); } } #定义句柄错误(err)(句柄错误(err,文件,行) //全局内存写入 __全局无效 内核写入(uint32\u t*start,uint32\u t条目) { uint32_t tid=线程idx.x+块idx.x*块dim.x; 而(tid请求的原因。@GregSmith非常感谢您对分析工具的详细解释。您有什么建议吗dea关于为什么第一篇文章中的内核具有高重放率(特别是高全局内存重放开销)?类似的情况已经被证明是对常量内存()的非一致访问()或高TLB未命中率(),这两种情况在这里都不会发生。如果您没有回答问题,请不要回答。您可以改为编辑您的问题(并明确在需要时添加新信息)@coder指令重放的原因有很多。全局、本地、共享和常量的地址差异是最常见的,开发人员可以采取行动。这些工具不会为具有地址差异的常量请求公开计数器。其他原因包括l1未命中和l1缓冲区已满,如写入缓冲区和请求缓冲区r、 我在费米和开普勒上分析了您的代码。开普勒GPU可以在一次过程中从所有单元收集计数器。没有全局地址差异。所谓地址差异,我的意思是扭曲中的线程访问不同缓存线中的地址,需要多次重放。对于大于32位。例如,64位存储需要2个问题,128位存储需要4个存储。,memory,cuda,overhead,replay,coalescing,Memory,Cuda,Overhead,Replay,Coalescing,nvprof探查器和API探查器给出了不同的结果: $ nvprof --events gst_request ./app ======== NVPROF is profiling app... ======== Command: app #Delay(ms) BW(GB/s) 13.345920 80.454690 ======== Profiling result: Invocations Avg Min Max Event

nvprof探查器和API探查器给出了不同的结果:

$ nvprof --events gst_request ./app
======== NVPROF is profiling app...
======== Command: app
#Delay(ms)  BW(GB/s)
 13.345920   80.454690
======== Profiling result:
          Invocations       Avg       Min       Max  Event Name
Device 0
    Kernel: kernel_write(unsigned int*, unsigned int)
                    1   8388608   8388608   8388608  gst_request

$ nvprof --events global_store_transaction ./app
======== NVPROF is profiling app...
======== Command: app
#Delay(ms)  BW(GB/s)
  9.469216  113.392892
======== Profiling result:
          Invocations       Avg       Min       Max  Event Name
Device 0
    Kernel: kernel_write(unsigned int*, unsigned int)
                    1   8257560   8257560   8257560  global_store_transaction
我的印象是,全球门店交易量不能低于gst要求。这是怎么回事?我不能在同一个命令中同时请求两个事件,因此我必须运行两个单独的命令。这可能是问题所在吗

奇怪的是,API profiler显示了不同的结果,并实现了完美的合并。这是输出,我必须运行两次才能获得正确的计数器:

$ cat config.txt
inst_issued
inst_executed
gst_request

$ COMPUTE_PROFILE=1 COMPUTE_PROFILE_CSV=1 COMPUTE_PROFILE_LOG=log.csv COMPUTE_PROFILE_CONFIG=config.txt ./app

$ cat log.csv
# CUDA_PROFILE_LOG_VERSION 2.0
# CUDA_DEVICE 0 GeForce GTX 580
# CUDA_CONTEXT 1
# CUDA_PROFILE_CSV 1
# TIMESTAMPFACTOR fffff67eaca946b8
method,gputime,cputime,occupancy,inst_issued,inst_executed,gst_request,gld_request
_Z12kernel_writePjj,7771.776,7806.000,1.000,4737053,3900426,557058,0

$ cat config2.txt
global_store_transaction

$ COMPUTE_PROFILE=1 COMPUTE_PROFILE_CSV=1 COMPUTE_PROFILE_LOG=log2.csv COMPUTE_PROFILE_CONFIG=config2.txt ./app

$ cat log2.csv
# CUDA_PROFILE_LOG_VERSION 2.0
# CUDA_DEVICE 0 GeForce GTX 580
# CUDA_CONTEXT 1
# CUDA_PROFILE_CSV 1
# TIMESTAMPFACTOR fffff67eea92d0e8
method,gputime,cputime,occupancy,global_store_transaction
_Z12kernel_writePjj,7807.584,7831.000,1.000,557058
这里gst_请求和全局_存储_事务完全相同,显示出完美的结合。哪一个是正确的(nvprof还是API分析器)?为什么NVIDIA VisualProfiler说我有非合并写入?仍然有重要的指令回放,我不知道它们来自哪里:(


有什么想法吗?我不认为这是硬件故障,因为我在同一台机器上有两块板,并且都显示出相同的行为。

这是什么GPU?如果GPU支持ECC,它是否启用?这是GeForce GTX 580,目前。“设备支持ECC:禁用”有什么想法吗?这可能是问题吗?CUDA命令行探查器仅从gf110(GTX580)上的单个SM.收集结果nvprof可以在一次过程中从所有SMs收集gst_请求;但是,它只能从1/4的L1单元收集全局_存储_事务,因此它从这些单元收集并缩放结果。这可能是您看到事务>请求的原因。@GregSmith非常感谢您对分析工具的详细解释。您有什么建议吗dea关于为什么第一篇文章中的内核具有高重放率(特别是高全局内存重放开销)?类似的情况已经被证明是对常量内存()的非一致访问()或高TLB未命中率(),这两种情况在这里都不会发生。如果您没有回答问题,请不要回答。您可以改为编辑您的问题(并明确在需要时添加新信息)@coder指令重放的原因有很多。全局、本地、共享和常量的地址差异是最常见的,开发人员可以采取行动。这些工具不会为具有地址差异的常量请求公开计数器。其他原因包括l1未命中和l1缓冲区已满,如写入缓冲区和请求缓冲区r、 我在费米和开普勒上分析了您的代码。开普勒GPU可以在一次过程中从所有单元收集计数器。没有全局地址差异。所谓地址差异,我的意思是扭曲中的线程访问不同缓存线中的地址,需要多次重放。对于大于32位。例如,64位存储需要2个问题,128位存储需要4个存储。