Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

295
Views
Sincronice el trabajo entre la CPU y la GPU dentro del búfer de un solo comando usando MTLSharedEvent

Estoy tratando de usar MTLSharedEvent junto con MTLSharedEventListener para sincronizar el cálculo entre GPU y CPU, como en el ejemplo proporcionado por Apple ( https://developer.apple.com/documentation/metal/synchronization/synchronizing_events_ between_a_gpu_and_the_cpu ). Básicamente, lo que quiero lograr es dividir el trabajo en 3 partes ejecutadas en orden, así:

  1. Cálculo GPU parte 1
  2. Cálculo de la CPU basado en los resultados de la parte 1 del cálculo de la GPU
  3. Cálculo de GPU parte 2 después del cálculo de CPU

Mi problema es que el bloque eventListener siempre se llama antes de que se programe la ejecución del búfer de comandos, lo que hace que mi tarea de CPU se ejecute primero en orden.

Para simplificar el caso, usemos comandos simples que llenen MTLBuffer con ciertos valores (mi caso de uso original es más complicado, ya que usa codificadores de cómputo con sombreadores personalizados, pero se comporta de la misma manera):

 let device = MTLCreateSystemDefaultDevice()! let queue = device.makeCommandQueue()! let event = device.makeSharedEvent()! let dispatchQueue = DispatchQueue(label: "myqueue") let eventListener = MTLSharedEventListener(dispatchQueue: dispatchQueue) let metalBuffer = device.makeBuffer(length: 2048, options: MTLResourceOptions.storageModeShared)! let buffer = queue.makeCommandBuffer()! NSLog("Start - signaled value: \(event.signaledValue)") event.notify(eventListener, atValue: 1) { event, value in // CPU work let pointer = metalBuffer.contents().assumingMemoryBound(to: UInt8.self) for i in 0..<512 { (pointer + i).pointee = (pointer + i).pointee + 1; } NSLog("Event notification - signaled value: \(value), buffer status: \(buffer.status.rawValue)") event.signaledValue = 2 } // GPU work part 1 let encoder1 = buffer.makeBlitCommandEncoder()! encoder1.fill(buffer: metalBuffer, range: .init(0...127), value: 22) encoder1.endEncoding() // signal with 1 to start CPU task buffer.encodeSignalEvent(event, value: 1) // wait for value >= 2 to proceed buffer.encodeWaitForEvent(event, value: 2) // GPU work part 2 let encoder2 = buffer.makeBlitCommandEncoder()! encoder2.fill(buffer: metalBuffer, range: .init(128...511), value: 255) encoder2.endEncoding() buffer.addScheduledHandler { buffer in NSLog("Buffer scheduled - signaled value: \(event.signaledValue)") } buffer.addCompletedHandler { buffer in NSLog("Buffer completed - signaled value: \(event.signaledValue)") } buffer.commit() buffer.waitUntilCompleted()

Producción:

 2022-01-09 23:46:08.774 Sync[76882:3531755] Metal GPU Frame Capture Enabled 2022-01-09 23:46:08.805 Sync[76882:3531755] Start - signaled value: 0 2022-01-09 23:46:08.808 Sync[76882:3531764] Event notification - signaled value: 1, buffer status: 2 (Commited) 2022-01-09 23:46:08.809 Sync[76882:3531763] Buffer scheduled - signaled value: 2 2022-01-09 23:46:08.809 Sync[76882:3531763] Buffer completed - signaled value: 2

Como puede ver, eventListener registra el estado del búfer como .commited . ¿Qué pasa aquí? ¿Me estoy perdiendo de algo?

Sistema: macOS 12.0.1, Apple M1 Pro, Xcode 13.2.1

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Está perfectamente bien que el búfer de comando esté comprometido. De hecho, si no se comprometiera, nunca podrá notify el bloqueo.

GPU y CPU se ejecutan en paralelo. Entonces, cuando usa MTLEvent , no deja de ejecutar el código de la CPU (en realidad, todo el código Swift). Simplemente le dice a la GPU en qué orden ejecutar el código de la GPU.

Entonces, ¿qué está pasando en tu caso?

  1. Todo su código se ejecuta en un solo hilo de CPU sin ninguna interrupción.
  2. GPU comienza a ejecutar comandos de búfer de comandos solo cuando llamas a commit() . Antes, la GPU en realidad no hace nada. Acaba de programar el comando para que se ejecute en la GPU, pero no lo ejecuta.
  3. Cuando GPU ejecuta comandos, busca su MTLEvent . Realiza la parte 1, luego codifica el valor 1 para el evento, realiza el bloque de notificación, codifica el valor 2 , realiza el segundo bloque de GPU.

Pero nuevamente, todo el trabajo real de la GPU comienza solo cuando llamas a commit() en el búfer de comando. Es por eso que el búfer ya está comprometido en el bloque de notificación. Porque se realiza después de commit() .

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!