Otimizando FCP/LCP com cache de consultas de módulos raw-view

Estou tentando melhorar o First Contentful Paint (FCP) e o Largest Contentful Paint (LCP) com estas duas PRs:

Estou realmente interessado no impacto real dessas mudanças – então, por favor, experimente e dê algum feedback.

E, claro, qualquer ajuda para testes, refatoração e cobertura de testes é mais do que bem-vinda.

11 curtidas

O primeiro parece uma otimização fácil que faz sentido, @david e @eviltrout dedicaram tempo à otimização dessa área, então ficarei muito curioso para ver o que eles pensam sobre isso.

O segundo parece um pouco mais frágil a longo prazo, entendo totalmente o desejo de otimizar, mas me preocupa um pouco, pois será uma área que precisaremos manter.

5 curtidas

Olá @rrit - obrigado pelos PRs. O primeiro parece uma boa melhoria. Você conseguiu medir o impacto no desempenho? Quanto tempo ele economiza?

Como @sam disse, a manutenibilidade do segundo é um pouco preocupante. Parece que é um copiar/colar do código fonte do Ember? Você mudou algo para melhorar o desempenho?

4 curtidas

lookupView-patch

Implementado agora via Map em vez de Array.

Tempo gasto na inicialização da aplicação em lookupView - para instância de desenvolvimento:

Tempo economizado: ~115 ms

Isso diminui o tempo gasto dentro de appendOutletView de 1.083 ms para 946 ms - para instância de desenvolvimento.


patch em helpers de handlebar brutos

Sim, é na verdade um copy-paste com uma alteração: usar uma verificação barata para isPath.

      // substitui @ember/-internals/utils isPath
      // @see: https://github.com/emberjs/ember.js/blob/3537670c14883346e11e841fcb71333384fcbc87/packages/%40ember/-internals/metal/lib/path_cache.ts#L5-L7
      // @see: https://github.com/emberjs/ember.js/blob/255a0dd3c7de1187f4a2f61a97cf78bfff8f66a8/packages/%40ember/-internals/glimmer/lib/utils/bindings.ts#L70
      let isPath = context.indexOf('.') > -1;

Por exemplo, renderTopicListItem aciona muitas chamadas de _getPath (mais 50-100 ms para economizar):
Firefox Profiler (callstack filtrado para _getPath dentro de renderTopicListItem)

Talvez as chamadas caras para _getPath sejam algo a ser otimizado em Ember.js e não em Discourse.


E confira o Firefox Profiler para obter informações sobre a execução de JavaScript:

4 curtidas

Obrigado pelos patches. O segundo parece um pouco frágil.

Seus benchmarks estão rodando em modo de desenvolvimento ou modo de produção? O Ember tem um perfil bem diferente em ambos.

2 curtidas

@david encontrou uma maneira excelente de corrigir este problema - veja o comentário dele no github.

O tempo para chamadas a renderTopicListItem na página ‘latest’ cai de 348 ms para 201 ms em um build de produção do Ember.

Os benchmarks anteriores ainda estavam rodando em modo de desenvolvimento.


Como posso rodar benchmarks no modo de produção do Ember.js?

# Inicia o ember em modo de produção
d/ember-cli server --environment="production"
2 curtidas

Infelizmente, não consegui replicar esse grande aumento de velocidade. No Firefox e Chrome (macOS), não estou vendo nenhuma melhoria mensurável. O Chrome gasta cerca de 23ms em renderTopicListItem. O Firefox 30ms. Em um dispositivo Android mais antigo (Pixel 3), estou vendo cerca de 108ms. Os números não parecem mudar antes/depois da alteração.

A propósito, medi esses números usando a API de performance. Adicionei performance.mark("rtli-start") no início de renderTopicListItem, e então performance.measure("rtli", "rtli-start") no final.

Em seguida, recarreguei o navegador com as ferramentas de desenvolvedor fechadas e plugins do navegador desativados (ferramentas de desenvolvedor e plugins do navegador podem afetar significativamente o desempenho de renderização). Então, após o carregamento ser concluído, abri as ferramentas de desenvolvedor e executei isso para somar as medições:

performance.getEntriesByName("rtli").reduce((v, m) => v + m.duration, 0);

Com certeza vamos mesclar essa alteração - é claramente uma implementação melhor. Mas não tenho certeza se ela nos dará uma diferença visível no desempenho de renderização :thinking:

7 curtidas

Ainda consigo reproduzir os benefícios de desempenho usando a API de desempenho no modo privado do Firefox (Linux).

Testando http://localhost:4200/latest
O tempo gasto em renderTopicListItem caiu de ~290 ms para ~190 ms.

Minha instância de teste do Discourse tem muitos tópicos com muitas respostas e muitos autores diferentes - dados extraídos de uma instância produtiva. Isso resulta em muitos elementos para serem renderizados.
Talvez essa seja a diferença em nossos benchmarks?


Pré-renderização de conteúdo abaixo da dobra

O Discourse pré-renderiza 30 tópicos na página ‘latest’. Em seguida, o conteúdo é exibido pela primeira vez (FCP). Acima da dobra, apenas ~12 tópicos são visíveis.

O mesmo para uma página de tópico: 20 posts pré-renderizados, mas no máximo 6 posts de uma linha são visíveis acima da dobra.

Este pode ser outro ponto de otimização para FCP.

1 curtida

Você se importaria de compartilhar as versões do Firefox e do sistema operacional? O número de 290ms é quase 3x mais lento do que um dispositivo Android de 2018, o que é um pouco surpreendente.

Isso pode explicar parte da diferença, sim. No meu caso, eu os executei usando dados ao vivo do Meta:

bin/ember-cli --environment production --proxy https://meta.discourse.org

Sim, esta é uma melhoria possível. No entanto, precisaremos ter muito cuidado para que o layout e/ou a rolagem não saltem (por exemplo, se o usuário estiver atualizando a página quando já estiver rolado até a metade). A definição de ‘abaixo da dobra’ também varia com base no dispositivo/navegador/tema.

3 curtidas

Proxy para meta.discourse.org

Infelizmente, executar o ember com um proxy falha para mim:

d/ember-cli --environment production --proxy https://meta.discourse.org

http://localhost:4200/

Discourse Build Error

Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames:
Host: localhost. is not in the cert's altnames: DNS:*.cdck-prod-meta.discourse.cloud

http://127.0.0.1:4200/

Discourse Build Error

Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames:
Host: meta.discourse.org. is not in the cert's altnames: DNS:*.cdck-prod-meta.discourse.cloud

Sistema usado para benchmarks

Extraído do about:support do Firefox

Nome Firefox
Versão 95.0.2
Build-ID 20211219102529
Distributions-ID canonical-002
User-Agent Mozilla/5.0 (X11; Linux x86_64; rv:95.0) Gecko/20100101 Firefox/95.0
Sistema Operacional Linux 5.10.0-0.bpo.9-amd64 #1 SMP Debian 5.10.70-1~bpo10+1 (2021-10-10)
Tema do Sistema Operacional Adwaita-dark / Adwaita
Arquivo do Programa /snap/firefox/777/usr/lib/firefox/firefox
Nome Firefox Developer Edition
Versão 96.0b10
Build-ID 20211228195952
Diretório de Atualização /opt/firefox-dev-autoinstall
Canal de Atualização aurora
User-Agent Mozilla/5.0 (X11; Linux x86_64; rv:96.0) Gecko/20100101 Firefox/96.0
Sistema Operacional Linux 5.10.0-0.bpo.9-amd64 #1 SMP Debian 5.10.70-1~bpo10+1 (2021-10-10)
Tema do Sistema Operacional Adwaita-dark / Adwaita
Arquivo do Programa /opt/firefox-dev-autoinstall/firefox-bin

Extraído do Chromium chrome://system/

CHROME VERSION 90.0.4430.212 built on Debian 10.9, running on Debian 10.11
OS VERSION Linux: 5.10.0-0.bpo.9-amd64

Versão do SO:

# cat /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 10 (buster)"
NAME="Debian GNU/Linux"
VERSION_ID="10"
VERSION="10 (buster)"
VERSION_CODENAME=buster
ID=debian
2 curtidas

O PR para a refatoração foi mesclado:

Obrigado por levantar isso, @rrit - é uma boa melhoria!

5 curtidas

Este tópico foi automaticamente fechado após 9 horas. Novas respostas não são mais permitidas.