- Aggiungere operazioni asincrone a HLO è complicata (ad es.
all-reduce-start
eall-reduce-done
). - La suddivisione iniziale e completata potrebbe essere inadeguata per parte dell'uso asincrono d'uso diversi.
Per colmare il primo problema, proponiamo di introdurre un'ultima serie di nuovi
codici operativi asincroni: kAsyncStart
, kAsyncUpdate
e kAsyncDone
. L'idea
consiste nel creare un opcode generico asincrono in grado di aggregare qualsiasi istruzione HLO.
L'operazione effettiva che verrà eseguita in modo asincrono sarà codificata utilizzando
chiamato calcolo che ha solo l'istruzione come radice e qualsiasi
per gli input. Gestione e aliasing del buffer di input/output in corso
possono essere condivisi per qualsiasi operazione asincrona. Il comando async-start
la forma di output sarà quindi una tupla di operandi di input, valori di output ed eventuali
stato intermedio necessario per async-update
o async-done
istruzioni.
%async_op {
%param0 = f32[64] parameter(0)
ROOT %op = f32[32] op(f32[64] %param0), op_specific_attr=”foo”
}
%async-start = (f32[64], f32[32], s32[]) async-start(f32[64] %operand),
calls=%async_op
%async-done = f32[32] async-done((f32[64], f32[32], s32[]) %async-start)
Nella rappresentazione precedente, solo async-start
ha un calcolo chiamato dal
è banale scoprire che cosa fa async-done
seguendo il suo operando
trova il valore async-start
corrispondente per trovare il calcolo chiamato.
Nota anche
che il primo elemento nella tupla di output di async-start
alias con
operando, in modo che il buffer rimanga attivo fino almeno fino all'istruzione asincrona.
Allo stesso modo, gli alias del secondo elemento con l'output async-done
e
Il terzo elemento è lo stato del contesto utilizzato per tenere traccia
un'operazione asincrona. Questa rappresentazione supporta anche più tensori
l'input e/o l'output dell'operazione asincrona e l'aliasing funziona allo stesso modo
modo:
%async_op {
%param0 = f32[64] parameter(0)
%param1 = f32[64] parameter(1)
ROOT %op = (f32[32], f32[32]) op(f32[64] %param0, f32[64] %param1),
op_specific_attr=”foo”
}
%async-start = ((f32[64], f32[64]), (f32[32], f32[32]), s32[])
async-start(f32[64] %operand0, f32[64] %operand1),
calls=%async_op
%async-done = (f32[32], f32[32]) async-done(%async-start)
Inoltre, l'operazione può essere ulteriormente scomposta in zero o più async-update
che eseguono calcoli intermedi. L'aliasing di input/output funziona
allo stesso modo con l'istruzione async-update
e ogni async-start
e
Le istruzioni di async-update
devono avere un utente che sia un altro
async-update
o async-done
:
%async_op {
%param0 = f32[64] parameter(0)
ROOT %op = f32[32] op(f32[64] %param0), op_specific_attr=”foo”
}
%async-start = (f32[64], f32[32], s32[]) async-start(f32[64] %operand),
calls=%async_op
%async-update0 = (f32[64], f32[32], s32[]) async-update(
(f32[64], f32[32], s32[]) %async-start)
%async-update1 = (f32[64], f32[32], s32[]) async-update(
(f32[64], f32[32], s32[]) %async-update0)
%async-done = f32[32] async-done((f32[64], f32[32], s32[]) %async-update1)
Sintassi dello zucchero
Dato che disporre di un calcolo separato per definire l'operazione che eseguita in modo asincrono è un po' ingombrante, proponiamo anche una sintassi stampano e analizzano automaticamente le operazioni asincrone come se fossero di prima qualità opcode. L'idea è trattare i suffissi "-start", "-update" e "-done" in particolare creando automaticamente il calcolo e l'istruzione (senza ) durante l'analisi. Ad esempio, lo snippet di codice riportato sopra può essere nei campi seguenti e i due possono essere analizzati nella stessa rappresentazione:
%op-start = (f32[64], f32[32], s32[]) op-start(f32[64] %operand),
op_specific_attr=”foo”
%op-update0 = (f32[64], f32[32], s32[]) op-update(
(f32[64], f32[32], s32[]) %op-start),
op_specific_attr=”foo”
%op-update1 = (f32[64], f32[32], s32[]) op-update(
(f32[64], f32[32], s32[]) %op-update0)
%op-done = f32[32] op-done((f32[64], f32[32], s32[]) %op-update1)
Per non creare ambiguità, lo strumento di verifica non consente a un'operazione di
essere aggregato con async-start se abbiamo definito esplicitamente un codice operativo
con i suffissi "-start" e/o "-done". Anche questa è una modalità di interpretazione letterale
si schiudono nel caso in cui abbiamo istruzioni che richiedono un trattamento a livello di HLO che
non si adatta al modello descritto sopra (ad es. l'input/output dell'aliasing
buffer). All'inizio, quindi, copy-start
/copy-done
,
collective-permute-start
/collective-permute-done
e così via continueranno a utilizzare
i rispettivi opcode di prima classe anziché i nuovi
Codici operativi async-start
/async-done
finché non puliamo il codice per rimuoverli
i codici operativi "-start"/"-done".