技术开发 频道

使用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不做密集运算,只处理游戏逻辑和接口封装,完全是足以胜任(在很多引擎中,还有执行效率更低的脚本代码存在)。况且CLIC++是可以混合编译运行的。在遇到明显运算瓶颈的时候,我们还可以用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
相关文章