使用CLI开发高性能3D Engine(2)下
[IT168 技术文档]终于写到这个看到CLI第一个蹦出来的问题了。怀疑C/C++以外别的语言性能,这恐怕是大多数游戏程序员的共同爱好吧:)
一开始我也有这样的的怀疑。就在早段时间,由于新引擎在gf2mx上界面绘制效率甚至感觉还不如上一版本victory v2的水平。同事们都很着急,经过各种方法的性能分析都找不到原因,于是CLI语言本身被当成了替罪羊。VTune8分析混合代码的时候问题特别严重,C++的函数几乎分析不出来,一切都指向了几个CLI函数。于是,我们采用vs2005自带的性能分析器进行分析,(说句题外话,VS2005的性能分析器真不错,个人感觉分析信息不比VTune的少,貌似执行效率还要影响的小得多)结果发现,根本不是CLI的问题,这次的情况是因为只是绘制界面,以前的引擎完全没有启动3d环境,都是CPU做的2D处理,因为古董显卡gf2mx的像素填充,纹理采样的瓶颈和CPU相对强大,居然要比GPU硬件加速的绘制还要略为快一些。
不支持inline,托管对象也会有一些额外的效率开销,等等一些特性,会让CLI效率相对C++有一些降低。但是,在C++底层引擎的支持下,CLI不做密集运算,只处理游戏逻辑和接口封装,完全是足以胜任(在很多引擎中,还有执行效率更低的脚本代码存在)。况且CLI和C++是可以混合编译运行的。在遇到明显运算瓶颈的时候,我们还可以用C++完成关键运算。
C++和CLI的性能测试对比:
下面是我对C++和CLI托管代码做的一个非常简单的性能测试代码
#include "stdafx.h"
#include "windows.h"
#include "math.h"
![]()
using namespace System;
![]()
float __pow_cpp(float af)
...{
float f = af-1;
if( f<0 )
return 0;
else
return __pow_cpp(f);
}
![]()
ref struct CliInterface
...{
float __pow(float f)
...{
return f*f;
}
float math_test(int a ,
float b ,
int c )
...{
float ret = 0;
for( int i=0 ; i<1000000 ; i++ )
...{
ret += (((a+c)%c)*b/c)-b;
}
return ret;
}
float callcpp_test(float a)
...{
float ret = 0;
for( int i=0 ; i<1000000 ; i++ )
...{
ret = __pow_cpp(a);
}
return ret;
}
float callcli_test(float a)
...{
float ret = 0;
for( int i=0 ; i<1000000 ; i++ )
...{
ret = __pow(a);
}
return ret;
}
void alloc_test()
...{
for( int i=0 ; i<1000000 ; i++ )
...{
CliInterface^ obj = gcnew CliInterface;
delete obj;
}
}
};
![]()
struct CppInterface
...{
float __pow(float f)
...{
return f*f;
}
float math_test(int a ,
float b ,
int c )
...{
float ret = 0;
for( int i=0 ; i<1000000 ; i++ )
...{
ret += (((a+c)%c)*b/c)-b;
}
return ret;
}
float call_test(float a)
...{
float ret = 0;
for( int i=0 ; i<1000000 ; i++ )
...{
ret = __pow_cpp(a);
}
return ret;
}
void alloc_test()
...{
for( int i=0 ; i<1000000 ; i++ )
...{
CppInterface* obj = new CppInterface;
delete obj;
}
}
};
![]()
int main(array<System::String ^> ^args)
...{
Console::WriteLine(L"Hello World");
![]()
CliInterface^ cliobj = gcnew CliInterface;
CppInterface* cppobj = new CppInterface;
![]()
...{//math test
__int64 climath1,climath2;
QueryPerformanceCounter( (LARGE_INTEGER*)&climath1 );
cliobj->math_test(1,2,3);
QueryPerformanceCounter( (LARGE_INTEGER*)&climath2 );
![]()
__int64 cppmath1,cppmath2;
QueryPerformanceCounter( (LARGE_INTEGER*)&cppmath1 );
cppobj->math_test(1,2,3);
QueryPerformanceCounter( (LARGE_INTEGER*)&cppmath2 );
![]()
Console::WriteLine
( L"math cli={0} || cpp={1}" , climath2-climath1 ,
cppmath2-cppmath1 );
}
![]()
...{//call test
__int64 climath1,climath2;
QueryPerformanceCounter( (LARGE_INTEGER*)&climath1 );
cliobj->callcpp_test(1);
QueryPerformanceCounter( (LARGE_INTEGER*)&climath2 );
![]()
__int64 clicppmath1,clicppmath2;
QueryPerformanceCounter( (LARGE_INTEGER*)&clicppmath1 );
cliobj->callcli_test(1);
QueryPerformanceCounter( (LARGE_INTEGER*)&clicppmath2 );
![]()
__int64 cppmath1,cppmath2;
QueryPerformanceCounter( (LARGE_INTEGER*)&cppmath1 );
cppobj->call_test(1);
QueryPerformanceCounter( (LARGE_INTEGER*)&cppmath2 );
![]()
Console::WriteLine
( L"call clicpp={0} || clicli={0} || cpp={1}" ,
climath2-climath1 , clicppmath2-clicppmath1 , cppmath2-cppmath1 );
}
![]()
...{//alloc test
__int64 climath1,climath2;
QueryPerformanceCounter( (LARGE_INTEGER*)&climath1 );
cliobj->alloc_test();
QueryPerformanceCounter( (LARGE_INTEGER*)&climath2 );
![]()
__int64 cppmath1,cppmath2;
QueryPerformanceCounter( (LARGE_INTEGER*)&cppmath1 );
cppobj->alloc_test();
QueryPerformanceCounter( (LARGE_INTEGER*)&cppmath2 );
![]()
Console::WriteLine
( L"alloc cli={0} || cpp={1}" , climath2-climath1 , cppmath2-cppmath1 );
}
![]()
delete cppobj;
return 0;
}
0
相关文章
