SORU
7 HAZİRAN 2014, CUMARTESİ


Hızlı performans: dizileri sıralama

Hızlı bir algoritma uygulanması ve performans çok düşük olduğunu fark etti. Derin kazma sonra darboğazları biri bir şey dizileri sıralama kadar basit olduğunu anladım. İlgili kısmı burada

let n = 1000000
let x = Int[](count: n, repeatedValue: 0)
for i in 0..n {
    x[i] = random()
}
// start clock here
let y = sort(x)
// stop clock here

C , benzer bir operasyonu sürüyor0.06 sbilgisayarımda.

Python alır0.6(tamsayılar listesi için hile yok, sadece y = sıralanmış(x)).

Swift yer alıyor6ben aşağıdaki komut ile derleme:

xcrun swift -O3 -sdk `xcrun --show-sdk-path --sdk macosx`

Ve kadar sürer88 sben aşağıdaki komut ile derleme:

xcrun swift -O0 -sdk `xcrun --show-sdk-path --sdk macosx`

""Hata Ayıklama benzer. "inşa" vs Sürümü ile böyle büyük mükafat olarak zamanlamaları

Burada yanlış olan nedir? Saf Python ile karşılaştırıldığında, C , ama 10 kat yavaşlama ile karşılaştırıldığında, bazı performans kaybı anlayamadım.


Düzenleme:mweathers -Ofast 25 *değişen bu kod neredeyse hızlı C sürümü olarak çalışmasını sağlayan fark! Ancak, 27* *dilin semantik çok — benim test değişiyortamsayı taşmaları ve dizi indeksleme taşmaları için devre dışı denetler. -Ofast ile örneğin, aşağıdaki Swift kodu çökmesini olmadan sessizce ve Çöp yazdırır) çalışır:

let n = 10000000
println(n*n*n*n*n)
let x = Int[](count: n, repeatedValue: 10)
println(x[n])

Yani -Ofast bizim istediğimiz değil; Swift bütün mesele yerde güvenlik ağları var. Tabii ki güvenlik ağları performansı üzerinde bazı etkileri var, ama bu program 100 kez daha yavaş olun olmamalıdır. Java zaten dizi sınırları kontrol eder unutmayın, ve tipik durumlarda yavaşlama faktörü 2'den çok daha az. Ve Çınlama ve GCC kontrol (imzalı) için -ftrapv tamsayı taşmaları var ve çok yavaş da değil.

Dolayısıyla soru şu: nasıl güvenlik ağları kaybetmeden Swift makul bir performans alabilir miyiz?


Edit 2:Daha fazla kıyaslama bazı mısralar çok basit bir döngü ile yaptım

for i in 0..n {
    x[i] = x[i] ^ 12345678
}

(Burada xor işlemi daha kolay derleme Kanunu ile ilgili mevzuat döngü bulabildiğim bir şey yok. Kolay ama aynı zamanda "" herhangi bir çek tamsayı taşmaları ile ilgili gerektirir bu anlamda.) zararsız spot bir operasyon almaya çalıştım

Yine -O3 -Ofast arasında performans olarak büyük bir fark vardı. Derleme kod bir göz attım:

  • -Ofast ile ne beklediğiniz çok anlıyorum. İlgili Bölüm 5 makine dili talimatları ile bir döngü.

  • -O3 ile en çılgın hayallerimin bile ötesinde bir şey. Derleme kod iç döngü yayılan 88 hatları. Hepsini anlamaya çalışmadım, ama en şüpheli parçaların 13 çağırmaları "" ve başka bir 13 çağırmaları "". callq _swift_release callq _swift_retain Yani26 yordam iç döngü içinde çağırır!


Edit 3:Yorum, Ferruccio-dahili fonksiyonları güvenmeyin bu anlamda adil olan kriterler (örneğin tür) istedi. Aşağıdaki program oldukça iyi bir örnek olduğunu düşünüyorum

let n = 10000
let x = Int[](count: n, repeatedValue: 1)
for i in 0..n {
    for j in 0..n {
        x[i] = x[j]
    }
}

Aritmetik yok, tamsayı taşmaları hakkında endişelenmenize gerek yok yani. Yaptığımız tek şey sadece dizi başvurular çok. Ve sonuçları burada—Swift-O3 kaybeder-Ofast: ile karşılaştırıldığında, yaklaşık 500 faktör vardır

  • C -O3:0.05 s
  • -O0 C: s 0.4
  • Java:0.2 s
  • PyPy ile Python: s 0.5
  • Python:S 12
  • -Ofast Swift: 0.05 s
  • Swift -O3:S 23
  • -O0 Swift: s 443

Eğer derleyici anlamsız döngüler tamamen optimize olabilir endişeleriniz varsa, o x[i] ^= x[j] örneğin x[0] çıkışlar bir yazdırma deyimi eklemek için değiştirebilirsiniz. Bu hiçbir şeyi değiştirmez; zamanlama çok benzer olacaktır.)

Ve evet, Python uygulaması in listesi aptal ve saf bir Python uygulaması ve iç içe for döngüsü burada. Olmalıdırçokunoptimised daha yavaş Hızlı. Bir şey gerçekten Hızlı ve bir dizi indeksleme ile kırık gibi görünüyor.


Edit 4:Bu sorunlar (ve diğer bazı performans sorunları) Xcode 6 beta 5 giderildi gibi görünüyor.

Sıralama için, şimdi aşağıdaki zamanlamaları var:

  • çınlama -O3: 0.06 s
  • swiftc -Ofast: s 0.1
  • swiftc -O: 0.1 s
  • swiftc: s 4

İç içe döngüler için:

  • çınlama -O3: 0.06 s
  • swiftc -Ofast: s 0.3
  • swiftc -O: s 0.4
  • swiftc: s 540

Artık -Ofast güvenli kullanmak için bir sebep yok gibi görünüyor (bir.k.bir. -Ounchecked); düz -O eşit derecede iyi bir kod üretir.

CEVAP
8 HAZİRAN 2014, Pazar


tl;dr Swift şimdi bu kriter ile C varsayılan sürümü optimizasyon seviyesine kadar hızlı [-O].

Burada yerinde bir Swift quicksort:

func quicksort_swift(inout a:CInt[], start:Int, end:Int) {
    if (end - start < 2){
        return
    }
    var p = a[start   (end - start)/2]
    var l = start
    var r = end - 1
    while (l <= r){
        if (a[l] < p){
            l  = 1
            continue
        }
        if (a[r] > p){
            r -= 1
            continue
        }
        var t = a[l]
        a[l] = a[r]
        a[r] = t
        l  = 1
        r -= 1
    }
    quicksort_swift(&a, start, r   1)
    quicksort_swift(&a, r   1, end)
}

Ve C aynı:

void quicksort_c(int *a, int n) {
    if (n < 2)
        return;
    int p = a[n / 2];
    int *l = a;
    int *r = a   n - 1;
    while (l <= r) {
        if (*l < p) {
            l  ;
            continue;
        }
        if (*r > p) {
            r--;
            continue;
        }
        int t = *l;
        *l   = *r;
        *r-- = t;
    }
    quicksort_c(a, r - a   1);
    quicksort_c(l, a   n - l);
}

Hem iş:

var a_swift:CInt[] = [0,5,2,8,1234,-1,2]
var a_c:CInt[] = [0,5,2,8,1234,-1,2]

quicksort_swift(&a_swift, 0, a_swift.count)
quicksort_c(&a_c, CInt(a_c.count))

// [-1, 0, 2, 2, 5, 8, 1234]
// [-1, 0, 2, 2, 5, 8, 1234]

Hem de yazılı olarak aynı programda denir.

var x_swift = CInt[](count: n, repeatedValue: 0)
var x_c = CInt[](count: n, repeatedValue: 0)
for var i = 0; i < n;   i {
    x_swift[i] = CInt(random())
    x_c[i] = CInt(random())
}

let swift_start:UInt64 = mach_absolute_time();
quicksort_swift(&x_swift, 0, x_swift.count)
let swift_stop:UInt64 = mach_absolute_time();

let c_start:UInt64 = mach_absolute_time();
quicksort_c(&x_c, CInt(x_c.count))
let c_stop:UInt64 = mach_absolute_time();

Bu saniye için mutlak kez dönüştürür:

static const uint64_t NANOS_PER_USEC = 1000ULL;
static const uint64_t NANOS_PER_MSEC = 1000ULL * NANOS_PER_USEC;
static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MSEC;

mach_timebase_info_data_t timebase_info;

uint64_t abs_to_nanos(uint64_t abs) {
    if ( timebase_info.denom == 0 ) {
        (void)mach_timebase_info(&timebase_info);
    }
    return abs * timebase_info.numer  / timebase_info.denom;
}

double abs_to_seconds(uint64_t abs) {
    return abs_to_nanos(abs) / (double)NANOS_PER_SEC;
}

İşte derleyicinin optimazation düzeyde bir özeti:

[-Onone] no optimizations, the default for debug.
[-O]     perform optimizations, the default for release.
[-Ofast] perform optimizations and disable runtime overflow checks and runtime type checks.

Saniye süre ile[-Photoshop]içinn=10_000:

Swift:            0.895296452
C:                0.001223848

Burada Swift'in yerleşik sıralama ()n=10_000:

Swift_builtin:    0.77865783

Burada[-O]içinn=10_000:

Swift:            0.045478346
C:                0.000784666
Swift_builtin:    0.032513488

Gördüğünüz gibi, Hızlı performansı 20 kat artırıldı.

mweathers' answer, ayarı göre[-Ofast]yapan gerçek fark, bu kez sonuçlanırn=10_000:

Swift:            0.000706745
C:                0.000742374
Swift_builtin:    0.000603576

Ve içinn=1_000_000:

Swift:            0.107111846
C:                0.114957179
Swift_sort:       0.092688548

Karşılaştırma için, bu[-Photoshop]içinn=1_000_000:

Swift:            142.659763258
C:                0.162065333
Swift_sort:       114.095478272

Yani herhangi bir iyileştirme Hızlı gelişimi neredeyse 1000x bu aşamada bu kriter C, daha yavaş oldu. Öte yandan her iki Derleyiciler için ayarlanmış [-Ofast] Swift aslında C ' den biraz daha iyi değilse en azından iyi bir performans sergilemiş

O işaret edilmiştir [-Ofast] dilin semantiği, potansiyel olarak zararlı hale dönüşür. Bu böyle büyük mükafat 5.0 sürümü Apple Birleşik Devletleri notlar:

Yeni optimizasyon seviye Ofast, LLVM içinde kullanılabilir, agresif iyileştirmeler sağlar. -Ofast birçok kod için güvenli olan bazı muhafazakar kısıtlamalar, çoğunlukla kayan nokta işlemleri için, rahatlatır. Derleyici yüksek performans önemli galibiyet getirebilecek.

Ama hepsi bunu savunuyoruz. Olsun bu mantıklı ya da değil bilmiyorum, ama ne söyleyebilirim görünüyor yeterince makul kullanın [-Ofast] bir yayın ise yapmayacaksın yüksek duyarlıklı kayan nokta aritmetik ve emin hiçbir tamsayı veya bir dizi taşmaları Olası program. Eğer yüksek performans ihtiyacınız yoksave/ kesin aritmetik taşma Çek o zaman şimdilik başka bir dil seçin.

BETA 3 UPDATE:

n=10_000ile[-O]:

Swift:            0.019697268
C:                0.000718064
Swift_sort:       0.002094721

Genel olarak hızlı sıralama oldukça önemli ölçüde değişti biraz Swift-dahili görünüşe göre daha hızlı ve.

SON GÜNCELLEME:

[-Photoshop]:

Swift:   0.678056695
C:       0.000973914

[-O]:

Swift:   0.001158492
C:       0.001192406

[-Ounchecked]:

Swift:   0.000827764
C:       0.001078914

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Ciaran Blumenfeld

    Ciaran Blume

    20 NİSAN 2009
  • fireflame65

    fireflame65

    27 Mart 2007
  • Lena Danya

    Lena Danya

    11 NİSAN 2010