Çeviri belleği kopyalamak için hızlı bir yöntem için OYNAYABİLİRSİNİZ TÜRLERİNİN | Netgez.com
SORU
24 Temmuz 2011, Pazar


Çeviri belleği kopyalamak için hızlı bir yöntem için OYNAYABİLİRSİNİZ TÜRLERİNİN

Genel bakış

Başka bir biçime dönüştürmek için ihtiyacım olan görüntü bir tampon var. Kökeni resim arabelleği Dört Kanal 8 kanal başına bit Alfa, Kırmızı, Yeşil ve Mavi. Hedef tampon üç kanal, 8 kanal başına bit, Mavi, Yeşil ve Kırmızı.

Kaba kuvvet yöntemi:

// Assume a 32 x 32 pixel image
#define IMAGESIZE (32*32)

typedef struct{ UInt8 Alpha; UInt8 Red; UInt8 Green; UInt8 Blue; } ARGB;
typedef struct{ UInt8 Blue; UInt8 Green; UInt8 Red; } BGR;

ARGB orig[IMAGESIZE];
BGR  dest[IMAGESIZE];

for(x = 0; x < IMAGESIZE; x  )
{
     dest[x].Red = orig[x].Red;
     dest[x].Green = orig[x].Green;
     dest[x].Blue = orig[x].Blue;
}

Ancak, bir döngü ve üç bayt kopyalar tarafından sağlanan daha fazla hıza ihtiyacım var. Bellek sayısı okur ve yazar azaltmak için, 32 bit bir makinede çalışan olduğum düşünülürse kullanabileceğim birkaç numara olabileceğini umuyorum.

Ek bilgi

Her resim en az 4 piksel katı. 16 TÜRLERİNİN bayt adres ve döngü başına 12 RGB bayt içine taşıyın. Belki de bu gerçek, özellikle güzel 32 bit sınırları içine düşer gibi şeyleri hızlandırmak için kullanılabilir.

Ben erişmek için Filmler - ve süre gerektirir hareketli tüm tampona GPU, bellek, hareket sonucu geri dışarı, aslında bu Filmler üzerinde çalışabilirsiniz kaç porsiyon görüntü aynı anda, hem de büyük bir bellek bloğu hamle aslında oldukça verimli olabilir bu çok değerli bir keşif.

Süre verebileceğim örnek küçük arabellekleri yukarıda, gerçekten hareketli HD video (1920 x 1080) ve bazen daha büyük, çoğunlukla daha küçük, tamponlar etrafında, o sırada 32 x 32 durum olabilir önemsiz, kopyalama 8.3 MB görüntü veri bayt bayt gerçekten, gerçekten kötü.

Çalışan Intel işlemci (Core 2 ve üstü) ve böylece orada akışı ve veri işleme komutları bildiğim kadarıyla yok, ama bilmiyorum - belki işaretçileri yere bakmak için özel veri işleme talimatları iyi olurdu.

Bu OS X bir uygulama içine gidiyor, ve böyle büyük mükafat 4 kullanıyorum. Montaj ağrısız ve açık bir yol varsa, bu yol aşağı Seyahat iyiyim ama bu Kur üzerinde daha önce yapmadığı beni içine çok fazla zaman batan dikkatli yapar.

Pseudo-code, ince komple bir çözüm, algoritma ve hemen belli olmayabilir herhangi bir hile bir açıklama sadece aramıyorum.

CEVAP
24 Temmuz 2011, Pazar


Bayt takas çalışan 4 farklı versiyon yazdım. -O3 -mssse3 10 kez koştu ile gcc 4.2.1 onları kullanarak rastgele veri 32 MB üzerinde derlenmiş ve ortalamalar bulundu.

İlk sürümü C döngü her piksel ayrı ayrı dönüştürmek için OSSwapInt32 işlevi -O3 11 *bir talimat derler) kullanır.

void swap1(ARGB *orig, BGR *dest, unsigned imageSize) {
    unsigned x;
    for(x = 0; x < imageSize; x  ) {
        *((uint32_t*)(((uint8_t*)dest) x*3)) = OSSwapInt32(((uint32_t*)orig)[x]);
    }
}

İkinci yöntem, aynı işlemi gerçekleştirir, ama C döngüsü yerine satır içi derleme bir döngü kullanır.

void swap2(ARGB *orig, BGR *dest, unsigned imageSize) {
    asm (
        "0:\n\t"
        "movl   (%1),%êx\n\t"
        "bswapl %êx\n\t"
        "movl   %êx,(%0)\n\t"
        "addl   $4,%1\n\t"
        "addl   $3,%0\n\t"
        "decl   %2\n\t"
        "jnz    0b"
        :: "D" (dest), "S" (orig), "c" (imageSize)
        : "flags", "eax"
    );
}

Üçüncü sürüm just a poseur's answer modifiye edilmiş bir versiyonu. Giriş bağımsız değişkeni uyumlu olması gerekmez, böylece GCC benzerleri için yerleşik işlevleri çevirdim ve lddqu yerleşik işlevi kullanılır.

typedef uint8_t v16qi __attribute__ ((vector_size (16)));
void swap3(uint8_t *orig, uint8_t *dest, size_t imagesize) {
    v16qi mask = __builtin_ia32_lddqu((const char[]){3,2,1,7,6,5,11,10,9,15,14,13,0xFF,0xFF,0xFF,0XFF});
    uint8_t *end = orig   imagesize * 4;
    for (; orig != end; orig  = 16, dest  = 12) {
        __builtin_ia32_storedqu(dest,__builtin_ia32_pshufb128(__builtin_ia32_lddqu(orig),mask));
    }
}

Son olarak, dördüncü sürümü üçüncü satır içi derleme eşdeğerdir.

void swap2_2(uint8_t *orig, uint8_t *dest, size_t imagesize) {
    int8_t mask[16] = {3,2,1,7,6,5,11,10,9,15,14,13,0xFF,0xFF,0xFF,0XFF};//{0xFF, 0xFF, 0xFF, 0xFF, 13, 14, 15, 9, 10, 11, 5, 6, 7, 1, 2, 3};
    asm (
        "lddqu  (%3),%%xmm1\n\t"
        "0:\n\t"
        "lddqu  (%1),%%xmm0\n\t"
        "pshufb %%xmm1,%%xmm0\n\t"
        "movdqu %%xmm0,(%0)\n\t"
        "add    $16,%1\n\t"
        "add    $12,%0\n\t"
        "sub    $4,%2\n\t"
        "jnz    0b"
        :: "r" (dest), "r" (orig), "r" (imagesize), "r" (mask)
        : "flags", "xmm0", "xmm1"
    );
}

2010 MacBook Pro, 2.4 ı5, 4GB RAM, Ghz, bunların her biri için ortalama zamanlar:

Version 1: 10.8630 milliseconds
Version 2: 11.3254 milliseconds
Version 3:  9.3163 milliseconds
Version 4:  9.3584 milliseconds

Gördüğünüz gibi, derleyici derleme yazmana gerek yok optimizasyonu yeterince iyi. Ayrıca, vektör fonksiyonları sadece 1,5 milisaniye daha hızlı veri 32 MB vardı, eğer SSSE3 desteği yoktu olan ilk Intel Mac'ler, destek olmak istiyorsanız fazla zarar vermesinler diye.

Edit: liori standart sapma bilgi istedi. Ne yazık ki, veri noktaları kurtardı etmemiştim, 25 yineleme ile başka bir test yaptım.

              Average    | Standard Deviation
Brute force: 18.01956 ms | 1.22980 ms (6.8%)
Version 1:   11.13120 ms | 0.81076 ms (7.3%)
Version 2:   11.27092 ms | 0.66209 ms (5.9%)
Version 3:    9.29184 ms | 0.27851 ms (3.0%)
Version 4:    9.40948 ms | 0.32702 ms (3.5%)

Ayrıca, burada herkes istediği durumda yeni test, ham veri. Her yineleme için, 32 MB veri kümesi rasgele oluşturulmuş ve dört fonksiyonları ile çalıştırıldı. Mikrosaniye her fonksiyonun çalışma zamanı aşağıda listelenmiştir.

Brute force: 22173 18344 17458 17277 17508 19844 17093 17116 19758 17395 18393 17075 17499 19023 19875 17203 16996 17442 17458 17073 17043 18567 17285 17746 17845
Version 1:   10508 11042 13432 11892 12577 10587 11281 11912 12500 10601 10551 10444 11655 10421 11285 10554 10334 10452 10490 10554 10419 11458 11682 11048 10601
Version 2:   10623 12797 13173 11130 11218 11433 11621 10793 11026 10635 11042 11328 12782 10943 10693 10755 11547 11028 10972 10811 11152 11143 11240 10952 10936
Version 3:    9036  9619  9341  8970  9453  9758  9043 10114  9243  9027  9163  9176  9168  9122  9514  9049  9161  9086  9064  9604  9178  9233  9301  9717  9156
Version 4:    9339 10119  9846  9217  9526  9182  9145 10286  9051  9614  9249  9653  9799  9270  9173  9103  9132  9550  9147  9157  9199  9113  9699  9354  9314

Bunu PaylaÅŸ:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VÄ°DEO

Rastgele Yazarlar

  • campos9896

    campos9896

    24 Mart 2012
  • george sarintzotis

    george sarin

    2 Aralık 2007
  • vgeller1

    vgeller1

    22 Kasım 2009