【问题标题】:Segmentation fault is thrown when using Metal (Mac OS X 10.15.6)使用 Metal (Mac OS X 10.15.6) 时引发分段错误
【发布时间】:2021-01-09 06:05:36
【问题描述】:

我正在尝试通过 Apple 文档学习 Metal。到目前为止,我已经完成了一个计算 4096 个随机数平方根的应用程序。但是,当我通过终端运行它时,它会立即引发分段错误。

输出:

Segmentation fault: 11
logout
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

[Process completed]

到目前为止,我已经尝试在代码中几乎所有位置插入std::couts,我发现问题出在生成随机数的函数 (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));
    }
}

【问题讨论】:

    标签: objective-c macos metal


    【解决方案1】:

    generateRandomFloatData 中的buffernil,因为_mBufferAnil

    _mBufferAnil,因为 _mDevicenil

    MTLCreateSystemDefaultDevice 返回nil 因为(来自MTLCreateSystemDefaultDevice

    在 macOS 中,为了让系统提供默认的 Metal 设备对象,您必须链接到 CoreGraphics 框架。如果您正在编写默认不使用图形的应用程序,例如命令行工具,您通常需要明确地执行此操作。

    你之前的问题:

    为什么 Metal 在终端运行时不起作用,但在 Xcode 运行时却很好?

    在 Xcode 中 MTLCreateSystemDefaultDevice 在我的 Mac 上返回

    _mDevice: -> -> 名称 = 英特尔高清显卡 4000

    在终端 MTLCreateSystemDefaultDevice 返回

    _mDevice: 名称 = 英特尔高清显卡 4000

    显然 Xcode 将设备包装在调试设备中,这具有修复问题的副作用。

    【讨论】:

      猜你喜欢
      • 2021-01-20
      • 2017-07-30
      • 1970-01-01
      • 2014-06-27
      • 1970-01-01
      • 2011-10-02
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多