Pregunta

No sé mucho sobre el funcionamiento interno de compilador JIT y optimizaciones, pero por lo general tratan de usar el "sentido común" de adivinar lo que podría ser optimizado y lo que no podía. Por lo que no estaba escribiendo un método de prueba de unidad sencilla hoy:

@Test  // [Test] in C#
public void testDefaultConstructor() {
    new MyObject();
}

Este método es en realidad todo lo que necesito. Se comprueba que existe el constructor por defecto y se ejecuta sin excepciones.

Pero luego empecé a pensar en el efecto de las optimizaciones del compilador / JIT. Podría el compilador / JIT optimizar este método mediante la eliminación de la declaración new MyObject(); por completo? Por supuesto, sería necesario para determinar que el gráfico de llamadas no tiene efectos secundarios a otros objetos, que es el caso típico de un constructor normal que simplemente inicializa el estado interno del objeto.

supongo que sólo el JIT se le permitiría llevar a cabo una optimización tales. Esto probablemente significa que no es algo que deba preocuparse, ya que el método de prueba se realiza sólo una vez. Son mis suposiciones correcta?

Sin embargo, yo estoy tratando de pensar en el tema general. Cuando pensé en cómo evitar que este método está optimizado, pensé que pueda assertTrue(new MyObject().toString() != null), pero esto es muy dependiente de la implementación real del método toString(), e incluso entonces, el JIT puede determinar que método toString() siempre devuelve un no nulo cadena (por ejemplo, si en realidad se está llamando Object.toString()), y por lo tanto optimizar toda la rama. Así de esta manera no funcionaría.

Yo sé que en C # que puedo utilizar [MethodImpl(MethodImplOptions.NoOptimization)], pero esto no es lo que estoy buscando en realidad. Tengo la esperanza de encontrar una manera (independiente del lenguaje) de asegurarse de que una parte específica (s) de mi código funcionarán realmente como espero, sin el JIT interferir en este proceso.

Además, ¿hay casos típicos de optimización que debería tener en cuenta al crear mis pruebas unitarias?

Muchas gracias!

¿Fue útil?

Solución

No se preocupe por ella. No está permitido optimizar cada vez todo lo que puede hacer una diferencia en su sistema (excepto para la velocidad). Si un objeto nuevos, código se llama, la memoria se asigna, que tiene que trabajar.

Si lo tenía protegido por un if (falso), donde falsa es una final, que podría ser optimizado fuera del sistema por completo, entonces se podría detectar que el método no hace nada y optimizarlo a cabo (en teoría ).

Edit: por cierto, también puede ser lo suficientemente inteligente como para determinar que este método:

newIfTrue(boolean b) {
    if(b)
        new ThisClass();
}

siempre va a hacer nada si b es falsa, y, finalmente, darse cuenta de que en algún momento de su código B siempre es falsa y compilar esta rutina de ese código completo.

Aquí es donde el JIT puede hacer cosas que es prácticamente imposible en cualquier lenguaje no administrado.

Otros consejos

Creo que si le preocupa que conseguir optimizado de distancia, que puede estar haciendo un poco excesivo prueba.

En un lenguaje estático, que tienden a pensar que el compilador como una prueba. Si se aprueba la compilación, eso significa que ciertas cosas están ahí (como métodos). Si usted no tiene otra prueba que ejerce su constructor por defecto (que no lo puedo demostrar lanzar excepciones), es posible que desee pensar en por qué está escribiendo ese constructor por defecto en el primer lugar (YAGNI y todo eso).

Sé que hay personas que no están de acuerdo conmigo, pero siento que este tipo de cosas es sólo algo que va a hinchar a conocer su número de pruebas por ninguna razón útil, incluso mirando a través de gafas de TDD.

Piénsalo de esta manera:

Vamos a suponer que el compilador puede determinar que el gráfico de llamadas no tiene ningún efecto secundario (no creo que es posible, recuerdo vagamente algo sobre P = NP de mis cursos CS). Se optimizará cualquier método que no tiene efectos secundarios. Como la mayoría de las pruebas no tienen y no deben tener ningún efecto secundario a continuación compilador puede optimizar todo por la borda.

El JIT sólo se le permite realizar operaciones que no afectan a la semántica del lenguaje garantizados. En teoría, se podría eliminar la asignación y llamar al constructor MyObject si se puede garantizar que la llamada no tiene efectos secundarios y nunca puede lanzar una excepción (sin contar OutOfMemoryError).

En otras palabras, si el JIT optimiza la llamada fuera de su prueba, entonces la prueba habría pasado de todos modos .

PS: Tenga en cuenta que esto se aplica debido a que está haciendo funcionalidad las pruebas en lugar de rendimiento prueba. En las pruebas de rendimiento, es importante asegurarse de que el JIT no optimiza la operación de distancia que se está midiendo, de lo contrario sus resultados se vuelven inútiles.

Parece que en C # que podría hacer esto:

[Test]
public void testDefaultConstructor() {
    GC.KeepAlive(new MyObject());
}

AFAIU, el método GC.KeepAlive no ser inline por el JIT, por lo que el código se garantiza que funcione como se espera. Sin embargo, no sé una construcción similar en Java.

¿Por qué es importante? Si el compilador / JIT puede determinar de forma estática sin afirma van a ser golpeado (que podría causar efectos secundarios), entonces está bien.

Cada I / O es un efecto secundario, por lo que sólo puede poner

Object obj = new MyObject();
System.out.println(obj.toString());

y estás bien.

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