使用P/invoke来提高性能,可行还是只是一厢情愿的想法
本文关键字:一厢情愿 invoke 高性能 使用 | 更新日期: 2023-09-27 18:03:14
这是一个我可能应该早点问的问题,但我没有急于在MonoTouch中使用p/invoke类型的东西。
基本上,我有一个关于大量浮点运算的性能问题,特别是涉及最小/最大函数,向量乘法和类似的东西(基本上检测不同类型的形状是否相交)。
这些操作的原因是因为用c#编写的2D物理引擎。
在某些平台上,如Windows Phone 7和Xbox 360,物理引擎的运行没有任何问题,它窃取了一些CPU周期,但留下了足够的时间来确保游戏以稳定的帧率运行。
问题是在iPhone上运行的MonoTouch。看起来MonoToch在如此多的浮点运算中并不是那么出色,iPhone(甚至iPad 2)发现自己受到了严重的影响,物理是明显的性能瓶颈。我已经分析了性能,它归结为一组相对基本的数学函数,正如我之前提到的,没有真正的方法来优化这些函数,物理引擎本身写得很好,我看不出它有任何明显的落后,坦率地说,我怀疑它作为一个2D c#物理引擎有什么问题。
为此,我决定找到一个用C(或c++,如果可能的话)编写的物理引擎,并将其与主要的MonoTouch应用程序连接起来。我的理由是,由于MonoTouch的性能问题可能与MonoTouch编译器不能像Wp7/xbox 360 JIT编译器那样快速编译。net代码有关(这是可以理解的),将内容移出MonoTouch并在本机运行将有助于提高性能。所以我的想法是,我将使用Box2D,写一堆静态包装器函数(如CreateWorld (), CreateBox (), GetBodyPosition (int id),等等,等等)和钩通过p/invoke功能并将它集成到我的物理包装类,以这种方式核心游戏逻辑需要最小的没有修改,我可以保持原始代码的完整性设计还获得性能的提高是因为物理运行在本机c .
但这让我想到,性能问题源于非常简单和直接的数学函数,简单的乘法和大小比较。如果通过p/invoke运行函数会提高速度,那么只需重写一个函数,比如Vector2。Max作为C函数并调用它也可以提高性能?
然而,这似乎有点牵强,如果是这样的话,Mono不会这样做吗?
所以我想我的总体问题是,静态链接的本地库在从p/invoke调用时比MonoTouch编译的等效c#函数执行得更好吗?
实际上只有一种方法可以确定它是否更快:对您的案例进行基准测试。可能是本机库使用的c编译器能够比mono的jit进行更多的优化,或者它可能只是cpu不适合您的特定工作负载。
如果您想尝试使用本机库,请记住您不想经常从托管调用本机代码,每次托管到本机转换都会对性能造成重大影响(影响程度取决于许多因素,但转换越少越好)。
也就是说,我个人的猜测是mono jit不能很好地处理浮点运算(之前在某些cpu上有这个问题,我现在不记得这些问题是否仍然存在,也不记得在哪个cpu上),所以你会从使用本机库中受益。
如果你的代码中有一些关键部分,你可以尝试使用"unsafe"来避免数组访问的自动范围检查。对于像2向量或3向量这样的短数组和简单的运算(如范数或点积),它可能会产生影响。
简单的数学运算不应该变慢,但是如果没有分析结果,很难判断代码的哪个部分变慢。如果本机版本大量使用sse,或者您的托管版本无意中使用了大量的装箱等,可能会导致差异。
为了使p/invoke有用,你应该做一些做大量工作的调用,所以如果你能在一次调用本机dll中更新整个状态,这可能是有用的。但我绝对不会尝试将琐碎的函数变成本机。
除了Rolf的出色反应外,您还可以考虑在构建游戏时使用LLVM优化。
我发现Windows Phone 7的JIT优于Mono的静态编译器