Почему Swift в этом тесте обработки изображений в 100 раз медленнее C?

Как и многие другие разработчики, я был очень взволнован новым языком Swift от Apple. 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 с. Другими словами, для обработки одного кадра требуется код 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

Другими словами, для обработки одного кадра требуется Swift ~ 120ms, который принимает C всего 1 мс.

Что случилось?

Обновление: я использую 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 до других чисел. Заметьте, теперь я получаю еще более быстрое время 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

Обновление: `-Ofast` помогает

С -Ofast, предложенным @mweathers, скорость Swift достигает разумного диапазона.

На моем ноутбуке версия Swift с -Ofast получает 0.013s для 10 кадров и 0.048s для 100 кадров, близкую к половине производительности C.

Ответ 1

Создание с помощью:

xcrun swift -Ofast test.swift -o test

Я получаю время:

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

Ответ 2

Давайте просто сосредоточимся на ответе на вопрос, который начался с "Почему": поскольку вы не включали оптимизацию, а Swift сильно зависит от оптимизации компилятора.

Тем не менее, обработка изображений в C действительно глупо. Это то, для чего у вас есть CGImage и друзья.