As frequentemente conhecidas como likely
e unlikely
macros ajudam o compilador a saber se uma entrada if
geralmente será inserida ou ignorada. Usá-lo resulta em algumas melhorias (um pouco menores) no desempenho.
Comecei a usá-los recentemente e não sei com que frequência essas dicas devem ser usadas. Atualmente, eu o uso com a verificação de erros if
s, que geralmente são marcados como unlikely
. Por exemplo:
mem = malloc(size);
if (unlikely(mem == NULL))
goto exit_no_mem;
Parece bom, mas as checagens de erros if
ocorrem com bastante frequência e, conseqüentemente, o uso das macros mencionadas.
Minha pergunta é: é demais ter likely
e unlikely
macros em todas as verificações de erros if
?
Enquanto estamos nisso, que outros lugares são usados com frequência?
No meu uso atual, está em uma biblioteca que faz uma abstração do subsistema em tempo real, para que os programas se tornem portáteis entre RTAI, QNX e outros. Dito isto, a maioria das funções é pequena e chama diretamente uma ou duas outras funções. Muitas são até static inline
funções.
Portanto, antes de tudo, não é um aplicativo que eu possa criar um perfil. Não faz sentido "identificar gargalos", pois é uma biblioteca, não um aplicativo independente.
Segundo, é mais ou menos como "eu sei que isso é improvável, é melhor dizer ao compilador". Eu não tento ativamente otimizar o if
.
fonte
likely
eunlikely
existe e o que eles fazem. Não encontrei nada que realmente sugerisse quando e onde é melhor usá-los.Respostas:
Você precisa tanto de desempenho que esteja disposto a poluir seu código com isso? É uma otimização menor.
A menos que você possa responder
yes
a todas as perguntas acima, não se preocupe com coisas assim.Editar: em resposta à edição. Mesmo quando não é possível criar um perfil, geralmente é possível estimar pontos de acesso. Uma função de alocação de memória chamada por todos é uma boa candidata, especialmente porque requer apenas um único uso da macro para funcionar em toda a biblioteca.
fonte
(un)likely
macro raramente é usada e apenas em código extremamente crítico de desempenho? É "má prática" usá-lo com frequência ou apenas "desnecessário"?if (likely(x==2 || x==3)) doOneThing(); else switch(x) { ... }
, poderia julgar que o uso de umif
para os valores 2 e 3 não era meramente uma conseqüência do programador não saber que C pode associar doiscase
rótulos a um único manipulador.Se você estiver escrevendo para x86 / x64 (e não estiver usando CPUs de 20 anos), o ganho de desempenho ao usar __builtin_expect () será desprezível, se houver. A razão disso é que as modernas CPUs x86 / x64 (embora não tenham 100% de certeza sobre o Atom), têm previsão dinâmica de ramificação, portanto, essencialmente, a CPU "aprende" sobre a ramificação que é usada com mais frequência. Claro, essas informações podem ser armazenadas apenas para um número limitado de ramificações; no entanto, existem apenas dois casos possíveis. Se (a) for uma ramificação "freqüentemente usada", seu programa se beneficiará dessa previsão dinâmica de ramificação e se (b) for ramificação "rara", você não verá realmente nenhum desempenho realista devido a erros de previsão em ramificações tão raras (20 ciclos de CPU de erro de previsão de ramificação não são MUITO ruins se ocorrer uma vez na lua azul).
NB: isso NÃO implica que, em x86 / x64 moderna, a importância de erros de ramificação tenha diminuído: qualquer ramificação com 50-50 de chance de salto no salto ainda sofrerá uma penalidade (IIRC 10-20 ciclos de CPU), portanto, nos loops internos, ramificações podem ainda precisa ser evitado. É apenas a importância de __builtin_expect () no x86 / x64 que diminuiu (IIRC, cerca de 10 a 15 anos atrás) - principalmente por causa da previsão dinâmica de ramificação.
NB2: para outras plataformas além de x86 / x64, YMMV.
fonte
unlikely
anotação-