18 de mayo de 2013

Dramas de Windows 8

A estas alturas no es ningún secreto que en el escritorio Windows 8 ha tenido bastante menos éxito que el que se presupone a un nuevo sistema operativo de Microsoft debería conseguir. Su cuota de uso en la web es peor que la de Vista, y Vista ya de por si no fue precisamente popular. Pero el caso de Windows 8 no se queda ahí, hay varias historias entrecruzadas rondando internet -no todas negativas- que dan para hablar largo y tendido.

Uno de mis favoritos son este o este, en los que se argumenta que la culpa de los malos resultados de Windows 8 la tienen los vendedores de PCs tradicionales, por querer seguir vendiendo....PCs tradicionales, y por no querer seguir las indicaciones de Microsoft. Lo cierto es que son hipótesis creíbles, teniendo en cuenta la existencia de Surface como supuesta muestra de lo que Windows 8 debería ser.

Uno de los últimos dramas ocurrió hace unos días, en un post del "Corporate Vice President of Corporate Communications" de Microsoft. Este responsable de comunicación decidió utilizar una técnica comunicativa muy común, consistente en acusar a los medios de comunicación de sensacionalismo. Es decir, echar balones fuera. Lo cómico es que esos medios sensacionalistas coinciden al señalar lo que todos sabemos: Imposibilidad de arrancar en el escritorio clásico, ausencia de botón de inicio. Pero está previsto que la próxima actualización de Windows, 8.1 "Blue", restaure precisamente ese funcionalidad. El responsable de "comunicaciones corporativas" puede decir lo que quiera, pero con los hechos Microsoft da la razón a los medios a quienes acusan de sensacionalistas.

Y, por supuesto, repite una y mil veces aquello de que ellos escuchan atentamente a sus clientes. Sin embargo, todos recordamos que la ausencia del botón de inicio y la imposibilidad de iniciar en el escritorio clásico fueron mencionados repetidamente en los análisis de todas las versiones preliminares de Windows 8. Surgieron varios programas para añadir de nuevo el botón de inicio, y en lugar de escuchar a los clientes, Microsoft intentó activamente hacer difícil la creación de esos programas.

Otro drama interesante es la curiosa persistencia de gente que sigue afirmando en serio que la(s) interfaz(ces) de Windows no tienen ningún problema, que es mejor que Windows 7 y que es cosa de acostumbrarse. Como ya mencioné, a la dualidad de interfaces de Windows 8 sólo cabe acostumbrarse como uno se acostumbra en Linux a las diferencias entre aplicaciones GNOME y KDE, es decir, educando al cerebro para que ignore los problemas.

Pero no todo es malo. Poca, muy poca gente menciona que Windows 8 está teniendo cierto éxito en las tabletas, pasando en un año de una cuota de mercado del 0% al 7.8%. Teniendo en cuenta que se trata de la entrada de un jugador nuevo en medio de una competencia feroz entre iPad y Android, me parecen cifras más que respetables. Puede que Windows 8 haya causado un lío tremendo en el escritorio con su mezcla de interfaces, pero está claro que obtienen un beneficio de todo eso, que es ser un buen sistema operativo para tabletas.

3 de mayo de 2013

Las novedades de Linux 3.9

(Si, si, perdón por el retraso).

Ya se ha anunciado la versión 3.9 del kernel Linux. Esta versión incluye soporte experimental en Btrfs para los modos RAID5/6 y mejor defragmentación en archivos compartidos por snapshots; soporte para el emulador "goldfish" usado por el SDK de Android; posibilidad de usar dispositivos SSD como dispositivos cache; dos nuevas arquitecturas: Synopsys ARC 700 y Meta Imagination; soporte de KVM en la arquitectura ARM; un driver de Intel que inyecta ciclos ociosos para mejorar en rendimiento-por-vatio, soporte para portátiles Chrome OS, un nuevo estado de suspensión energético, y la eliminación de la opción obsoleta CONFIG_EXPERIMENTAL. También se han incluido drivers nuevos y muchas otras mejoras y pequeños cambios. La lista completa de cambios, en inglés, puede encontrarse aquí, como siempre.


· Soporte experimental de RAID5/6 y defragmentación optimizada en presencia de snapshots:

    · RAID5/6: Btrfs ha añadido soporte de RAID5 y RAID6. El soporte es aun experimental y no está preparado para gestionar cuelgues del sistema, por lo tanto sólo se recomienda su uso en pruebas.
    · Defragmentación optimizada en presencia de snapshots: Debido al diseño copy-on-write de Btrfs, varios snapshots pueden compartir los mismos bloques de datos. Esta compartición de bloques podía deshacerse tras un proceso de defragmentación, ya que al intentar defragmentar parte de un archivo se activaba el proceso de copy-on-write, y quedaba un archivo fragmentado y otro defragmentado, y los datos de ambos duplicados y no compartidos. En esta versión el proceso de defragmentación tiene en cuenta la presencia de snapshots.


· Emulador "goldfish" de Android: El entorno de desarrollo de Android proporciona una plataforma de virtualización ARM basada en QEMU llamada "goldfish". Esta plataforma proporciona una CPU virtual y controladores para la batería, MMC, sonido, gráficos, etc. Esta versión de Linux incorpora el soporta para esta plataforma goldfish, lo cual hace más sencillo desarrollar para Android.

· Almacenamiento SSD como caché: El device-mapper ha añadido un target (dm-cache) que permite utilizar dispositivos veloces (por ejemplo, SSD) como cachés de dispositivos más lentos (como los discos tradicionaes). Este target soporta plugins que implementan diferentes políticas respecto al funcionamiento de caché. Soporta modos de escritura writeback y writethrough. Documentación: Documentation/device-mapper/cache.txt

· Nueva arquitectura: procesadores Synopsys ARC 700: Esta versión soporta la familia de procesadores ARC700 processor (750D y 770D) fabricados por Synopsys.

El ARC700 es un core RISC de 32 bits con MMU, altamente configurable y eficiente energéticamente. Está embebido en SoCs que se incluyen en televisiones, reproductores digitales, dispositivos de red. Hay más información sobre estos procesadores  aquí. Más información sobre el proceso de porteo a Linux puede encontrarse en esta charla: ELCE-Barclone '12. La toolchain GNU, basada en GCC 4.4 + uClibc 0.9.30.3 está disponible en GitHub

· Nueva arquitectura: procesadores Meta Imagination: Esta versión incluye soporte para los procesadores Meta ATP (Meta 1) y Meta HTP (Meta 2) de Imagination Technologies.

Los procesadores Meta son procesadores de propósito general de 32 bits, con soporte de multihilo por hardware, y que también incluyen un conjunto de instrucciones DSP. Pueden encontrarse en muchas radios digitales. Pueden ejecutar diferentes sistemas operativos en diferentes hilos de hadware, por ejemplo, una radio digital podría ejecutar un RTOS para decodificar señales y audio en tres hilos de hardware, y ejecutar Linux en un cuarto hilo para gestionar la infertaz de usuario, red, etc.  Los HTPs también son capaces de ejecutar Linux SMP en múltiples hilos hardware. El conjunto de instrucciones y la documentación sobre la arquitectura pueden encontrarse aquí.

· Soporte de KVM en ARM: La arquitectura ARM ahora soporta el sistema de virtualización KVM.

· Driver Intel PowerClamp para la inyección de ciclos ociosos para mejora del rendimiento energético: El driver Intel PowerClam permite inyectar ciclos "idle" a las CPUs. El objetivo es mantener el estado energético-C para un determinado conjunto de CPUs. Comparado con otros sistemas existentes en el kernel, como ACPI PAD (desactivar CPUs) y modulación de frecuencia, este sistema es a menudo más eficiente en términos de rendimiento/W. Documentación: Documentation/thermal/intel_powerclamp.txt

· Nuevo estado de suspensión "suspend-freeze": Esta versión introduce un nuevo modo de suspensión. Equivale a procesos congelados + dispositivos dormidos + procesadores ociosos. Este estado es útil para 1) plataformas que no soporta suspensión a memoria, o la que tienen está mal implementada 2) plataformas que tienen un estado energético ocioso extremadamente eficiente y que pueden ser utilizadas para reemplazar a la suspensión a memoria.

Comparado con la suspensió a memoria, suspend-freeze ahorra menos energía porque el sistema aun está en estado de ejecución, pero tiene menos latencia en la reanudación porque no toca la BIOS y los procesadores están en estado ocioso. Comparado con RTPM/estado ocioso, suspend-freeze ahorra más energía porque el procesador tiene más tiempo para dormir una vez que los procesos han sido congelados, y puede ahorra más energía de los dispositivos que no tienen buen soporte RTPM. Para activar este modo de suspensión, haga "echo freeze > /sys/power/state"

· Soporte de portátiles Chrome OS: Se ha añadido soporte para todos los dispositivos de los portátiles Chrome vendidos por varios fabricantes.

· Eliminación de CONFIG_EXPERIMENTAL: CONFIG_EXPERIMENTAL era una opción de configuración que tenía como objeto activar características experimentales que la gente normal no debía usar. Pero los cambios en el modelo de desarrollo y el directorio staging lo han convertido en obsoleto. Estos días casi todas las distros la activan por defecto, convirtiéndolo en algo inútil, por lo que ha sido eliminada. A partir de ahora, los desarrolladores añadirán el texto "(EXPERIMENTAL)" en el título de la opción de configuración para prevenir a los usuarios.

Y eso es todo. La lista completa de cambios en inglés, aquí 

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.