Pena de desempenho de 20% para um bom design de software

17

Estou escrevendo uma pequena biblioteca para cálculos matriciais esparsos como uma maneira de me ensinar a fazer o melhor uso da programação orientada a objetos. Eu trabalhei muito duro para ter um bom modelo de objeto, onde as partes (matrizes esparsas e os gráficos que descrevem sua estrutura de conectividade) são muito fracamente acopladas. Na minha opinião, o código é muito mais extensível e sustentável para ele.

No entanto, também é um pouco mais lento do que se eu tivesse usado uma abordagem contundente. Para testar as vantagens de ter esse modelo de objeto, escrevi um novo tipo de matriz esparsa que quebrou o encapsulamento do gráfico subjacente para ver quanto mais rápido isso seria executado.

A princípio, parecia bastante sombrio; o código do qual eu me orgulhava era 60% mais lento que uma versão sem design de software elegante. Mas pude fazer algumas otimizações de baixo nível - incorporando uma função e alterando um pouco um loop - sem alterar a API. Com essas mudanças, agora é apenas 20% mais lento que a concorrência.

O que me leva à minha pergunta: quanto de perda de desempenho devo aceitar se significa que tenho um bom modelo de objeto?

Daniel Shapero
fonte
Qual operação de matriz esparsa você estava medindo?
Bill Barth
Vetor de matriz multiplicado. As matrizes variou em tamanho a partir de . Fiz o gráfico Laplaciano para gráficos aleatórios Erdos-Renyi com grau médio d = log 2 n . Além disso, o número de 20% piora em algumas máquinas, então agora estou mais inclinado a jogar tudo fora. Suspiro profundon=1024,...,16384d=registro2n
Daniel Shapero
3
Qual linguagem de programação você está usando? Normalmente, algo como o C ++ permite que você se divirta com designs elegantes (ish) a um custo baixo (ou inexistente). Em outras linguagens sem metaprogramação (Java, Fortran, etc), um custo de 20% parece razoável.
LKlevin
Você pode nos mostrar seu código? Qual idioma você usou? Quais sinalizadores de compilador e compilação? Você encontrou exatamente de onde vem o desempenho? Como você se certificou de encontrar o motivo certo? Qual perfilador você usou e como você o usou? Você tem certeza de que o modelo de objeto legal não é implementado de maneira ineficiente? 20% é pequeno o suficiente para que você precise coletar muitos dados e fazer uma análise detalhada antes de dizer que é definitivamente devido ao design, em vez de, digamos, implementação inferior ou outros problemas de codificação.
Kirill
Nota curta: todo mundo parece elogiar publicamente o bom design sobre o desempenho puro (com razões muito válidas, é claro). Mas então, por que tanto código do mundo real é realmente, realmente impossível de manter? Todos os slobs de código estão se sentindo culpados e, portanto, publicamente silenciosos?
AlexEd

Respostas:

9

Muito poucos desenvolvedores científicos de software entendem bons princípios de design, então peço desculpas se essa resposta for um pouco demorada. Do ponto de vista da engenharia de software, o objetivo do desenvolvedor de software científico é projetar uma solução que satisfaça um conjunto de restrições que geralmente são conflitantes .

Aqui estão alguns exemplos típicos dessas restrições, que podem ser aplicados ao design da sua biblioteca de matrizes esparsas:

  • Concluído em um mês
  • Funciona corretamente no seu laptop e em várias estações de trabalho
  • Executa com eficiência

Os cientistas estão gradualmente prestando mais atenção a alguns outros requisitos comuns da engenharia de software:

  • Documentação (Guia do usuário, tutorial, comentário de código)
  • Manutenção (controle de versão, teste, projeto modular)
  • Reutilização (design modular, "flexibilidade")

Você pode precisar de mais ou menos de um desses requisitos. Se você está tentando ganhar um prêmio de Gordon Bell por desempenho, mesmo frações de um por cento são relevantes, e poucos juízes avaliarão a qualidade do seu código (desde que você possa convencê-lo de que é certo). Se você estiver tentando justificar a execução desse código em um recurso compartilhado, como um cluster ou um supercomputador, frequentemente precisará defender reivindicações sobre o desempenho do seu código, mas essas raramente são muito rigorosas. Se você está tentando publicar um artigo em um diário descrevendo os ganhos de desempenho de sua abordagem, precisa legitimamente ser mais rápido que seus concorrentes, e 20% do desempenho é uma troca que eu faria com prazer para melhor manutenção e reutilização.

Voltando à sua pergunta, o "bom design", com tempo de desenvolvimento suficiente, nunca deve sacrificar o desempenho. Se o objetivo é criar código que seja executado o mais rápido possível, o código deve ser projetado com base nessas restrições. Você pode usar técnicas como geração de código, montagem embutida ou aproveitar as bibliotecas altamente ajustadas para ajudá-lo a resolver seu problema.

Mas e se você não tiver tempo de desenvolvimento suficiente? O que é bom o suficiente? Bem, depende, e ninguém será capaz de lhe dar uma boa resposta a esta pergunta sem mais contexto.

FWIW: Se você realmente está interessado em escrever kernels de matriz esparsa de alto desempenho, deve comparar com uma instalação PETSc otimizada e trabalhar com a equipe deles, se estiver derrotando-os, eles ficarão felizes em incorporar kernels ajustados à biblioteca.

Aron Ahmadia
fonte
Estou curioso sobre geradores de código - acho que eles podem ser úteis para mim, mas estou preocupado que eles sejam difíceis de manter. Sei que os programadores Java os usam muito, mas geralmente são personalizados para gerar código para aplicativos específicos. Você conhece algum código científico que os utilize?
Daniel Shapero
ATLAS, FFTW, Espiral, OSKI, Ignição, stencil_codegen, para citar vários. Não é publicamente anunciado, mas não ficaria surpreso se vários dos kernels importantes no MKL e ESSL forem gerados dessa maneira. Escrever código de geração sustentável de kernel seria uma questão interessante de acompanhamento. Tenho experiência nisso, mas não me consideraria uma autoridade.
Aron Ahmadia
12

É uma pergunta sobre o que você gasta seu tempo. Para a maioria de nós, gastamos 3/4 do tempo programando e 1/4 do tempo aguardando resultados. (Seus números podem variar, mas acho que o número não é completamente sem méritos.) Portanto, se você tiver um design que permita programar duas vezes mais rápido (3/4 de uma unidade de tempo em vez de 1,5 unidades de tempo), então você o desempenho pode atingir 300% do desempenho (de 1/4 a 1 unidade de tempo) e você ainda fica à frente em termos de tempo real gasto na solução do problema.

Por outro lado, se você estiver fazendo cálculos pesados, seus cálculos podem parecer diferentes e você pode gastar mais tempo otimizando seu código.

Para mim, 20% parece uma troca bastante boa se você acabar sendo mais produtivo.

Wolfgang Bangerth
fonte
Boa resposta, também acrescentaria a importância em que o desempenho é importante. Um determinado código científico não está fazendo apenas a multiplicação de matrizes; se 20% do seu tempo de execução estiver na multiplicação de matrizes, um desempenho de 20% atingirá apenas uma diferença de 4% no geral, e eu aceitaria isso em troca de uma biblioteca mais fácil de usar.
Aurelius
11
E uma biblioteca melhor escrita significa menos erros, para que você gaste menos tempo esperando resultados incorretos.
Davidmh
4

IMHO uma penalidade de até 50% (por qualquer motivo) não é tão ruim.

Na verdade, eu vi uma diferença de 0 a 30% no desempenho apenas com base no tipo de compilador. Isso se aplica à escassa rotina MatMult do PETSc em matrizes decorrentes de discretizações de FE de baixa ordem.

stali
fonte
1

O design do software não melhora automaticamente com o tempo. O desempenho será. Você receberá os 20% de volta com sua próxima CPU. Além disso, um bom design de software tornará mais fácil estender ou melhorar a biblioteca no futuro.

MirekE
fonte
Eu não acho que isso responda à pergunta.
nicoguaro
0

Um princípio geral é buscar um bom design primeiro e depois otimizar o desempenho apenas se necessário . Casos de uso em que um ganho de desempenho de 20% é realmente necessário provavelmente serão bastante raros, se surgirem.

jolvi
fonte