为iOS Metal

时间:2016-09-29 12:25:02

标签: ios c memory-management gpgpu metal

作为this answer的后续问题。我试图用在Metal中的内核函数替换在CPU上运行的for循环来并行化计算并加快性能。

我的功能基本上是一个卷积。由于我反复接收输入数组值的新数据(数据来自AVCaptureSession),因此使用newBufferWithBytesNoCopy:length:options:deallocator:似乎是创建MTLBuffer对象的合理选项。以下是相关代码:

id <MTLBuffer> dataBuffer = [device newBufferWithBytesNoCopy:dataVector length:sizeof(dataVector) options:MTLResourceStorageModeShared deallocator:nil];
id <MTLBuffer> filterBuffer = [device newBufferWithBytesNoCopy:filterVector length:sizeof(filterVector) options:MTLResourceStorageModeShared deallocator:nil];
id <MTLBuffer> outBuffer = [device newBufferWithBytesNoCopy:outVector length:sizeof(outVector) options:MTLResourceStorageModeShared deallocator:nil];

运行时,我收到以下错误:

  

断言失败`newBufferWithBytesNoCopy:指针0x16fd0bd48不是4096字节对齐。'

现在,我没有分配任何内存,但是(出于测试目的)只是创建一个固定大小的空浮点数并用随机数填充它。所以我的主要问题是:

如何以正确的方式分配这些浮动数组,以满足以下要求

  

此值必须导致页面对齐的内存区域。

另外,还有一些问题:

  • 使用MTLBuffer方法创建newBufferWithBytesNoCopy是否有意义,或者在性能方面复制数据并不是真正的问题? (我的实际数据将包含每个视频帧约43'000个浮点值。)
  • MTLResourceStorageModeShared是<{1}}
  • 的正确选择
  • API参考说明

      

    返回的新MTLBuffer对象的存储分配与指针输入值相同。现有的内存分配必须由单个VM区域覆盖,通常使用vm_allocate或mmap进行分配。特别禁止malloc分配的内存。

    这是否仅适用于输出缓冲区,还是MTLResourceOptions不能使用MTLBuffer使用的所有对象的存储分配?

1 个答案:

答案 0 :(得分:5)

分配页面对齐内存的最简单方法是使用posix_memalign。这是一个使用页面对齐内存创建缓冲区的完整示例:

void *data = NULL;
NSUInteger pageSize = getpagesize();
NSUInteger allocationSize = /* required byte count, rounded up to next multiple of page size */ pageSize * 10;
int result = posix_memalign(&data, pageSize, allocationSize);

if (result == noErr && data) {
    id<MTLBuffer> buffer = [device newBufferWithBytesNoCopy:data
                                                     length:allocationSize
                                                    options:MTLResourceStorageModeShared
                                                deallocator:^(void *pointer, NSUInteger length)
                                                            {
                                                                free(pointer);
                                                            }];
    NSLog(@"Created buffer of length %d", (int)buffer.length);
}

由于您无法确保您的数据将以页面对齐的指针到达,因此您可能最好只分配MTLBuffer任何可容纳数据的大小,而不使用无副本变种。如果需要对数据进行实时处理,则应创建缓冲池并在它们之间循环,而不是等待每个命令缓冲区完成。 Shared存储模式适用于这些用例。与malloc相关的警告仅适用于无复制案例,因为在其他情况下,Metal会为您分配内存。