7 de abril de 2013

Baseline, el nuevo JIT javascript de Firefox (y de paso, la historia de los JITs de Firefox)

Como colofón a la entrada anterior, hoy tengo la oportunidad de retomar la sana costumbre de proselitismo firefoxero, como se hacía en los tiempos del anuncio de dos páginas en el New York Times pagado con donaciones ("crowdfunding" que se diría ahora, en lugar del "fundraising" que se utilizó entonces), o los primeros 100 millones de descargas. Sin intención anti-blink, que conste (aunque quizás la entrada aparentara lo contrario, blink me parece el sucesor más fiel al espíritu del webkit original).

Firefox ha anunciado que acaba de introducir en sus builds nocturnas un nuevo JIT: Baseline. El anuncio es una lectura muy interesante que merece un post épico sobre la intrincada historia de los motores Javascript de Firefox y la evolución de sus JITs.

SpiderMonkey: intérprete a secas

En un principio, el motor Javascript de Firefox (llamado SpiderMonkey desde que Brendan Eich lo escribió mientras creaba el lenguaje) era simplemente un intérprete de bytecode. Por aquel entonces los JITs eran algo reservado a Java y similares. En Firefox 3.5 se introdujo el primer JIT, TraceMonkey. Por aquel entonces tanto el V8 de Chrome como el Squirrelfish de Apple del mundo Webkit ya tenían sus JITs.

TraceMonkey: tracing JIT

Este JIT de Mozilla, sin embargo, era algo diferente. Los motores de webkit eran JITs "whole-method", que quiere decir que compilaban a código nativo métodos enteros. Sin embargo, Javascript es un lenguaje con variables de tipado dinámico, es decir, el tipo de una variable pueden cambiar durante la ejecución, por lo que el tipo de muchas variables no puede determinarse durante la compilación. Por eso, las implementaciones de lenguajes de tipado dinámico tienen que implementar un sistema que vaya tomando nota del tipo de cada variable y pueda enfrentarse a cambios de tipos. Los JITs webkit generaban código nativo que incluía ese sistema, sistema que, como es de esperar, afecta notablemente al rendimiento.

TraceMonkey no generaba código nativo para métodos, lo generaba para "traces", que no son más que una ruta de código determinada. El intérprete empieza a interpretar el bytecode, y cuando el bytecode saltaba "hacia atrás" (caso típico de un loop), tomaba nota de ello. Cuando ese mismo salto ocurría varias veces, TraceMonkey generaba código nativo para esa porción de código.

La gran ventaja de este método era que al entrar en acción no para generar código genérico para una función, sino una ruta de código muy concreta ya ejecutada muchas veces, y conociendo el conjunto de tipos concreto utilizados por las variables en esas ejecuciones, TraceMonkey tenía la oportunidad de optimizar el código nativo para ese conjunto de tipos, sin incluir todo un sistema capaz de funcionar con tipos dinámicos (sólo comprobaciones de cambio de tipo), por lo que el código generado estaba más optimizado que el código de los JITs webkit. Las desventajas era que si una trace cambiaba los tipos asumidos, había que desecharla y volver al intérprete inicial. Y si una ruta de código con muchos "ifs" pasaba siempre por las mismas condiciones y de repente en una cambiaba de dirección, lo mismo.

TraceMonkey era bueno optimizando loops con tipos y rutas de código estables, pero para lo demás se volvía al (lento) intérprete. Los webkit generaban código nativo menos optimizado, por incluir toda la gestión de tipos, pero podían optimizar cualquier función, no una ruta concreta, y su optimización era válida en presencia de cambios de tipos y de rutas de código, y duraba para todo el programa.

JaegerMonkey: whole-method JIT, pero sin eliminar TraceMonkey

Aunque TraceMonkey era bueno en lo suyo, había espacios donde claramente no podía competir en todos los casos con los JITs webkit, así que Firefox 4 introdujo un JIT "whole-method" como los de ellos, llamado JaegerMonkey. Sin embargo, TraceMonkey seguía siendo el mejor para loops estables, por lo que se siguió recurriendo a él para esos casos.

JaegerMonkey + type inference: adios a TraceMonkey

Firefox 9 añadió a SpiderMonkey (el intérprete) inferencia de tipos. A grandes rasgos, la inferencia de tipos consiste en intentar averiguar lo máximo posible sobre los tipos de las variables y sus cambios en todo momento. Gracias a esa información JaegerMonkey pasó a poder hacer optimizaciones de tipos parecidas a las de TraceMonkey.

Dado que JaegerMonkey hacía más o menos el trabajo de TraceMonkey y la integración entre ambos era problemática (y, además, TraceMonkey se había convertido en un monstruo al que se había intentado forzar a hacer lo que no podía), se desactivó TraceMonkey por defecto en Firefox 10, y se eliminó por completo en Firefox 11.

IonMonkey: whole-method JIT + type inference + IR, pero también JaegerMonkey

Firefox 18 (publicado hace medio año) incluyó otro JIT, IonMonkey. Sus fundamentos vienen a ser los mismos que los de JaegerMonkey, excepto en un aspecto. Al compilar una función, JaegerMonkey lo hace traduciendo el bytecode a código máquina nativo más o menos directamente.

IonMonkey no hace esa traducción directa, traduce en primer lugar el código Javascript en primer lugar a unas estructuras de datos, una "representación intermedia" (IR), sobre la cual se pueden aplicar algoritmos de optimización mucho más complejos e infinitamente más eficientes. Es así, de hecho, como funcionan los grandes compiladores. Sólo hay un problema, y es que esta clase de compilación es compleja, lenta y usa muchos recursos. Se trata de la mejor optimización posible, pero sólo merece la pena en métodos que verdaderamente lo merezcan. Por lo que se siguió utilizando JaegerMonkey, que hacía optimizaciones regulares, pero rápidas.

Llegados a este punto, el esquema es:
 · Se empieza con el intérprete SpiderMonkey (que es lento pero es la mejor opción para el código no crítico que casi no se ejecuta, ya que esos casos las compilaciones son más costosas que los beneficios potenciales)
 · Si una función se llama bastante se hace una optimización simple pero rápida con JaegerMonkey.
 · Si esa función sigue llamándose con mucha insistencia, se hace una optimización profunda pero lenta con IonMonkey.
 · Si hay un cambio de tipos en una función en alguno de los dos JITs, se desechan las optimizaciones y se vuelve al intérprete (pero ocurre con menos frecuencia que en TraceMonkey)

Baseline: adiós a JaegerMonkey

El esquema presente de los JITs de Firefox parece equilibrado, pero a través de tanto cambio ha acumulado deficiencias. El encargado de recoger información de los tipos es el intérprete SpiderMonkey, que se lo pasa a los JITs. Es por esa razón que si hay un cambio de tipos es necesario desechar el código nativo generado y volver al (lento) intérprete, para sea él quien recoja la información de los nuevos tipos.

Baseline es un reemplazo de JaegerMonkey, diseñado como él para generar código poco optimizado pero con rapidez, con la diferencia de que es capaz de analizar tipos por si mismo, y gracias a una optimización llamada "inline cache", si hay un cambio de tipos es capaz de adaptarse e incorporarlo a la optimización existente sin empezar de cero. Y toda la información de tipos es compartida con IonMonkey. De ese modo, un cambio de tipos en el código nunca supone el regreso al intérprete, sino a la optimización media de Baseline.

Es más, su gestión de tipos es mucho más avanzada que la del intérprete y permite mejores optimizaciones y consume menos memoria que Jaeger, sin que por ello deje de compilar con rapidez. Además, las llamadas entre código nativo optimizado por Ion y el optimizado por Baseline son más rápidas que con Jaeger. Baseline además comparte mucho código con IonMonkey, y por último, Baseline entrará a optimizar una función cuando se ejecuta 10 veces, mucho antes que JaegerMonkey, que lo hacía tras 40. Los benchmarks muestran una mejora notoria y plena competitividad con otros motores javascript (que, aunque no lo he mencionado, también han ido mejorando con el tiempo).

Y ese es el resumen de la evolución de los motores Javascript de Firefox...

Extra: OdinMonkey (asm.js)

...con una excepción: OdinMonkey, también conocido como asm.js, que es algo reciente. Es un experimento de Mozilla, y no tiene que ver con los motores javascript referidos anteriormente. Se trata de un subconjunto de Javascript legalmente válido, pero que renuncia a las funcionalidades más costosas del lenguaje, como el tipado dinámico o la gestión de memoria automática.

Este subconjunto de Javascript se ha diseñado con la idea -francamente revolucionaria- de permitir compilar código C/C++. Es decir, coger un programa C/C++ y compilarlo no a código x86, sino a este subconjunto de Javascript. Es decir, que este subconjunto de Javascript funcionaría como una especie de "representación intermedia", de pseudobytecode.

Lo gracioso está en que, al prescindir de las características complejas, es posible utilizar no un compilador JIT, sino uno "ahead-of-time", para generar código muy optimizado a partir de ese Javascript especial. Y por muy optimizado estamos hablando que es el doble de lento que los programas generados por compiladores como clang (y eso es ser muy, muy rápido). Ah, y con la seguridad de una máquina virtual.

De momento, asm.js supone la obsolescencia del Native Client de Google Chrome, pero los desarrolladores están planeando facilitar que asm.js pueda ser usado por lenguajes como Java o C#, con lo cual asm.js podría convertirse en una VM universal que compita con las de esos lenguajes.

4 de abril de 2013

Google anuncia Blink, un fork de Webkit, y a nadie debería sorprenderle

Pues si, no es una broma retrasada del April Fools: Google ha decidido hacer un fork de Webkit. Se trata de una decisión tajante y las consecuencias son fáciles de adivinar, así que no hay mucho que decir al respecto, más allá de lo obvio: es una mala noticia y una prueba de que Google cada vez defiende más sus intereses sin permitirse sentimentalismos (igual que Apple). De hecho me apunto una predicción: aunque Google haga público el código de Blink, acabará haciendo el desarrollo en secreto, como ya hace con Android.

Sin embargo, no se dejen engañar: aunque no era muy conocido, los conflictos y problemas en Webkit existían y eran abundantes, y aunque quizás un fork quedaba lejos, hacía tiempo que había dejado de tener una dirección única. Permitanme citarles un par de blogs que permiten intuir los problemas del proyecto Webkit:

"WebKit has eight build systems, which cause perverse behavior. Peel back the covers and you’ll find tension about past code forks: V8 vs. Apple’s JavaScriptCore (“Nitro”), iOS (in a secret repository at apple.com for years, finally landing), various graphics back ends, several network stacks, two multi-process models (Chrome’s, stealth-developed for two years; and then Apple’s “WebKit2″ framework). Behind the technical clashes lie deep business conflicts."

Brendan Eich, "Why Mozilla Matters", escrito el pasado 14 de Febrero.

Y este otro:

"what’s not shared in WebKit ports:


  • Anything on the GPU
    • 3D Transforms
    • WebGL
    • Video decoding
  • 2D drawing to the screen
    • Antialiasing approaches
    • SVG and CSS gradient rendering
  • Text rendering and hyphenation
  • Network stack (SPDY, prerendering, WebSocket transport)
  • A JavaScript engine
    • JavaScriptCore is in the WebKit repo. There are bindings in WebKit for both it and V8
  • Rendering of form controls
  • video and audio element behavior (and codec support)
  • Image decoding
  • Navigating back/forward
    • The navigation parts of pushState()
  • SSL features like Strict Transport Security and Public Key Pins"

Paul Irish, "Webkit for developers"

En efecto, como se puede deducir de esos posts hace tiempo que Webkit estaba forkeado de facto, y lejos de ser ese motor de navegador minimalista y moderno que era en sus inicios, se había convertido -por culpa de Apple y Google- en un monstruo. Cada corporación intentaba plasmar sus intereses, y en las áreas más conflictivas en lugar de buscar un consenso técnico cada uno empotraba su solución particular. Parece ahora obvio que la comunidad estaba rota hace tiempo, y simplemente estamos asistiendo a su confirmación oficial.

Personalmente no me afecta demasiado, ya que siempre me negué a usar Chrome, un navegador que recoge datos privados de sus usuarios y que incluye publicidad del Chromebook (¿software de escritorio con adware incorporado? ¿estamos en 2001?). Hubo un tiempo en el que los problemas de rendimiento y memoria de Firefox me tentaron a usar Chromium, aunque no me gustaba demasiado su carácter de segundón, pero hace tiempo que Firefox eliminó (y mejoró con creces) esos problemas, y se trata de una fundación sin ánimo de lucro con un buen historial de respeto a la privacidad. Viendo el panorama me alegro de no haber cambiado, porque visto lo visto, Firefox va a seguir siendo el único gran navegador verdaderamente neutral.

2 de abril de 2013

Mis 2 mBTC sobre Bitcoin

Como últimamente se habla mucho sobre Bitcoin, he decidido probarlo (subiéndome al tren el último, para variar), escribir sobre el tema, y, ya de paso, poner aquí, en mi blog, una dirección de bitcoin de pedigüeñeo descarado: 1HCP4dqRyr3GNMLWcCpvCnefKNZ1YQA8Lc , que pienso añadir al blog, porque es gratis y porque si. ¿A qué viene esto?, se preguntarán. ¿Acaso soy tan creído como para pensar que este blog es lo suficientemente bueno como para los que me leen que bañen en oro? ¿He bebido el kool-aid de los fieles de Bitcoin, la moneda-dios? Me temo que no, en ninguno de los dos casos.

De hecho, estoy bastante seguro de que no recibiré nada que no sea irrelevante, pero eso es lo de menos. A mi entender, lo interesante de bitcoin es que es tan sencillo e inofensivo que incluso si no se pudiesen convertir a €/$, daría igual, son lo suficientemente divertidos como para servir de entretenimiento por si mismos. De hecho, no tengo intención alguna convertir los míseros dólares que he conseguido, ni de emplear un mísero ciclo de mi GPU en minar nada, ni esperar a que se revaloricen con la esperanza de hacerme millonario. Me hace ilusión ver subir el balance y poder enviar a otros, no hay más.

En realidad, lo que más quería tratar sobre Bitcoin es lo difícil que resulta encontrar artículos de calidad sobre el tema. En la mayoría de artículos existen dos grandes corrientes de opinión sobre el Bitcoin: o es la moneda del futuro que va a derribar al dólar y al euro y a acabar con los bancos, o es una estafa piramidal que se derrumbará mañana mismo. Lo más probable es que las expectativas reales de Bitcoin no se encuentren en ningún extremo.

Respecto al fervor Bitcoin, toda o casi toda la comunidad de bitcoin sigue la creencia de que las monedas fiduciarias como el euro y el dólar son una estafa inflacionaria impuesta por gobiernos y poderes financieros a las sociedades modernas y están destinados al fracaso. Estas ideas están muy generalizadas en internet (incluido este blog, hace años) entre todo tipo de ideologías y ha sido popularizadas por la corriente liberal-austriaca. Sin embargo, la visión del mundo de esa escuela no es necesariamente correcta.

Un mundo en el que bitcoin fuese la moneda principal no impediría por si sola la acaparación usurera, ni la aparición de esquemas financieros sobre él (como ha ocurrido con el oro en el pasado). Eso no quiere decir que el bitcoin sea por si mismo un mal invento, al contrario, es un ingenio muy interesante. Pero el bitcoin no puede por si mismo no puede hacer buenos a quienes no quieren serlo, ni puede modificar todas las reglas del juego (si alguien cree que el Bitcoin por si sólo puede hacer surgir una economía mágica donde todo es utópico, nadie es pobre, todo es maravilloso y el Estado pasa a ser algo secundario, tengo unos cuantos puentes que venderle). Por otra parte, aunque el euro, el dólar y demás monedas fiduciarias son criticables, la idea de que van a derrumbarse inevitablemente mañana por el mero hecho de serlo, me temo que se sustenta más en fe que en otra cosa.

Respecto a los escépticos, están, para empezar, los defectos habituales que citan la mayoría de los artículos (ejemplo, el hecho de que si un ladrón logra acceder a tu cartera, es muy fácil hacer desaparecer su contenido sin que ningún cuerpo policial pueda recuperarlas jamás). Pero esos son defectos que, para los defensores de Bitcoin, son ventajas, y lo son desde ese punto de vista.

El argumento detractor típico que se suele escuchar es que el bitcoin es esencialmente una estafa piramidal especuladora. Ciertamente, existen razones para pensarlo: la utilidad del bitcoin debería estar en su uso como moneda, y si bien ese uso existe, si uno echa un ojo a las comunidades bitcoin, no predomina el intercambio de servicios y bienes, sino personas que acaparan esperando la revalorización infinita de su cartera. Suelen creerse más inteligentes que los críticos catastrofistas cierrabares, que para ellos son meros envidiosos que no supieron entrar a tiempo: una psicología bastante parecida a la de quienes invertían en pisos en España hace unos años.

Sin embargo, no todo es blanco o negro. Los "especuladores" del bitcoin pueden ganar mucho dinero en el proceso y muchos, de hecho, se han hecho ricos, lo cual no es ninguna estupidez ni tiene nada de irreal. Y si bien Bitcoin puede sufrir una corrección severa, es arriesgado predecir cuándo ocurriría. Podría tardar años y antes de ello llegar la cotización BTC/USD a niveles astronómicos. Recuerden que en la burbuja inmobiliaria española se estuvo hablando del encarecimiento de los pisos durante muchos años previos a la explosión.

Pero incluso se sufriera un crash catastrófico, eso no tendría por qué significar el fin de Bitcoin, podría ser simplemente la normalización de su demanda.

En mi opinión, la mayor influencia de Bitcoin en el mundo va a ser el ejemplo. Para empezar, hay que tener en cuenta que se trata de la primera criptomoneda p2p verdaderamente popular, pero no tiene por qué ser la última. Y, sobre todo, si Bitcoin se hiciera verdaderamente popular, no les quepa duda que el sistema financiero intentaría imitar algunas de sus ventajas. Los bancos centrales, por ejemplo, están tanteando con crear sus propias monedas electrónicas. Bitcoin es muy útil para esos esfuerzos. La digitalización del dinero, en general, es un tema muy interesante y que traerá muchos cambios, pero me cuesta creer que Bitcoin vaya a ser el destino final de los ahorros de todo el mundo para el resto de la historia. Quizás sea mejor pensar en Bitcoin como un prototipo; eso si, como un prototipo exitoso, y a día de hoy muy entretenido.