2016-05-17 13 views
0

Ich schrieb einen einfachen Code wie folgt, um zu prüfen, ob GPU könnte einige Rechenarbeiten tun.konnte keine Daten aus GPU bei der Verwendung von Metall

id<MTLDevice> device = MTLCreateSystemDefaultDevice(); 
NSLog(@"Device: %@", [device name]); 

id<MTLCommandQueue> commandQueue = [device newCommandQueue]; 

NSError * ns_error = nil; 
id<MTLLibrary>defaultLibrary = [device newLibraryWithFile:@"/Users/i/tmp/tmp6/s.metallib" error:&ns_error]; 

// Buffer for storing encoded commands that are sent to GPU 
id<MTLCommandBuffer> commandBuffer = [commandQueue commandBuffer]; 

// Encoder for GPU commands 
id <MTLComputeCommandEncoder> computeCommandEncoder = [commandBuffer computeCommandEncoder]; 

//set input and output data 
float tmpbuf[1000]; 
float outbuf[1000]; 
for(int i = 0; i < 1000; i++) 
{ 
    tmpbuf[i] = i; 
    outbuf[i] = 0; 
} 

int tmp_length = 100*sizeof(float); 
id<MTLBuffer> inVectorBuffer = [device newBufferWithBytes: tmpbuf length: tmp_length options: MTLResourceOptionCPUCacheModeDefault ]; 
[computeCommandEncoder setBuffer: inVectorBuffer offset: 0 atIndex: 0 ]; 
id<MTLBuffer> outVectorBuffer = [device newBufferWithBytes: outbuf length: tmp_length options: MTLResourceOptionCPUCacheModeDefault ]; 
[computeCommandEncoder setBuffer: outVectorBuffer offset: 0 atIndex: 1 ]; 


//get fuction 
id<MTLFunction> newfunc = [ defaultLibrary newFunctionWithName:@"sigmoid" ]; 

//get pipelinestat 
id<MTLComputePipelineState> cpipeline = [device newComputePipelineStateWithFunction: newfunc error:&ns_error ]; 

[computeCommandEncoder setComputePipelineState:cpipeline ]; 

// 
MTLSize ts= {10, 10, 1}; 
MTLSize numThreadgroups = {2, 5, 1}; 
[computeCommandEncoder dispatchThreadgroups:numThreadgroups threadsPerThreadgroup:ts]; 
[ computeCommandEncoder endEncoding ]; 
[ commandBuffer commit]; 

//get data computed by GPU 
NSData* outdata = [NSData dataWithBytesNoCopy:[outVectorBuffer contents ] length: tmp_length freeWhenDone:false ]; 
float final_out[1000]; 
[outdata getBytes:final_out length:tmp_length]; 

//In my option, each value of final_out should be 0 
for(int i = 0; i < 1000; i++) 
{ 
    printf("%.2f : %.2f\n", tmpbuf[i], final_out[i]); 
} 

Die Shader-Datei, name s.shader, ist wie folgt, wobei dieser Wert mit dem Ausgang zuzuweisen 10,0

using namespace metal; 
kernel void sigmoid(const device float *inVector [[ buffer(0) ]], 
       device float *outVector [[ buffer(1) ]], 
       uint id [[ thread_position_in_grid ]]) { 
    // This calculates sigmoid for _one_ position (=id) in a vector per call on the GPU 
    outVector[id] = 10.0; 
} 

In dem obigen Codes, habe ich durch GPU durch variable final_out berechneten Daten. In meiner Option sollte jeder Wert von final_out 10.0 sein, wie in s.shader dargestellt. Alle Werte von final_out sind jedoch 0. Jedes Problem beim Zurückholen von Daten von der GPU? Danke.

Antwort

2

Das Commit eines Befehlspuffers weist den Treiber einfach an, mit der Ausführung zu beginnen. Wenn Sie die Ergebnisse einer GPU-Operation auf der CPU zurücklesen möchten, müssen Sie entweder den aktuellen Thread mit -waitUntilCompleted blockieren oder einen Block hinzufügen, der aufgerufen wird, wenn der Befehlspuffer mit der -addCompletedHandler:-Methode abgeschlossen ist.

Noch eine Anmerkung: Es sieht so aus, als ob Sie Puffer mit einem Speichermodus von Shared verwenden. Wenn Sie jemals Puffer mit dem Speichermodus Managed verwenden möchten, müssen Sie auch einen Blit-Befehlscodierer erstellen und synchronizeResource: mit dem/den entsprechenden Puffer (n) aufrufen und dann warten, bis der Vorgang wie oben beschrieben abgeschlossen ist Zurück die Ergebnisse von der GPU.

+0

Dank warrenm, ich würde die Codes verbessern, wie Sie sagten. – Pony

+0

das Problem besteht immer noch. Ich fügte "[commandBuffer waitUntilCompleted];" nach commandBuffer Commit, und ich habe keine Puffer mit einem Speichermodus von Managed verwendet. Das Zurückholen von Daten von der GPU ist jedoch fehlgeschlagen. – Pony

+0

Sie senden ein 2D-Gitter, aber der Parameter 'thread_position_in_grid' ist 1D. Das ist eine ungültige Konfiguration, die eine Assertion auslösen sollte, wenn Sie mit aktivierter Validierungsebene arbeiten. – warrenm

Verwandte Themen