Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

281
Vistas
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 Respuestas
Responde la pregunta

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 Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda