Pergunta

Eu tenho uma biblioteca C com inúmeras rotinas de matemática para lidar com vetores, matrizes, quaternions e assim por diante. Ele precisa permanecer em C porque muitas vezes eu usá-lo para o trabalho incorporado e como uma extensão Lua. Além disso, tenho ++ invólucros de classe C para permitir uma gestão objeto mais conveniente e sobrecarga de operador para operações matemáticas usando a API C. O invólucro consiste unicamente em um arquivo de cabeçalho e tanto o uso em inlining é feito possível.

Existe uma penalidade apreciável para envolver o código C contra portar e inlining a implementação diretamente na classe C ++? Esta biblioteca é utilizada em aplicações críticas de tempo. Então, faz o impulso de eliminar engano compensar a dor de cabeça manutenção de duas portas?

Exemplo de interface de C:

typedef float VECTOR3[3];

void v3_add(VECTOR3 *out, VECTOR3 lhs, VECTOR3 rhs);

Exemplo de invólucro C ++:

class Vector3
{
private:
    VECTOR3 v_;

public:
    // copy constructors, etc...

    Vector3& operator+=(const Vector3& rhs)
    {
        v3_add(&this->v_, this->v_, const_cast<VECTOR3> (rhs.v_));
        return *this;
    }

    Vector3 operator+(const Vector3& rhs) const
    {
        Vector3 tmp(*this);
        tmp += rhs;
        return tmp;
    }

    // more methods...
};
Foi útil?

Solução

O seu próprio invólucro será embutido, no entanto, as suas chamadas de método para a biblioteca C normalmente não vai. (Isso exigiria link-time-otimizações que são tecnicamente possível, mas AFAIK rudimentar na melhor das hipóteses em ferramentas de hoje)

Geralmente, uma chamada de função, como tal, não é muito caro. O custo do ciclo diminuiu consideravelmente nos últimos anos, e isso pode ser previsto com facilidade, por isso a pena a chamada como tal é insignificante.

No entanto, inlining abre a porta para mais otimizações: se você tem v = a + b + c, sua classe de mensagens publicitárias forças a geração de variáveis ??de pilha, enquanto que para as chamadas inlined, a maioria dos dados pode ser mantido na FPU pilha. Além disso, o código embutido permite simplificar as instruções, considerando valores constantes, e muito mais.

Assim, enquanto o medida antes de investir regra vale, eu esperaria algum espaço para melhorias aqui.


Uma solução típica é trazer o implementaiton C para um formato que pode ser usado quer como funções em linha ou como "C" corpo:

// V3impl.inl
void V3DECL v3_add(VECTOR3 *out, VECTOR3 lhs, VECTOR3 rhs)
{
    // here you maintain the actual implementations
    // ...
}

// C header
#define V3DECL 
void V3DECL v3_add(VECTOR3 *out, VECTOR3 lhs, VECTOR3 rhs);

// C body
#include "V3impl.inl"


// CPP Header
#define V3DECL inline
namespace v3core {
  #include "V3impl.inl"
} // namespace

class Vector3D { ... }

Isso provavelmente faz sentido apenas para os métodos selecionados com corpos simples comparedly. Eu mover os métodos para um namespace separado para implementação do C ++, como você geralmente não precisa-los diretamente.

(Note que a linha é apenas uma sugestão compilador, ele não força o método a ser embutido. Mas isso é bom: se o tamanho do código de um circuito interno excede o cache de instruções, inlining facilmente dói desempenho)

Se o passe / retorno por referência podem ser resolvidos depende da força de seu compilador, eu vi muitos onde foo (X * a) forças empilhar variáveis, enquanto X foo () faz valores manter-se em registros.

Outras dicas

Se você está apenas envolvendo as chamadas de biblioteca C em funções de classe C ++ (em outras palavras, as funções C ++ fazer nada além de funções de chamada C), em seguida, o compilador irá otimizar essas chamadas para que ele não é uma penalidade de desempenho.

Tal como acontece com qualquer pergunta sobre o desempenho, você vai ser dito para medir a obter a sua resposta (e essa é a resposta estritamente correto).

Mas, como regra geral, por métodos in-line simples que pode realmente ser embutido, você verá nenhuma penalidade de desempenho. Em geral, um método em linha que não faz nada, mas passar a chamada para outra função é um grande candidato para inlining.

No entanto, mesmo se os seus métodos de mensagens publicitárias não foram inline, eu suspeito que você iria notar nenhuma penalidade de desempenho - nem mesmo um mensurável - a menos que o método de embalagem estava sendo chamado em algum circuito crítico. Mesmo assim, provavelmente só iria ser mensuráveis ??se a função embrulhada em si não fazer muito trabalho.

Este tipo de coisa é a última coisa para se preocupar. Primeiro preocupar em fazer o seu código correto, sustentável, e que você está usando algoritmos apropriados.

Como de costume com tudo relacionado à otimização, a resposta é que você tem que medir o próprio desempenho antes de saber se a otimização vale a pena.

  • benchmark duas funções diferentes, um chamando as funções de estilo C diretamente e outra chamada através do invólucro. Ver qual corre mais rápido, ou se a diferença está dentro da margem de erro da medição (o que significa que não há diferença que você pode medir).
  • olhar para o código gerado pelo conjunto das duas funções no passo anterior (em gcc, uso ou -S -save-temps). Veja se o compilador fez algo estúpido, ou se os seus invólucros ter qualquer bug desempenho.

A menos que a diferença de desempenho é muito grande em favor de não usar o wrapper, reimplementar não é uma boa idéia, já que corre o risco de erros introduzindo (o que poderia até mesmo causar resultados que sane olhar, mas estão errados). Mesmo que a diferença é grande, seria mais simples e menos arriscada para lembre-C ++ é muito compatível com C e usar sua biblioteca no estilo C, mesmo no código C ++.

Eu não acho que você vai notar muita diferença perf. Assumindo seu apoio plataforma de destino todos os seus tipos de dados,

Eu estou de codificação para o DS e alguns outros dispositivos ARM e flutuantes pontos são maus ... Eu tive que typedef float para FixedPoint <16,8>

Se você está preocupado que a sobrecarga de chamar funções está retardando para baixo, por que não testar inlining o código C ou transformá-lo em macros?

Além disso, por que não melhorar a precisão const do código C, enquanto você está nisso -. Const_cast realmente deve ser usado com moderação, especialmente em interfaces que você controla

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top