Pergunta

Considerando que você está tentando apenas otimizar a velocidade, quais são as boas heurísticas para decidir se deve ou não incorporar uma função?Obviamente, o tamanho do código deve ser importante, mas existem outros fatores normalmente usados ​​quando (digamos) o gcc ou o icc determinam se uma chamada de função deve ser incorporada?Houve algum trabalho acadêmico significativo na área?

Foi útil?

Solução

A Wikipédia tem a alguns parágrafos sobre isso, com alguns links na parte inferior:

  • Além de problemas de tamanho de memória e cache, outra consideração é a pressão de registro.Do ponto de vista do compilador, "as variáveis ​​adicionadas do procedimento embutido podem consumir registros adicionais e, em uma área onde a pressão do registro já é alta, isso pode forçar o derramamento, o que causa acessos adicionais à RAM".

Linguagens com compiladores JIT e carregamento de classe de tempo de execução têm outras vantagens, uma vez que os métodos virtuais não são conhecidos estaticamente, mas o JIT pode coletar informações de perfil de tempo de execução, como frequência de chamada de método:

  • Projeto, implementação e avaliação de otimizações em um compilador Just-in-Time (para Java) fala sobre inlining de métodos estáticos e classes carregadas dinamicamente e suas melhorias no desempenho.

  • Praticando JUDÔ:Java sob otimizações dinâmicas afirma que sua "política de inlining é baseada no tamanho do código e nas informações de perfil.Se a frequência de execução de uma entrada de método estiver abaixo de um determinado limite, o método não será incorporado porque é considerado um método frio.Para evitar explosão de código, não inline um método com um tamanho de bytecode superior a 25 bytes....Para evitar o inlining ao longo de uma cadeia de chamadas profunda, o inlining para quando o tamanho do bytecode embutido acumulado ao longo da cadeia de chamadas excede 40 bytes." Embora tenham informações de perfil de tempo de execução (frequência de chamada de método), eles ainda têm cuidado para evitar inlining de grandes funções ou cadeias de funções para evitar o inchaço.

Uma pesquisa no Google Acadêmico revela uma série de artigos, como

Uma pesquisa no Google Livros revela um grande número de livros com artigos ou capítulos sobre inlining de funções em vários contextos.

  • O Manual de Design do Compilador:Otimizações e geração de código de máquina possui um capítulo sobre Técnicas Estatísticas e de Aprendizado de Máquina em Design de Compiladores, com heurísticas para definir diversos parâmetros, traçando o perfil dos resultados.Este capítulo faz referência ao artigo de Vaswani et al Modelos empíricos sensíveis à microarquitetura para otimizações de compiladores onde propõem "o uso da modelagem empírica técnicas para construir modelos sensíveis à microarquitectura para optimizações de compiladores".

  • (Alguns outros livros falam sobre inling do ponto de vista do programador, como C++ para programadores de jogos, que fala sobre os perigos de funções inlining com muita frequência e as diferenças entre inlining e macros.Os compiladores geralmente ignoram as solicitações in-line do programador se puderem determinar que elas causariam mais danos do que benefícios;isso pode ser substituído por macros como último recurso.)

Outras dicas

Uma chamada de função implica algum código adicional (o prólogo da função, onde o novo quadro de pilha é configurado, e o epílogo da função, onde ele é limpo).Se o seu compilador perceber que o código da função é pequeno em comparação com o prólogo e o epílogo, ele poderá decidir que não vale a pena fazer uma chamada real e incorporará a função.

O único benefício que vejo em chamar uma função em vez de inlinhá-la está relacionado ao tamanho.Acho que incorporar uma função e depois desenrolar um loop pode resultar em um aumento significativo de tamanho.

até onde eu vi, o tamanho da função é o único fator que os compiladores usam para determinar o in-line.No entanto, se você fizer otimização guiada por perfil (PGO), acredito que o compilador seja capaz de usar outras variáveis, como número de chamadas/tempo de configuração de chamadas.

No .NET é baseado principalmente no tamanho.Meça o tamanho da função pai e da função filho em bytes compilados.Em seguida, meça o tamanho da função combinada.Se a função combinada for menor, então inlining é uma boa ideia.

A razão para isso é tornar possível colocar o máximo de código possível no cache da CPU.As falhas de cache são muito mais caras do que as chamadas de função em CPUs modernas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top