cuda编程学习笔记 第二章 cuda memory management

应用的性能可能有 75% 都花费在内存相关问题上。

NVPROF and NVVP

这俩是调试工具,不知道是不是基于CUPTI (CUDA Profiler Tools Interface)。

NVPROF是命令行工具,nvvp是可视化工具。

nvvp有四个模块:Timeline,Summary,Guide,Analysis results
其中 Guide 适合新手,新手应该多注意。

为了分析出应用的性能瓶颈,我们需要timeling analysis 和 metric analysis

编译:
要include cuda_profiler_api.h 和 helper_functions.h
命令1
nvcc -I"D:/cuda/NVIDIA Corporation_v10.1/common/inc" -gencode arch=compute_61,code=sm_61 -Xcompiler /wd4819 -o sgemm sgemm.cu
命令2 创建 nvvp文件
nvprof -o sgemm.nvvp .\sgemm.exe
13388 NVPROF is profiling process 13388, command: .\sgemm.exe
Operation Time= 0.0046 msec
13388 Generated result file: D:\codes\Learn-CUDA-Programming-master\Learn-CUDA-Programming-master\Chapter02\02_memory_overview\01_sgemm\sgemm.nvvp

运行nvvp,打开 sgemm.nvvp文件

Global memory / device memory

global memory 是从host复制过去的默认空间
cudaMalloc 和 cudaFree cudaMemcpy

coalesced memory access / uncoalesced memory access

warp:32threads running in SMs。
例如 一个SM运行两个block,每个block128线程,则一共 8 个 warp。这些 warp 公用一个SM的shared memory。
每个warp中的线程以SIMT模式运行,也就是所有线程同时运行同一个命令

warp下的内存访问需要coalesced memory access,squential memory access is adjacent.

总而言之尽量连续访问、数据aligned

texture memory

一般用来存储大部分线程都要访问的少量数据,比如参数之类。同一个warp的线程访问同一个地址会导致所有线程在每个时钟周期请求数据,但是在texture memory上有优化。2D访问、3D访问也有优化,总之就是读的快、不能写。

shared memory

shared memory以banks的形式排列,要防止同一个warp里的线程同时访问同一个bank,至于不同warp之间的不太清楚。

registers

local variables are stored in registers
尽量别弄太多本地变量,寄存器和thread有关

pinned memory

尽量不在host 和 device之间传输数据
用pinned memory
把许多小数据传输合并成一个大batch
用计算来掩盖传输

传输数据时默认先创建一个pinned memory,然后将一个个page复制过去,再从pinned memory里将数据复制到device(通过DMA)。通过cudaMallocHost可以之间分配一个pinned memory。

Unified memory

给GPU和CPU提供一个统一的地址
cudaMallocManaged分配空间,不是立刻分配,下一次host第一个访问该空间就分配host,否则device。(first touch)

当device需要访问某个page,但是page正在host映射的空间里,这时会让host取消映射,transfer这个page到device的物理空间,device再映射这个page。

warp per page 技术,每个warp负责64K,一个page:

__global__ void init(int n, float *x, float *y) {
    int lane_id = threadIdx.x & 31;//本线程是该warp的第几个线程
    size_t warp_id = (threadIdx.x + blockIdx.x * blockDim.x) >> 5;//blockDim.x是一个block的线程数
    size_t warps_per_grid = (blockDim.x * gridDim.x) >> 5;//
    size_t warp_total = ((sizeof(float)*n) + STRIDE_64K-1) / STRIDE_64K;//pages

    // if(blockIdx.x==0 && threadIdx.x==0) {
    //     printf("\n TId[%d] ", threadIdx.x);
    //     printf(" WId[%u] ", warp_id);
    //     printf(" LId[%u] ", lane_id);
    //     printf(" WperG[%u] ", warps_per_grid);
    //     printf(" wTot[%u] ", warp_total);
    //     printf(" rep[%d] ", STRIDE_64K/sizeof(float)/32);
    // }

    for( ; warp_id < warp_total; warp_id += warps_per_grid) {
        #pragma unroll//告诉编译器任意展开并行等都是安全的
        for(int rep = 0; rep < STRIDE_64K/sizeof(float)/32; rep++) {
            size_t ind = warp_id * STRIDE_64K/sizeof(float) + rep * 32 + lane_id;
            if (ind < n) {
              x[ind] = 1.0f;
              // if(blockIdx.x==0 && threadIdx.x==0) {
              // 	printf(" \nind[%d] ", ind);
              // } 
              y[ind] = 2.0f;
            }
        }
    }
}

data prefetching: cudaMemPerfetchAsync()
预先告诉程序下一个设备是谁。这个最快。

cudaMemAdvice()系列API:
SetReadMostly、PreferredLocation、SetAccessBy等。

UM技术把device和host的内存看作同一个内存,可以用来解决很多GPU内存不够的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值