Skip to content

O Bun é projetado para velocidade. Caminhos críticos são extensivamente perfilados e benchmarked. O código-fonte de todos os benchmarks públicos do Bun pode ser encontrado no diretório /bench do repositório do Bun.

Medindo tempo

Para medir o tempo com precisão, o Bun oferece duas APIs de tempo de execução:

  1. A função padrão Web performance.now()
  2. Bun.nanoseconds() que é similar ao performance.now() exceto que retorna o tempo atual desde que a aplicação iniciou em nanosegundos. Você pode usar performance.timeOrigin para converter isso para um timestamp Unix.

Ferramentas de benchmark

Ao escrever seus próprios benchmarks, é importante escolher a ferramenta certa.

  • Para microbenchmarks, uma ótima ferramenta de propósito geral é mitata.
  • Para teste de carga, você deve usar uma ferramenta de benchmark HTTP que seja pelo menos tão rápida quanto Bun.serve(), ou seus resultados serão distorcidos. Algumas ferramentas populares baseadas em Node.js como autocannon não são rápidas o suficiente. Recomendamos uma das seguintes:
  • Para benchmark de scripts ou comandos CLI, recomendamos hyperfine.

Medindo uso de memória

O Bun possui dois heaps. Um heap é para o runtime JavaScript e o outro heap é para todo o resto.

Estatísticas do heap JavaScript

O módulo bun:jsc expõe algumas funções para medir uso de memória:

ts
import { heapStats } from "bun:jsc";
console.log(heapStats());

Ver estatísticas de exemplo

ts
{
  heapSize: 1657575,
  heapCapacity: 2872775,
  extraMemorySize: 598199,
  objectCount: 13790,
  protectedObjectCount: 62,
  globalObjectCount: 1,
  protectedGlobalObjectCount: 1,
  // Uma contagem de cada tipo de objeto no heap
  objectTypeCounts: {
    CallbackObject: 25,
    FunctionExecutable: 2078,
    AsyncGeneratorFunction: 2,
    'RegExp String Iterator': 1,
    FunctionCodeBlock: 188,
    ModuleProgramExecutable: 13,
    String: 1,
    UnlinkedModuleProgramCodeBlock: 13,
    JSON: 1,
    AsyncGenerator: 1,
    Symbol: 1,
    GetterSetter: 68,
    ImportMeta: 10,
    DOMAttributeGetterSetter: 1,
    UnlinkedFunctionCodeBlock: 174,
    RegExp: 52,
    ModuleLoader: 1,
    Intl: 1,
    WeakMap: 4,
    Generator: 2,
    PropertyTable: 95,
    'Array Iterator': 1,
    JSLexicalEnvironment: 75,
    UnlinkedFunctionExecutable: 2067,
    WeakSet: 1,
    console: 1,
    Map: 23,
    SparseArrayValueMap: 14,
    StructureChain: 19,
    Set: 18,
    'String Iterator': 1,
    FunctionRareData: 3,
    JSGlobalLexicalEnvironment: 1,
    Object: 481,
    BigInt: 2,
    StructureRareData: 55,
    Array: 179,
    AbortController: 2,
    ModuleNamespaceObject: 11,
    ShadowRealm: 1,
    'Immutable Butterfly': 103,
    Primordials: 1,
    'Set Iterator': 1,
    JSGlobalProxy: 1,
    AsyncFromSyncIterator: 1,
    ModuleRecord: 13,
    FinalizationRegistry: 1,
    AsyncIterator: 1,
    InternalPromise: 22,
    Iterator: 1,
    CustomGetterSetter: 65,
    Promise: 19,
    WeakRef: 1,
    InternalPromisePrototype: 1,
    Function: 2381,
    AsyncFunction: 2,
    GlobalObject: 1,
    ArrayBuffer: 2,
    Boolean: 1,
    Math: 1,
    CallbackConstructor: 1,
    Error: 2,
    JSModuleEnvironment: 13,
    WebAssembly: 1,
    HashMapBucket: 300,
    Callee: 3,
    symbol: 37,
    string: 2484,
    Performance: 1,
    ModuleProgramCodeBlock: 12,
    JSSourceCode: 13,
    JSPropertyNameEnumerator: 3,
    NativeExecutable: 290,
    Number: 1,
    Structure: 1550,
    SymbolTable: 108,
    GeneratorFunction: 2,
    'Map Iterator': 1
  },
  protectedObjectTypeCounts: {
    CallbackConstructor: 1,
    BigInt: 1,
    RegExp: 2,
    GlobalObject: 1,
    UnlinkedModuleProgramCodeBlock: 13,
    HashMapBucket: 2,
    Structure: 41,
    JSPropertyNameEnumerator: 1
  }
}

JavaScript é uma linguagem com coleta de lixo, não contagem de referência. É normal e correto que objetos não sejam liberados imediatamente em todos os casos, embora não seja normal que objetos nunca sejam liberados.

Para forçar a coleta de lixo manualmente:

ts
Bun.gc(true); // síncrono
Bun.gc(false); // assíncrono

Snapshots do heap permitem inspecionar quais objetos não estão sendo liberados. Você pode usar o módulo bun:jsc para tirar um snapshot do heap e depois visualizá-lo com as ferramentas de desenvolvedor do Safari ou WebKit GTK. Para gerar um snapshot do heap:

ts
import { generateHeapSnapshot } from "bun";

const snapshot = generateHeapSnapshot();
await Bun.write("heap.json", JSON.stringify(snapshot, null, 2));

Para visualizar o snapshot, abra o arquivo heap.json nas Ferramentas de Desenvolvedor do Safari (ou WebKit GTK)

  1. Abra as Ferramentas de Desenvolvedor
  2. Clique em "Timeline"
  3. Clique em "JavaScript Allocations" no menu à esquerda. Pode não estar visível até você clicar no ícone de lápis para mostrar todas as timelines
  4. Clique em "Import" e selecione seu JSON de snapshot do heap

Uma vez importado, você deve ver algo como isto:

O depurador web também oferece o recurso de timeline que permite rastrear e examinar o uso de memória da sessão de depuração em execução.

Estatísticas do heap nativo

O Bun usa mimalloc para o outro heap. Para reportar um resumo do uso de memória não-JavaScript, defina a variável de ambiente MIMALLOC_SHOW_STATS=1 e as estatísticas serão impressas na saída.

sh
MIMALLOC_SHOW_STATS=1 bun script.js
txt
heap stats:    peak      total      freed    current       unit      count
  reserved:   64.0 MiB   64.0 MiB      0       64.0 MiB                        not all freed!
 committed:   64.0 MiB   64.0 MiB      0       64.0 MiB                        not all freed!
     reset:      0          0          0          0                            ok
   touched:  128.5 KiB  128.5 KiB    5.4 MiB   -5.3 MiB                        ok
  segments:      1          1          0          1                            not all freed!
-abandoned:      0          0          0          0                            ok
   -cached:      0          0          0          0                            ok
     pages:      0          0         53        -53                            ok
-abandoned:      0          0          0          0                            ok
 -extended:      0
 -noretire:      0
     mmaps:      0
   commits:      0
   threads:      0          0          0          0                            ok
  searches:     0.0 avg
numa nodes:       1
   elapsed:       0.068 s
   process: user: 0.061 s, system: 0.014 s, faults: 0, rss: 57.4 MiB, commit: 64.0 MiB

Perfil de CPU

Perfile a execução JavaScript para identificar gargalos de desempenho com a flag --cpu-prof.

sh
bun --cpu-prof script.js

Isso gera um arquivo .cpuprofile que você pode abrir no Chrome DevTools (aba Performance → Carregar perfil) ou no profiler de CPU do VS Code.

Opções

sh
bun --cpu-prof --cpu-prof-name my-profile.cpuprofile script.js
bun --cpu-prof --cpu-prof-dir ./profiles script.js
FlagDescrição
--cpu-profHabilitar perfil
--cpu-prof-name <filename>Definir nome do arquivo de saída
--cpu-prof-dir <dir>Definir diretório de saída

Bun by www.bunjs.com.cn edit