tecnicas tag que page onpage define como lua profiling

lua - tag - tecnicas seo on page



Guía de optimización de LuaJIT 2 (3)

Actualizar

Mike ha creado y lanzado recientemente un maravilloso perfilador de peso ligero para LuaJIT, puedes encontrarlo here .

Actualizar

La wiki ha ganado algunas páginas más en esta área, especialmente esta , que detalla algunas cosas adicionales que no se mencionan en la respuesta original, y se basa en una lista de correo publicada por Mike.

LuaJIT lanzó recientemente su propia wiki y lista de correo , y con esas cosas se presentan muchas, muchas más gemas para acelerar el código de LuaJIT.

En este momento, la wiki es bastante delgada (pero siempre está buscando personas para agregarla), sin embargo, una gran página que se agregó recientemente es una lista de funciones de la JNI . Las funciones de la JNI hacen que el JIT se salte y retroceda al intérprete, por lo que, obviamente, uno debería evitar las funciones de la JNI tanto como sea posible en el hotpath, especialmente en los bucles.

Algunos temas de interés de la lista de correo:

Y solo para repetir lo que se dice más abajo (porque es tan útil), -jv es la mejor herramienta para ajustar el rendimiento, también debe ser su primera parada cuando esté -jv problemas.

Respuesta original

Dudo que encuentre mucho sobre esto en realidad, principalmente porque LJ2 todavía está en beta, y por lo tanto, la mayoría de los perfiles se realizan de forma ingenua, ya que no hay enganches de depuración para cosas específicas de LJ2 como el registrador de seguimiento.

En el lado positivo, el nuevo módulo FFI permite llamadas directas a temporizadores de alta resolución (o API de creación de perfiles como VTune / CodeAnalyst), puede crear perfiles de esa manera, pero cualquier cosa más requiere extensiones al núcleo LJ2 JIT, lo que no debería ser demasiado difícil. , ya que el código es claro y comentado.

Uno de los parámetros de línea de comando del registrador de trazas (tomado de here ):

Los comandos -jv y -jdump son módulos de extensión escritos en Lua. Se utilizan principalmente para depurar el propio compilador JIT. Para obtener una descripción de sus opciones y el formato de salida, lea el bloque de comentarios al comienzo de su fuente. Se pueden encontrar en el directorio lib de la distribución de origen o se pueden instalar en el directorio jit. Por defecto, es /usr/local/share/luajit-2.0.0-beta8/jit en los sistemas POSIX.

lo que significa que puede usar el código de módulo de los comandos para formar la base de un módulo de perfil para LuaJIT 2.

Actualizar

Con la actualización de la pregunta, esto se vuelve un poco más fácil de responder. Así que comencemos desde la fuente, LuaJIT.org :

antes de optimizar manualmente el código, siempre es una buena idea comprobar los recursos de optimización de optimización del JIT:

Compilacion

Desde la página En here podemos ver todas las opciones para configurar los parámetros del JIT. Para la optimización, nos centramos en la opción -O . Inmediatamente, Mike nos dice que habilitar todas las optimizaciones tiene un impacto mínimo en el rendimiento, así que asegúrese de ejecutar en -O3 (que ahora es el valor predeterminado), por lo tanto, las únicas opciones aquí de valor real para nosotros son los umbrales JIT y Trace.

Estas opciones son muy específicas para el código que está escribiendo, por lo tanto, no hay "configuraciones óptimas" genéricas aparte de las predeterminadas, pero no hace falta decir que si su código tiene muchos bucles, experimente con el desenrollado del bucle y el tiempo de ejecución ( pero vacíe el caché entre cada ejecución si está buscando un rendimiento de arranque en frío).

-jv también es útil para ayudar a evitar los issues/''fallbacks'' conocidos issues/''fallbacks'' que harán que el JIT se rescate.

El sitio en sí no ofrece mucho sobre cómo escribir un código mejor o más optimizado, a excepción de algunos pequeños detalles en el tutorial de FFI :

Función de caché

El almacenamiento en caché de funciones es un buen refuerzo de rendimiento en Lua, pero es menos importante concentrarse en LuaJIT, ya que el JIT realiza la mayoría de estas optimizaciones, es importante tener en cuenta que el almacenamiento en caché de las funciones de FFI C es malo , se prefiere almacenar en caché espacio de nombres que residen en.

Un ejemplo de la página:

malo:

local funca, funcb = ffi.C.funcb, ffi.C.funcb -- Not helpful! local function foo(x, n) for i=1,n do funcb(funca(x, i), 1) end end

bueno:

local C = ffi.C -- Instead use this! local function foo(x, n) for i=1,n do C.funcb(C.funca(x, i), 1) end end

Problemas de rendimiento de FFI

La sección de Status detalla varias construcciones y operaciones que degradan el rendimiento del código (principalmente porque no se compilan, pero en su lugar usan el respaldo de VM).

Ahora pasamos a la fuente de todas las gemas de LuaJIT, la lista de correo de Lua :

  • Evitar llamadas C y llamadas Lua de la JNI en bucles : si desea que el trazador LJ2 se active y proporcione comentarios útiles, debe evitar las funciones de la JNI (aún no implementadas) o las llamadas C donde el compilador de seguimiento no puede ir. Entonces, si tiene pequeñas llamadas de C que pueden importarse a lua y se usan en bucles, impórtelos, en el peor de los casos, podrían ser ''6% más lentos'' que la implementación del compilador de C, y en el mejor de los casos es más rápido.

  • Utilice matrices lineales sobre ipairs : según Mike, pairs / next siempre será más lento en comparación con otros métodos (también hay un pequeño chisme sobre el almacenamiento en caché de símbolos para el marcador).

  • Evite los bucles anidados : cada nivel de anidamiento requiere un pase adicional para trazar, y estará un poco menos optimizado, específicamente evite los bucles internos con iteraciones más bajas.

  • Puede usar matrices de base 0 : Mike dice que LuaJIT no tiene penalización de rendimiento para matrices basadas en 0, a diferencia de la Lua estándar.

  • Declare a los locales en el ámbito más interno posible : no hay una explicación real de por qué, pero IIRC tiene que ver con el análisis de vitalidad de la SSA. También contiene información interesante sobre cómo evitar demasiados locales (lo que rompe el análisis de la vivacidad).

  • Evite muchos bucles pequeños : esto desordena las heurísticas de desenrollado y ralentizará el código.

Tidbits más pequeños:

Las herramientas de perfil están disponibles para Lua normal, sin embargo, hay un proyecto más nuevo que es oficialmente compatible con LuaJIT (aunque dudo que tome en cuenta alguna de las características de LuaJIT), luatrace . La wiki de Lua también tiene una página con consejos de optimización para Lua normal, estos deberían ser probados para su efectividad bajo LuaJIT (la mayoría de estas optimizaciones probablemente ya se realizan internamente), sin embargo, LuaJIT todavía usa el GC predeterminado, esto lo deja como un área en la que las mejoras de optimización manual aún pueden ser grandes (hasta que Mike agrega el GC personalizado que mencionó haciendo aquí y allá).

La fuente de LuaJIT contiene algunas configuraciones para jugar con los elementos internos del JIT, sin embargo, estas requieren pruebas exhaustivas para ajustar el código específico de uno, de hecho, podría ser mejor evitarlas por completo, especialmente para aquellos que no lo son. Familiarizado con los internos del JIT.

Estoy buscando una buena guía sobre cómo optimizar el código Lua para LuaJIT 2 . Debería centrarse en los detalles de LJ2, como detectar qué trazas se están compilando y cuáles no, etc.

Cualquier punteros? La recopilación de enlaces a las publicaciones de Lua ML serviría como respuesta (puntos adicionales por resumir estos enlaces aquí).

Actualización: He cambiado el texto del título de "perfilado" a "guía de optimización", ya que esto tiene más sentido.


¡He usado ProFi en el pasado y lo he encontrado bastante útil!


No es exactamente lo que está buscando, pero he logrado algo de ingeniería inversa de las instalaciones de rastreo de jit. *. Lo que sigue es un poco tosco, inexacto, sujeto a cambios y muy incompleto. Empezaré a usarlo en luatrace pronto. Estas funciones se utilizan en varios de los archivos de la biblioteca -j. dump.lua es probablemente un buen lugar para comenzar.

jit.attach

Puede adjuntar devoluciones de llamada a varios eventos del compilador con jit.attach . La devolución de llamada se puede llamar:

  • cuando una función ha sido compilada a bytecode ("bc");
  • cuando se inicia o se detiene la grabación de la traza ("trace");
  • como se está grabando una traza ("registro");
  • o cuando una traza sale a través de una salida lateral ("texit").

Establecer una devolución de llamada con jit.attach(callback, "event") y borrar la misma devolución de llamada con jit.attach(callback)

Los argumentos pasados ​​a la devolución de llamada dependen del evento que se informa:

  • "bc": callback(func) . func es la función que acaba de ser grabada.
  • "trace": callback(what, tr, func, pc, otr, oex)
    • what es una descripción del evento de seguimiento: "flush", "start", "stop", "abort". Disponible para todos los eventos.
    • tr es el número de seguimiento. No disponible para descarga.
    • func es la función que se está rastreando. Disponible para iniciar y abortar.
    • pc es el contador del programa: el número de bytecode de la función que se está grabando (si es una función Lua). Disponible para iniciar y abortar.
    • otr start: el número de rastreo principal si se trata de un rastreo lateral, abortar: abort code (integer)?
    • inicio de oex : el número de salida para la traza principal, abortar: motivo del aborto (cadena)
  • "grabar": callback(tr, func, pc, depth) . Los primeros argumentos son los mismos que para el inicio de rastreo. depth es la profundidad de la alineación del bytecode actual.
  • "texit": callback(tr, ex, ngpr, nfpr) .
    • tr es el número de rastreo como antes
    • ex es el número de salida
    • ngpr y nfpr son el número de registros de propósito general y de punto flotante que están activos en la salida.

jit.util.funcinfo (func, pc)

Cuando se pasa func y pc desde una jit.attach llamada jit.attach , jit.util.funcinfo devuelve una tabla de información sobre la función, como debug.getinfo .

Los campos de la tabla son:

  • linedefined : como para debug.getinfo
  • lastlinedefined : como para debug.getinfo
  • params : el número de parámetros que toma la función
  • stackslots : el número de ranuras de pila que utiliza la variable local de la función
  • upvalues : el número de upvalues ​​que usa la función
  • bytecodes : el número de bytecodes en la función compilada
  • gcconsts : ??
  • nconsts : ??
  • currentline : como para debug.getinfo
  • isvararg : si la función es una función vararg`
  • source : como para debug.getinfo
  • loc : una cadena que describe la fuente y la línea actual, como "<source>: <line>"
  • ffid : el id de la función rápida de la función (si es una). En este caso, solo son válidos los upvalues anteriores y los siguientes.
  • addr : la dirección de la función (si no es una función Lua). Si se trata de una función C en lugar de una función rápida, solo los upvalues arriba son válidos