c# - ObjC 与 MonoTouch float 和数组性能

标签 c# objective-c ios ipad xamarin.ios

编辑:添加了unsafe C#代码的版本。谢谢大家的建议,unsafe C# 代码运行速度更快,但只有大约 3%。


精简版:我用 C# 和 Objective-C 编写了一些基准代码,并在 iPad 3 上对其进行了测试。MonoTouch/C# 版本需要的执行时间比之前多 50%-150% Objective-C 中的相同代码。这是我的问题:我可以编写比我用于基准测试的代码执行速度更快的 C# 代码吗(见下文),或者这是由某些固有的 MonoTouch/Obj-C 差异引起的?


长版:我刚刚为计划中的多平台游戏编写了一个小原型(prototype)。将游戏核心从 Windows/.NET 移植到 iPad 3/MonoTouch 后,我注意到代码在 iPad 上的运行速度要慢得多。游戏核心的某些关键部分在 iPad CPU 上的运行速度比在 Intel CPU 上慢大约 10 倍(这似乎是正常的,因为 iPad 运行的是 ARM 处理器)。

然而,由于这是我们游戏的一个主要问题,我在 iPad 3 上进行了一次小型基准测试,一次使用 MonoTouch,然后使用普通的 Objective-C 进行同样的测试。基准测试做了很多简单的 float添加和 float数组查找。由于 MonoTouch 是 GC'ed,我希望看到有利于 Obj-C 的微小差异,但令我惊讶的是,MonoTouch 代码比 Obj-C 代码需要更多的时间来运行。准确地说:

  • 需要Obj-C代码47'647 ms在 DEBUG 模式下运行,27'162 ms在 Release模式。
  • 未使用 unsafeMonoTouch 代码需要指点116'885 ms在 DEBUG 模式下运行,40'002 ms在 Release模式。
  • MonoTouch 代码unsafe需要指针 90'372 ms在 DEBUG 模式下运行,38'764 ms在 Release模式。

当然,RELEASE模式才是我关心的。

考虑到 MonoTouch 编译为相同的 native LLVM,这个差异对我来说似乎有点高。代码为 Obj-C。

这是我使用的 Obj-C 代码:

int i, j;
long time = GetTimeMs64();
float * arr = (float *) malloc(10000 * sizeof(float)); //  10'000
for (j = 0; j < 100000; j++) {                         // 100'000
    arr[0] = 0;
    arr[1] = 1;
    for (i = 2; i < 10000; i++) {                      //  10'000
        arr[i] = arr[i - 2] + arr[i - 1];
        if (arr[i] > 2000000000) {             // prevent arithm. overflow
            arr[i - 1] = 0;
            arr[i] = 1;
        }
    }
}
long time2 = GetTimeMs64() - time;

GetTimeMs64()使用 <sys/time.h>gettimeofday .

这是我的 C#/MonoTouch 代码,在 unsafe 中版本:

var array = new float[10000];                          //  10'000
var watch = System.Diagnostics.Stopwatch.StartNew();
fixed (float* arr = array)
{
    for (int j = 0; j < 100000; j++)                   // 100'000
    {
        *(arr + 0) = 0;
        *(arr + 1) = 1;
        for (int i = 2; i < 10000; i++)                //  10'000
        {
            *(arr + i) = *(arr + i - 2) + *(arr + i - 1);
            if (*(arr + i) > 2000000000)               // prevent arithm. overflow
            {
                *(arr + i - 1) = 0;
                *(arr + i) = 1;
            }
        }
    }
}

watch.Stop();

编辑 2:这是我们从 Xamarin 得到的答案:

There are two issues with this particular example that impair mono performance.

First, if you're using the default MonoTouch compiler, and not LLVM, you can expect lower performance as it's tunned for compilation speed and not execution speed. LLVM will give you better results.

Second, mono complies with the ECMA spec regarding floating point and does all computations with double precision. This usually have a measurable performance cost specially if compared to C code using floats.

We've been looking into ways to relax the double precision performance without compromising correctness or, at least, have an opt in mechanism.

最佳答案

正如 Marc 建议您应该使用不安全 代码一样,MonoTouch 支持此 .NET 功能。

这将删除 .NET 数组边界检查,这是 .NET 的一个不错、更安全的功能,但会降低性能(因为每个数组访问都必须被检查).

这将使您的代码看起来更像 Objective-C 代码(无论是源代码还是 native 代码)并且性能应该更接近。我仍然建议您仅在性能非常重要时才使用不安全代码(并且在衡量 yield 值得之后)。

关于c# - ObjC 与 MonoTouch float 和数组性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12428229/

相关文章:

iphone - ios我可以从不同的线程观察者(NSNotificationCenter)

c# - DNX SDK版本 'dnx-clr-win-x86.1.0.0-beta8-15530'安装失败

c# - 在运行时加载程序集

c# - 在 C# 中如何使用大于 MaxValue 的数字进行数学运算(或数学运算)?

iphone - Facebook SDK iOS 中的用户未登录错误

ios - 横向图像选择器。

c# - 在 SQL 查询中传递 DECLARE 参数

ios core plot增加CPTPlotSymbol可点击区域

iphone - 文本滚动到 UITextView 框边界之外

ios - 在 iPad 中从纵向模式切换到横向模式时如何正确加载图像和按钮