2017-11-28 11 views
0

メタルフレームワーク(および一般的にはGPGPU)の初心者であり、何が起こっているのかをよりよく知るためにコードを使いこなそうとしています。メタルを配列内に出力する

次のコードは、単に入力配列の要素を出力し、5.0を追加するだけです。何らかの理由で、しかし、出力配列にデータをコピー、それだけで以下

[6.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] 

を出力し、最後のステップで私の小さなプログラムされています

import Foundation 
import Metal 

//Metal Setup 
var device = MTLCreateSystemDefaultDevice()! 
var commandQueue = device.makeCommandQueue()! 
var library = device.makeDefaultLibrary()! 
var commandBuffer = commandQueue.makeCommandBuffer()! 
var commandEncoder = commandBuffer.makeComputeCommandEncoder()! 

//Prepare Inputs/Outputs 
var input = [Float](repeating: 1, count: 10) 
var output = [Float](repeating: 0, count: 10) 
//Setup Pipeline 
let kernel = library.makeFunction(name: "sigmoid")! 
var pipelineState = try device.makeComputePipelineState(function: kernel) 
commandEncoder.setComputePipelineState(pipelineState) 

//Create GPU Buffers for input/output 
let bytelength = input.count * MemoryLayout<Float>.size 

var inputBuffer = device.makeBuffer(bytes: &input, length: bytelength, options: []) 
var outputBuffer = device.makeBuffer(bytes: &output, length: bytelength, options: []) 

commandEncoder.setBuffer(inputBuffer, offset: 0, index: 0) 
commandEncoder.setBuffer(outputBuffer, offset: 0, index: 1) 

//Setup threads 
var threadsPerGroup = MTLSize(width: 32, height: 1, depth: 1) 
var numThreadGroups = MTLSize(width: (input.count + 31)/32, height: 1, depth: 1) 
commandEncoder.dispatchThreads(numThreadGroups, threadsPerThreadgroup: threadsPerGroup) 

//Start the program on the GPU, wait until finished. 
commandEncoder.endEncoding() 
commandBuffer.commit() 
commandBuffer.waitUntilCompleted() 

//Get result from GPU to CPU data. 
var result = [Float](repeating: 0, count: input.count) 
var data = NSData(bytesNoCopy: (outputBuffer?.contents())!, length: bytelength, freeWhenDone: false) 
data.getBytes(&result, length: bytelength) 
print(result) 

カーネルコードはかなり愚かです:

#include <metal_stdlib> 

using namespace metal; 

kernel void sigmoid(const device float *inVector [[ buffer(0) ]], 
        device float *outVector [[buffer(1) ]], 
        uint id [[ thread_position_in_grid ]]) { 

    outVector[id] = inVector[id] + 5.0; 
} 

これは私が読んできたチュートリアルと一貫しているようです。私もSwift 4のちょっと新しくなったので、私が書いたコードがこれについての最良の方法かどうかは分かりません。すべての助けがありがたいです。

+1

計算機能のスレッド/呼び出しの数はいくらですか? 32(シングルスレッドグループ)、そうですか? 'id'の値が10以上の人はどうなりますか?ええ、わからない。 ;)関数の先頭に 'if(id> = 10)return;'を入れてみてください。 (実際のコードでは、ハードコーディングするのではなく、バッファを使用してカウントを渡したいと思っています) –

+0

ありがとう、これは本当です。私が使用していないスレッドを使用することには意味がありません。しかし、これは私のベクトルの最初のエントリだけに私の出力コンピューティングの私の全体的な問題で私を助けません。 –

+1

GPUカーネルをデバッグするのは難しいです。私が試みる一つの方法は 'outVector [id] =(float)id;'で、どのスレッドIDがバッファ内のどの位置に書き込まれているのか調べます。また、入力バッファと出力バッファを異なる値で埋めることで、正確に何が起こっているのかをよりよく理解することができます。 –

答えて

0

私が後で考え出したように、私のnumThreadsGroupは、グリッドごとにスレッドが1つしかないことを保証します。その整数を10に変更すると、I.E。私の配列のサイズ、それは正しく評価されます。私は愚かですが、私はスレッドとスレッドグループがMetalとどのようにやり取りするかをもっと知る必要があると思います。