我正在尝试通过Apple文档学习Metal。到目前为止,我已经完成了编写一个计算4096个随机数的平方根的应用程序。但是,当我通过终端运行它时,它将立即引发分段错误。
输出:
Segmentation fault: 11
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.
[Process completed]
到目前为止,我已经尝试将std::cout
s几乎插入所有代码中,并且发现问题出在生成随机数(generateRandomFloatData(id<MTLBuffer> buffer)
)的函数上。
当我尝试打印输入缓冲区的地址时,得到以下输出:
0x0
Segmentation fault: 11
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.
[Process completed]
奇怪的是,它打印出NULL指针的地址。
更多测试显示,更改功能以正确输入char指针会输出0x7ffee8bd8620
指向该字符串的地址。
我的代码有问题吗?
//
// main.mm
// MetalComputeCPP
//
// Created by [] on 5/1/21.
// Copyright © 2021 thng. All rights reserved.
//
#include <iostream>
#include <ApplicationServices/ApplicationServices.h>
#include <Metal/Metal.h>
#include <Foundation/Foundation.h>
#include <chrono>
const unsigned int arrayLength = 1 << 12;
const unsigned int bufferSize = arrayLength * sizeof(float);
void generateRandomFloatData(id<MTLBuffer> buffer) {
std::cout << ((float*)buffer.contents) << "\n";
float* dataPtr = ((float*)buffer.contents);
for (unsigned long index = 0; index < arrayLength; index++)
{
dataPtr[index] = (float)((rand()/(float)(RAND_MAX))*10);
std::cout << dataPtr[index] << "\n";
}
}
int main(int argc, const char * argv[]) {
id<MTLDevice> _mDevice = MTLCreateSystemDefaultDevice();
NSError* error = nil;
id<MTLLibrary> defaultLibrary = [_mDevice newDefaultLibrary];
id<MTLFunction> SqrtFunction = [defaultLibrary newFunctionWithName:@"SqrtArray"];
id<MTLComputePipelineState> _mSqrtFunctionPSO = [_mDevice newComputePipelineStateWithFunction: SqrtFunction error:&error];
id<MTLCommandQueue> _mCommandQueue = _mDevice.newCommandQueue;
id<MTLBuffer> _mBufferA = [_mDevice newBufferWithLength:bufferSize options:MTLResourceStorageModeShared];
id<MTLBuffer> _mBufferResult = [_mDevice newBufferWithLength:bufferSize options:MTLResourceStorageModeShared];
MTLSize gridSize = MTLSizeMake(arrayLength, 1, 1);
NSUInteger threadGroupSize = _mSqrtFunctionPSO.maxTotalThreadsPerThreadgroup;
if (threadGroupSize > arrayLength)
{
threadGroupSize = arrayLength;
}
MTLSize threadgroupSize = MTLSizeMake(threadGroupSize, 1, 1);
generateRandomFloatData(_mBufferA);
std::cout << "Generated random float data.\n";
id<MTLCommandBuffer> commandBuffer = _mCommandQueue.commandBuffer;
id<MTLComputeCommandEncoder> computeEncoder = [commandBuffer computeCommandEncoder];
[computeEncoder setComputePipelineState:_mSqrtFunctionPSO];
[computeEncoder setBuffer:_mBufferA offset:0 atIndex:0];
[computeEncoder setBuffer:_mBufferResult offset:0 atIndex:1];
[computeEncoder dispatchThreads:gridSize
threadsPerThreadgroup:threadgroupSize];
[computeEncoder endEncoding];
[commandBuffer commit];
std::chrono::high_resolution_clock::time_point start = std::chrono::high_resolution_clock::now();
[commandBuffer waitUntilCompleted];
std::chrono::high_resolution_clock::time_point end = std::chrono::high_resolution_clock::now();
uint64_t time = std::chrono::duration_cast<std::chrono::nanoseconds>(end-start).count();
float* a = ((float*)_mBufferA.contents);
float* result = ((float*)_mBufferResult.contents);
bool err = false;
for (unsigned long index = 0; index < arrayLength; index++)
{
if (abs(result[index] - (float)sqrt(a[index])) > 0.0001) err = true;
std::cout << "√" << a[index] << (err ? " != " : " = ") << result[index] << "\n";
}
std::cout << time << " nanoseconds\n";
printf("Compute results as expected\n");
return 0;
}
//
// File.metal
// MetalComputeCPP
//
// Created by [] on 5/1/21.
// Copyright © 2021 thng. All rights reserved.
//
#include <metal_stdlib>
using namespace metal;
kernel void SqrtArray(device const float* inA,
device float* outB,
uint ind [[thread_position_in_grid]]) {
//(x^n-k)' = (nx^(n-1))
//f(x0)/f'(x0)
outB[ind] = 0.1;
for (int i = 0; i < 20; i++) {
outB[ind] = outB[ind]-((outB[ind]*outB[ind]-inA[ind])/(outB[ind]*2));
}
}
buffer
在generateRandomFloatData
是nil
因为_mBufferA
是nil
。
_mBufferA
是nil
因为_mDevice
是nil
。
MTLCreateSystemDefaultDevice
返回,nil
因为(来自MTLCreateSystemDefaultDevice)
在macOS中,为了使系统提供默认的Metal设备对象,您必须链接到CoreGraphics框架。如果要编写默认情况下不使用图形的应用程序(例如命令行工具),通常需要明确地执行此操作。
您之前的问题:
为什么通过终端运行Metal时不起作用,而通过Xcode运行时则很好?
在MTLCreateSystemDefaultDevice
Mac上的Xcode中返回
_mDevice:<CaptureMTLDevice:0x10050bbb0>-> <MTLDebugDevice:0x10050aae0>-> <MTLIGAccelDevice:0x1031c8000>名称= Intel HD Graphics 4000
在终端MTLCreateSystemDefaultDevice
退货
_mDevice:<MTLIGAccelDevice:0x7f9c32f17000>名称= Intel HD Graphics 4000
Apparenlty Xcode将设备包装在调试设备中,这具有解决问题的副作用。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句