Como fizemos para não consumir CPU quando o aplicativo está apenas aberto
O editor fica aberto o dia inteiro, mas o tempo em que realmente digitamos é apenas uma parte disso. Durante o restante do tempo, o mote não agenda nem quadros nem temporizadores, e garante isso em duas camadas — com inspeção de código e medições em dispositivos reais.

O editor é o aplicativo que fica aberto por mais tempo no notebook. Mas o tempo em que realmente escrevemos não é longo. Na maior parte do tempo, ele simplesmente fica aberto em silêncio enquanto fazemos outras coisas.
Por isso, o mote estabeleceu um princípio.
Se o documento não mudou e não há animações, não faça nada.
Não há quadros agendados, temporizadores repetitivos nem verificações periódicas. Não é uma otimização, mas um princípio de design que deve ser respeitado antes de qualquer funcionalidade.
Se nada está acontecendo, também são 0 quadros
É difícil saber se um aplicativo está quieto apenas pelo uso de CPU. Isso acontece porque o valor oscila a cada medição e, quando arredondado, pode facilmente virar 0.
Por isso, o mote olha primeiro para a quantidade de quadros. Se não houver nenhuma alteração no documento durante os 10 segundos após a janela ser aberta, a quantidade de quadros renderizados deve ser exatamente 0. A contagem é feita diretamente dentro do aplicativo e, se ele renderizar um único quadro, o código não é integrado.
Mesmo com 0 quadros, ainda não dá para ficar tranquilo. Isso porque as threads podem continuar despertando em segundo plano. Também registramos quantas vezes por segundo todas as threads do processo despertam. Como ainda estamos construindo uma referência, esse número sozinho não impede o desenvolvimento.
A única exceção é o piscar do cursor. Em vez de usar um temporizador repetitivo, depois de piscar uma vez ele agenda novamente a próxima ação. Quando a janela perde o foco, ele para imediatamente. O orçamento de CPU em repouso, incluindo o cursor, é de 0,3%.
Não analisamos o desempenho em repouso de forma isolada. Se adiarmos a renderização, é fácil reduzir a quantidade de quadros a 0, mas o caractere digitado pode demorar a aparecer. Por isso, verificamos ao mesmo tempo a latência da entrada do teclado, a velocidade de inicialização e a memória. Se qualquer um dos limites for ultrapassado, o código não é integrado.

Uma vez no código, outra vez no dispositivo real
Os princípios ficam menos claros com o passar do tempo. Por isso, verificamos duas vezes.
Primeiro, inspecionamos o código. Procuramos automaticamente temporizadores repetitivos, ticks que nunca terminam, polling que fica alternando entre dormir e despertar e código que relê desnecessariamente o arquivo inteiro. Quando algo assim é encontrado, o CI para ali. Se for uma exceção realmente necessária, é preciso explicar, logo acima do código, por que a tarefa termina.
Em seguida, medimos em um dispositivo real. Nesse momento, seguimos quatro condições.
Medimos em uma tela real com GPU. O ponteiro fica fora da janela. Usamos um barramento de sessão real e contamos os quadros exatamente no momento em que são renderizados.
Essas condições surgiram depois de enfrentarmos falhas. Certa vez, foram gerados 150 quadros em repouso simplesmente porque o ponteiro estava sobre a janela. Em uma sessão isolada, a inicialização atrasou vários segundos porque o toolkit ficou esperando uma resposta. Quando usamos um contador que informava os quadros com atraso, os quadros da tela de inicialização acabaram se misturando ao período de repouso.
Também não avaliamos a memória pelo valor absoluto. A memória ocupada pelo toolkit e pelo driver gráfico varia em dezenas de MB dependendo do ambiente.
Em vez disso, usamos um documento vazio como referência. Observamos apenas quanto a mais é usado ao abrir um documento em comparação com o documento vazio. Em uma medição recente, o documento vazio usou 116 MB, e o documento de 100 KB usou 120 MB. A memória adicional usada pelo mote foi de 4 MB, dentro do orçamento de 8 MB.
Não medimos assim desde o começo. Houve uma ocasião em que pensamos ter ultrapassado o orçamento de memória, mas descobrimos que não era o aplicativo: a memória básica do ambiente de execução havia aumentado. Desde aquele dia, em vez do valor absoluto, passamos a medir “quanto foi acrescentado pela nossa funcionalidade”.

Durante o desenvolvimento, também mostramos na tela a quantidade de temporizadores ativos. Se não for 0, dá para perceber imediatamente antes de fazer o commit.
O salvamento automático também segue esse princípio. O temporizador é agendado uma única vez somente quando o documento muda e é removido quando o salvamento termina. Ele não desperta periodicamente para verificar: “Alguma coisa mudou?”.
Não são números para derrotar os concorrentes
No começo, queríamos apresentar o desempenho em repouso como uma vantagem sobre o Typora. Mas, quando medimos diretamente, vimos que não era assim.
No mesmo dispositivo e sob as mesmas condições, o uso de CPU em repouso do Typora foi de 0,1%. Praticamente igual ao do mote. Os aplicativos em que confirmamos uma diferença foram o Obsidian, com 0,8%, e o MarkText, com 0,6%.
Também já escrevemos algo errado. Durante algum tempo, o documento dizia: “O Typora usa CPU quando fica aberto”. Os 34,6% usados como fundamento não eram uma medição do Typora, mas do apostrophe. Depois de verificar novamente, corrigimos a frase imediatamente.
Os 0 quadros em repouso não são uma afirmação dirigida aos concorrentes. São uma disciplina que o mote impõe a si mesmo. Se não há nenhuma tarefa sendo executada repetidamente, podemos explicar a qualquer momento o que o aplicativo está fazendo.
Também há coisas das quais abrimos mão por causa desse princípio
Muitas vezes, não podemos usar o método mais conveniente.
Em vez de verificar periodicamente se um arquivo foi alterado externamente, precisamos receber as notificações de alteração do sistema operacional. Em vez de deixar as fórmulas a cargo de uma webview, criamos diretamente o mecanismo de layout. Também não podemos deixar as animações rodando continuamente. Todo movimento tem um começo e um fim e, quando termina, deve parar por completo.
Não vamos dizer que a bateria dura várias horas a mais. Esse é um número que não medimos. O que verificamos foi a quantidade de quadros, o uso de CPU e até a quantidade de vezes que as threads despertaram.
Não fazer nada quando nada está acontecendo.
No mote, isso não é uma funcionalidade, mas um princípio pelo qual todas as funcionalidades precisam passar.