Wie viele andere Entwickler war ich sehr gespannt auf die neue Swift-Sprache von Apple. Apple hat behauptet, dass seine Geschwindigkeit schneller als Objective C ist und zum Schreiben von Betriebssystemen verwendet werden kann. Und nach dem, was ich bisher gelernt habe, ist es eine statisch typisierte Sprache und in der Lage, den genauen Datentyp (wie die Ganzzahllänge) genau zu kontrollieren. Es sieht also so aus, als hätten Sie ein gutes Potenzial für leistungskritische Aufgaben wie die Bildverarbeitung, oder?
Das dachte ich mir, bevor ich einen Schnelltest durchführte. Das Ergebnis hat mich wirklich überrascht.
Hier ist ein einfaches Code-Snippet in 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;
}
Ich habe es auf meinem Macbook Air 2011 mit dem folgenden Befehl kompiliert:
clang -O3 test.c -o test
Die 10-Frame-Verarbeitungszeit beträgt etwa 0,01 s. Mit anderen Worten, der C-Code benötigt 1 ms, um einen Frame zu verarbeiten:
$ time ./test
real 0m0.010s
user 0m0.006s
sys 0m0.003s
Dann habe ich eine Swift-Version des gleichen Codes:
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)
}
Die Build-Befehlszeile lautet:
xcrun swift -O3 test.swift -o test
Hier benutze ich das gleiche O3
Level-Optimierungs-Flag, um den Vergleich hoffentlich fair zu gestalten. Die resultierende Geschwindigkeit ist jedoch 100-mal langsamer:
$ time ./test
real 0m1.172s
user 0m1.146s
sys 0m0.006s
Mit anderen Worten, Swift benötigt ~120 ms, um einen Frame zu verarbeiten, was C nur 1 ms dauert.
Was ist passiert?
Update: Ich verwende 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
Update: mehr Ergebnisse mit verschiedenen laufenden Iterationen:
Hier sind die Ergebnisse für unterschiedliche Anzahl von “Frames”, dh die wichtigsten ändern for
Loop-Nummer von 10 zu anderen Nummern. Beachten Sie, dass ich jetzt eine noch schnellere C-Code-Zeit bekomme (Cache heiß?), Während sich die Swift-Zeit nicht zu sehr ändert:
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
Update: `-Ofast` hilft
Mit -Ofast
vorgeschlagen von @mweathers, die Swift-Geschwindigkeit steigt in einen vernünftigen Bereich.
Auf meinem Laptop die Swift-Version mit -Ofast
erhält 0,013 s für 10 Frames und 0,048 s für 100 Frames, fast die Hälfte der C-Leistung.
Hilft es aus Neugier, die Mischungsberechnung durch zu ersetzen
var b = (UInt16)(px[i]) &* (UInt16)(al[i])
was, wenn ich die Dokumente richtig lese, dazu führt, dass Swift die Überlaufprüfung vermeidet?– Rici
8. Juni 2014 um 3:36 Uhr
Was passiert, wenn Sie den Code so anpassen, dass er denselben Prozess zweimal durchführt (dh Iterationen von 10 auf 20 erweitert)? Ich könnte mir vorstellen, dass das Starten der Swift-Laufzeit etwas mehr kostet als das Starten der C-Laufzeit.
– Tommi
8. Juni 2014 um 3:52 Uhr
können Sie den Assembler-Code ausgeben? Meine Vermutung ist, dass die Clang-Version möglicherweise die Division durch Konstante 255 optimiert
– blutig
8. Juni 2014 um 3:53 Uhr
Versuchen Sie, nur das Profil zu erstellen
blend
Funktion. Das Füllen des Arrays und Unterschiede in der Umgebungskonfiguration spielen wahrscheinlich eine Rolle.– Rechnung
8. Juni 2014 um 3:58 Uhr
Wenn man den gesamten Link liest, kann man sehen, dass „Ändern des Swift-Compilers – Optimierungsstufe in Xcode auf ‚Schnellste, nicht überprüft‘ dies beschleunigt hat, um mit Ihrem C++ vergleichbar zu sein.“
– Jim Balter
8. Juni 2014 um 4:21 Uhr