1 pontos por GN⁺ 2024-09-02 | 1 comentários | Compartilhar no WhatsApp

Otimização do tamanho do binário da biblioteca {fmt}

  • Introdução à biblioteca {fmt}

    • {fmt} é uma biblioteca de formatação conhecida pelo pequeno tamanho de binário
    • Em comparação com IOStreams, Boost Format, tinyformat e outros, o tamanho de código por chamada de função é muito menor
    • Minimiza a sobrecarga de templates por meio de apagamento de tipos (type erasure)
  • Formatação por meio de apagamento de tipos

    • A função format delega o trabalho para a função vformat
    • O iterador de saída e outros tipos de saída também passam por apagamento de tipos via uma API de buffer projetada especificamente para isso
    • Minimiza o uso de templates para reduzir o tamanho do binário e o tempo de build
  • Código de exemplo

    #include <fmt/base.h>
    int main() { fmt::print("The answer is {}.", 42); }
    
    • O código acima compila para um tamanho muito menor do que o código com IOStreams
    • Mesmo em comparação com printf, o tamanho é parecido, além de oferecer segurança de tipos em tempo de execução
  • Otimização do tamanho do binário

    • Em 2020, foi feito um trabalho para reduzir o tamanho da biblioteca para menos de 100 kB
    • O tamanho do binário na versão mais recente (11.0.2) é de 75 kB
    • Ao desativar o suporte a locale, o tamanho pode ser reduzido para 71 kB
  • Análise com a ferramenta Bloaty

    • A formatação de números, especialmente de números de ponto flutuante, ocupa uma grande parte
    • Se o suporte a ponto flutuante não for necessário, ele pode ser desativado
  • Otimização de formatação por tipo

    • Definindo a macro FMT_BUILTIN_TYPES como 0, apenas o tipo int é tratado de forma especial, e os demais tipos são tratados pela API de extensão
    • Com esse método, o tamanho do binário pode ser reduzido para 31 kB
  • Remoção de artefatos de locale

    • Usando a macro FMT_USE_LOCALE para remover artefatos de locale, o tamanho pode ser reduzido para 27 kB
  • Trade-off entre velocidade e tamanho

    • Ao otimizar para tamanho com a macro FMT_OPTIMIZE_SIZE, o binário pode ser reduzido para 23 kB
  • Remoção da dependência da biblioteca padrão de C++

    • Desativando exceções e usando a opção -nodefaultlibs, a dependência do runtime de C++ é removida
    • Com a introdução de um alocador customizado usando malloc e free, o tamanho do binário pode ser reduzido para 14 kB
  • Verificação do resultado

    • Foi confirmado com o comando ldd que a dependência do runtime de C++ foi removida

Resumo do GN⁺

  • A biblioteca {fmt} é uma biblioteca de formatação que oferece pequeno tamanho de binário e segurança de tipos em tempo de execução
  • Por meio de apagamento de tipos e configurações de macros, é possível reduzir bastante o tamanho do binário
  • Ao remover a dependência da biblioteca padrão de C++, ela pode ser usada com eficiência até mesmo em sistemas embarcados
  • Bibliotecas com funcionalidades parecidas incluem IOStreams, Boost Format e tinyformat

1 comentários

 
GN⁺ 2024-09-02
Comentários do Hacker News
  • O {fmt} é independente de localidade por padrão
  • A formatação de ponto flutuante exige muito código
    • Vale a pena ler sobre o projeto Dragonbox, que traz código otimizado
  • O alocador padrão do C++ não usa malloc e free
    • Há curiosidade sobre por que o alocador padrão do libc++ não chama malloc e free da libc
  • Existe um projeto que torna possível ter printf("Hello, World!\n") em um executável de 1008 bytes
    • É difícil comparar diretamente, mas serve como referência
  • Em um sistema onde um programa em C com uma função main vazia ocupa 6 kB, o {fmt} adiciona menos de 10 kB ao binário
    • É um teste interessante
  • Esperava-se que uma biblioteca pequena de formatação precisasse de cerca de 50 bytes para imprimir strings e inteiros
    • Strings consistem em cerca de 4 instruções
    • Inteiros consistem em cerca de 20 instruções
    • Ponto flutuante não é usado em muitos programas, então deveria ser compilado só quando necessário
    • Se o espaço de código de um microcontrolador é de 2 kilobytes, não se inclui uma biblioteca de formatação de strings de 14 kilobytes
  • Esse tipo de otimização fora da caixa é muito divertido
  • Levou um tempo para perceber que "14k" significava "14kB"
  • O fmt sempre causa problemas
    • O mesmo acontece no .NET
    • Se você lida muito com formatação/parsing de números, o linker acaba incluindo muito código relacionado a ponto flutuante e BigInt, o que aumenta o tamanho do binário