#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 помещает устройство в устройство отладки, что имеет побочный эффект устранения проблемы.