为什么Swift在这个图像处理测试中比C慢100倍?

Pen*_*eng 58 c macos performance swift

像许多其他开发人员一样,我对Apple的新Swift语言感到非常兴奋.Apple声称它的速度比Objective C快,可以用来编写操作系统.从我到目前为止所学到的,它是一种静态类型语言,能够精确控制确切的数据类型(如整数长度).所以它看起来像具有良好的潜在处理性能关键任务,如图像处理,对吧?

在我进行快速测试之前,这就是我的想法.结果真的让我感到惊讶.

这是C中的一个简单代码片段:

test.c的:

#include <stdio.h>
#include <stdint.h>
#include <string.h>

uint8_t pixels[640*480];
uint8_t alpha[640*480];
uint8_t blended[640*480];

void blend(uint8_t* px, uint8_t* al, uint8_t* result, int size)
{
    for(int i=0; i<size; i++) {
        result[i] = (uint8_t)(((uint16_t)px[i]) *al[i] /255);
    }
}

int main(void)
{
    memset(pixels, 128, 640*480);
    memset(alpha, 128, 640*480);
    memset(blended, 255, 640*480);

    // Test 10 frames
    for(int i=0; i<10; i++) {
        blend(pixels, alpha, blended, 640*480);
    }

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

我使用以下命令在Macbook Air 2011上编译它:

clang -O3 test.c -o test
Run Code Online (Sandbox Code Playgroud)

10帧处理时间约为0.01秒.换句话说,它需要C代码1ms来处理一帧:

$ time ./test
real    0m0.010s
user    0m0.006s
sys     0m0.003s
Run Code Online (Sandbox Code Playgroud)

然后我有一个相同代码的Swift版本:

test.swift:

let pixels = UInt8[](count: 640*480, repeatedValue: 128)
let alpha = UInt8[](count: 640*480, repeatedValue: 128)
let blended = UInt8[](count: 640*480, repeatedValue: 255)

func blend(px: UInt8[], al: UInt8[], result: UInt8[], size: Int)
{
    for(var i=0; i<size; i++) {
        var b = (UInt16)(px[i]) * (UInt16)(al[i])
        result[i] = (UInt8)(b/255)
    }
}

for i in 0..10 {
    blend(pixels, alpha, blended, 640*480)
}
Run Code Online (Sandbox Code Playgroud)

构建命令行是:

xcrun swift -O3 test.swift -o test
Run Code Online (Sandbox Code Playgroud)

在这里,我使用相同的O3级别优化标志来进行比较,希望是公平的.但是,结果速度慢了100倍:

$ time ./test

real    0m1.172s
user    0m1.146s
sys     0m0.006s
Run Code Online (Sandbox Code Playgroud)

换句话说,处理一帧需要Swift~120ms,这只需要1 ms.

发生了什么?

更新:我正在使用clang:

$ gcc -v
Configured with: --prefix=/Applications/Xcode6-Beta.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.34.4) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.2.0
Thread model: posix
Run Code Online (Sandbox Code Playgroud)

更新:使用不同的运行迭代获得更多结果:

以下是不同数量的"帧"的结果,for即将主循环数从10 更改为其他数字.现在注意我的C代码时间更快(缓存热点?),而Swift时间不会变化太多:

             C Time (s)      Swift Time (s)
  1 frame:     0.005            0.130
 10 frames(*): 0.006            1.196
 20 frames:    0.008            2.397
100 frames:    0.024           11.668
Run Code Online (Sandbox Code Playgroud)

更新:`-Ofast`有帮助

随着-Ofast@mweathers的建议,Swift速度上升到合理的范围.

在我的笔记本电脑上,Swift版本-Ofast的10帧为0.013秒,100帧为0.048秒,接近C性能的一半.

小智 25

建筑用:

xcrun swift -Ofast test.swift -o test

我得到的时间是:

real    0m0.052s
user    0m0.009s
sys 0m0.005s
Run Code Online (Sandbox Code Playgroud)

  • @JeremyBanks:-Ofast更改语言的语义.这不安全.你正在将Swift变成一种类似C++的语言.静默忽略整数溢出,数组溢出等. (35认同)
  • @grasGendarme:数组绑定检查确实*不*暗示因子100减速(它应该更像是因子<< 2).参看 Java与C. (7认同)
  • @JukkaSuomela数组绑定检查肯定会在这样的内循环中占100倍减速,超过一百万次迭代 (6认同)
  • 更多关于-Ofast影响的例子:http://stackoverflow.com/questions/24101718/swift-performance-sorting-arrays (5认同)
  • @gordy:参见[this](http://stackoverflow.com/questions/24101718/swift-performance-sorting-arrays),了解一些Swift与Java与Python与C++的比较.并且请记住,Java也会检查边界(以及更多 - 它还必须检查空指针). (5认同)
  • 我会成为"那个人":为什么你甚至只发布基准的一面?! (2认同)

gna*_*729 11

让我们专注于问题的答案,该问题以"为什么"开头:因为你没有改变优化,Swift在很大程度上依赖于编译器优化.

也就是说,在C中进行图像处理确实很糟糕.这就是你拥有CGImage和朋友的原因.