PHP GR8: JIT melhorará o desempenho do PHP 8



PHP é uma das principais linguagens de desenvolvimento do Badoo. Nos nossos datacenters, milhares de núcleos de processadores estão ocupados executando milhões de linhas de código PHP. Estamos acompanhando de perto as notícias e procurando ativamente maneiras de melhorar a produtividade, pois mesmo uma pequena otimização em nossos volumes leva a uma economia significativa de recursos. Uma das principais notícias de desempenho do PHP é o aparecimento do JIT na oitava versão da linguagem. Isso, é claro, não poderia ficar sem nossa atenção, e traduzimos o artigo sobre o que é JIT, como ele será implementado em PHP, por que foi decidido fazê-lo e o que esperar dele.

Se você não saiu da caverna ou não veio do passado (neste caso, seja bem-vindo), você já sabe que o PHP 8 terá o JIT: outro dia, a votação foi silenciosa e pacífica e a grande maioria dos participantes votou a favor da implementação, então está tudo decidido .

Em um ataque de alegria, você pode até descrever vários movimentos malucos como na foto (a propósito, isso é chamado de "Detroit JIT":



Agora, sente-se e leia este artigo sobre desmistificação de mitos. Quero esclarecer o mal-entendido associado ao que é o JIT e como é útil, e falar sobre como ele funciona (mas não com muitos detalhes para que você não fique entediado).

Como não sei quem lerá o artigo, passarei de perguntas simples a complexas. Se você já sabe a resposta para a pergunta no título, pode pular com segurança o capítulo correspondente.

O que é o JIT?


O PHP é implementado com base em uma máquina virtual (chamamos de Zend VM). A linguagem compila o código-fonte PHP em instruções que a máquina virtual entende (isso é chamado de estágio de compilação). As instruções da máquina virtual obtidas no estágio de compilação são denominadas opcodes. No estágio de tempo de execução, a Zend VM executa os códigos de operação, realizando o trabalho necessário.

Este circuito funciona muito bem. Além disso, ferramentas como APC (antes) e OpCache (hoje) armazenam em cache os resultados do estágio de compilação; portanto, esse estágio é realizado apenas se necessário.

Em resumo, o JIT é uma estratégia de compilação just-in-time (no momento certo), na qual o código é primeiro convertido em uma representação intermediária, que depois se transforma em um código de máquina dependente da arquitetura durante a execução.

No PHP, isso significa que o JIT considerará as instruções para a máquina virtual recebida no estágio de compilação como uma representação intermediária e produzirá o código da máquina que não será mais executado pela VM do Zend, mas diretamente pelo processador.

Por que o PHP precisa do JIT?


Pouco antes do advento do PHP 7.0, o foco principal da equipe do PHP era o desempenho da linguagem. A maioria das principais mudanças no PHP 7.0 ocorreu no patch do PHPNG, que melhorou bastante a maneira como o PHP usa memória e processador. Desde então, cada um de nós tem que olhar para o desempenho da linguagem.

Após o lançamento do PHP 7.0, as melhorias de desempenho continuaram: uma tabela de hash (a principal estrutura de dados em PHP) foi otimizada, a especialização de certos opcodes na Zend VM e a especialização de certas sequências no compilador foram implementadas, o Optimizer (componente OpCache) foi constantemente aprimorado e muitas outras alterações foram implementadas.

A dura verdade é que, como resultado de todas essas otimizações, estamos nos aproximando rapidamente do limite de oportunidades de melhoria de desempenho.

Observe: por "limite de oportunidades de aprimoramento", quero dizer o fato de que as compensações que você precisa fazer para obter mais melhorias não parecem mais atraentes. Quando se trata de otimizar o desempenho, sempre falamos em trade-offs. Muitas vezes, por uma questão de produtividade, temos que sacrificar a simplicidade. Todo mundo gostaria de pensar que o código mais simples também é o mais rápido, mas no mundo moderno da programação C não é assim. O mais rápido na maioria das vezes é o código preparado para tirar proveito da estrutura interna da arquitetura ou das estruturas construídas na plataforma / compilador. A simplicidade por si só não garante melhor desempenho.

Portanto, nesta fase, a melhor maneira de obter ainda mais desempenho do PHP é implementar o JIT.

O JIT acelerará meu site?


Muito provavelmente, insignificante.

Esta pode não ser a resposta que você estava esperando. O fato é que, em geral, os aplicativos PHP são limitados por entrada / saída (limite de E / S) e o JIT funciona melhor com o código limitado pelo processador (limite da CPU).

O que significa "limitado por E / S e processador"?


Para descrever as características do desempenho geral de algum código ou aplicativo, usamos os termos "limitado pela entrada-saída" e "limitado pelo processador".

A definição mais simples:

  • o código limitado pela E / S funcionará muito mais rápido se encontrarmos uma maneira de melhorar (reduzir, otimizar) as operações de E / S executadas;
  • o código limitado ao processador funcionará muito mais rápido se encontrarmos uma maneira de melhorar (reduzir, otimizar) as instruções executadas pelo processador ou aumentar magicamente a velocidade do clock do processador.

O código e o aplicativo podem ser limitados por E / S, processador ou ambos.

Em geral, os aplicativos PHP tendem a ser limitados pela E / S: seu principal gargalo é geralmente as operações de E / S - conectando, lendo e gravando no banco de dados, caches, arquivos, soquetes, etc.

Como é o código PHP com processador limitado?


Talvez alguns programadores PHP sejam novos no código limitado ao processador devido à natureza da maioria dos aplicativos PHP: eles geralmente atuam como um link para o banco de dados ou cache, captam e produzem pequenas quantidades de respostas HTML / JSON / XML.

Você pode olhar para sua base de código e encontrar muitos códigos que não têm nada a ver com E / S, código que chama funções que não têm nada a ver com E / S. E você pode ficar confuso ao saber que isso não torna seu aplicativo limitado pelo processador, embora seu código tenha mais linhas que não funcionam com E / S do que funcionam.

O fato é que o PHP é uma das linguagens interpretadas mais rapidamente. Não há diferença perceptível entre chamar uma função que não usa E / S no Zend VM e no código da máquina. Obviamente, há alguma diferença, mas o código da máquina e a Zend VM usam a convenção de chamada, portanto, não importa -___() você chama -___() nos códigos de -___() ou no código da máquina - isso não terá um efeito perceptível. sobre o desempenho de todo o aplicativo que faz a chamada.

Nota: em termos simples, uma convenção de chamada é uma sequência de instruções executadas antes de inserir outra função. Nos dois casos, a convenção de chamada passa argumentos para a pilha.

Você pergunta: "E loops, chamadas finais e mais?" O PHP é inteligente o suficiente - e quando o Optimizer do OpCache estiver ativado, seu código será magicamente convertido em uma versão mais eficiente do que você escreveu.

Deve-se observar aqui que o JIT não alterará as convenções de chamada do Zend VM. Isso é feito porque o PHP deve poder alternar entre os modos JIT e VM a qualquer momento (portanto, eles decidiram manter as convenções atuais). Como resultado, todas as chamadas que você vê em qualquer lugar usando o JIT não funcionarão muito mais rápido.

Se você quiser ver como é o código PHP limitado pelo processador, dê uma olhada aqui: https://github.com/php/php-src/blob/master/Zend/bench.php . Este é um exemplo extremo, mas mostra que todo o esplendor do JIT é revelado em matemática.

Teve que fazer um compromisso tão extremo para acelerar os cálculos matemáticos em PHP?


Não. Fizemos isso com o objetivo de expandir o alcance da aplicação do idioma (e expandir significativamente).

Não queremos nos gabar, mas o PHP domina a web. Se você está envolvido em desenvolvimento web e não considera o uso do PHP no seu próximo projeto, está fazendo algo errado (na opinião de um desenvolvedor PHP muito tendencioso).

À primeira vista, pode parecer que a aceleração dos cálculos matemáticos no PHP tenha uma aplicação muito estreita. No entanto, isso nos abre, por exemplo, aprendizado de máquina, renderização 3D, renderização 2D (GUI) e análise de dados.

Por que isso não pode ser implementado no PHP 7.4?


Acima, chamei o JIT de um compromisso extremo e realmente penso assim: esta é uma das estratégias de compilação mais difíceis entre todas as existentes, se não as mais difíceis. A implementação do JIT é um aumento significativo na complexidade.

Se você perguntar a Dmitry, o autor do JIT, se ele complicou o PHP, ele responderá: "Não, eu odeio complexidade" (esta é uma citação).

Essencialmente, "complexo" significa "aquilo que não entendemos". E hoje, poucos desenvolvedores de idiomas realmente entendem a implementação existente do JIT.

O trabalho no PHP 7.4 está progredindo rapidamente, e a introdução do JIT nesta versão levará ao fato de que apenas alguns podem depurar, corrigir e melhorar o idioma. Isso é inaceitável para quem votou contra o JIT no PHP 7.4.

Antes do lançamento do PHP 8, muitos de nós entenderiam a implementação do JIT. Existem recursos que queremos implementar e ferramentas que queremos reescrever para a oitava versão, portanto, precisamos primeiro entender o JIT. Precisamos desse tempo e estamos muito agradecidos por a maioria ter votado para nos dar.

Complexo não é sinônimo de terrível. A complexidade pode ser tão bonita quanto uma nebulosa estelar, e isso é apenas sobre JIT. Em outras palavras, mesmo quando 20 pessoas em nossa equipe começarem a entender o JIT não menos do que Dmitry, isso não mudará a complexidade da natureza do JIT.

O desenvolvimento do PHP desacelerará?


Não há razão para pensar assim. Temos tempo suficiente, portanto, pode-se argumentar que, quando o PHP 8 estiver pronto, já haverá o suficiente entre nós que dominarão o JIT o suficiente para trabalhar não menos eficientemente do que hoje, quando se trata de corrigir bugs e desenvolver o PHP.

Ao tentar correlacionar isso com a ideia da complexidade original do JIT, lembre-se de que na maior parte do tempo gasto na introdução de novos recursos, é gasto discutindo-os. Na maioria das vezes, ao trabalhar com recursos e corrigir bugs, escrever um código leva minutos ou horas e as discussões levam semanas ou meses. Em casos raros, o código precisa ser escrito por horas ou dias, mas mesmo assim as discussões sempre duram mais.

Isso é tudo que eu queria dizer.

E como estamos falando de desempenho, convido meu colega Pavel Murzakov para o relatório em 17 de maio na conferência do PHP Rússia. Pasha sabe como extrair o último segundo da CPU do código PHP!

Source: https://habr.com/ru/post/pt448622/


All Articles