Estamos procurando uma biblioteca universal rápida para trabalhar com arquivos gráficos, entender o benchmark do Google



Hoje em dia, quando as redes neurais exploram a expansão do Big Data, e a inteligência artificial está considerando se é rentável para ele receber um salário por seu trabalho no Bitcoin, a tarefa que encontrei na biblioteca multiplataforma aberta mais rápida para carregar, salvar e transcodificar arquivos gráficos parecia um verdadeiro anacronismo . Mas, de fato, essa tarefa é mais relevante do que nunca - para todas as tecnologias de visão computacional e aprendizado de máquina, é necessário fazer o download de gigabytes de imagens e, às vezes, os dados intermediários devem ser salvos como imagens. Portanto, fazer isso da maneira mais rápida é muito desejável. Neste artigo, encontraremos a biblioteca que procuramos e, o mais importante, lidaremos com um produto muito útil que simplifica bastante tarefas semelhantes e muitas outras - o Google Benchmark.

Portanto, a declaração exata do problema afirma: no aplicativo, os arquivos jpeg e tiff com profundidade de cor de 24 e 8 bits e bmp de 32 bits são carregados na memória. Os tamanhos de imagem variam de pequeno (32x32 pixels) a grande, com uma resolução de 15K. No processo, os arquivos são modificados, após o que precisam ser salvos no disco nos formatos especificados. E isso deve ser feito por uma biblioteca de código aberto de plataforma cruzada que tenha desempenho máximo nos modernos processadores Intel, com suporte para instruções de vetores AVX2. A biblioteca também suporta a biblioteca de formatos de textura compactada DirectX DXT1. O Windows Imaging Component é considerado como referência de desempenho - a estrutura padrão para trabalhar com imagens no Windows, ou seja, você precisa encontrar uma biblioteca que funcione em pé de igualdade ou mais rápido que o WIC.

Mas o requisito mais importante é que seja necessária uma solução agora, mas melhor ontem.

Conheça as bibliotecas para trabalhar com bmp, tiff, jpeg


A solução começa com uma etapa óbvia e descomplicada, embora não muito rápida - um estudo completo do github Wikileaks , stackoverflow e outro google em busca de candidatos adequados para o papel da biblioteca desejada. Havia alguns deles:

  • FreeImage . Uma concha sobre as famosas bibliotecas LibJPEG, LibPNG, LibTIFF. O suporte ao DXT1 está presente através do plug-in. A desvantagem é que a qualidade da economia de jpeg na API é definida com muita discrição - 100, 75,50 e 25%. Para alterar esse parâmetro, você precisará entender e editar o código. O projeto é dinâmico e em desenvolvimento - a versão mais recente 3.18.0 foi lançada em 31 de julho de 2018. A montagem no Windows é trivial, todos os componentes são criados automaticamente.
  • Cimg Este é um wrapper de arquivo de cabeçalho C ++ sobre um pacote de artefato antigo ImageMagick . O pacote requer uma instalação de compilação separada, também é possível usá-lo diretamente, ignorando o Cimg. Possui muitas possibilidades para trabalhar com imagens: filtros, transformações, definição de morfologia, etc. Suporta HDR, não suporta DXT1.
  • DevIL ( Biblioteca de imagens do desenvolvedor ). Uma biblioteca C muito simples no estilo OpenGL. Ele contém um shell sobre LibJPEG, LibPNG, LibTIFF, mas também possui extensa funcionalidade interna, além de suportar muitos formatos de imagem, incluindo DXT1. Para montagem, usa o CMake. A maioria das dependências, incluindo LibJPEG, LibPNG, LibTIFF, não estão incluídas no DevIL e devem ser baixadas e compiladas separadamente. A atualização mais recente do DevIL referente ao sistema de compilação é datada de 01/01/2017, e a anterior geralmente ocorreu em 2014, portanto, se houver possíveis problemas com a biblioteca, pode haver problemas com sua solução.
  • OpenImageIO . Está posicionado como uma ferramenta de desenvolvedor de software profissional para trabalhar com imagens. Ele suporta, na forma de plug-ins, o trabalho com muitos formatos de foto exóticos e até vídeo. O Build for Windows requer Boost e Qt 4. pré-compilados. Não existe uma versão montada pronta para teste.
  • Boost GIL (Biblioteca de Imagens Genéricas) Boost e pronto. Embora nem todos. Esta biblioteca também contém um wrapper sobre LibJPEG, LibPNG e LibTIFF.
  • SDL_image 2.0 Usado com a biblioteca SDL e, você vai rir, mas também contém um shell sobre LibJPEG, LibPNG e LibTIFF.

Todas as bibliotecas encontradas foram compiladas no Windows usando o nível máximo de otimização do compilador do Visual Studio e a opção / arch: AVX2.

O mesmo se aplica às bibliotecas LibJPEG, LibPNG e LibTIFF, para acelerar o trabalho retirado do novo pacote da biblioteca OpenCV .

Conheça o Google Benchmark


A próxima etapa da solução também é óbvia - criar uma referência para comparar o desempenho das bibliotecas encontradas e o uso da biblioteca de microbenchmarking do Google Benchmark, amplamente conhecida em círculos estreitos, torna tudo simples e rápido.
O Google Benchmark pode medir com precisão o desempenho dos trechos de código inseridos no corpo do ciclo C ++ 11.

static void BM_foo1(benchmark::State& state) { //     Init_your_code(); for (auto _ : state){ //  -  your_code_to_benchmark(); } 

em funções registradas como referência

 //       BENCHMARK(BM_foo1); 

E execute-os:

 BENCHMARK_MAIN(); 

Em seguida, emita um relatório no formato especificado - saída do console, json, csv.

O relatório conterá dados no sistema de execução (processador, configuração de cache), o tempo total operacional global de cada uma das funções medidas, bem como o tempo que eles levam no processador. Esses tempos geralmente diferem - o primeiro, por exemplo, inclui um atraso de leitura / gravação, e o segundo para os benchmarks multithread é a soma do tempo de operação de todos os núcleos.

O último parâmetro exibido pelo benchmark do Google é o número de iterações executadas para a função, necessárias para a correção precisa estatisticamente do tempo de operação. O sistema seleciona você mesmo, automaticamente, fazendo medições preliminares.

O que é uma "medida precisa" do tempo de execução? Você pode escrever dissertações sobre esse tópico, mas, neste caso, basta dizer que:

  • Por padrão, a medição está em clusters de processadores, ou seja, a ordem teórica de precisão é exatamente isso. A saída padrão é em nanossegundos;
  • os resultados em todos os testes que vi são muito estáveis ​​de lançamento para lançamento;
  • de acordo com meus dados de inteligência, o benchmark do Google é usado e totalmente confiável pelos seus resultados pelos desenvolvedores de software de computador a bordo de uma das maiores preocupações automotivas do mundo. Então vamos acreditar.

A única coisa que vale a pena prestar atenção: o benchmark do Google não fornece "limpeza" do cache entre o início das iterações do benchmark. Se necessário, você deve cuidar disso.

Mas o benchmark do Google pode fazer muitas outras coisas:

  • calcular a complexidade assintótica do algoritmo (O);
  • funcione corretamente com benchmarks multithread, medindo sua duração não nos ticks do processador, mas no modo "tempo real" (relógio de parede);
  • use sua própria função de medição de tempo "manual", que pode ser útil, por exemplo, ao medir o trabalho na GPU;
  • definir automaticamente parâmetros de referência com diferentes conjuntos de argumentos para um determinado corpo da função medida;
  • mostrar o valor médio, mediana e desvio padrão para várias partidas do benchmark;
  • Defina seus próprios contadores e tags que serão refletidos no relatório de benchmark do Google.

O benchmark do Google é baixado do repositório github , montado para a plataforma apropriada usando o Cmake (o assembly do Visual Studio está disponível para Windows), a biblioteca resultante será vinculada ao seu projeto (no caso do Windows, também é necessário um link com a biblioteca shlwapi), o arquivo de cabeçalho do benchmark é adicionado ao seu código .h, após o qual tudo funciona como descrito acima.

Se não funcionar, o único lugar, além do site já indicado , onde você pode obter pelo menos algumas informações e ajuda no benchmark do Google é um fórum especializado sobre produtos .

No nosso caso, tudo funcionou sem problemas. Após a comunicação com os clientes, foram definidos quatro benchmarks, que são carregados e salvos com um nome diferente:

  • Arquivo jpeg de 8 bits com uma resolução de 15k
  • Arquivo jpeg de 24 bits com resolução de 15k
  • Arquivo tiff de 24 bits com resolução de 15k
  • Arquivo bmp de 32 bits com resolução de 32x32

Conheça os resultados


Foi originalmente planejado que todas as bibliotecas encontradas, ou seja, FreeImage, Cimg, DevIL, OpenImageIO, Boost GIL e SDL_image 2.0, participariam da comparação de testes com o Windows Imaging Component (WIC). Mas as três últimas bibliotecas, dependendo de "monstros" como Boost e SDL, foram solicitadas pelos clientes a deixarem em reserva em caso de emergência, se a biblioteca desejada não for encontrada entre as três primeiras. E, felizmente, ela foi encontrada. Embora não imediatamente.

A seguir, um relatório gerado pelo benchmark do Google, que mostra que:

  • O FreeImage completamente com uma pontuação esmagadora perde o WIC em todos os testes, portanto não pode mais ser considerado.
  • O Cimg perde o WIC de maneira limpa em todos os lugares, exceto no carregamento de tiff, onde é um pouco (menos de 5%) mais rápido. Infelizmente, ele também terá que ser excluído. Além disso, isso se aplica ao uso direto do pacote ImageMagick.

Continua sendo a biblioteca DevIL. Ele mostra excelentes resultados em casos de carregamento de bmp e tiff (3 e 2,8 vezes maior que o WIC!), Jpeg preto e branco (1,75x melhor que o WIC), mas diminui um pouco o carregamento de um jpeg de 24 bits normal - ele o faz 3 % mais lento que o WIC.
08/15/18 11:15:44
Running c:\WIC\WIC_test\Release\WIC_test.exe
Run on (8 X 4008 MHz CPU s)
CPU Caches:
L1 Data 32K (x4)
L1 Instruction 32K (x4)
L2 Unified 262K (x4)
L3 Unified 8388K (x1)
BenchmarkTimeCPUIterations
BM_WIC8jpeg72 ms70 ms11
BM_cimg8jpeg562 ms52 ms10
BM_FreeImage8jpeg147 ms144 ms5
BM_devIL8jpeg41 ms41 ms17
BM_WIC24jpeg266 ms260 ms3
BM_cimg24jpeg656 ms128 ms6
BM_FreeImage24jpeg594 ms594 ms1
BM_devIL24jpeg276 ms276 ms3
BM_WIC24tiff844 ms844 ms1
BM_cimg24tiff808 ms131 ms5
BM_FreeImage24tiff953 ms938 ms1
BM_devIL24tiff305 ms305 ms2
BM_WIC323 ms3 ms236
BM_cimg3271 ms7 ms90
BM_FreeImage326 ms5 ms112
BM_devIL321 ms1 ms747
Obviamente, o DevIL também pode ser rejeitado nesta fase, mas aqui outra biblioteca aparece no quadro - Libjpeg-turbo .

Sua saída pode ser facilmente recebida com aplausos - Libjpeg-turbo é uma biblioteca de plataforma cruzada que implementa completamente a funcionalidade libjpeg (API) e adiciona sua própria funcionalidade (por exemplo, trabalhando com buffers de 32 bits). Ao mesmo tempo, para a arquitetura x86, o Libjpeg-turbo usa ativamente instruções vetoriais (SSE2, AVX2) e, de acordo com seus criadores, é 2-6 vezes mais rápido que o libjpeg (!)

Portanto, o próximo passo é criar o DevIL com Libjpeg-turbo em vez de libjpeg. O Libjpeg-turbo, com a ajuda do CMake, cria o Visual Studio sem problemas e, quase imediatamente (com a substituição do único #define, que determina a versão do libjpeg no arquivo de cabeçalho do DevIL), ele começa a trabalhar como parte do DevIL.

Como resultado, o relatório de benchmark do Google se parece com o seguinte:
BenchmarkTimeCPUIterations
BM_WIC8jpeg72 ms68 ms9
BM_cimg8jpeg565 ms39 ms10
BM_FreeImage8jpeg148 ms141 ms5
BM_devIL8jpeg31 ms31 ms24
BM_WIC24jpeg269 ms266 ms2
BM_cimg24jpeg675 ms131 ms5
BM_FreeImage24jpeg604 ms594 ms1
BM_devIL24jpeg149 ms150 ms5
BM_WIC24tiff833 ms828 ms1
BM_cimg24tiff785 ms138 ms5
BM_FreeImage24tiff943 ms938 ms1
BM_devIL24tiff318 ms320 ms2
BM_WIC324 ms3 ms236
BM_cimg3274 ms8 ms56
BM_FreeImage326 ms5 ms100
BM_devIL321 ms1 ms747
Obviamente, as melhorias de desempenho com jpeg nem sequer são o dobro em comparação com o libjpeg, mas deve ser assim - porque a superioridade da velocidade se aplica apenas à codificação / decodificação de jpeg, e o teste inclui a sobrecarga de ler / gravar um arquivo.

Mas pode-se ver que, em média, o DevIL é mais rápido que o WIC no caso de jpeg de 8 bits 2,3 vezes, jpeg de 24 bits 1,8 vezes, tiff de 24 bits - 2,7 vezes, bmp de 32 bits - 3,5 vezes.

O problema está resolvido. Três dias úteis antes do feriado de verão foram completamente gastos na decisão. É claro que, se houvesse um pouco mais, seria possível que houvesse uma biblioteca com resultados ainda mais impressionantes, e se fosse muito mais, então talvez eu escrevesse a biblioteca que estava procurando por mim mesma.

Mas mesmo o que é impressionante. Portanto, se você estiver procurando por uma biblioteca multiplataforma rápida e fácil para trabalhar com arquivos gráficos em todos os sentidos, preste atenção ao DevIL e, se precisar fazer medições comparativas do código com rapidez e precisão, o benchmark do Google está ao seu dispor.

Source: https://habr.com/ru/post/pt425021/


All Articles