Dada a previsão de ramificação e também o efeito das otimizações do compilador, qual código tende a oferecer desempenho superior?
Observe que bRareExceptionPresent representa uma condição incomum. Não é o caminho normal da lógica.
/* MOST COMMON path must branch around IF clause */
bool SomeFunction(bool bRareExceptionPresent)
{
// abort before function
if(bRareExceptionPresent)
{
return false;
}
.. function primary body ..
return true;
}
/* MOST COMMON path does NOT branch */
bool SomeFunction(bool bRareExceptionPresent)
{
if(!bRareExceptionPresent)
{
.. function primary body ..
}
else
{
return false;
}
return true;
}
optimization
theory
dyasta
fonte
fonte
Respostas:
No mundo de hoje, não importa muito, se é que realmente.
A previsão dinâmica de ramificação (algo pensado por décadas (consulte Uma Análise dos Esquemas Dinâmicos de Predição de Ramificação em Cargas de Trabalho do Sistema publicadas em 1996)) é um lugar bastante comum.
Um exemplo disso pode ser encontrado no processador ARM. Do Centro de Informações do Braço na Previsão de Filiais
A questão então é "o que é predição dinâmica de ramificação no processador de braço?" A leitura contínua da previsão de ramificação dinâmica mostra que ele usa um esquema de previsão de 2 bits (descrito no artigo) cria informações sobre se a ramificação é forte ou fracamente captada ou não.
Com o tempo (e com o tempo, quero dizer algumas passagens por esse bloco), isso cria informações sobre como o código irá seguir.
Para previsão estática , ele analisa a aparência do código e de que maneira a ramificação é feita no teste - para uma instrução anterior ou outra no código:
Como mencionado por Sparky, isso se baseia no entendimento de que o loop é repetido com mais freqüência do que não. O loop se ramifica para trás (ele possui uma ramificação no final do loop para reiniciá-lo na parte superior) - normalmente faz isso.
O perigo de tentar adivinhar o compilador é que você não sabe como esse código será realmente compilado (e otimizado). E na maioria das vezes, isso não importa. Com a previsão dinâmica, duas vezes por meio da função, ele prevê uma pular a declaração de guarda para um retorno prematuro. Se o desempenho de dois pipelines liberados for de desempenho crítico, há outras coisas com que se preocupar.
O tempo que leva para ler um estilo sobre o outro é provavelmente de maior importância - tornando o código limpo para que um humano possa lê-lo, porque o compilador vai se sair bem, não importa o quão confuso ou idealizado você escreva o código.
fonte
Meu entendimento é que, na primeira vez em que a CPU encontrar uma ramificação, ela preverá (se houver suporte) que ramificações para frente não são obtidas e ramificações para trás. A justificativa para isso é que os loops (que geralmente se ramificam para trás) são assumidos.
Em alguns processadores, você pode dar uma dica nas instruções de montagem sobre qual caminho é o mais provável. Detalhes disso me escapam no momento.
Além disso, alguns compiladores C também oferecem suporte à previsão de ramificação estática, para que você possa dizer ao compilador qual ramificação é mais provável. Por sua vez, pode reorganizar o código gerado ou usar instruções modificadas para tirar proveito dessas informações (ou até mesmo ignorá-las).
Espero que isto ajude.
fonte
__builtin_expect
?