A estrutura do Flutter funciona bem e rápido por padrão, mas isso significa que você não precisa pensar em desempenho? Não. É absolutamente real escrever aplicativos Flutter que serão lentos. Por outro lado, você também pode usar a estrutura ao máximo e tornar seus aplicativos não apenas rápidos, mas também eficientes, consumindo menos tempo do processador e da bateria.

É isso que queremos ver: um resultado estatisticamente significativo da comparação de duas versões do seu aplicativo por alguma métrica significativa. Leia para descobrir como.
Existem algumas diretrizes gerais para otimizar o desempenho no Flutter:
- Envolva o menor número possível de widgets ao atualizar o estado.
- Atualize o status somente quando necessário.
- Execute tarefas computacionalmente intensivas de seus métodos de
build
e, idealmente, do isolado principal.
A triste verdade é que, para muitas perguntas sobre como otimizar o desempenho, a resposta será "que sorte". Essa otimização específica vale o esforço e o custo de manutenção desse widget específico? Essa abordagem em particular faz sentido nessa situação em particular?
A única resposta útil para essas perguntas é teste e medição. Quantifique como cada escolha afeta o desempenho e tome decisões com base nesses dados.
A boa notícia é que o Flutter fornece ótimas ferramentas de perfil de desempenho, como o Dart DevTools (atualmente na versão de pré-visualização), que inclui o Flutter Inspector, ou você pode usar o Flutter Inspector diretamente do Android Studio (com o plug-in Flutter instalado). Você tem um Flutter Driver
para testar seu aplicativo e o Profile mode
para salvar informações de desempenho.
A má notícia é que os smartphones modernos são muito inteligentes.
O problema com reguladores
A quantificação do desempenho do aplicativo Flutter é especialmente difícil para os controladores iOS e Android. Esses daemons no nível do sistema controlam a velocidade dos processadores central e gráfico, dependendo da carga. Obviamente, isso é bom, pois fornece uma operação suave com menos consumo de bateria.
A desvantagem é que você pode tornar seu aplicativo muito mais rápido aumentando a quantidade de trabalho que ele executa.
Abaixo, você pode ver como a adição de um ciclo de chamadas de impressão sem sentido ao aplicativo fez o regulador alternar a CPU para uma frequência aumentada, o que tornou o aplicativo muito mais rápido e seu desempenho mais previsível.

O problema com os reguladores: por padrão, você não pode confiar nos seus números. Neste diagrama de amplitude, temos execuções separadas no eixo x (marcado pela hora exata em que foram iniciadas) e tempo de construção no eixo Y. Como você pode ver, quando introduzimos algumas instruções de impressão completamente desnecessárias, isso leva ao fato de que o tempo de construção diminui. mas não para cima.
Nesta experiência, o pior código resultou em um tempo de construção mais rápido (veja acima), um tempo de rasterização mais rápido e uma taxa de quadros mais alta. Quando um código objetivamente pior leva a melhores indicadores de desempenho, você não pode confiar nesses indicadores como um guia (recomendação).
Este é apenas um exemplo de como o teste de desempenho de aplicativos para dispositivos móveis pode ser pouco intuitivo e complexo.
Abaixo, compartilho algumas das dicas que reuni enquanto trabalhava no aplicativo Developer Quest do Flutter para Google I / O.
Dicas gerais
- Não meça o desempenho no modo de depuração (
DEBUG mode
). Avalie o desempenho apenas no Profile mode
perfil. - Meça em um dispositivo real, não no iOS Simulator ou Android Emulator. Os emuladores de software são ótimos para o desenvolvimento, mas têm características de desempenho diferentes das reais. O Flutter não permitirá que você trabalhe no modo de criação de perfil em um dispositivo simulado, porque não faz sentido. Os dados coletados dessa maneira não são aplicáveis ao desempenho real.
- Idealmente, use exatamente o mesmo dispositivo físico. Torne-o seu dispositivo de teste de desempenho dedicado e nunca use-o para mais nada.
- Explore o Flutter Performance Profiling Tools .
Reguladores de CPU / GPU
Conforme discutido acima, os sistemas operacionais modernos alteram a frequência de cada processador e GPU à sua disposição, de acordo com a carga e algumas outras heurísticas. (Por exemplo, tocar na tela geralmente aumenta a velocidade do seu telefone Android.)
No Android, você pode desativar esses controles. Chamamos esse processo de "trava de escala".
- Crie um script que desabilite os controles no seu dispositivo para testar o desempenho. Você pode usar o exemplo do Skia para se inspirar. Você também pode conferir a API da CPU Unix .
- Você pode querer algo menos versátil e mais leve se não fizer tanto trabalho de teste quanto o Skia. Confira o script do shell no Developer Quest para ver para onde ir. Por exemplo, a próxima parte do script define a CPU para o controlador do espaço do usuário (o único controlador que não altera a frequência do processador).
- Seu objetivo aqui não é simular o desempenho real (os usuários não desligam os reguladores em seus dispositivos), mas ter indicadores de desempenho comparáveis entre as execuções.
- No final, você precisa experimentar e adaptar o shell script ao dispositivo que você usará. Isso funciona, mas até você fazer isso, seus dados de desempenho o enganarão.

Uma versão anterior do Developer Quest, testada com o Flutter Driver na minha área de trabalho.
Driver de vibração
O Driver Flutter permite que você teste automaticamente seu aplicativo. Leia a seção “Performance Profiling” no flutter.dev para descobrir como usá-lo ao criar seu perfil no aplicativo.
- Para testar o desempenho, não teste manualmente seu aplicativo. Sempre use o driver Flutter para obter dados realmente indicativos.
- Escreva seu código do Flutter Driver para que ele verifique o que você realmente deseja medir. Se você precisar de desempenho geral do aplicativo, tente passar por todas as partes do aplicativo e faça o que o usuário faria.
- Se o seu aplicativo tiver um elemento aleatório (
Random
, eventos de rede etc.), crie "simulação" para essas situações. As execuções de teste devem ser o mais próximas possível. - Se desejar, você pode adicionar eventos personalizados à linha do tempo usando os
startSync()
e finishSync()
da classe Timeline . Isso pode ser útil se você estiver interessado no desempenho de uma função específica. Coloque startSync()
no início e finishSync()
no final. - Salve o resumo ( writeSummaryToFile ) e, mais importante, a linha do tempo bruta ( writeTimelineToFile ).
- Teste cada versão do seu aplicativo várias vezes. No Developer Quest, passei 100 partidas. (Quando você mede coisas barulhentas, como usar a métrica p99, pode precisar de muito mais execuções.) Para sistemas baseados em POSIX, isso significa simplesmente fazer algo como o seguinte:
for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done
for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done
for i in {1..100}; do flutter drive --target=test_driver/perf.dart --profile; done
.

Ferramenta de linha do tempo do Chrome para verificar os resultados de criação de perfil no Flutter.
Linha do tempo
Linha do tempo é a saída bruta de seus resultados de criação de perfil. Flutter grava essas informações em um arquivo JSON, que pode ser baixado no chrome://tracing
.
- Entenda como abrir a linha do tempo completa no Chrome. Você simplesmente abre o
chrome://tracing
no navegador Chrome, clique em "Carregar" e selecione o arquivo JSON. Você pode ler mais neste pequeno guia . (Também há uma ferramenta de linha do tempo do Flutter que está atualmente na visualização de tecnologia. Eu não a usei porque o projeto Developer Quest foi lançado antes das ferramentas do Flutter estarem prontas.) - Use as teclas WSAD para navegar na linha do tempo em
chrome://tracing
e 1234 para alterar os modos de operação. - Ao configurar o teste de desempenho pela primeira vez, considere executar o Flutter Driver com a ferramenta Systrace Android. Isso fornece uma idéia melhor do que realmente está acontecendo no dispositivo, incluindo informações sobre o dimensionamento da frequência do processador. Não meça o aplicativo inteiro com o Systrace, pois isso tornará tudo mais lento e menos previsível.
- Como executar o Android Systrace com Flutter Driver? Primeiro, inicie o Android Systrace com
/path/to/your/android/sdk/platform-tools/systrace/systrace.py --atrace-categories=gfx,input,view,webview,wm,am,sm,audio,video,camera,hal,app,res,dalvik,rs,bionic,power,pm,ss,database,network,adb,pdx,sched,irq,freq,idle,disk,load,workq,memreclaim,regulators,binder_driver,binder_lock
. Em seguida, flutter run test_driver/perf.dart --profile --trace-systrace
aplicativo flutter run test_driver/perf.dart --profile --trace-systrace
. Por fim, execute a flutter drive --driver=test_driver/perf_test.dart --use-existing-app=http://127.0.0.1:NNNNN/
Flutter Driver flutter drive --driver=test_driver/perf_test.dart --use-existing-app=http://127.0.0.1:NNNNN/
(em que NNNNN é a porta que fornece o aplicativo de vibração acima).
Métricas
É melhor analisar o maior número de métricas possível, mas decidi que algumas são mais úteis que outras.
O tempo de construção e o tempo de rasterização (métricas fornecidas por padrão usando o TimelineSummary
) são úteis apenas para testes de desempenho realmente difíceis, que não incluem muito mais do que a criação de uma interface com o usuário.
Não considere TimelineSummary.frameCount
como uma maneira de calcular quadros por segundo (FPS). As ferramentas de perfil de vibração não fornecem informações reais sobre taxa de quadros. TimelineSummary
fornece o método countFrames()
, mas conta apenas o número de montagens de quadros concluídas. Um aplicativo bem otimizado que limita reconstruções desnecessárias (atualizações) terá FPS mais baixo do que um aplicativo não otimizado que reconstrói com freqüência.
Pessoalmente, obtenho os dados mais úteis medindo o tempo total do processador gasto executando o código Dart. Isso conta o código executado nos métodos de build
e fora deles. Supondo que você execute testes de criação de perfil em um dispositivo com bloqueio de escala, o tempo total da CPU pode ser considerado uma boa aproximação de quanto mais / menos bateria seu aplicativo consumirá.

A maneira mais fácil de descobrir o tempo total do processador gasto na execução do código Dart é estimar o número de eventos MessageLoop:FlushTasks
na linha do tempo. Para Developer Quest, escrevi uma ferramenta Dart para extraí-los.
Para encontrar lixo (lixo) (ou seja, quadros perdidos), procure extremos. Por exemplo, para um caso específico do Developer Quest e o dispositivo em que testamos, é útil examinar o tempo de construção do 95º percentil. (O tempo de construção do percentil 90 foi muito semelhante, mesmo se você comparar o código com níveis completamente diferentes de desempenho, e os números do percentil 99 forem geralmente barulhentos. Seu desempenho pode variar.)

Como mencionado acima, teste cada versão do seu aplicativo várias (talvez 100) vezes. Em seguida, use dados médios ou percentuais com campos de erro. Melhor ainda, use gráficos de extensão.
Resultados
Após o ajuste, você pode comparar com confiança e realizar experimentos. Abaixo, você pode ver a resposta para um dilema comum: “essa otimização dos custos de manutenção vale a pena?”

Penso que, neste caso em particular , a resposta é sim. Graças a apenas algumas linhas de código, cada passagem automatizada de nosso aplicativo leva em média 12% menos tempo de CPU.
Mas - e esta é a principal mensagem deste artigo - as medidas de outra otimização podem mostrar algo completamente diferente. É tentador, mas errado, tentar extrapolar amplamente uma medição de desempenho.
Em outras palavras: "que sorte". E nós temos que aturar isso.