web-dev-qa-db-ja.com

この画像処理テストでは、なぜSwiftはCの100倍遅いのですか?

他の多くの開発者と同様に、新しい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;
}

Macbook Air 2011で次のコマンドを使用してコンパイルしました。

clang -O3 test.c -o test

10フレームの処理時間は約0.01秒です。言い換えると、1フレームを処理するにはCコード1msが必要です。

$ time ./test
real    0m0.010s
user    0m0.006s
sys     0m0.003s

次に、同じコードの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)
}

ビルドコマンドラインは次のとおりです。

xcrun Swift -O3 test.Swift -o test

ここでは、同じO3レベル最適化フラグを使用して、比較がうまくいくように比較します。ただし、結果の速度は100倍遅くなります。

$ time ./test

real    0m1.172s
user    0m1.146s
sys     0m0.006s

言い換えると、Cがわずか1ミリ秒かかる1フレームの処理にSwift〜120ミリ秒かかります。

どうした?

更新:私は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

更新:異なる実行反復でより多くの結果:

異なる数の「フレーム」の結果を次に示します。つまり、メインのforループ番号を10から他の番号に変更します。注:Swift時間はあまり変化しませんが、Cコードの時間はさらに高速になります(キャッシュがホットですか?):

             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

更新: `-Ofast`が役立ちます

@mweathersによって提案された-Ofastを使用すると、Swift速度は妥当な範囲に上がります。

私のラップトップでは、Swiftバージョン-Ofastのバージョンは、10フレームで0.013秒、100フレームで0.048秒になり、Cパフォーマンスの半分に近くなります。

57
Penghe Geng

で構築:

xcrun Swift -Ofast test.Swift -o test

私はの時間を取得しています:

real    0m0.052s
user    0m0.009s
sys 0m0.005s
24
mweathers

「理由」で始まった質問への答えに集中しましょう。最適化をオンにしなかったため、Swiftはコンパイラの最適化に大きく依存しています。

とは言っても、Cで画像処理を行うのは非常に簡単です。それはあなたがCGImageと友人を持っているものです。

11
gnasher729