Ошибка сегментации возникает при использовании Metal (Mac OS X 10.15.6)

#objective-c #macos #metal

#objective-c #macos #Металлические

Вопрос:

Я пытаюсь изучить Metal с помощью документации Apple. На данный момент я закончил писать приложение, которое вычисляет квадратный корень из 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]
 

Как ни странно, он выводит адрес нулевого указателя.

Дополнительные тесты показали, что изменение функции для ввода указателя символа корректно выводит адрес 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:amp;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 << " nanosecondsn";
    printf("Compute results as expectedn");
    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));
    }
}
 

Ответ №1:

buffer это generateRandomFloatData nil потому _mBufferA , что есть nil .

_mBufferA это nil потому _mDevice , что есть nil .

MTLCreateSystemDefaultDevice возвращает nil , потому что (из MTLCreateSystemDefaultDevice)

В macOS, чтобы система предоставила объект Metal Device по умолчанию, необходимо выполнить ссылку на CoreGraphics framework. Обычно вам нужно сделать это явно, если вы пишете приложения, которые не используют графику по умолчанию, например, инструменты командной строки.

Ваш предыдущий вопрос:

Почему Metal не работает при запуске через терминал, но работает нормально при запуске через Xcode?

В Xcode MTLCreateSystemDefaultDevice возвращается на мой Mac

_mDevice: <CaptureMTLDevice: 0x10050bbb0> -> <MTLDebugDevice: 0x10050aae0> -> <MTLIGAccelDevice: 0x1031c8000> имя = Intel HD Graphics 4000

В терминале MTLCreateSystemDefaultDevice возвращает

_mDevice: <MTLIGAccelDevice: 0x7f9c32f17000> имя = Intel HD Graphics 4000

По-видимому, Xcode помещает устройство в устройство отладки, что имеет побочный эффект устранения проблемы.