2012-03-29 18 views
61

Mi aplicación necesita ejecutar muchos contextos separados en el mismo proceso (de un único subproceso). Todos ellos comparten un solo LLVMContext.sugerencia de diseño: llvm contextos de tiempo de ejecución múltiples

El proceso se ejecutará en muchos contextos (en el sentido del hilo); es decir, cada uno ejecuta una función en un objeto de continuación basado en boost::context (todavía en bóveda, lib preaprobada) significa que cada contexto puede ceder, pero básicamente se ejecutan en el mismo proceso de subproceso único. Cada uno debe ejecutarse básicamente de forma independiente del otro, y lo que es más importante, un error de compilación en cada uno no debe afectar la ejecución de los demás.

Cada uno de estos contextos invocará el código dinámicamente que abarca varias unidades de traducción (TU). algunas unidades de traducción se pueden compartir en muchos de estos contextos. los errores de compilación en una unidad de traducción nueva o modificada no deberían afectar a otros contextos.

Aclaración Edición: Por ejemplo, T.U. A puede compartirse entre dos contextos, el contexto X e Y. solo por el hecho de tener una imagen completa, digamos que X también ejecutará código de otras unidades de traducción, es decir, B y D, mientras que Y también tendrá C. En algún punto, X decide hacer una modificación a A, por lo que crea una nueva TU A.1, que es una copia de A, y aplica la modificación allí, por lo que no afectará el contexto Y. Espero que este ejemplo aclare la requisito.

Mi impulso inicial era asociar una llvm::Module para cada contexto, pero desde su indefinida en LLVM lo que sucede con un módulo en un estado intermedio de compilación, que decidió añadir una llvm::Module para cada unidad de traducción (ver this question for the reason), además de la política de copia sobre escritura que expliqué anteriormente para cuando las modificaciones de una unidad de traducción ocurren localmente en un contexto, con el fin de evitar una modificación que afecte a otros contextos.

La principal pregunta de dos veces que he tengo es:

  • ¿Cómo se enlazan entre sí los diferentes módulos en un contexto con el fin de invocarlos como una biblioteca unificada? Estoy usando la API de C++. Soy particularmente cauteloso con this nasty, old bug que afecta esta funcionalidad. ¿Esta falla aún me afectaría si transfiere la propiedad de todos los módulos al JIT con ExecutionEngine::addModule()?

  • ¿Cuáles son los pasos necesarios una vez que una modificación en una unidad de traducción fuerza la actualización de uno de los módulos? ¿Debo soltar/eliminar el antiguo objeto del módulo y crear uno nuevo? ¿Existe una política de reciclaje que no haya leído?

Una cuestión secundaria que tengo de este es:

  • ¿Cuántas ExecutionEngine necesito? uno para toda la aplicación? uno por contexto? uno por módulo?

Espero que el alcance de la pregunta no sea demasiado abrumador.

+2

No soy un experto, pero creo que puedo agregar algo aquí para al menos comenzar. A la pregunta 1a: la parte inferior de [su enlace] (http://llvm.org/bugs/show_bug.cgi?id=2606) parece afirmativa que arrojar sus módulos en JIT funcionará efectivamente alrededor del error. Para 1b: los [documentos de API] (http://llvm.org/docs/doxygen/html/classllvm_1_1Module.html) sugieren que no hay reciclaje de recursos, solo una [estructura de paso] (http://llvm.org/docs/WritingAnLLVMPass) .html). Entonces, depende de la mutación de tus módulos. A 2: digo, deje que su diseño y necesidades lo determinen, dadas las soluciones a sus primeras dos preguntas. ¡Buena suerte! – MrGomez

+0

Y eso es tan expresamente escueto como puedo hacer mi pseudo-respuesta. Avíseme si prefiere formalizar esto en una respuesta real, a pesar de mi error admitido a través de las notas de diseño, la documentación y la teoría de compilación detrás de cómo opera LLVM. – MrGomez

Respuesta

1

Creo que necesita un marco conceptual para "colgar" sus ideas. Pensar en los diversos bits de ejecución como comandos (tal vez incluso implementar usando el patrón de comando) le dará un conjunto más obvio de puntos de interacción. Habiendo dicho eso; Necesitarás un contexto para cada ejecución discreta a la que quieras volver. Más de dos requerirán que usted cree una contabilidad apropiada. Creo que dos se manejan esencialmente de forma gratuita en el impulso.
La comunicación entre los bits de ejecución es similar a usted. Crear un estado (recuerdo) que se comparte entre los contextos de ejecución es una solución que viene a la mente. También es posible que ya tenga el estado adecuado integrado en su tiempo de ejecución, y luego no se requerirá ninguna capa adicional. Como señaló, los globales no son sus amigos en estas interacciones. El control de versiones y la resolución de nombres también son un problema. Mantener separados los bits de ejecución ayuda a resolver este problema. Una vez que resuelve el problema de coordinación, esto es más una cuestión de rastrear qué bits ya ha creado. Esto también significa que no hay necesidad de reciclar, solo crea nuevos cada vez y no hay recarga. También deberá administrar el final de la vida útil de estos bits una vez que hayan finalizado la ejecución. Propongo un ExecutionEngine por bit de ejecución. No hacer esto significa mucho más trabajo tratando de "proteger" el código de trabajo de los efectos del código que está mal. Creo que es posible hacer esto con un solo motor, pero sería significativamente más arriesgado.

Cuestiones relacionadas