2012-03-29 10 views
61

La mia applicazione deve eseguire molti contesti separati nello stesso processo (a thread singolo). Tutti condividono un singolo LLVMContext.suggerimento di progettazione: llvm più contesti di runtime

Il processo eseguirà molti contesti (nel senso del thread); ovvero, ognuno di essi esegue una funzione in un oggetto di continuazione basato su boost::context (ancora su vault, librerie pre-approvate) significa che ogni contesto può produrre, ma fondamentalmente viene eseguito nello stesso processo a thread singolo. Ognuno dovrebbe funzionare fondamentalmente indipendentemente dall'altro e, cosa più importante, un errore di compilazione in ognuno di essi non dovrebbe influire sull'esecuzione degli altri.

Ciascuno di questi contesti invocherà il codice dinamicamente che si estende su più unità di traduzione (TU). alcune unità di traduzione possono essere condivise in molti di questi contesti. errori di compilazione in un'unità di traduzione nuova o modificata non dovrebbero influenzare altri contesti.

Chiarimento Modifica: Ad esempio, T.U. A potrebbe essere condiviso tra due contesti, il contesto X e Y. solo per il fatto di avere un'immagine completa, diciamo che X eseguirà anche il codice da altre unità di traduzione, cioè B e D, mentre Y avrà anche C. A un certo punto, X decide di apportare una modifica ad A, quindi crea una nuova TU A.1, che è una copia di A, e applica la modifica lì, quindi quelli non influenzeranno il contesto Y. Spero che questo esempio chiarisca il Requisiti.

mio impulso iniziale è stato quello di associare un llvm::Module per ogni contesto, ma dal momento che la sua indefinita in LLVM cosa succede con un modulo in uno stato intermedio di compilazione, ho deciso di aggiungere un llvm::Module per ogni unità di traduzione (vedi this question for the reason), più la politica copy-on-write che ho spiegato prima per quando le modifiche di un'unità di traduzione avvengono localmente in un contesto, al fine di evitare una modifica che interessa altri contesti.

La principale domanda duplice ho ho è:

  • Come faccio a collegare insieme i diversi moduli in un contesto per invocare loro come una libreria unificata? Sto usando l'API C++. Sono particolarmente cauto su this nasty, old bug che influisce su questa funzionalità. Questo errore potrebbe ancora influire su di me se trasferissi la proprietà di tutti i moduli al JIT con ExecutionEngine::addModule()?

  • Quali sono i passaggi richiesti una volta che una modifica su un'unità di traduzione forza l'aggiornamento di uno dei moduli? devo eliminare/cancellare il vecchio oggetto modulo e crearne uno nuovo? c'è una politica di riciclaggio di cui non ho letto?

una questione secondaria ho su questo è:

  • Quanti ExecutionEngine ho bisogno? uno per l'intera applicazione? uno per contesto? uno per modulo?

Spero che lo scopo della domanda non sia troppo travolgente.

+2

Non sono un esperto, ma penso di poter aggiungere qualcosa qui almeno per iniziare. Alla domanda 1a: la parte inferiore di [il tuo link] (http://llvm.org/bugs/show_bug.cgi?id=2606) sembra affermativa che il lancio dei tuoi moduli in JIT funzionerà effettivamente attorno al bug. A 1b: i [documenti API] (http://llvm.org/docs/doxygen/html/classllvm_1_1Module.html) non suggeriscono il riciclaggio delle risorse, solo una [struttura del passaggio] (http://llvm.org/docs/WritingAnLLVMPass .html). Quindi, dipende dalla mutazione dei tuoi moduli. Per 2: dico, lascia che sia il tuo design e i tuoi bisogni a determinarlo, date le soluzioni alle tue prime due domande. In bocca al lupo! – MrGomez

+0

E questo è espressamente teso come posso fare la mia pseudo-risposta. Fammi sapere se preferisci che lo formalizzi in una risposta vera, nonostante abbia ammesso di aver confuso le note di progettazione, la documentazione e la teoria del compilatore dietro il funzionamento di LLVM. – MrGomez

risposta

1

Penso che tu abbia bisogno di una struttura concettuale per "appendere" le tue idee. Pensare ai vari bit in esecuzione come comandi (magari anche implementando l'utilizzo del pattern di comando) ti darà un insieme più ovvio di punti di interazione. Detto ciò; avrai bisogno di un contesto per ogni esecuzione discreta a cui desideri tornare. Più di due richiederanno di creare un'appropriata contabilità. Credo che due siano gestiti essenzialmente gratis.
La comunicazione tra i bit di esecuzione è simile a voi. La creazione di uno stato (memento) condiviso tra i contesti di esecuzione è una soluzione che viene in mente. Potresti anche avere uno stato adatto integrato nel tuo tempo di esecuzione, quindi non sarà richiesto alcun livello aggiuntivo. Come hai sottolineato, i globals non sono tuoi amici in queste interazioni. Anche il versioning e la risoluzione dei nomi sono un problema. Mantenere separati i bit di esecuzione è molto importante per risolvere questo problema. Una volta risolto il problema di coordinamento, si tratta più di tenere traccia dei bit che hai già creato. Ciò significa anche che non è necessario riciclare, basta crearne di nuovi ogni volta e non è necessario ricaricare. Dovrai anche gestire la fine della vita di questi bit una volta completato l'esecuzione. Sto proponendo uno ExecutionEngine per bit di esecuzione. Non fare questo significa molto più lavoro nel tentativo di "proteggere" il codice di lavoro dagli effetti del codice che è sbagliato. Credo che sia possibile farlo con un singolo motore, ma sarebbe molto più rischioso.

Problemi correlati