¿Por qué genera código Java para realizar una operación funcione más lentamente que un “bucle intérprete”?

StackOverflow https://stackoverflow.com/questions/875695

Pregunta

Tengo algo de código Java que realiza operaciones a nivel de bits en un BitSet. Tengo una lista de las operaciones y puede "interpretar" ellos haciendo un bucle por encima de ellos, pero es importante para mí que puedo realizar estas operaciones lo más rápido posible, por lo que he estado tratando de generar dinámicamente código para aplicarlas. Genero fuente de Java para realizar las operaciones y compilar una clase que implementa estas operaciones utilizando Javassist.

Por desgracia, mi código generado dinámicamente corre más lento que el código interpretado. Parece ser que esto se debe a HotSpot es la optimización del código interpretado, pero no es la optimización del código compilado: Después de lo corro unos pocos miles de veces, mi código interpretado ejecuta dos veces tan rápido como lo hizo al principio, pero mi código compilado no muestra aumento de velocidad. Consistente con esta hipótesis, mi código interpretado es inicialmente más lento que el código compilado, pero es el tiempo más rápido.

No estoy seguro de por qué ocurre esto. Mi conjetura es que tal vez Javassist utiliza un cargador de clases cuyas clases HotSpot no toca. Pero no soy experto en la carga de clases en Java, así que no estoy seguro si esto es una suposición razonable, o cómo hacer para probarlo. Así es como yo estoy creando y cargando la clase con Javassist:

ClassPool pool = ClassPool.getDefault();
CtClass tClass = pool.makeClass("foo");

// foo implements MyInterface, with one method
tClass.addInterface(pool.get(MyInterface.class.getName()));

// Get the source for the method and add it
CtMethod tMethod = CtNewMethod.make(getSource(), tClass);
tClass.addMethod(tMethod);

// finally, compile and load the class
return (MyInterface)tClass.toClass().newInstance();

¿Alguien tiene una idea de lo que está pasando aquí? Te lo agradecería cualquier ayuda que puede dar.

Estoy usando la JVM servidor Sun 1.6 en Windows XP de 32 bits.

¿Fue útil?

Solución

HotSpot no le importa dónde viene el código. Por ejemplo, el código que va felizmente en línea llamado a través de una llamada a un método virtual con una aplicación cargada por un cargador de clases diferentes.

Le sugiero que escriba en el código fuente de las operaciones que están tratando de llevar a cabo para este punto de referencia, a continuación, punto de referencia que. Por lo general es más fácil que escribir un ejemplo de código generado en lugar de escribir el generador de todos modos.

Hay una serie de razones por las que podría no HotSpot optimizar el código tan duro como pudo. Por ejemplo métodos muy largas tenderán a no ser inline o han método inline en ellos.

Otros consejos

Creo entender lo que estaba pasando aquí. Mi primer error fue generando métodos que eran demasiado tiempo. Después de que me fijo, me di cuenta de que aunque mi código generado seguía siendo lento, con el tiempo se acercó a la velocidad del código interpretado.

Creo que el mayor aumento de velocidad aquí viene de HotSpot optimizar mi código. En la versión interpretada, hay muy poco código para optimizar, por lo HotSpot saca rápido el cuidado de él. En la versión generada, hay una gran cantidad de código para optimizar, por lo HotSpot toma más tiempo para trabajar su magia sobre todo el código.

Si Paso los puntos de referencia durante el tiempo suficiente, ahora veo mi código generado realizar sólo un poco mejor que el código interpretado.

Hay una configuración de JVM que controla cómo el código rápido debe ser compilado -XX: CompileThreshold = 10000

  

Número de invocaciones / procedimiento se ramifica antes de compilar [-client: 1500]

No sé si esto ayuda, porque en tu ejemplo, el tamaño parecen jugar un papel vital.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top