IE9 y el Dead Code Elimination

Llevamos muchos años oyendo que Mozilla Firefox es el navegador más rápido. Unos cuantos menos oyendo que Google Chrome es aún más rápido. Y aún más oyendo decir que Internet Explorer era el más lento de todos. Se ha convertido en una especie de mantra, de verdad fundamental e incuestionable. Casi tan incuestionable como que los ingenieros de Microsoft son todos borderline.

Pero resulta que en el último año los borderline se han puesto las pilas con Internet Explorer 9 y llevan un año mostrándonos como, Platform Preview tras Platform Preview, IE9 iba poco a poco reduciendo la diferencia que le separaba de Firefox y Chrome en muchos aspectos, especialmente en el capítulo de soporte a estándares y rendimiento.

En cuanto al primero, asistimos a un ejercicio curioso de manipulación. Cualquiera que esté mínimamente informado sabrá que HTML5 no es un estándar, sino un borrador de trabajo (Working Draft) sobre un futuro estándar. Borrador de trabajo que, por cierto, algunos estiman que no será aprobado como estándar de forma oficial hasta… ¡2022! (no lo digo yo, ni Microsoft, lo dice el editor del estándar, empleado de Google para más señas).

Pues esta verdad con respecto a HTML5 y al hecho de que no es más que un borrador, no impide a algunos atacar a otros bajo la ofensa de no haber implementado características del borrador que no son, ni mucho menos, estables. Sentencia: se sigue sin ser respetuoso con los estándares (a pesar de no existir como tales).

La Noticia

Pero si el proceso resulta bastante evidente con respecto al soporte a estándares, no menos lo es en lo que respeta al rendimiento. Está claro que no resulta sencillo aceptar que las cosas están cambiando. A todos nos pasa, damos algo tan por sentado que cuando deja de ser así, preferimos mirar para otro lado o rebelarnos ante ello. Esto último está pasando con la reciente noticia de que IE9 Platform Preview es el navegador más rápido en el test de SunSpider. No voy a hablar de aceleración por hardware, porque si nos metemos en ese terreno la ventaja es tan abrumadora que nadie podría poner en duda que IE9 es, hoy en día, líder indiscutible en prácticamente todos los aspectos.

EL FUD (Fear, Uncertainty and Doubt)

El FUD, ese viejo conocido. Si preguntas a cualquier persona que pertenezca al software libre o que tenga antipatía de algún modo por Microsoft (puedes entrar en Barrapunto o Meneame y elegir al azar), te dirá que lo inventó Microsoft.

Puede que sea verdad, pero lo que es indudablemente cierto es que ha hecho aparición para amortiguar el efecto mediático que habría supuesto que IE9 fuera más rápido que ningún otro navegador, en un microbenchmark creado por la competencia (Sunspider es obra de la gente de WebKit, motor de Safari y Chrome entre otros).

El resultado ha sido muy satisfactorio. Acceder a Google, poner los términos Internet Explorer y Sunspider, no nos devuelve ningún resultado la primera página relacionado con el éxito de IE9, sólo nos habla del posible (para algunos indudable) asunto de las “trampas” en el microbenchmark. Es decir, hemos pasado de una publicidad positiva basada en hechos objetivos, a una publicidad negativa basada en un supuesto no demostrado y en la viralidad que cualquier crítica, justificada o no, adquiere cuando el objeto del chismorreo es Microsoft. Si esto no es FUD de manual, ya me diréis.

El Chismorreo

El chismorreo empezó como empiezan estas cosas, con una opinión legítima: un desarrollador de Mozilla se preguntaba porqué Chackra, el motor de Javascript que lleva IE9, no ejecutaba una función parte de uno de los tests (math-cordic) que se ejecutan en Sunspider. En principio se planteaba si era posible que se debiera a la detección de ese método como candidato a una Dead Code Elimination.

Una optimización de este tipo busca código que no tiene ningún efecto de un programa y lo elimina. Cuando trabajamos con entornos sin análisis estático del código, es relativamente sencillo no darse cuenta de que, probablemente por un error de programación, estamos ejecutando código que no produce ningún resultado. Un ejemplo burdo:

public int Multiplicar(int operando1, int operando2)
{
    int resultado = 0;
    for(int i=0; i<operando2; i++)
    {
        resultado += operando1;
    }

    return operando1 * operando2;
}

En este ejemplo, el bucle es un candidado a ser eliminado, puesto que no realiza ningún función práctica. Exactamente lo mismo ocurría con el método cordicsincos() objeto de esta polémica.

A partir de aquí, el revuelo cuando alguien decidió sugerir que esto no era una simple característica nueva en Chackra sino una optimización específicamente pensada para mejorar los resultados en Sunspider y colocarse primero. “Cheat” y “Microsoft” juntos en la misma frase, resultado esperado: el rumor se extendió por la pólvora. La base para tal afirmación estaba en el hecho de que, modificando el código y manteniendo un fragmento candidado a ser eliminado, el sistema de análisis del DCE no lo descubría y no lo borraba.

De poco ha valido la explicación que ha aportado la gente del equipo de IE9 en su blog: DCE es una nueva característica, está en desarrollo y no cubre todos los escenarios, además de ser necesario mantener un balance entre la cantidad de análisis que se hace sobre el código JS antes de compilarlo, y el rendimiento. Obviamente este tipo de análisis no son triviales y requieren de un tiempo que puede, en definitiva, no merecer la pena cuando va a resultar más rápido ejecutar directamente el código innecesario.

Con lo que el escenario en que ahora mismo nos encontramos es que la noticia con respecto a IE9 no es que sea tanto o más rápido que sus competidores en este microbenchmark, sino que un ingenierio de la competencia descubrió que el nuevo sistema de DCE de un código que no es ni siquiera una beta, no es capaz de detectar todos los posibles escenarios, pero sí lo hace con uno concreto que forma parte de un microbenchmark (al que tanto Microsoft como gente de Mozilla han restado importancia puesto que no se asemeja al funcionamiento de los sitios web del mundo real).

Mi conclusión

Creo que no hace falta que la aporte, porque ya se desprende de mi tono en el artículo. Mi experiencia profesional es limitada y también mi conocimiento de los navegadores. No viví la famosa guerra de los 90, ni la forma en que se regía y comportaba Microsoft en aquellos años. No dudo que fuera el “evil” en el que, supuestamente, Google no quiere convertirse.

Pero desde que yo estoy en esta profesión, apróximadamente 2006, no he visto ningún movimiento por parte de Microsoft que haya sido mejor o peor que los que ha llevado a cabo Google, Apple o cualquiera de las grandes compañías en el sector. Sin embargo, mientras a Apple se le ríen las gracias (ayer mismo compré un cable para mi Touch que, por no ser de Apple, no lleva un chip y resulta totalmente inútil, 13 euros a la basura), a Google se le permite que gestione nuestros datos personales con mucha alegría y poca gente habla de lo que está haciendo Oracle con MySQL y Java, a Microsoft se la mira con una lupa lo suficientemente potente como para distorsionar la realidad y ver oscuras conspiraciones donde no hay más que un fragmento de código que no es lo suficientemente completo y maduro como para cubrir todos los escenarios posibles.

Flaco favor nos hacemos los unos a los otros si el escenario de “batalla” se desplaza de la mera destreza técnica a las más burdas tácticas propagandísticas.

Bibliografía:

Forzar ejecución en 32 bits

Escenario: una aplicación .NET ejecutándose en una máquina de 64 bits, que falla. Exactamente el mismo ejecutable, sobre una máquina de un compañero en 32 bits, funciona perfectamente. ¿Podemos forzar a esa aplicación a ejecutarse con compatibilidad 32 bits, como hacen montones de aplicación hoy en día en los entornos de 64 (me viene a la cabeza Visual Studio 2010, por ejemplo). Claramente, sí.

Después de un poco de investigación, encontré este enlace describiendo las distintas posibilidades que tenemos. Voy a explicar cuál es la que aplicaba a mi escenario.

Modificar flag en Assembly

En mi caso, dado que era un compilado ya desplegado (fuera la opción VS) y que era una aplicación de escritorio (fuera la opción de IIS), me quedé con la posibilidad de modificar un flag del assembly.

En cada assembly existen unas ciertas cabeceras que son modificables mediante la herramienta “CoreFlags”. En este caso concreto, es el flag 32BIT el que tenemos que modificar. Para hacer el cambio, abriríamos una consola de Visual Studio y ejecutaríamos el siguiente comando, para marcar el flag y asegurarnos de que nuestra aplicación se ejecuta sobre 32 bits

CorFlags Assembly_a_modificar.exe /32BIT+

Para desactivar el flag, el comando es casi idéntico.

CorFlags Assembly_a_modificar.exe /32BIT-

Espero que os resulte tan útil como a mí.

Silverlight–FallbackValue y TargetNullValue

En estos días me encuentro inmerso en un proyecto con Silverlight. Uno de los últimos problemas que me he encontrado involucraba el siguiente escenario:

  1. Control cuya visibilidad está enlazado a una propiedad de un objeto (en este caso, un campo del Content de un NavigationFrame)
  2. Este frame, en un primer momento, tiene null en esta propiedad Content, hasta que navega.

El problema es que esta navegación se producía un instante después de que el control se creara, por lo que durante ese instante, el binding fallaba y la propiedad de visibilidad se establecía a Visible, que supongo que es el valor por defecto. Después de darle muchas vueltas encontré estas dos propiedades interesantes para este tipo de escenarios.

FallbackValue

Nos sirve para establecer un valor para el binding, cuando el binding no es capaz de resolverse y obtener un valor. Por ejemplo, en mi escenario, hasta que el NavigationFrame no navegaba por primera vez a alguna pantalla, su Content era null. Al estar mi binding enlazado a una de las propiedades del objeto que esperaba encontrar en Content, y ser éste un null, internamente el Binding estaba fallando con NullReferenceException.

Para esta situación de fallo, FallbackValue es perfecta. Básicamente estás diciéndole al binding: “si no eres capaz de calcular un valor, ponme éste directamente”.

TargetNullValue

Esta otra propiedad nos ayuda en otro escenario típico: el valor al que estamos enlazando, es null. Si por ejemplo la visibilidad de nuestro control dependiera de una propiedad string con valores “VISIBLE” y “NOVISIBLE”, podríamos crear un sencillo conversor que se encargara de devolver Visibility.Visible para el primer valor, y Visibility.Collapsed para el segundo.

¿Qué pasaría si la propiedad string contuviera un null? En tal caso, podríamos o bien modificar nuestro conversor para devolver Visibility.Collapsed también con un valor null. Pero, ¿y si no hemos creado ningún conversor? ¿No es un poco tedioso tener que crear uno sólo para gestionar los valores null?

Para eso precisamente existe TargetNullValue, que nos permite indicarle al Binding qué valor por defecto queremos que se asigne a la propiedad bindeada, en caso de que el origen del binding (source) tenga un valor null.

 

Espero que le resulte útil a alguien. A mí ya me hizo perder una hora y pico…

 

Bibliografía

MSDN: BindingBase.FallbackValue

MSDN: BindingBase.TargetNullValue