2007.07.20 실험 조건을 조금 바꿔서 테스트를 다시 해봤다. 지난번엔 Debug 모드로 컴파일했는데, 이번에는 Release 모드에서 Use Link Time Code Generation 최적화 옵션을 추가했다. 뿐만 아니라 /clr 옵션을 제거한 완벽한 네이티브 C++과도 성능을 비교했다.
Best Practices for Writing Efficient and Reliable Code with C++/CLI를 보면 이런 대목이 있다.
One thing to keep in mind is that, even though C++ Interop will, in general, provide better performance when compared to P/Invoke, there is still a cost to the managed-to-native transition; therefore, keeping transitions to a minimum will help performance.
어느 정도의 오버헤드가 있는지 구체적으로 언급하지 않았기에 테스트해봤다. 결과는 주석으로 달아놨는데, 함수 호출 횟수를 생각하면 큰 문제라고 보긴 힘들지 않을까?
라고 잠정적인 결론을 내려본다.
#pragma unmanaged void NativeFunction() { std::string s1 = " Test Test Test Test "; std::string s2 = " Performance Performance Performance Performance "; std::string merged(s1); merged.append(s2); } #pragma unmanaged void NativeFunction2() { for(int i=0; i<30000000; i++) { std::string s1 = " Test Test Test Test "; std::string s2 = " Performance Performance Performance Performance "; std::string merged(s1); merged.append(s2); } } #pragma managed void ManagedFunction() { DateTime prev = DateTime::Now; for(int i=0; i<30000000; i++) { NativeFunction(); } TimeSpan passed = DateTime::Now - prev; Console::WriteLine(passed.ToString()); } #pragma managed void ManagedFunction2() { DateTime prev = DateTime::Now; NativeFunction2(); TimeSpan passed = DateTime::Now - prev; Console::WriteLine(passed.ToString()); } int main(array<System::String ^> ^args) { // 58.641 seconds ManagedFunction(); // 58.071 seconds ManagedFunction2(); return 0; }
완전한 네이티브 C++로 ManagedFunction()과 비슷한 코드를 만들어 테스트해봤다. /clr 옵션을 줬을 때 컴파일러가 멍청한 짓거리를 하지 않는지 확인해보고 싶었다. 너무 간단한 코드라 신빙성이 부족하지만, 결과만 봐선 일단 C++/CLI의 네이티브 코드가 순수 네이티브 코드와 다르지 않을 거라 추측할 수 있다.
void NativeFunction() { std::string s1 = " Test Test Test Test "; std::string s2 = " Performance Performance Performance Performance "; std::string merged(s1); merged.append(s2); } void ManagedFunctionStub() { clock_t prev = ::clock(); for(int i=0; i<30000000; i++) { NativeFunction(); } clock_t now = clock(); double time_in_milliseconds = now - prev; std::cout << time_in_milliseconds / 1000 << " seconds passed." << std::endl; } int _tmain(int argc, _TCHAR* argv[]) { // 59.578 seconds passed. ManagedFunctionStub(); return 0; }