2008-09-30 13 views
26

Visual Studio incluye soporte para __forceinline. Microsoft Visual Studio 2005 estados de documentación:¿Cuándo debería usar __forceinline en lugar de inline?

La palabra clave __forceinline anula el análisis coste/beneficio y se basa en el criterio del programador lugar.

Esto plantea la pregunta: ¿Cuándo es incorrecto el análisis de costo/beneficio del compilador? Y, ¿cómo se supone que debo saber que está mal?

¿En qué situación se supone que sé mejor que mi compilador sobre este tema?

Respuesta

14

El compilador toma sus decisiones en base al análisis de código estático, mientras que si lo hace como dice don, está llevando a cabo un análisis dinámico que puede llegar mucho más lejos. El número de llamadas a una pieza específica de código a menudo está determinado en gran medida por el contexto en el que se utiliza, p. los datos. Perfilar un conjunto típico de casos de uso hará esto. Personalmente, reúno esta información al permitir la creación de perfiles en mis pruebas automáticas de regresión. Además de forzar en línea, he desenrollado bucles y llevado a cabo otras optimizaciones manuales sobre la base de dichos datos, con buenos resultados. También es imprescindible volver a perfilar después, ya que a veces sus mejores esfuerzos pueden llevar a una disminución del rendimiento. De nuevo, la automatización hace que esto sea mucho menos doloroso.

Sin embargo, la mayoría de las veces, en mi experiencia, ajustar alogoritmos da mejores resultados que la optimización de código directo.

5

La única manera de estar seguro es medir el rendimiento con y sin. A menos que esté escribiendo código crítico de alto rendimiento, esto generalmente será innecesario.

35

Conoces mejor que el compilador solo cuando tus datos de perfil te lo dicen.

+1

En caso de ser la respuesta arriba;) – aaronsnoswell

1

Existen varias situaciones en las que el compilador no puede determinar categóricamente si es apropiado o beneficioso para alinear una función. Inlinear puede implicar compensaciones que el compilador no está dispuesto a hacer, pero usted está (por ejemplo, bloat de código).

En general, los compiladores modernos en realidad son bastante buenos para tomar esta decisión.

8

he desarrollado software para dispositivos con recursos limitados durante 9 años o así y la única vez que he visto nunca la necesidad de utilizar __forceinline fue en un bucle estrecho donde un controlador de la cámara necesaria para copiar los datos de píxeles de una captura el búfer a la pantalla del dispositivo. Allí pudimos ver claramente que el costo de una llamada de función específica acaparó realmente el rendimiento del dibujo de superposición.

29

El único lugar donde lo estoy usando es la verificación de licencia.

Un factor importante para proteger contra craqueo fácil * es verificar que tiene licencia en varios lugares en lugar de solo uno, y no desea que estos lugares sean la misma llamada a la función.


*) No convierta esto en una discusión de que todo se puede descifrar, lo sé. Además, esto solo no ayuda mucho.

+2

1, el pensamiento inteligente y una idea que voy a tomar prestado. –

+0

Estoy planeando usar __foceinline por el mismo motivo. ¿Puedes estar al 100% de que estará en línea cuando usas __forceinline? Estoy en duda ya que msdn también dice: "No se puede obligar al compilador a alinear una función en particular, incluso con la palabra clave __forceinline". – mentat

+0

@Koray: debe verificar el código generado. En mi experiencia, sí, ti funciona incluso para funciones gigantescas. Una excepción (IIRC) son las funciones con argumentos variables, y es probable que la documentación se refiera a eso. – peterchen

3

La directiva en línea será totalmente inútil cuando se utiliza para funciones que son:

recursiva, larga, compuesta de bucles,

Si desea forzar esta decisión utilizando __forceinline

1

Cuando sabe que la función va a ser llamada en un lugar varias veces para un cálculo complicado, entonces es una buena idea usar __forceinline. Por ejemplo, una multiplicación de matriz para la animación puede necesitar ser llamada tantas veces que las llamadas a la función comenzará a ser notado por su generador de perfiles. Como dijeron los otros, el compilador no puede saberlo realmente, especialmente en una situación dinámica donde la ejecución del código es desconocida en tiempo de compilación.

3

En realidad, incluso con la palabra clave __forceinline. Visual C++ a veces elige no alinear el código. (Fuente: código fuente del ensamblaje resultante)

Siempre mire el código de ensamblaje resultante donde la velocidad es importante (como la necesidad de ejecutar ciclos internos ajustados en cada marco).

Algunas veces usar #define en lugar de en línea hará el truco. (por supuesto, pierdes un montón de control al usar #define, así que úsala solo cuando y donde realmente importa).

+2

En realidad, no hay necesidad de verificar el ensamblador (no es que duela demasiado). VS tiene una [advertencia para eso - C4714] (http://msdn.microsoft.com/en-us/library/a98sb923%28v=vs.110%29.aspx). –

0

En realidad, el impulso está cargado con él.

Por ejemplo

BOOST_CONTAINER_FORCEINLINE flat_tree& operator=(BOOST_RV_REF(flat_tree) x) 
    BOOST_NOEXCEPT_IF((allocator_traits_type::propagate_on_container_move_assignment::value || 
         allocator_traits_type::is_always_equal::value) && 
         boost::container::container_detail::is_nothrow_move_assignable<Compare>::value) 
{ m_data = boost::move(x.m_data); return *this; } 

BOOST_CONTAINER_FORCEINLINE const value_compare &priv_value_comp() const 
{ return static_cast<const value_compare &>(this->m_data); } 

BOOST_CONTAINER_FORCEINLINE value_compare &priv_value_comp() 
{ return static_cast<value_compare &>(this->m_data); } 

BOOST_CONTAINER_FORCEINLINE const key_compare &priv_key_comp() const 
{ return this->priv_value_comp().get_comp(); } 

BOOST_CONTAINER_FORCEINLINE key_compare &priv_key_comp() 
{ return this->priv_value_comp().get_comp(); } 

public: 
// accessors: 
BOOST_CONTAINER_FORCEINLINE Compare key_comp() const 
{ return this->m_data.get_comp(); } 

BOOST_CONTAINER_FORCEINLINE value_compare value_comp() const 
{ return this->m_data; } 

BOOST_CONTAINER_FORCEINLINE allocator_type get_allocator() const 
{ return this->m_data.m_vect.get_allocator(); } 

BOOST_CONTAINER_FORCEINLINE const stored_allocator_type &get_stored_allocator() const 
{ return this->m_data.m_vect.get_stored_allocator(); } 

BOOST_CONTAINER_FORCEINLINE stored_allocator_type &get_stored_allocator() 
{ return this->m_data.m_vect.get_stored_allocator(); } 

BOOST_CONTAINER_FORCEINLINE iterator begin() 
{ return this->m_data.m_vect.begin(); } 

BOOST_CONTAINER_FORCEINLINE const_iterator begin() const 
{ return this->cbegin(); } 

BOOST_CONTAINER_FORCEINLINE const_iterator cbegin() const 
{ return this->m_data.m_vect.begin(); } 
Cuestiones relacionadas