Benchmarks
O Clause comparado com o Erlang/OTP numa única máquina: os mesmos programas Erlang, compilados pelo erlc e pelo clau -O2, medem o tempo dos seus kernels após uma chamada de aquecimento. Estes números mudam a cada otimização.
- Média geométrica dos tempos dos kernels, Clause -O2 face ao JIT da BEAM (OTP)
- 1,49× mais rápido em média
- Kernels em que o Clause é mais rápido
- 31 / 31
- Média geométrica em 2026-10-12, a primeira execução registada
- 20,2×
Tempos dos kernels
Mediana de 3 execuções em milissegundos. A barra mostra o tempo do Clause dividido pelo do OTP numa escala logarítmica.
| Kernel | OTP JIT | Clause -O2 | Clause ÷ OTP | |
|---|---|---|---|---|
| Geração de dados | ||||
| bigint_factorialCalcula o fatorial de 3000 com inteiros grandes, 330 vezes | 1.620,17 | 212,76 | 0,13× | |
| binary_appendAcrescenta 10 000 inteiros de 32 bits a um binary crescente, 23 000 vezes | 1.080,93 | 802,57 | 0,74× | |
| list_of_tuplesConstrói uma lista de 200 000 tuplos pequenos, 260 vezes | 1.467,60 | 1.128,44 | 0,77× | |
| list_to_tupleConverte listas de 1000 elementos em tuplos, 170 000 vezes | 1.586,38 | 1.278,69 | 0,81× | |
| map_putInsere 2000 chaves inteiras num map, uma a uma, 4900 vezes | 1.605,84 | 1.519,51 | 0,95× | |
| string_buildConstrói 20 000 cadeias a partir de inteiros e átomos, 1000 vezes | 1.044,38 | 720,73 | 0,69× | |
| Processamento de dados | ||||
| binary_matchSoma 20 000 inteiros de 32 bits extraídos de um binary, 49 000 vezes | 1.272,63 | 1.071,47 | 0,84× | |
| comprehensionComprehension que filtra e duplica 20 000 inteiros, 15 000 vezes | 1.407,08 | 893,85 | 0,64× | |
| int_to_listConverte 20 000 inteiros em cadeias e de volta, 2000 vezes | 908,70 | 412,79 | 0,45× | |
| map_foldlAplica map e depois fold a 20 000 inteiros, 4500 vezes | 1.500,77 | 1.113,04 | 0,74× | |
| map_updateIncrementa cada valor de um map de 500 chaves, 24 000 vezes | 1.151,28 | 669,97 | 0,58× | |
| small_mapAtualiza 80 milhões de vezes um pequeno map de estado | 1.486,44 | 1.061,83 | 0,71× | |
| sortOrdena uma lista de 20 000 inteiros aleatórios, 600 vezes | 1.112,37 | 466,55 | 0,42× | |
| term_to_binaryCodifica e descodifica um termo aninhado grande, 4300 vezes | 1.433,29 | 1.071,95 | 0,75× | |
| E/S de ficheiros | ||||
| large_readLê um ficheiro de 16 MB em blocos de 64 KB, 370 vezes | 1.444,15 | 1.007,93 | 0,70× | |
| large_writeEscreve um ficheiro de 16 MB em blocos de 64 KB, 200 vezes | 1.019,80 | 989,09 | 0,97× | |
| read_fileLê um ficheiro inteiro de 16 MB numa só chamada, 330 vezes | 1.485,52 | 1.483,03 | 1,00× | |
| read_lineLê linha a linha um ficheiro de texto de 20 000 linhas, 52 vezes | 1.522,07 | 1.467,28 | 0,96× | |
| small_filesEscreve, relê e apaga 500 ficheiros pequenos, 11 vezes | 1.209,75 | 1.116,40 | 0,92× | |
| Recolha de lixo | ||||
| explicit_collectForça a recolha de lixo com 10 000 tuplos vivos, 5100 vezes | 1.547,98 | 639,85 | 0,41× | |
| grow_shrinkFaz crescer o heap com uma lista de 200 000 elementos e larga-a, 300 vezes | 1.041,41 | 861,75 | 0,83× | |
| long_lived_churnMantém uma janela deslizante de 10 000 elementos vivos no meio de lixo, 370 vezes | 1.351,27 | 1.095,82 | 0,81× | |
| short_processesLança 5000 processos efémeros que geram lixo cada um, 69 vezes | 1.667,28 | 1.037,98 | 0,62× | |
| Bibliotecas | ||||
| qlcExecuta a transformação qlc sobre 27 consultas e 3 módulos, 11 vezes | 1.873,72 | 1.714,66 | 0,92× | |
| Troca de mensagens | ||||
| fan_in100 processos enviam 1000 mensagens cada um a um só, 25 vezes | 1.402,68 | 391,78 | 0,28× | |
| large_messageEnvia uma lista de 100 000 elementos a outro processo e de volta, 560 vezes | 1.063,94 | 789,04 | 0,74× | |
| ping_pongTroca uma mensagem entre dois processos 2 milhões de vezes | 1.504,97 | 904,20 | 0,60× | |
| ringPassa um testemunho 3050 vezes por um anel de 1000 processos | 1.438,21 | 1.099,66 | 0,76× | |
| Sockets em loopback | ||||
| tcp_connectAbre 900 ligações TCP em loopback, com eco de 25 mensagens de 1 KB em cada | 1.418,85 | 1.047,85 | 0,74× | |
| tcp_echoEco de 30 000 mensagens de 1 KB por TCP em loopback | 1.455,62 | 1.136,06 | 0,78× | |
| udp_round_tripIda e volta de um datagrama de 1 KB, 27 900 vezes, por UDP em loopback | 1.458,07 | 1.196,82 | 0,82× | |
Programas completos
Tempo real em segundos, incluindo o arranque, mediana das execuções.
| Programa | OTP JIT | Clause -O2 | Clause ÷ OTP | |
|---|---|---|---|---|
| bench_datagenConstrói em massa listas, tuplos, maps, binaries e inteiros grandes | 8,54 | 5,72 | 0,67× | |
| bench_dataprocOrdenação, fold, atualização de maps, matching de binaries e conversões | 10,45 | 6,76 | 0,65× | |
| bench_fileEscrita e leitura de ficheiros pequenos e grandes, leitura por linhas | 6,95 | 6,24 | 0,90× | |
| bench_gcProcessos efémeros, heap que cresce e encolhe, dados vivos | 5,83 | 3,69 | 0,63× | |
| bench_libraryA parse transform do qlc em runtime, como qlc:q/1 a usa | 2,30 | 1,89 | 0,82× | |
| bench_msgPingue-pongue, fan-in, anel de processos e cópia de mensagens grandes | 5,69 | 3,28 | 0,58× | |
| bench_socketEco TCP, ligações TCP e idas e voltas UDP em loopback | 5,99 | 4,57 | 0,76× |
Progresso
Média geométrica do tempo do Clause dividido pelo do OTP em cada dia com execuções registadas. As execuções anteriores a 2026-10-21 não estavam fixadas a um conjunto de CPUs, pelo que parte da alteração desse dia se deve à fixação.
| Data | Commit | Clause ÷ OTP |
|---|---|---|
| 2026-10-12 | a7bc0c9b | 20,2× |
| 2026-10-13 | 8a244d9c | 16,9× |
| 2026-10-14 | 55f42a9d | 16,9× |
| 2026-10-15 | 6ed3851c | 2,73× |
| 2026-10-16 | 97295c84 | 1,95× |
| 2026-10-17 | a8c3f8f6 | 1,38× |
| 2026-10-18 | 336caea7 | 1,41× |
| 2026-10-20 | 7d7a2f2e | 1,00× |
| 2026-10-21 | 71ec52f8 | 0,78× |
| 2026-10-23 | dea68508 | 0,69× |
| 2026-10-24 | af105043 | 0,65× |
| 2026-10-26 | d6eafa72 | 0,71× |
| 2026-10-30 | f4e5f3e0 | 0,67× |
Tamanho dos executáveis
Tamanho em megabytes dos programas de teste tal como o Clause os constrói em cada nível de otimização.
| Programa | -O0 | -O2 | -O2 --lto |
|---|---|---|---|
| bench_datagen | 9,90 MB | 9,82 MB | 9,82 MB |
| bench_dataproc | 10,42 MB | 10,01 MB | 10,01 MB |
| bench_file | 11,34 MB | 10,59 MB | 10,59 MB |
| bench_gc | 9,89 MB | 9,81 MB | 9,81 MB |
| bench_library | 10,24 MB | 9,94 MB | 9,95 MB |
| bench_msg | 9,91 MB | 9,82 MB | 9,82 MB |
| bench_socket | 11,58 MB | 10,64 MB | 10,65 MB |
Tamanhos com -O2 das últimas 6 execuções dos benchmarks, da mais antiga para a mais recente, um commit do Clause por execução. A tabela abaixo acrescenta o total de todos os programas bench_* e o tamanho do compilador clau.
- 2026-10-207d7a2f2e
- 2026-10-2171ec52f8
- 2026-10-23dea68508
- 2026-10-24af105043
- 2026-10-26d6eafa72
- 2026-10-30f4e5f3e0
| Data | Commit | Todos os programas bench_* | clau |
|---|---|---|---|
| 2026-10-20 | 7d7a2f2e | 38,59 MB | 59,50 MB |
| 2026-10-21 | 71ec52f8 | 38,78 MB | 59,54 MB |
| 2026-10-23 | dea68508 | 38,79 MB | 59,54 MB |
| 2026-10-24 | af105043 | 38,81 MB | 59,65 MB |
| 2026-10-26 | d6eafa72 | 62,21 MB | 59,98 MB |
| 2026-10-30 | f4e5f3e0 | 70,63 MB | 60,75 MB |
Configuração
- Máquina
- Intel64 Family 6 Model 183 Stepping 1, GenuineIntel, 32 CPUs lógicos, Windows 11 (10.0.26200)
- Conjunto de CPUs
- Núcleos de desempenho 0-15, 16 de 32 CPUs lógicos
- Erlang/OTP
- 29, ERTS 17.1
- Commit do Clause
- f4e5f3e0
- Execução
- 2026-10-30
O OTP e o Clause correm nos mesmos CPUs: cada programa de benchmark está fixado aos núcleos de desempenho do processador, pelo que num CPU híbrido nenhum kernel acaba num núcleo de eficiência mais lento. Ambos mantêm um escalonador ativo por cada CPU do conjunto, sem o vincular a um CPU concreto dentro dele.
Para executar os benchmarks, use make benchmark ou make-benchmark.bat no repositório do Clause; as notas de benchmarks descrevem os programas e as opções. Notas de benchmarks
Clause