Documentação
Relatório de desempenho
O custo dos apps NSH, medido. Como o NSH os mantém rápidos e como medir o seu próprio app está em Desempenho.
#Linhas de base
A partir das linhas de base do próprio NSH (Apple silicon, salvo indicação em contrário):
| Cenário | Números |
|---|---|
| App contador, headless (debug) | Primeiro quadro ~0,5–0,65 ms (58 ops / 49 itens de montagem); um toque ~0,15 ms |
| App contador, Mac Catalyst (release) | Primeiro quadro ~1,05–1,15 ms (cerca de 0,7 ms disso para dispor 10 textos com CoreText pela primeira vez); um toque ~0,12 ms |
| Lista de fotos da galeria, headless (debug) | Primeiro quadro 653 ops / 224 nós, ~2,7 ms |
| Rolagem da lista de fotos, Catalyst (release) | Refazer o bind de uma linha durante uma rolagem lenta ~0,4 ms; uma tela inteira de ~32 linhas em um fling rápido 0,9–1,6 ms |
| Rolagem da lista de fotos, emulador Android (arm64, release) | Refazer o bind de uma linha ~0,3–0,4 ms (JS ~60 µs) |
| Inicialização do engine (release) | ~75–155 µs; as APIs globais (fetch, URL, …) não custam nada até o primeiro uso, depois ~90 µs |
| Hot reload | ~120 ms entre salvar um arquivo e a nova versão estar em execução; aplicar a atualização leva 0,2–0,5 ms |
#Linux (GTK 4)
Medido em um desktop Linux (x86_64, 24 threads, GPU NVIDIA), builds de release, a galeria em uma janela de 1896 × 1030 em um
display de 120 Hz, com cada leitura feita automaticamente por examples/gallery/tools/perf.py (nsh test --target linux --fps,
uma linha por segundo; a CPU é a do processo inteiro, em porcentagem de um núcleo). Frame p95 é o tempo da thread principal por
quadro desenhado no percentil 95: abaixo de 8,3 ms, um quadro cabe em um refresh de 120 Hz.
#Demos animadas
| Demo | FPS | Frame p95 | CPU |
|---|---|---|---|
| Stocks: 22 sparklines ao vivo, um gráfico intradiário, livro de ofertas, fita | 117–120 | 5–6 ms | 25–29% (1200 × 800), 28–32% (1896 × 1030) |
| Stocks, com a janela preenchendo um display 4K de 144 Hz a 1,6× | 143–145 | 4,1–4,4 ms | 26–29% |
| Canvas: um medidor, um relógio, uma matriz de pontos | 120 | 2,6–4,4 ms | 5–10% |
| Animations: três loops nativos, springs, sequências | 120 | 2,0 ms | 12–13% |
#Todas as páginas
Todas as páginas da galeria, ao abrir e enquanto o teste as rola, em uma janela de 1200 × 800 em um display de 144 Hz (a
mesma máquina). O NSH só desenha um quadro quando algo na tela muda, então FPS aqui é a taxa enquanto algo
se move: um quadro por intervalo mediano entre quadros desenhados (perf.py, moving); nos 144 do display, cada quadro de uma
animação ou de uma rolagem chega um refresh depois do anterior. Acima de um refresh é a parcela de quadros que levaram mais
que um refresh (6,9 ms). GIF e WebP em Images tocam em suas próprias taxas de quadros (cerca de 50 FPS aqui), assim como o vídeo. Physics, Overlays e Menus são curtas: em 1200 × 800 uma rolagem chega ao fim em poucos quadros, então elas são medidas em uma janela de 900 × 500, onde têm espaço para rolar.
| Página | Origem dos quadros | FPS | Frame p95 | Acima de um refresh | CPU |
|---|---|---|---|---|---|
| Stocks | Dados ao vivo, loops nativos | 144 | 4,1 ms | 0% | 26% |
| Stocks, rolagem | Dados ao vivo, rolagem | 144 | 4,1 ms | 0% | 25% |
| Photos, rolagem | Rolagem | 144 | 2,8 ms | 2% | 9% |
| Lists, rolagem | Rolagem | 143 | 1,7 ms | 0% | 7% |
| Scrolling, rolagem | Rolagem | 144 | 1,6 ms | 1% | 4% |
| Navigation, rolagem | Rolagem | 143 | 1,7 ms | 0% | 2% |
| Form, rolagem | Rolagem | 144 | 1,3 ms | 0% | 4% |
| Resizable, rolagem | Rolagem | 143 | 0,6 ms | 0% | 1% |
| Dock, rolagem | Rolagem | 142 | 0,5 ms | 1% | 1% |
| Gestures | Springs, um anel pulsante | 144 | 1,6 ms | 0% | 1–5% |
| Physics, rolagem | Rolagem (janela de 900 × 500) | 144 | 1,6 ms | 1% | 1% |
| Animations | Loops nativos | 144 | 2,6 ms | 0–1% | 5% |
| Canvas, rolagem | Rolagem, loops nativos | 144 | 4,2 ms | 0% | 1–4% |
| Styles, rolagem | Rolagem | 144 | 2,3 ms | 2% | 3% |
| Tailwind | Utilitários animate-* |
144 | 1,7 ms | 0% | 3–8% |
| Text, rolagem | Rolagem | 144 | 1,9 ms | 0% | 4% |
| Text View, rolagem | Rolagem | 141 | 1,8 ms | 2% | 7% |
| Images, rolagem | Rolagem, quadros de GIF e WebP | 143 | 2,9 ms | 2% | 8% |
| Components, rolagem | Rolagem | 144 | 1,4 ms | 0% | 3% |
| Overlays, rolagem | Rolagem (janela de 900 × 500) | 144 | 1,7 ms | 0% | 2% |
| Menus, rolagem | Rolagem (janela de 900 × 500) | 144 | 1,9 ms | 0% | 2% |
| Controls | Transições | 144 | 0,9 ms | 0% | 1–4% |
| Web e vídeo | Quadros de vídeo, a página | 135–142 | 1,0 ms | 0% | 7–8% |
#Memória
Em repouso, 3 s após a inicialização (runners de release, janela de 480 × 640). Private é a memória que pertence apenas ao processo (USS); resident soma as páginas das bibliotecas compartilhadas (GTK, o driver da GPU), que todo app GTK na máquina compartilha:
| App | Renderizador | Private (USS) | Resident (RSS) |
|---|---|---|---|
App Rust (nsh init --template rust) |
GL (ngl) |
~49 MB | ~142 MB |
| App Rust | Cairo (GSK_RENDERER=cairo) |
~28 MB | ~95 MB |
Contador TSX (examples/counter) |
GL | ~79 MB | ~166 MB |
| Janela GTK 4 com um label, como referência | Vulkan / Cairo | ~62 / ~40 MB | ~132 / ~109 MB |
Revisitar uma página não acrescenta memória; a primeira visita a uma página faz o processo crescer pelo que ele mantém em cache de propósito (imagens decodificadas, limitadas a 128 MB) e pelas bibliotecas que carrega no primeiro uso (WebKitGTK para web views).
#Tamanho do app
Um app hello world criado por nsh init com cada template, e dois apps usados por pessoas, como nsh package --target linux
os compila para x86_64. O runner é o único executável do app; o pacote é o .tar.gz no qual ele é distribuído. Os hello
worlds são compilados com link-time optimization e stripped (CARGO_PROFILE_RELEASE_LTO=fat,
CARGO_PROFILE_RELEASE_CODEGEN_UNITS=1, CARGO_PROFILE_RELEASE_STRIP=true):
| App | Escrito em | Runner | Pacote |
|---|---|---|---|
Hello world (--template rust) |
Rust | 16,5 MB | 7,5 MB |
Hello world (--template ts) |
TSX, sobre QuickJS | 25,7 MB | 11,6 MB |
Hello world (--template mixed) |
TSX e um crate Rust | 25,8 MB | 11,7 MB |
| sysmon 0.1.3 | Rust | 20,9 MB (stripped) | 9,7 MB |
| Omasend 0.2.0 | Rust | 22,3 MB | 9,8 MB |
Os runners TSX contêm o runtime QuickJS, os módulos nativos e o renderizador; o código do app em si é o seu bundle, ao lado do runner, com menos de 1 KB em um hello world.
O que explica esses números:
- O renderizador: com o driver da NVIDIA, o NSH desenha com o renderizador GL do GSK, cujos quadros custam uma fração dos do
renderizador Vulkan nesse caso (a demo Animations: ~1 ms de desenho por quadro em vez de ~9,5 ms).
GSK_RENDERERainda escolhe. - Rasters do canvas: cada canvas é rasterizado uma vez em tiles de 256 px mantidos na GPU. Um valor animado redesenha apenas a área que as operações que o leem cobrem, sobre os pixels mantidos da parte estática do desenho; um canvas fora de vista espera até rolar para dentro da visão.
- Paths postos de lado uma vez:
fillRectefillTextdepois de um path longo o deixam no lugar até que seja usado de novo (uma linha de 400 pontos e depois 240 barras: 0,63 ms).
#macOS (AppKit)
Medido em um MacBook Pro (Apple M3, 24 GB) em seu display ProMotion integrado de 120 Hz, builds de release, a galeria em
uma janela de 1200 × 800, com cada leitura feita automaticamente por examples/gallery/tools/perf.py (nsh test --target macos --fps, uma linha por segundo; a CPU é a do processo inteiro, em porcentagem de um núcleo, e a GPU, sua parcela da GPU). As fases são
as da thread principal por quadro: tick (as animações nativas do display link) e canvas (a reprodução dos desenhos).
#Demos animadas
| Demo | FPS | Frame p95 | CPU | GPU |
|---|---|---|---|---|
| Stocks: 22 sparklines ao vivo, um gráfico intradiário, livro de ofertas, fita | 120 | 2,7–3,7 ms | 33–36% | 18–22% |
| Canvas: um medidor, um relógio, uma matriz de pontos | 119–120 | 0,6–0,7 ms | 4–7% | 0% |
| Animations: três loops nativos, springs, sequências | 119–120 | 0,3–1,6 ms | 5–8% | 0% |
Em Stocks, o tempo da thread principal por quadro é de ~1,6 ms de ticks, dos quais ~0,45 ms reproduzem as partes animadas dos canvases; o Core Animation desenha o restante de cada canvas em suas próprias threads.
#Todas as páginas
Todas as páginas da galeria, ao abrir e enquanto o teste as rola, na mesma janela de 1200 × 800. Como no Linux, FPS é a taxa enquanto algo se move (um quadro por intervalo mediano entre quadros desenhados); nos 120 do display, cada quadro de uma animação ou de uma rolagem chega um refresh depois do anterior. Acima de um refresh é a parcela de quadros que levaram mais que um refresh (8,3 ms). Uma página em repouso não desenha quadros e usa de 2 a 5% de CPU. GIF e WebP em Images tocam no Core Animation e o vídeo no AVFoundation, em suas próprias taxas de quadros.
| Página | Origem dos quadros | FPS | Frame p95 | Acima de um refresh | CPU |
|---|---|---|---|---|---|
| Stocks | Dados ao vivo, loops nativos | 120 | 3,2 ms | 0% | 35% |
| Stocks, rolagem | Dados ao vivo, rolagem | 120 | 3,5 ms | 0% | 36% |
| AI Chat, rolagem | Rolagem | 120 | 2,4 ms | 1% | 5% |
| Photos, rolagem | Rolagem | 120 | 1,4 ms | 0% | 10% |
| Lists, rolagem | Rolagem | 120 | 1,6 ms | 0% | 8% |
| Scrolling, rolagem | Rolagem | 120 | 2,7 ms | 0% | 6% |
| Navigation, rolagem | Rolagem | 120 | 0,2 ms | 0% | 4% |
| Form, rolagem | Rolagem | 120 | 0,6 ms | 0% | 5% |
| Resizable, rolagem | Rolagem | 120 | 0,3 ms | 0% | 4% |
| Dock, rolagem | Rolagem | 120 | 0,3 ms | 1% | 5% |
| Gestures | Springs, um anel pulsante | 120 | 0,4 ms | 0% | 4% |
| Physics, rolagem | Rolagem | 120 | 0,3 ms | 0% | 4% |
| Animations | Loops nativos | 120 | 0,3 ms | 0% | 5% |
| Canvas, rolagem | Rolagem, loops nativos | 120 | 1,2 ms | 0% | 7% |
| Styles, rolagem | Rolagem, uma transformação oscilante | 120 | 1,0 ms | 0% | 6% |
| Tailwind | Utilitários animate-* |
120 | 0,5 ms | 0% | 4% |
| Text, rolagem | Rolagem | 120 | 0,3 ms | 0% | 5% |
| Text View, rolagem | Rolagem | 120 | 0,7 ms | 0% | 5% |
| Images, rolagem | Rolagem | 120 | 0,4 ms | 0% | 5% |
| Components, rolagem | Rolagem | 120 | 0,3 ms | 0% | 5% |
| Overlays, rolagem | Rolagem | 120 | 0,3 ms | 0% | 4% |
| Menus, rolagem | Rolagem | 120 | 0,3 ms | 0% | 5% |
| Controls | Transições | 120 | 0,3 ms | 0% | 4% |
| Web e vídeo, rolagem | Rolagem | 120 | 0,2 ms | 0% | 6% |
| System | requestAnimationFrame, timers |
120 | 0,2 ms | 0% | 3% |
| Standard APIs, rolagem | Rolagem | 120 | 0,3 ms | 0% | 5% |
| Storage, rolagem | Rolagem | 120 | 0,3 ms | 0% | 5% |
#Memória
Em repouso, 3 s após a inicialização (runners de release). Footprint é a memória que o macOS atribui ao processo (o que o Activity Monitor mostra); resident soma as páginas das bibliotecas compartilhadas do sistema:
| App | Janela | Footprint | Resident (RSS) |
|---|---|---|---|
App Rust (nsh init --template rust) |
1200 × 800 | ~19 MB | ~86 MB |
Contador TSX (examples/counter) |
1200 × 800 | ~20 MB | ~89 MB |
| Janela AppKit com um label, como referência | 480 × 640 | ~17 MB | ~80 MB |
Ao longo do tour da galeria, o processo mantém de 84 a 230 MB até a página Canvas e ~350–360 MB a partir da página Text View, com o que ele mantém em cache de propósito (imagens decodificadas, limitadas a 128 MB; os documentos da página Text View) e os frameworks que carrega no primeiro uso (WebKit para web views); os rasters da página Canvas, até ~310 MB com os três canvases na tela, são liberados quando a página fecha.
#Tamanho do app
Os apps hello world criados por nsh init com cada template, como nsh package --target macos os compila para Apple
silicon (arm64), com link-time optimization e stripped como no Linux, e os dois apps acima como são distribuídos para Apple
silicon. O executável é o runner dentro do .app; o zip é o .app compactado (ditto -c -k):
| App | Escrito em | Executável | Compactado .app |
|---|---|---|---|
Hello world (--template rust) |
Rust | 12,4 MB | 6,0 MB |
Hello world (--template ts) |
TSX, no QuickJS | 19,8 MB | 9,5 MB |
Hello world (--template mixed) |
TSX e um crate Rust | 19,8 MB | 9,5 MB |
| sysmon 0.1.3 | Rust | 21,6 MB | 8,4 MB (.tar.gz da sua release) |
| Omasend 0.2.0 | Rust | 18,4 MB | 9,7 MB (.tar.gz da sua release) |
O que explica esses números:
- Quadros só para mudanças: o display link dispara enquanto uma animação nativa roda e para junto com ela; uma
animação para com a sua página (a exclusão da sua view encerra seus keyframes, um loop para no
cleanupdo seu componente). - Canvases desenhados onde custam menos: um canvas que pinta com frequência (uma animação, dados ao vivo) desenha nas
threads do Core Animation (
drawsAsynchronously), o que mantém a thread principal livre; um canvas redesenhado de vez em quando desenha imediatamente, sem a memória gráfica que o desenho assíncrono retém. Um valor animado redesenha apenas a área coberta pelas operações que o leem. - Partes estáticas do canvas mantidas: quando um desenho permanece inalterado, uma parte longa antes da sua primeira operação animada é mantida como uma layer; a cada quadro, essa layer é desenhada e apenas o restante animado é reexecutado, imediatamente na thread principal (o medidor, o relógio e a matriz de pontos da página Canvas: nenhum trabalho de GPU e metade da memória).
- Conteúdo desenhado quando muda: textos e canvases desenham em layers próprias, de novo quando o conteúdo ou o tamanho muda, não quando se movem ou rolam.
#Windows (Win32, Direct2D)
Medido em um desktop com Windows 11 (Intel Core i7-13700KF, 32 GB, NVIDIA GeForce RTX 3060 Ti) com um display 4K de
144 Hz a 150%, builds de release, a galeria em uma janela de 1200 × 800 (1800 × 1200 pixels), cada leitura feita
automaticamente por examples/gallery/tools/perf.py (nsh test --target windows --fps, uma linha por segundo; a CPU é a do processo inteiro, em
porcentagem de um núcleo). As fases são as da thread principal por quadro: paint (o Direct2D desenhando a janela) e,
dentro dela, canvas (gravação e reexecução de desenhos).
#Demos animadas
| Demo | FPS | Frame p95 | Paint / canvas por quadro | CPU |
|---|---|---|---|---|
| Stocks: 22 sparklines ao vivo, um gráfico intradiário, livro de ofertas, tape | 144 | 3,7–4,3 ms | 1,4 / 0,13 ms | 36–43% |
| Canvas: um medidor, um relógio, uma matriz de pontos | 144 | 1,0–2,0 ms | 0,8–1,4 / 0,05 ms | 21–35% |
| Animations: três loops nativos, springs, sequências | 144 | 1,0–3,6 ms | 0,9–1,9 ms | 20–41% |
Stocks faz de 16 a 17 commits por segundo, cada um em até 2,1 ms de JS e 1,7 ms do core na thread do engine (p95).
#Todas as páginas
Todas as páginas da galeria, ao abrirem e enquanto o teste as rola, na mesma janela de 1200 × 800. Como no Linux e no macOS, FPS é a taxa enquanto algo se move (um quadro por intervalo mediano entre quadros desenhados); a 144 do display, cada quadro de uma animação ou de uma rolagem vem um refresh depois do anterior. Mais de um refresh é a proporção de quadros que levaram mais que um refresh (6,9 ms). Uma página em repouso não desenha quadros e usa de 0 a 2% de CPU. Os GIF e WebP de Images rodam em suas próprias taxas de quadros (cerca de 40 FPS aqui). Physics, Overlays, Menus e Storage são medidas em uma janela de 900 × 500, onde há espaço para rolar.
| Página | Origem dos quadros | FPS | Frame p95 | Mais de um refresh | CPU |
|---|---|---|---|---|---|
| Stocks | Dados ao vivo, loops nativos | 144 | 3,9 ms | 0% | 36% |
| Stocks, scrolling | Dados ao vivo, rolagem | 144 | 4,3 ms | 0% | 43% |
| Photos, scrolling | Rolagem | 143 | 2,1 ms | 0% | 9% |
| Lists, scrolling | Rolagem | 144 | 2,0 ms | 1% | 19% |
| Scrolling, scrolling | Rolagem | 143 | 2,1 ms | 0% | 7% |
| Navigation, scrolling | Rolagem | 144 | 0,8 ms | 0% | 9% |
| Form, scrolling | Rolagem | 144 | 0,8 ms | 0% | 12% |
| Resizable, scrolling | Rolagem | 143 | 0,4 ms | 0% | 4% |
| Dock, scrolling | Rolagem | 144 | 0,5 ms | 1% | 5% |
| Gestures | Springs, um anel pulsante | 144 | 1,8 ms | 0% | 36% |
| Physics, scrolling | Rolagem (janela de 900 × 500) | 144 | 0,8 ms | 0% | 4% |
| Animations | Loops nativos | 144 | 1,0 ms | 0% | 28% |
| Canvas, scrolling | Rolagem, loops nativos | 144 | 2,0 ms | 0% | 35% |
| Styles, scrolling | Rolagem, uma transformação oscilante | 144 | 2,1 ms | 0% | 39% |
| Tailwind | Utilitários animate-* |
144 | 0,6 ms | 0% | 19% |
| Text, scrolling | Rolagem | 144 | 1,6 ms | 0% | 8% |
| Text View, scrolling | Rolagem | 144 | 1,1 ms | 0% | 10% |
| Images, scrolling | Rolagem, quadros de GIF e WebP | 143 | 4,8 ms | 2% | 23% |
| Components, scrolling | Rolagem | 144 | 1,0 ms | 1% | 11% |
| Overlays, scrolling | Rolagem (janela de 900 × 500) | 144 | 0,6 ms | 0% | 1% |
| Menus, scrolling | Rolagem (janela de 900 × 500) | 144 | 0,6 ms | 0% | 2% |
| Controls | Transições | 117–144 | 1,5 ms | 0% | 22% |
| Web and video, scrolling | Rolagem | 144 | 1,6 ms | 0% | 15% |
| System | requestAnimationFrame, timers |
144 | < 0,1 ms | 0% | 1% |
| Storage, scrolling | Rolagem (janela de 900 × 500) | 144 | 0,5 ms | 0% | 1% |
#Memória
Em repouso, 3 s após a inicialização (runners de release, janela de 1200 × 800). Private working set é a memória que o processo usa sozinho (coluna Memory do Task Manager); private bytes é o que ele tem alocado (committed); working set soma as páginas das bibliotecas do sistema que ele compartilha com outros processos (Direct3D, Direct2D, DirectWrite, o driver da GPU):
| App | Private working set | Private bytes | Working set |
|---|---|---|---|
App Rust (nsh init --template rust) |
~14 MB | ~60 MB | ~53–71 MB |
Contador em TSX (examples/counter) |
~15 MB | ~61 MB | ~56–71 MB |
Ao longo do tour da galeria, o working set fica em ~108–115 MB em Stocks, ~230 MB a partir da página Canvas, ~320–340 MB a partir da página Text View e ~390–405 MB depois que Web and video abre o WebView2 (cujas páginas rodam nos processos próprios do WebView2), com o que ele guarda em cache de propósito (imagens decodificadas, limitadas a 128 MB; os documentos da página Text View).
#Tamanho do app
Os apps hello world criados por nsh init com cada template, como nsh package --target windows os compila para x86_64
(os runners Rust com link-time optimization e stripped, como no Linux). O executável é o <Name>.exe do app;
o zip é o .zip gravado ao lado do seu diretório:
| App | Escrito em | Executável | Zip |
|---|---|---|---|
Hello world (--template rust) |
Rust | 15,0 MB | 6,7 MB |
Hello world (--template ts) |
TSX, no QuickJS | 28,6 MB | 12,4 MB |
Hello world (--template mixed) |
TSX e um crate Rust | 26,3 MB | 11,5 MB |
O que explica esses números:
- Quadros só para mudanças, desenhados só onde mudaram: o ticker sincronizado com o compositor roda enquanto uma animação nativa, uma transição ou um frame callback está em execução. Um quadro desenha as áreas das views que mudaram (onde estavam e onde estão), sobre os pixels que a janela mantém, e apresenta ao compositor apenas essas áreas (Stocks: ~34 views por quadro).
- Canvases gravam sua parte animada: um desenho é gravado como command lists do Direct2D, vetorial e nítido em qualquer escala. Quando um valor animado muda, apenas as operações a partir da primeira que lê um valor animado são gravadas de novo; o que vem antes é mantido (Stocks: ~26 ms de gravação por segundo para 22 sparklines pulsantes e o gráfico).
- Só o que aparece é desenhado: os filhos de uma scroll view ou de uma view com clipping que estão fora de vista ficam de fora do quadro, e views sem conteúdo próprio desenham apenas o fundo e a borda.
#iOS (UIKit)
Medido no simulador do iOS (um iPhone 18 Pro Max, no MacBook Pro acima), builds de release, com o mesmo tour
(perf.py --target ios: nsh test --target ios --fps, os toques de um dedo como o UIKit os recebe). O simulador apresenta
a 60 Hz; em um iPhone com tela ProMotion, os display links do NSH rodam a 120 Hz da tela (os apps que nsh package
compila e o host de desenvolvimento pedem isso com CADisableMinimumFrameDurationOnPhone). As fases são tick (animações
nativas), drain (aplicação dos batches do engine) e scroll (o que acompanha uma scroll view: listas, células sticky,
valores vinculados).
| Página | Origem dos quadros | FPS | Frame p95 | CPU |
|---|---|---|---|---|
| Home, scrolling | Rolagem | 60 | 0,1 ms | 6% |
| Stocks | Dados ao vivo, loops nativos | 60 | 0,3 ms | 22% |
| Stocks, scrolling | Dados ao vivo, rolagem | 60 | 0,3 ms | 25% |
| Photos, scrolling | Rolagem | 60 | 1,2 ms | 6% |
| Lists, scrolling | Rolagem | 60 | 1,1 ms | 8% |
| Scrolling, scrolling | Rolagem | 60 | 0,1 ms | 7% |
| Navigation, scrolling | Rolagem | 60 | 0,2 ms | 7% |
| Form, scrolling | Rolagem | 60 | 0,3 ms | 7% |
| Gestures | Springs, um anel pulsante | 60 | 0,3 ms | 3% |
| Animations | Loops nativos | 60 | 0,7 ms | 6% |
| Canvas | Loops nativos | 60 | 0,4 ms | 16% |
| Styles | Uma transformação oscilante | 60 | 0,4 ms | 4% |
| Tailwind, scrolling | Rolagem | 60 | 0,2 ms | 7% |
| Text, scrolling | Rolagem | 60 | 0,1 ms | 7% |
| Text View, scrolling | Rolagem | 60 | 0,1 ms | 6% |
| Images, scrolling | Rolagem | 60 | 0,1 ms | 5% |
| Components, scrolling | Rolagem | 60 | 0,2 ms | 6% |
| Overlays, scrolling | Rolagem | 60 | 0,1 ms | 6% |
| Menus, scrolling | Rolagem | 60 | 0,2 ms | 7% |
| Controls, scrolling | Rolagem, transições | 60 | 0,2 ms | 5% |
| Web and video, scrolling | Rolagem | 60 | 0,1 ms | 8% |
| System | requestAnimationFrame, timers |
60 | 0,3 ms | 4% |
| Standard APIs, scrolling | Rolagem | 60 | 0,1 ms | 7% |
| Storage, scrolling | Rolagem | 60 | 0,1 ms | 8% |
FPS é a taxa enquanto algo se move, como acima: a 60 do simulador, cada quadro vem um refresh depois do anterior. Toda página sem nada se movendo não desenha quadros e usa de 1 a 2% de CPU em repouso. O processo ocupa 40 MB na página inicial da galeria e ~180 MB depois do tour completo (imagens em cache de propósito, os documentos da página Text View).
Em um iPhone 17 Pro (ProMotion, 120 Hz), com o host de desenvolvimento e uma demo na tela, as páginas animadas desenham a cada refresh:
| Página | Origem dos quadros | FPS | Frame p95 | Mais de um refresh | CPU | Memória |
|---|---|---|---|---|---|---|
| Stocks | Dados ao vivo, loops nativos | 120 | 0,2–0,3 ms | 0% | 46–70% | 41–43 MB |
| Canvas | Loops nativos | 120 | 0,1 ms | 0% | 25–36% | 37–38 MB |
| Animations | Loops nativos | 120 | 0,2 ms | 0% | 3–11% | 37 MB |
Stocks faz 20 commits por segundo (um tick a cada 50 ms), cada um em 1,5 ms de JS e 1,4 ms do core na thread do engine (p95 de 2,2 e 2,0 ms), que fica ocupada de 4 a 6% do tempo.
#Medindo um app
Para medir um app da mesma forma, execute seus testes ou steps com --fps e -v em --target linux, macos, windows ou ios:
cargo build --release -p nsh-cli
python3 examples/gallery/tools/perf.py --target macos --only Stocks,Canvas # the gallery, page by page
echo 'await app.wait(5000)' | nsh -v test App.tsx --target linux --fps # any app