No meu design de classe, uso classes abstratas e funções virtuais extensivamente. Tive a sensação de que funções virtuais afetam o desempenho. Isso é verdade? Mas acho que essa diferença de desempenho não é perceptível e parece que estou fazendo otimização prematura. Certo?
c++
performance
optimization
virtual-functions
Navaneeth KN
fonte
fonte
Respostas:
Uma boa regra geral é:
O uso de funções virtuais terá um efeito muito leve no desempenho, mas é improvável que isso afete o desempenho geral do seu aplicativo. Melhores lugares para procurar aprimoramentos de desempenho são em algoritmos e E / S.
Um excelente artigo que fala sobre funções virtuais (e mais) são os Indicadores de Função de Membro e os Delegados de C ++ mais rápidos possíveis .
fonte
Sua pergunta me deixou curiosa, então fui em frente e executei alguns tempos na CPU PowerPC em ordem de 3GHz com a qual trabalhamos. O teste que fiz foi criar uma classe vetorial 4d simples com funções get / set
Depois, configurei três matrizes, cada uma contendo 1024 desses vetores (pequenos o suficiente para caber em L1) e executei um loop que os adicionou um ao outro (Ax = Bx + Cx) 1000 vezes. Corri isso com as funções definidas como
inline
,virtual
e chamadas de função regulares. Aqui estão os resultados:Portanto, neste caso (onde tudo se encaixa no cache), as chamadas de função virtual eram 20x mais lentas que as chamadas embutidas. Mas o que isto significa realmente? Cada viagem pelo loop causava exatamente
3 * 4 * 1024 = 12,288
chamadas de função (1024 vetores vezes quatro componentes e três chamadas por adição); portanto, esses tempos representam1000 * 12,288 = 12,288,000
chamadas de função. O loop virtual demorou 92ms a mais que o loop direto, portanto, a sobrecarga adicional por chamada foi de 7 nanossegundos por função.A partir disso, concluo: sim , funções virtuais são muito mais lentas que funções diretas e não , a menos que você esteja planejando chamá-las dez milhões de vezes por segundo, não importa.
Consulte também: comparação da montagem gerada.
fonte
Quando o Objective-C (onde todos os métodos são virtuais) é a linguagem principal do iPhone e o Java é a principal linguagem do Android, acho que é bastante seguro usar funções virtuais C ++ em nossas torres de núcleo duplo de 3 GHz.
fonte
Em aplicativos muito críticos de desempenho (como videogames), uma chamada de função virtual pode ser muito lenta. Com o hardware moderno, a maior preocupação com o desempenho é a falta de cache. Se os dados não estiverem no cache, poderá levar centenas de ciclos até que estejam disponíveis.
Uma chamada de função normal pode gerar uma falha no cache de instruções quando a CPU busca a primeira instrução da nova função e ela não está no cache.
Uma chamada de função virtual precisa primeiro carregar o ponteiro vtable do objeto. Isso pode resultar em uma falha no cache de dados. Em seguida, ele carrega o ponteiro de função da vtable, o que pode resultar em outra falha no cache de dados. Em seguida, chama a função que pode resultar em uma falta no cache de instruções como uma função não virtual.
Em muitos casos, duas falhas extras no cache não são uma preocupação, mas em um loop restrito no código crítico de desempenho, ele pode reduzir drasticamente o desempenho.
fonte
Na página 44 do manual "Otimizando software em C ++" da Agner Fog :
fonte
switch
. Comcase
valores totalmente arbitrários , com certeza. Mas se todos oscase
s forem consecutivos, um compilador poderá otimizar isso em uma tabela de salto (ah, isso me lembra os bons e velhos dias do Z80), que deve ser (por falta de um termo melhor) tempo constante. Não que eu recomende tentar substituir vfuncs porswitch
, o que é ridículo. ;)absolutamente. Era um problema quando os computadores rodavam a 100Mhz, já que toda chamada de método exigia uma consulta na vtable antes de ser chamada. Mas hoje .. em uma CPU 3Ghz que possui cache de 1º nível com mais memória do que meu primeiro computador tinha? De modo nenhum. Alocar memória da RAM principal custará mais tempo do que se todas as suas funções fossem virtuais.
É como nos velhos tempos em que as pessoas diziam que a programação estruturada era lenta porque todo o código era dividido em funções, cada função exigia alocações de pilha e uma chamada de função!
A única vez em que me incomodo em considerar o impacto no desempenho de uma função virtual é se ela foi muito usada e instanciada em código de modelo que acabou em tudo. Mesmo assim, eu não gastaria muito esforço nisso!
O PS pensa em outras linguagens 'fáceis de usar' - todos os seus métodos são virtuais e escondidos atualmente.
fonte
Há outro critério de desempenho além do tempo de execução. Uma Vtable também ocupa espaço de memória e, em alguns casos, pode ser evitada: ATL usa " ligação dinâmica simulada " em tempo de compilação com modelosobter o efeito do "polimorfismo estático", que é meio difícil de explicar; você basicamente passa a classe derivada como parâmetro para um modelo de classe base; portanto, em tempo de compilação, a classe base "sabe" qual é sua classe derivada em cada instância. Não permitirá que você armazene várias classes derivadas diferentes em uma coleção de tipos de base (isso é polimorfismo em tempo de execução), mas de um sentido estático, se você quiser criar uma classe Y igual a uma classe de modelo X preexistente, que possui o ganchos para esse tipo de substituição, você só precisa substituir os métodos mais importantes e, em seguida, obter os métodos básicos da classe X sem ter que ter uma tabela v.
Em classes com grande presença de memória, o custo de um único ponteiro vtable não é muito alto, mas algumas das classes ATL no COM são muito pequenas, e vale a pena economizar com o vtable se o caso de polimorfismo em tempo de execução nunca ocorrer.
Veja também esta outra questão SO .
A propósito, aqui está uma postagem que descobri que fala sobre os aspectos de desempenho no tempo da CPU.
fonte
Sim, você está certo e, se estiver curioso sobre o custo da chamada de função virtual, poderá achar este post interessante.
fonte
A única maneira possível de ver que uma função virtual se tornará um problema de desempenho é se muitas funções virtuais forem chamadas em um loop restrito e se e somente se causarem uma falha na página ou outra operação de memória "pesada".
Embora, como outras pessoas tenham dito, nunca seja um problema para você na vida real. E se você acha que é, execute um criador de perfil, faça alguns testes e verifique se isso realmente é um problema antes de tentar "cancelar a designação" do seu código para obter um benefício de desempenho.
fonte
Quando o método de classe não é virtual, o compilador geralmente faz alinhamento. Por outro lado, quando você usa o ponteiro para alguma classe com função virtual, o endereço real será conhecido apenas no tempo de execução.
Isso é bem ilustrado pelo teste, diferença de tempo ~ 700% (!):
O impacto da chamada de função virtual depende muito da situação. Se houver poucas chamadas e uma quantidade significativa de trabalho dentro da função - isso pode ser insignificante.
Ou, quando é uma chamada virtual usada repetidamente várias vezes, enquanto faz alguma operação simples - pode ser realmente grande.
fonte
++ia
. E daí?Eu andei de um lado para o outro pelo menos 20 vezes em meu projeto em particular. Embora não pode haver algumas grandes ganhos em termos de reutilização de código, clareza, facilidade de manutenção e legibilidade, por outro lado, sucessos de desempenho ainda fazer existir com funções virtuais.
O impacto no desempenho será notado em um laptop / desktop / tablet moderno ... provavelmente não! No entanto, em certos casos com sistemas embarcados, o impacto no desempenho pode ser o fator determinante na ineficiência do seu código, especialmente se a função virtual for chamada repetidamente em um loop.
Aqui está um artigo datado que analisa as práticas recomendadas para C / C ++ no contexto de sistemas embarcados: http://www.open-std.org/jtc1/sc22/wg21/docs/ESC_Boston_01_304_paper.pdf
Para concluir: cabe ao programador entender os prós / contras do uso de uma determinada construção em detrimento de outra. A menos que você seja super orientado para o desempenho, provavelmente não se importa com o impacto no desempenho e deve usar todo o material OO em C ++ para ajudar a tornar seu código o mais utilizável possível.
fonte
Na minha experiência, o principal aspecto relevante é a capacidade de alinhar uma função. Se você tiver necessidades de desempenho / otimização que determinam uma função, você não poderá tornar a função virtual porque isso impediria. Caso contrário, você provavelmente não notará a diferença.
fonte
Uma coisa a notar é que isto:
pode ser mais rápido que isso:
Isso ocorre porque o primeiro método está chamando apenas uma função enquanto o segundo pode estar chamando muitas funções diferentes. Isso se aplica a qualquer função virtual em qualquer idioma.
Eu digo "may" porque isso depende do compilador, do cache etc.
fonte
A penalidade de desempenho do uso de funções virtuais nunca pode superar as vantagens que você obtém no nível do design. Supostamente, uma chamada para uma função virtual seria 25% menos eficiente que uma chamada direta para uma função estática. Isso ocorre porque há um nível de indireção no VMT. No entanto, o tempo gasto para fazer a chamada é normalmente muito pequeno comparado ao tempo gasto na execução real de sua função, de modo que o custo total de desempenho será mínimo, especialmente com o desempenho atual do hardware. Além disso, o compilador às vezes pode otimizar e ver que nenhuma chamada virtual é necessária e compilá-la em uma chamada estática. Portanto, não se preocupe, use funções virtuais e classes abstratas quantas forem necessárias.
fonte
The performance penalty of using virtual functions can sometimes be so insignificant that it is completely outweighed by the advantages you get at the design level.
a principal diferença está dizendosometimes
, nãonever
.Eu sempre me questionei isso, especialmente porque - há alguns anos atrás - eu também fiz esse teste comparando os tempos de uma chamada de método de membro padrão com uma virtual e fiquei realmente irritado com os resultados naquele momento, tendo chamadas virtuais vazias sendo 8 vezes mais lento que os não virtuais.
Hoje eu tive que decidir se deveria ou não usar uma função virtual para alocar mais memória na minha classe de buffer, em um aplicativo muito crítico para o desempenho, então pesquisei (e encontrei você) e, no final, fiz o teste novamente.
E fiquei realmente surpreso que isso - de fato - realmente não importa mais. Embora faça sentido ter inline mais rapidamente do que os não virtuais, e eles sendo mais rápidos que os virtuais, geralmente chega à carga do computador em geral, se seu cache tem os dados necessários ou não, e embora você possa otimizar no nível do cache, eu acho, que isso deve ser feito pelos desenvolvedores do compilador mais do que pelos desenvolvedores de aplicativos.
fonte