从内核中检索结果
Retrieving Results from Kernel
我在使用内核函数时遇到了一些问题。
我想做的只是将一个数组发送到函数,然后在数组中的 waitUntilCompleted
之后返回结果。
下面是一个数组,在malloc
之后循环填充0到123455的数字:
float *myVector = malloc(123456 * sizeof(float));
这是数组,连同 myVector
,将被发送到内核:
float *resultData = malloc(123456 * sizeof(float));
id <MTLBuffer> inBuffer = [device newBufferWithBytes:&myVector[0] length:sizeof(myVector) options:MTLResourceOptionCPUCacheModeDefault];
id <MTLBuffer> buffer = [device newBufferWithBytes:&resultData[0] length:sizeof(resultData) options:MTLResourceOptionCPUCacheModeDefault];
使用计算命令编码器,它们分别设置在索引 0
、1
和偏移量 0
。
以下设置线程组和组内线程的大小:
MTLSize threadGroupCounts = MTLSizeMake([device maxThreadsPerThreadgroup].width, 1, 1);
MTLSize threadGroups = MTLSizeMake((123456) / threadGroupCounts.width, 1, 1);
[commandEncoder dispatchThreadgroups:threadGroups threadsPerThreadgroup:threadGroupCounts];
[commandEncoder endEncoding];
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
我收到两次以下错误:
Execution of the command buffer was aborted due to an error during
execution. Caused GPU Hang Error (IOAF code 3)
在花了很多时间之后,我得出的结论是错误是由以下几行引起的:
MTLSize threadGroupCounts = MTLSizeMake([device maxThreadsPerThreadgroup].width, 1, 1);
MTLSize threadGroups = MTLSizeMake((123456) / [device maxThreadsPerThreadgroup].width, 1, 1);
例如,如果我将 (123456) / [device maxThreadsPerThreadgroup].width
设置为 32
,则不会发生错误,但结果将全为零,除了数组中的前 2 个值。
以下是我在处理后尝试获取结果的方式:
NSData *data = [NSData dataWithBytesNoCopy:buffer.contents length:sizeof(myVector) freeWhenDone:NO];
float *finalArray = malloc(sizeof(float) * 123456);
[data getBytes:&finalArray[0] length:sizeof(finalArray)];
函数如下:
kernel void test(const device float *inVector [[buffer (0)]],
device float *outVector [[buffer (1)]],
uint id [[thread_position_in_grid]])
{
outVector[id] = -inVector[id];
}
我想我在设置螺纹尺寸时遇到了问题。
作为测试,我想要实现的是设置允许的每个线程组的最大线程数,将数组的大小除以该数字并将其发送以进行处理。有人可以告诉我如何设置线程组大小,将数组发送到函数并最终正确正确地检索数组中的结果吗?
谢谢。
您计算 MTLBuffer
大小的方式有误。因为 myVector
是一个指针,所以 sizeof(myVector)
可能是 8,而不是 493824。这反过来又会导致您没有为数据分配足够的 space,并且读取超出内核函数中的缓冲区。在创建缓冲区时尝试使用与使用 malloc
分配浮点数组时相同的大小,看看是否有帮助。
您需要对使用 getBytes:length:
从输出缓冲区检索的字节数进行相应的更改。
我认为您计算线程组大小和数量的方式是合理的,但您应该注意整数截断。如果要处理的元素总数不能被线程组大小整除,您计算线程组计数的方式将向下舍入,导致您跳过一些元素。
避免这种情况的一种方法是取整您分派的线程组的数量,并显式检查缓冲区长度以防止越界访问。所以你会像这样计算你的线程组数量和大小:
const int elementCount = 123456;
MTLSize threadgroupSize = MTLSizeMake([device maxThreadsPerThreadgroup].width, 1, 1);
MTLSize threadgroups = MTLSizeMake(ceil(elementCount / (float)threadgroupSize.width), 1, 1);
...像这样传入缓冲区大小:
[computeCommandEncoder setBytes:&elementCount length:sizeof(elementCount) atIndex:2];
...并像这样检查边界:
kernel void test(const device float *inVector [[buffer (0)]],
device float *outVector [[buffer (1)]],
constant int &elementCount [[buffer (2)]],
uint id [[thread_position_in_grid]])
{
if (id < elementCount) {
outVector[id] = -inVector[id];
}
}
我在使用内核函数时遇到了一些问题。
我想做的只是将一个数组发送到函数,然后在数组中的 waitUntilCompleted
之后返回结果。
下面是一个数组,在malloc
之后循环填充0到123455的数字:
float *myVector = malloc(123456 * sizeof(float));
这是数组,连同 myVector
,将被发送到内核:
float *resultData = malloc(123456 * sizeof(float));
id <MTLBuffer> inBuffer = [device newBufferWithBytes:&myVector[0] length:sizeof(myVector) options:MTLResourceOptionCPUCacheModeDefault];
id <MTLBuffer> buffer = [device newBufferWithBytes:&resultData[0] length:sizeof(resultData) options:MTLResourceOptionCPUCacheModeDefault];
使用计算命令编码器,它们分别设置在索引 0
、1
和偏移量 0
。
以下设置线程组和组内线程的大小:
MTLSize threadGroupCounts = MTLSizeMake([device maxThreadsPerThreadgroup].width, 1, 1);
MTLSize threadGroups = MTLSizeMake((123456) / threadGroupCounts.width, 1, 1);
[commandEncoder dispatchThreadgroups:threadGroups threadsPerThreadgroup:threadGroupCounts];
[commandEncoder endEncoding];
[commandBuffer commit];
[commandBuffer waitUntilCompleted];
我收到两次以下错误:
Execution of the command buffer was aborted due to an error during execution. Caused GPU Hang Error (IOAF code 3)
在花了很多时间之后,我得出的结论是错误是由以下几行引起的:
MTLSize threadGroupCounts = MTLSizeMake([device maxThreadsPerThreadgroup].width, 1, 1);
MTLSize threadGroups = MTLSizeMake((123456) / [device maxThreadsPerThreadgroup].width, 1, 1);
例如,如果我将 (123456) / [device maxThreadsPerThreadgroup].width
设置为 32
,则不会发生错误,但结果将全为零,除了数组中的前 2 个值。
以下是我在处理后尝试获取结果的方式:
NSData *data = [NSData dataWithBytesNoCopy:buffer.contents length:sizeof(myVector) freeWhenDone:NO];
float *finalArray = malloc(sizeof(float) * 123456);
[data getBytes:&finalArray[0] length:sizeof(finalArray)];
函数如下:
kernel void test(const device float *inVector [[buffer (0)]],
device float *outVector [[buffer (1)]],
uint id [[thread_position_in_grid]])
{
outVector[id] = -inVector[id];
}
我想我在设置螺纹尺寸时遇到了问题。 作为测试,我想要实现的是设置允许的每个线程组的最大线程数,将数组的大小除以该数字并将其发送以进行处理。有人可以告诉我如何设置线程组大小,将数组发送到函数并最终正确正确地检索数组中的结果吗?
谢谢。
您计算 MTLBuffer
大小的方式有误。因为 myVector
是一个指针,所以 sizeof(myVector)
可能是 8,而不是 493824。这反过来又会导致您没有为数据分配足够的 space,并且读取超出内核函数中的缓冲区。在创建缓冲区时尝试使用与使用 malloc
分配浮点数组时相同的大小,看看是否有帮助。
您需要对使用 getBytes:length:
从输出缓冲区检索的字节数进行相应的更改。
我认为您计算线程组大小和数量的方式是合理的,但您应该注意整数截断。如果要处理的元素总数不能被线程组大小整除,您计算线程组计数的方式将向下舍入,导致您跳过一些元素。
避免这种情况的一种方法是取整您分派的线程组的数量,并显式检查缓冲区长度以防止越界访问。所以你会像这样计算你的线程组数量和大小:
const int elementCount = 123456;
MTLSize threadgroupSize = MTLSizeMake([device maxThreadsPerThreadgroup].width, 1, 1);
MTLSize threadgroups = MTLSizeMake(ceil(elementCount / (float)threadgroupSize.width), 1, 1);
...像这样传入缓冲区大小:
[computeCommandEncoder setBytes:&elementCount length:sizeof(elementCount) atIndex:2];
...并像这样检查边界:
kernel void test(const device float *inVector [[buffer (0)]],
device float *outVector [[buffer (1)]],
constant int &elementCount [[buffer (2)]],
uint id [[thread_position_in_grid]])
{
if (id < elementCount) {
outVector[id] = -inVector[id];
}
}