2011-09-18 6 views
13

Digamos que tengo algunas funciones, cada una de aproximadamente dos líneas simples de código, y se llaman así: A llamadas B llamadas C llamadas D ... llamadas K. (Así que, básicamente, se trata de una larga serie de llamadas a funciones breves). ¿Qué profundidad tendrán los compiladores en el árbol de llamadas para alinear estas funciones?¿Cuán profundo funcionan los compiladores en línea?

+0

¡Simplemente puede probar y mirar el conjunto! Sus documentos de compilación deberían indicarle cómo especificar la profundidad de entrada; Creo que es algo así como 50 para GCC por defecto. –

+2

Creo que esto debe ser específico del compilador y no publica información de su compilador. –

+1

Bajo MSVC usted tiene control parcial sobre esto usando '#pragma inline_depth' (http://msdn.microsoft.com/en-us/library/cx053bca.aspx) aunque he tenido problemas con él en ciertas situaciones (como recursivo enlining, que debe ser posible, pero nunca funcionó, terminó haciéndolo manualmente) – Necrolis

Respuesta

12

La pregunta no es significativa.

Si se piensa en procesos en línea, y sus consecuencias, se dará cuenta que:

  • Evita una llamada de función (con todo el ajuste de registro ahorro/cuadro)
  • Expone más contexto para el optimizador (tiendas muertos, código muerto, común elimintation sub-expresión ...)
  • código Duplicados (hinchazón de la caché de instrucciones y el tamaño del ejecutable, entre otras cosas)

al decidir ya sea en línea o no, el compilador realiza así un acto de equilibrio entre la hinchazón potencial creada y la ganancia de velocidad esperada. Este acto de equilibrio se ve afectado por las opciones: para gcc -O3 significa optimizar la velocidad, mientras que -Oz significa optimizar para el tamaño, ¡en la alineación tienen comportamientos casi opuestos!

Por lo tanto, lo que importa no es el "nivel de anidación" sino el número de instrucción (posiblemente ponderado, ya que no todos son iguales).

Esto significa que un simple función de reenvío:

int foo(int a, int b) { return foo(a, b, 3); } 

es esencialmente "transparente" desde el punto de vista inlining.

Por otro lado, una función que cuenta un centenar de líneas de código es poco probable que se inline. Excepto que las funciones gratuitas static llamadas solo una vez son casi sistemáticamente en línea, ya que no crean ninguna duplicación en este caso.

De estos dos ejemplos podemos conseguir un presentimiento de cómo se comportan los heurísticos:

  • los menos instrucciones de la función tienen, mejor para inling
  • menos a menudo se le llama, el mejor para inlining

Después de eso, son parámetros que debe ser capaz de establecer para influir de una manera u otra (MSVC como __force_inline que apunta con fuerza en inling, gcc ya que -finline-limit bandera para "elevar" la tresh edad en el cómputo de instrucciones, etc ...)


por la tangente: sabe usted de procesos en línea parcial?

Se introdujo en gcc en 4.6. La idea, como su nombre lo sugiere, es alinear parcialmente una función. Principalmente, para evitar la sobrecarga de una llamada de función cuando la función está "guardada" y puede (en algunos casos) regresar casi de inmediato.

Por ejemplo:

void foo(Bar* x) { 
    if (not x) { return; } // null pointer, pfff! 

    // ... BIG BLOC OF STATEMENTS ... 
} 

void bar(Bar* x) { 
    // DO 1 
    foo(x); 
    // DO 2 
} 

podría conseguir "optimizado" como:

void [email protected](Bar* x) { 
    // ... BIG BLOC OF STATEMENTS ... 
} 

void bar(Bar* x) { 
    // DO 1 
    if (x) { [email protected](x); } 
    // DO 2 
} 

Por supuesto, una vez más, la heurística para procesos en línea se aplican, pero se aplican más discriminada!


Y, por último, a menos que utilice WPO (optimización del programa entero) o LTO (Enlace Optimización del tiempo), las funciones sólo pueden ser inline si su definición se encuentra en la misma TU (Unidad de Traducción) que el sitio de llamada.

+0

Normalmente no hago esto, pero creo que debería cambiar la respuesta aceptada. :) No sabía acerca de la inclusión parcial y tampoco sobre la alineación en función del número de llamadas. Gracias por los detalles. –

7

He visto compiladores en línea con más de 5 funciones de profundidad. Pero en algún momento, básicamente se convierte en una compensación de eficiencia de espacio que hace el compilador. Cada compilador es diferente en este aspecto. Visual Studio es muy conservador con Inline. GCC (en virtud de -O3) y el compilador de Intel les encanta en línea ...

+0

IIRC en gcc depende de algún "recuento de instrucciones" aproximado para la función que está en línea (es decir, cuánto tiempo realmente es); el nivel de anidamiento no juega un rol por lo que leo en los documentos ('-finline-limit' y amigos), en el sentido de que la función de longitud 10 se alineará igual que 5 + anidada 5. – eudoxos

+1

Si se llaman las funciones solo una vez no hay razón para evitar la línea. GCC también se alineará agresivamente si los comentarios del perfil dicen que debería. –

+3

@ Zan Lynx: Eso es principalmente correcto. Hay algunos casos en los que es mejor no en línea. Si la función está en un bucle de rendimiento crítico y rara vez se llama (como un controlador de trampa), entonces es mejor no alinearlo para mantener el tamaño del código del bucle pequeño. (Esto a veces le permitirá usar saltos cortos en lugar de saltos largos) – Mysticial

Cuestiones relacionadas