Pular para o conteúdo principal

Aposentando Octane

· Leitura de 7 minutos
a equipe do V8

A história dos benchmarks de JavaScript é uma narrativa de constante evolução. À medida que a web se expandiu de simples documentos para aplicações dinâmicas no lado do cliente, novos benchmarks de JavaScript foram criados para medir cargas de trabalho que se tornaram importantes para novos casos de uso. Essa constante mudança deu aos benchmarks individuais tempos de vida finitos. À medida que os navegadores web e as implementações de máquinas virtuais (VM) começam a super-otimizar casos de teste específicos, os benchmarks deixam de ser proxies eficazes para seus usos originais. Um dos primeiros benchmarks de JavaScript, SunSpider, ofereceu incentivos iniciais para o envio rápido de compiladores otimizadores. No entanto, à medida que os engenheiros de VM descobriram as limitações dos microbenchmarks e encontraram novas maneiras de otimizar ao redor das limitações do SunSpider limitations, a comunidade de navegadores aposentou SunSpider como um benchmark recomendado.

A gênese do Octane

Projetado para mitigar algumas das fraquezas dos primeiros microbenchmarks, o conjunto de benchmarks Octane foi lançado pela primeira vez em 2012. Ele evoluiu de um conjunto anterior de simples casos de teste do V8 e tornou-se um benchmark comum para desempenho geral da web. Octane consiste em 17 testes diferentes, que foram projetados para cobrir uma variedade de cargas de trabalho diferentes, desde o teste de simulação de kernel de Martin Richards até uma versão do compilador TypeScript da Microsoft compilando a si mesmo. O conteúdo do Octane representou o consenso emergente sobre como medir o desempenho do JavaScript na época de sua criação.

Retornos decrescentes e super-otimização

Nos primeiros anos após seu lançamento, Octane forneceu um valor único para o ecossistema de máquinas virtuais de JavaScript. Ele permitiu que os motores, incluindo o V8, otimizassem seu desempenho para uma classe de aplicações que exigiam desempenho máximo. Essas cargas de trabalho intensivas de CPU foram inicialmente pouco atendidas pelas implementações de VM. Octane ajudou os desenvolvedores de motores a entregar otimizações que permitiram que aplicações pesadas em termos computacionais atingissem velocidades que tornaram o JavaScript uma alternativa viável ao C++ ou Java. Além disso, Octane impulsionou melhorias na coleta de lixo, que ajudaram os navegadores web a evitar pausas longas ou imprevisíveis.

No entanto, até 2015, a maioria das implementações de JavaScript havia realizado as otimizações do compilador necessárias para alcançar altas pontuações no Octane. Esforçar-se para alcançar pontuações ainda mais altas no Octane traduziu-se em melhorias cada vez mais marginais no desempenho de páginas web reais. Investigações sobre o perfil de execução de execução do Octane versus carregamento de sites comuns (como Facebook, Twitter ou Wikipédia) revelaram que o benchmark não exercita o analisador do V8 ou a pilha de carregamento do navegador da mesma forma que o código do mundo real faz. Além disso, o estilo de JavaScript do Octane não corresponde aos padrões e padrões usados pelas bibliotecas e frameworks modernos (sem mencionar o código transpilado ou os novos recursos da linguagem ES2015+). Isso significa que usar o Octane para medir o desempenho do V8 não capturava casos de uso importantes para a web moderna, como carregar frameworks rapidamente, suportar grandes aplicações com novos padrões de gerenciamento de estado ou garantir que os recursos ES2015+ sejam tão rápidos quanto seus equivalentes ES5.

Além disso, começamos a notar que otimizações de JavaScript que resultavam em pontuações mais altas no Octane frequentemente tinham efeitos prejudiciais em cenários reais. O Octane incentiva a inserção agressiva para minimizar a sobrecarga de chamadas de função, mas estratégias de inserção adaptadas ao Octane levaram a regressões devido ao aumento dos custos de compilação e maior uso de memória em casos de uso reais. Mesmo quando uma otimização pode ser genuinamente útil no mundo real, como é o caso de pré-alocação dinâmica, perseguir pontuações mais altas no Octane pode resultar no desenvolvimento de heurísticas excessivamente específicas que têm pouco efeito ou até prejudicam o desempenho em casos mais genéricos. Descobrimos que as heurísticas de pré-alocação derivadas do Octane levaram a degradações de desempenho em frameworks modernos como o Ember. O operador instanceof foi outro exemplo de uma otimização adaptada a um conjunto específico de casos do Octane que causou regressões significativas em aplicações Node.js.

Outro problema é que, com o tempo, pequenos bugs no Octane se tornam alvos para otimizações por si mesmos. Por exemplo, no benchmark Box2DWeb, aproveitar um bug onde dois objetos eram comparados usando os operadores < e >= proporcionou cerca de 15% de melhoria de desempenho no Octane. Infelizmente, essa otimização não teve efeito no mundo real e complica tipos de otimizações de comparação mais gerais. O Octane às vezes até penaliza negativamente otimizações reais: engenheiros trabalhando em outras máquinas virtuais notaram que o Octane parece penalizar análise preguiçosa, uma técnica que ajuda a maioria dos sites reais a carregar mais rápido, dado a quantidade de código obsoleto frequentemente encontrada.

Além do Octane e outros benchmarks sintéticos

Esses exemplos são apenas algumas das muitas otimizações que aumentaram as pontuações do Octane em detrimento da execução de sites reais. Infelizmente, problemas semelhantes existem em outros benchmarks estáticos ou sintéticos, incluindo Kraken e JetStream. Simplificando, tais benchmarks são métodos insuficientes para medir a velocidade no mundo real e criam incentivos para engenheiros de máquinas virtuais otimizarem em excesso casos específicos e sub-otimizarem casos genéricos, tornando o código JavaScript mais lento na prática.

Dado o platô nas pontuações em várias máquinas virtuais de JavaScript e o conflito crescente entre otimizações específicas para benchmarks do Octane e a implementação de melhorias para um amplo espectro de códigos reais, acreditamos que chegou a hora de aposentar o Octane como um benchmark recomendado.

O Octane permitiu que o ecossistema JavaScript alcançasse grandes avanços em JavaScript computacionalmente intensivo. O próximo desafio, no entanto, é melhorar o desempenho de páginas web reais, bibliotecas modernas, frameworks, recursos de linguagem ES2015+, novos padrões de gerenciamento de estado, alocação de objetos imutáveis e empacotamento de módulos como o browserify. Como o V8 roda em muitos ambientes, incluindo no servidor com Node.js, também estamos dedicando tempo para entender aplicações reais em Node.js e medir o desempenho de JavaScript no servidor mediante cargas de trabalho como AcmeAir.

Volte aqui para mais posts sobre melhorias em nossa metodologia de medição e novas cargas de trabalho que representam melhor o desempenho no mundo real. Estamos empolgados em continuar buscando o desempenho que mais importa para usuários e desenvolvedores!