【问题标题】:Performance of metal function multiple call金属函数多次调用的表现
【发布时间】:2017-07-11 12:56:02
【问题描述】:

我使用 Apple Metal 为 iPhone/iPad 进行刚体模拟。为此,我需要多次调用内核函数,而且我看到这需要很长时间,例如与 CUDA 相反。 我实现了 Metal 内核函数调用,就像 Apple 教程中描述的那样

let commandQueue = device.newCommandQueue()

var commandBuffers:[MTLCommandBuffer]=[]
var gpuPrograms:[MTLFunction]=[]
var computePipelineFilters:[MTLComputePipelineState]=[]
var computeCommandEncoders:[MTLComputeCommandEncoder]=[]

//here i fill all arrays for my command queue
//and next i execute it 

let threadsPerGroup = MTLSize(width:1,height:1,depth:1)
let numThreadgroups = MTLSize(width:threadsAmount, height:1, depth:1)

for computeCommandEncoder in computeCommandEncoders
{
    computeCommandEncoder.dispatchThreadgroups(numThreadgroups, threadsPerThreadgroup: threadsPerGroup)
}

for computeCommandEncoder in computeCommandEncoders
{
    computeCommandEncoder.endEncoding()
}

for commandBuffer in commandBuffers
{
    commandBuffer.enqueue()
}

for commandBuffer in commandBuffers
{
    commandBuffer.commit()
}

for commandBuffer in commandBuffers
{
    commandBuffer.waitUntilCompleted()
}

我每帧最多做几十个金属内核函数,它工作得太慢了。我用空的内核函数对其进行了测试——它告诉我,问题出在 Swift 执行部分。我的意思是,当我想在 CUDA 中执行内核函数时,我只是像通常的函数一样调用它,它运行得非常快。但是在这里我必须为每帧的每个函数的每次执行做很多动作。可能是我什么都不知道,但我想一次创建所有其他对象,然后制作类似

 commandQueue.execute()

执行所有内核函数。

我是否有权执行许多内核函数,或者有其他方法可以更快地执行?

【问题讨论】:

    标签: ios swift metal


    【解决方案1】:

    我有几个项目在一个步骤中使用多个着色器。我只创建了一个缓冲区和编码器,但创建了多个管道状态;每个计算函数一个。

    记住MTLCommandQueue是持久的,所以只需要创建一次,所以我的MetalKit View的drawRect()函数大致是这样的(它们之间传递了更多的着色器和纹理,但你对结构有所了解) :

    let commandBuffer = commandQueue.commandBuffer()
    let commandEncoder = commandBuffer.computeCommandEncoder()
    
    commandEncoder.setComputePipelineState(advect_pipelineState)
    commandEncoder.dispatchThreadgroups(threadgroupsPerGrid, 
        threadsPerThreadgroup: threadsPerThreadgroup)
    
    commandEncoder.setComputePipelineState(divergence_pipelineState)
    commandEncoder.dispatchThreadgroups(threadgroupsPerGrid, 
        threadsPerThreadgroup: threadsPerThreadgroup)
    
    [...]
    
    commandEncoder.endEncoding()
    commandBuffer.commit()
    

    我的代码实际上在其中一个着色器上迭代了 20 次,但运行起来仍然非常流畅,因此,如果您重新组织并使用单个缓冲区和单个编码器遵循此结构,并且每次传递只调用一次 endEncoding()commit() ,您可能会看到性能有所提升。

    May 是有效词 :)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-02
      • 2016-04-22
      • 1970-01-01
      • 2021-08-02
      • 2020-11-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多