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?
fonte
Respostas:
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:
Os cientistas estão gradualmente prestando mais atenção a alguns outros requisitos comuns da engenharia de software:
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.
fonte
É 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.
fonte
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.
fonte
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.
fonte
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.
fonte