Pergunta

Visual Studio inclui suporte para __forceinline. Os Microsoft Visual Studio 2005 estados de documentação:

O __forceinline chave substituições o custo / benefício e confia no julgamento do programador em seu lugar.

Isso levanta a questão: Quando é a análise errada de custo / benefício do compilador? E, como é que eu vou saber que é errado?

Em que cenário é assumido que eu sei melhor do que o meu compilador sobre esta questão?

Foi útil?

Solução

O compilador está fazendo as suas decisões com base em análise de código estático, enquanto que se o seu perfil como diz don, você está realizando uma análise dinâmica que pode ser muito mais longe do alcance. O número de chamadas para uma peça de código específica é, muitas vezes, em grande parte determinada pelo contexto em que é utilizada, por exemplo, os dados. Perfilar um conjunto típico de casos de uso vai fazer isso. Pessoalmente, eu recolher esta informação, permitindo perfis em meus testes de regressão automatizados. Além forçando inlines, tenho laços desenroladas e realizadas outras otimizações manuais com base em tais dados, com bons resultados. É também imperativo ao perfil novamente depois, como às vezes seus melhores esforços podem realmente levar a uma redução no desempenho. Mais uma vez, a automação torna isso muito menos doloroso.

Na maioria das vezes, porém, na minha experiência, aprimorando alogorithms dá resultados muito melhores do que otimização de código em linha reta.

Outras dicas

Você sabe melhor do que o compilador somente quando seus dados de perfil diz-lhe assim.

O único lugar que eu estou usando é a verificação da licença.

Um fator importante para proteger contra fácil * craqueamento é verificar sendo licenciado em vários lugares, em vez de apenas um, e você não quer que esses lugares para ser a mesma chamada de função.


*) Por favor, não transformar isso em uma discussão de que tudo pode ser quebrada - Eu sei. Além disso, isso por si só não ajuda muito.

software

Eu desenvolvi para dispositivos com recursos limitados para 9 anos ou mais e o única tempo que eu já vi a necessidade de uso __forceinline estava em um loop onde um driver de câmera necessária para cópia dados de pixel de uma captura de tampão para a tela do dispositivo. Não podemos ver claramente que o custo de uma chamada de função específica realmente monopolizou o desempenho desenho sobreposição.

A única maneira de ter certeza é para medir o desempenho com e sem. A menos que você está escrevendo altamente código crítico de desempenho, este será geralmente desnecessário.

A directiva em linha será totalmente inútil quando usado para funções que são:

recursiva, longo, composto por loops,

Se você quiser forçar essa decisão usando __forceinline

Na verdade, mesmo com a palavra chave __forceinline. Visual C ++, por vezes, opta por não inline o código. (Fonte:. Resultando código fonte assembly)

sempre olhar para o código de montagem resultando em que a velocidade é de importância (tais como espiras internas apertadas necessárias para ser executado em cada quadro).

Às vezes usando #define em vez de em linha irá fazer o truque. (É claro que você solta um monte de verificação usando #define, então usá-lo apenas quando e onde realmente importa).

Para código SIMD.

código SIMD muitas vezes usa constantes números / mágica. Em uma função regular, cada const __m128 c = _mm_setr_ps(1,2,3,4); torna-se uma referência de memória.

Com __forceinline, compilador pode carregá-lo uma vez e reutilizar o valor, a menos que seus escapamentos código registra (geralmente 16).

caches de CPU são grandes, mas registros ainda mais rápido é.

P.S. Só tenho 12% de melhoria de desempenho por si só __forceinline.

Existem várias situações em que o compilador não é capaz de determinar categoricamente se é apropriado ou benéfico para inline uma função. Inlining pode envolver trade-off do que o compilador não está disposto a fazer, mas você está (por exemplo ,, inchaço de código).

Em geral, compiladores modernos são realmente muito bons em tomar essa decisão.

Quando você sabe que a função vai ser chamados em um só lugar várias vezes por um cálculo complicado, então é uma boa idéia para uso __forceinline. Por exemplo, uma multiplicação de matrizes para a animação pode precisar de ser chamado tantas vezes que as chamadas para a função vai começar a ser notado pelo seu perfil. Como foi dito por outros, o compilador não pode realmente saber sobre isso, especialmente em uma situação dinâmica, onde a execução do código é desconhecido em tempo de compilação.

Na verdade, impulso é carregado com ele.

Por exemplo

 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(); }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top