성능 저하를 최소화하면서 C & C++ 라이브러리를 동기화하는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/286105

문제

저는 벡터, 행렬, 쿼터니언 등을 처리하기 위한 수많은 수학 루틴이 포함된 C 라이브러리를 가지고 있습니다.임베디드 작업과 Lua 확장으로 자주 사용하기 때문에 C에 남아 있어야 합니다.또한 C API를 사용하여 수학 연산을 위한 연산자 오버로딩과 보다 편리한 개체 관리를 허용하는 C++ 클래스 래퍼가 있습니다.래퍼는 헤더 파일로만 구성되며 인라인에 최대한 많이 사용됩니다.

C 코드를 래핑하는 것과 구현을 C++ 클래스로 직접 포팅 및 인라인하는 경우 상당한 페널티가 있습니까?이 라이브러리는 시간이 중요한 애플리케이션에 사용됩니다.그렇다면 간접 제거로 인한 향상이 두 포트의 유지 관리 문제를 보상합니까?

C 인터페이스의 예:

typedef float VECTOR3[3];

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

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...
};
도움이 되었습니까?

해결책

래퍼 자체는 상환되지만 C 라이브러리에 대한 메소드 호출은 일반적으로 그렇지 않습니다. (이것은 기술적으로 가능한 링크 시간-최적화가 필요하지만 오늘날의 도구에서 최대의 기초가 필요합니다)

일반적으로 함수 호출은 그다지 비싸지 않습니다. 주기 비용은 지난 몇 년 동안 상당히 감소했으며 쉽게 예측할 수 있으므로 호출 페널티는 무시할 수 있습니다.

그러나 Inlining은 더 많은 최적화의 문을 열어줍니다. v = a + b + c가있는 경우 래퍼 클래스는 스택 변수 생성을 강요하는 반면, 인쇄 된 호출의 경우 대부분의 데이터는 FPU 스택에 보관할 수 있습니다. 또한 상감 코드는 일정한 값을 고려하는 지침을 단순화 할 수 있습니다.

그래서 투자하기 전에 측정하십시오 규칙은 사실입니다. 여기서 개선의 여지가있을 것으로 기대합니다.


일반적인 솔루션은 C 구현을 인라인 함수 또는 "C"바디로 사용할 수있는 형식으로 가져 오는 것입니다.

// 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 { ... }

이것은 간단한 신체를 가진 선택된 방법에 대해서만 의미가있을 수 있습니다. 일반적으로 직접 필요하지 않기 때문에 메소드를 C ++ 구현을위한 별도의 네임 스페이스로 옮깁니다.

(인라인은 컴파일러 힌트 일 뿐이며, 방법이 인쇄되도록 강요하지는 않습니다. 그러나 좋습니다. 내부 루프의 코드 크기가 명령 캐시를 초과하여 인라인이 쉽게 해를 끼치는 경우).

패스/반환 바로 회의를 해결할 수 있는지 여부는 컴파일러의 강도에 따라 달라집니다. foo (x * out)가 스택 변수를 강제하는 곳을 보았지만 x foo ()는 레지스터에 값을 유지합니다.

다른 팁

C 라이브러리 호출을 C ++ 클래스 함수로 래핑하는 경우 (즉, C ++ 함수는 호출 C 함수 외에는 아무것도 수행하지 않는 경우) 컴파일러는 이러한 호출을 최적화하여 성능 페널티가되지 않도록합니다.

성능에 관한 모든 질문과 마찬가지로 답변을 얻기 위해 측정하라는 메시지가 표시됩니다(이것이 엄연히 정답입니다).

그러나 경험상 실제로 인라인될 수 있는 간단한 인라인 메서드의 경우 성능 저하가 나타나지 않습니다.일반적으로 호출을 다른 함수에 전달하는 것 외에는 아무 작업도 수행하지 않는 인라인 메서드는 인라인을 위한 훌륭한 후보입니다.

그러나 래퍼 메서드가 인라인되지 않은 경우에도 일부 중요한 루프에서 래퍼 메서드가 호출되지 않는 한 성능 저하(측정 가능한 성능 저하)도 느끼지 못할 것입니다.그럼에도 불구하고 래핑된 함수 자체가 많은 작업을 수행하지 않는 경우에만 측정 가능합니다.

이런 종류의 일은 마지막으로 걱정할 사항입니다.먼저 코드를 정확하고, 유지 관리 가능하게 만들고, 적절한 알고리즘을 사용하고 있는지 걱정하세요.

최적화와 관련된 모든 것이 평소와 마찬가지로, 최적화가 가치가 있는지 알기 전에 성능 자체를 측정해야 한다는 것이 답입니다.

  • 두 가지 다른 함수를 벤치마크합니다. 하나는 C 스타일 함수를 직접 호출하고 다른 하나는 래퍼를 통해 호출합니다.어느 것이 더 빠르게 실행되는지 또는 차이가 측정 오차 범위 내에 있는지 확인하십시오(측정할 수 있는 차이가 없음을 의미함).
  • 이전 단계에서 두 함수에 의해 생성된 어셈블리 코드를 살펴보세요(gcc에서는 -S 또는 -save-temps).컴파일러가 어리석은 짓을 했는지, 래퍼에 성능 버그가 있는지 확인하세요.

래퍼를 사용하지 않는 것에 비해 성능 차이가 너무 크지 않는 한 버그가 발생할 위험이 있으므로 다시 구현하는 것은 좋은 생각이 아닙니다(이로 인해 정상적인 것처럼 보이지만 잘못된 결과가 발생할 수도 있음).차이가 크더라도 C++가 C와 매우 호환된다는 점만 기억하고 C++ 코드 내에서도 라이브러리를 C 스타일로 사용하는 것이 더 간단하고 덜 위험할 것입니다.

나는 당신이 그다지 큰 차이를 보지 않을 것이라고 생각하지 않습니다. 대상 플랫폼이 모든 데이터 유형을 지원한다고 가정하면

나는 DS를 코딩하고 있으며 몇 가지 다른 팔 장치와 부동 소수점은 사악합니다 ... 고정 점으로 플로트를 입력해야했습니다 <16,8>

함수 호출로 인한 오버헤드로 인해 속도가 느려지는 것이 걱정된다면 C 코드를 인라인하거나 매크로로 변환하는 것을 테스트해 보는 것은 어떨까요?

또한 C 코드의 const 정확성을 향상시키는 것은 어떨까요? const_cast는 실제로 제어하는 ​​인터페이스에서 특히 자제해서 사용해야 합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top