c++ - Consejos de predicción de bifurcación portátil
optimization compiler-construction (5)
¿Qué hay de malo en buscar un compilador específico a través de #ifdef
y ocultar estas cosas detrás de una macro personalizada? Puede #define
para expandir a la expresión simple en los casos en que no tenga un compilador que admita estas sugerencias de optimización. Hace poco hice algo similar con las capturas previas explícitas de caché que GCC admite a través de una función intrínseca.
¿Hay alguna forma portátil de hacer sugerencias de predicción de sucursal? Considere el siguiente ejemplo:
if (unlikely_condition) {
/* ..A.. */
} else {
/* ..B.. */
}
¿Es esto algo diferente que hacer?
if (!unlikely_condition) {
/* ..B.. */
} else {
/* ..A.. */
}
¿O es la única forma de usar sugerencias específicas del compilador? (por ejemplo __builtin_pectivo en GCC)
¿Los compiladores tratarán las condiciones if
diferente según el orden de las condiciones?
En la mayoría de los casos, el siguiente código
if (a)
{
...
}
else
{
...
}
es en realidad
evaluate(A)
if (!A)
{
jmp p1
}
... code A
jmp p2
p1:
... code !A
p2:
Tenga en cuenta que si A es verdadero, el "código A" ya está en tramitación. El procesador verá el comando "jmp p2" adelante y cargará el código p2 en la tubería.
Si A es falso, el "código! A" puede no estar en la línea principal, por lo tanto, puede ser más lento.
Conclusiones
- do If (X) si X es más probable que! X
- intente evaluar A tan pronto como sea posible, para que la CPU pueda optimizar dinámicamente la tubería.
:
evaluate(A)
do more stuff
if (A)
...
La forma canónica de hacer predicción de bifurcación estática es que if
se predice no bifurcada (es decir, cada cláusula if
se ejecuta, no else
), y se toman bucles y goto
hacia atrás. Por lo tanto, no exponga el caso común si espera que la predicción estática sea significativa. Moverse por un ciclo no anulado no es tan fácil; Nunca lo intenté pero supongo que ponerlo como una cláusula else
debería funcionar de manera bastante portátil.
Muchos compiladores admiten alguna forma de #pragma unroll
de #pragma unroll
, pero aún será necesario protegerlo con algún tipo de #if
para proteger a otros compiladores.
Las sugerencias de predicción de bifurcación pueden expresar teóricamente una descripción completa de cómo transformar el gráfico de control de flujo de un programa y organizar los bloques básicos en la memoria ejecutable ... por lo que hay una variedad de cosas para expresar, y la mayoría no serán muy portátiles.
Como recomienda GNU en la documentación de __builtin_expect
, la optimización guiada por perfil es superior a las sugerencias y con menos esfuerzo.
La optimización es intrínsecamente un compilador, por lo que debe usar la funcionalidad del compilador para ayudarlo. El lenguaje en sí no se preocupa por las optimizaciones (ni las impone).
Así que lo mejor que puede hacer sin las extensiones específicas del compilador es organizar su código de tal manera que sus compiladores "hagan lo correcto" sin ayuda. Pero si quiere estar seguro, toque las extensiones del compilador. (Puede intentar abstraerlos detrás del preprocesador, para que su código permanezca portátil.)
Solo sé consistente con lo que haces. Me gusta usar
if (!(someExpression))
Pero el compilador debería tratar esto por igual.