Estaba revisando un documento que habla sobre las técnicas de optimización del compilador Just -In-Time (JIT) para Java. Uno de ellos fue la "inversión de bucle". Y el documento dice:
Reemplaza un
while
bucle regular con undo-while
bucle. Y eldo-while
bucle se establece dentro de unaif
cláusula. Este reemplazo conduce a dos saltos menos.
¿Cómo funciona la inversión de bucle y cómo optimiza nuestra ruta de código?
NB: Sería genial si alguien pudiera explicar con un ejemplo de código Java y cómo JIT lo optimiza al código nativo y por qué es óptimo en los procesadores modernos.
java
jvm
jit
machine-instruction
Molesto
fuente
fuente
Respuestas:
Flujo de trabajo:
Flujo de trabajo:
Comparando estos dos, puede ver fácilmente que el último puede no hacer ningún salto en absoluto, siempre que haya exactamente un paso a través del bucle, y generalmente el número de saltos será uno menos que el número de iteraciones. El primero tendrá que saltar hacia atrás para verificar la condición, solo para saltar fuera del ciclo cuando la condición sea falsa.
Los saltos en arquitecturas modernas de CPU con canalización pueden ser bastante costosos: como la CPU está terminando la ejecución de las comprobaciones antes del salto, las instrucciones posteriores a ese salto ya están en el medio del proceso. Todo este procesamiento debe descartarse si falla la predicción de la rama. La ejecución adicional se retrasa mientras se vuelve a cebar la tubería.
Explicando la predicción de bifurcación mencionada : para cada tipo de salto condicional, la CPU tiene dos instrucciones, cada una de las cuales incluye una apuesta sobre el resultado. Por ejemplo, colocaría una instrucción que diga " salte si no es cero, apostando a que no sea cero " al final de un ciclo porque el salto tendrá que realizarse en todas las iteraciones excepto en la última. De esa manera, la CPU comienza a bombear su canalización con las instrucciones que siguen al objetivo de salto en lugar de las que siguen la instrucción de salto en sí.
Nota IMPORTANTE
Por favor, no tome esto como un ejemplo de cómo optimizar a nivel de código fuente. Eso sería completamente equivocado ya que, como ya se desprende de su pregunta, la transformación del primer formulario al segundo es algo que el compilador JIT hace como una cuestión de rutina, completamente por sí solo.
fuente
do-while
código de bytes generado para el código fuente dado es irrelevante, porque en realidad no lo escribimos. Escribimos elwhile
bucle y dejamos que el compilador y JIT conspiren para mejorarlo por nosotros (a través de la inversión del bucle) si es necesario.Esto puede optimizar un bucle que siempre se ejecuta al menos una vez.
Un
while
bucle regular siempre saltará al principio al menos una vez y saltará al final una vez al final. Un ejemplo de un bucle simple que se ejecuta una vez:Por
do-while
otro lado, un bucle saltará el primer y último salto. Aquí hay un ciclo equivalente al anterior, que se ejecutará sin saltos:fuente
boolean b = true; while(b){ b = maybeTrue();}
queboolean b;do{ b = maybeTrue();}while(b);
debería ser suficiente.Caminemos por ellos:
La
while
versión:n
y saltamos adone();
si la condición no es verdadera.n
.done()
.La
do-while
versión:(Recuerde, en realidad no hacemos esto en el código fuente [que introduciría problemas de mantenimiento], el compilador / JIT lo hace por nosotros).
n
y saltamos adone();
si la condición no es verdadera.n
.done()
.Entonces, por ejemplo, si
n
comienza siendo9
, nunca saltamos en lado-while
versión, mientras que en lawhile
versión tenemos que volver al principio, hacer la prueba y luego saltar al final cuando vemos que no es cierto. .fuente
La inversión de bucle es una técnica de optimización del rendimiento que mejora el rendimiento ya que el procesador puede lograr el mismo resultado con menos instrucciones. Esto debería mejorar principalmente el rendimiento en condiciones de contorno.
Este enlace proporciona otro ejemplo de inversión de bucle. En algunas arquitecturas donde decrementar y comparar se implementan como un solo conjunto de instrucciones, tiene sentido convertir un bucle for a un tiempo con la operación de decremento y comparación.
Wikipedia tiene un muy buen ejemplo y lo vuelvo a explicar aquí.
será convertido por el compilador a
¿Cómo se traduce esto en rendimiento? Cuando el valor de i es 99, el procesador no necesita realizar un GOTO (que se requiere en el primer caso). Esto mejora el rendimiento.
fuente