本文共 3983 字,大约阅读时间需要 13 分钟。
数据预取:
数据预取意味着将数据迁移到处理器的内存,并在处理器开始访问该数据之前将其映射到该处理器的页表中。 数据预取的目的是避免错误,同时建立数据局部性。 这对于在任何给定时间主要从单个处理器访问数据的应用程序都是最有价值的。 随着访问处理器在应用程序的生命周期内发生变化,可以相应地预取数据以跟踪应用程序的执行流程。 由于工作是在CUDA中的流中启动的,因此预计数据预取也是流式操作,如以下API所示:cudaError_t cudaMemPrefetchAsync(const void *devPtr, size_t count, int dstDevice, cudaStream_t stream);
其中由devPtr指针指定的内存区域和计数字节数(ptr向下舍入到最接近的页边界并向上舍入到最接近的页边界的计数)将通过在流中排列迁移操作而迁移到dstDevice。 传递给dstDevice的cudaCpuDeviceId将导致数据迁移到CPU内存。
考虑下面的简单代码示例:void foo(cudaStream_t s) { char *data; cudaMallocManaged(&data, N); init_data(data, N); // execute on CPU cudaMemPrefetchAsync(data, N, myGpuId, s); // prefetch to GPU mykernel << <..., s >> >(data, N, 1, compare); // execute on GPU cudaMemPrefetchAsync(data, N, cudaCpuDeviceId, s); // prefetch to CPU cudaStreamSynchronize(s); use_data(data, N); cudaFree(data);}
如果没有性能提示,内核mykernel会在首次访问数据时出错,这会造成额外的故障处理开销,并且通常会降低应用程序的速度。 通过预先预取数据,可以避免页面错误并实现更好的性能。
此API遵循流排序语义,即直到流中的所有先前操作都完成后才开始迁移,并且在迁移完成之前,流中的任何后续操作都不会开始。数据使用提示:当多个处理器需要同时访问相同的数据时,数据预取本身是不够的。 在这种情况下,应用程序提供有关如何实际使用数据的提示很有用。 以下咨询API可用于指定数据使用情况:cudaError_t cudaMemAdvise(const void *devPtr, size_t count, enum cudaMemoryAdvise advice, int device);
其中为包含在从devPtr地址开始的区域中的数据指定的建议(其计数字节长度四舍五入到最接近的页面边界)可以采用以下值:
char *dataPtr;size_t dataSize = 4096;// Allocate memory using malloc or cudaMallocManageddataPtr = (char *)malloc(dataSize);// Set the advice on the memory regioncudaMemAdvise(dataPtr, dataSize, cudaMemAdviseSetReadMostly, 0);int outerLoopIter = 0;while (outerLoopIter < maxOuterLoopIter) { // The data is written to in the outer loop on the CPU initializeData(dataPtr, dataSize); // The data is made available to all GPUs by prefetching. // Prefetching here causes read duplication of data instead // of data migration for (int device = 0; device < maxDevices; device++) { cudaMemPrefetchAsync(dataPtr, dataSize, device, stream); } // The kernel only reads this data in the inner loop int innerLoopIter = 0; while (innerLoopIter < maxInnerLoopIter) { kernel << <32, 32 >> >((const char *)dataPtr); innerLoopIter++; } outerLoopIter++;}
也可以使用以下某个值取消设置每个建议:cudaMemAdviseUnsetReadMostly,cudaMemAdviseUnsetPreferredLocation和cudaMemAdviseUnsetAccessedBy。
查询使用属性:程序可以通过使用以下API查询通过cudaMemAdvise或cudaMemPrefetchAsync分配的内存范围属性:cudaMemRangeGetAttribute(void *data, size_t dataSize, enum cudaMemRangeAttribute attribute, const void *devPtr, size_t count);
该函数查询以devPtr开始的内存范围的属性,其大小为计数字节。 内存范围必须指向通过cudaMallocManaged分配或通过__managed__
变量声明的托管内存。 有可能查询
另外,可以使用相应的cudaMemRangeGetAttributes函数来查询多个属性。
转载地址:http://sspfo.baihongyu.com/