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;
}