2016-01-28 29 views
6

Görüntü işleme algoritmaları geliştiriyorum (GCC kullanarak, ARMv7'yi hedefleme (Raspberry Pi 2B)).Hızlı arama/8 bitlik bir dizide eşleşen tek baytların yerine, ARM

void ChangeIndex(uint8_t * mask, size_t size, uint8_t oldIndex, uint8_t newIndex) 
{ 
    for(size_t i = 0; i < size; ++i) 
    { 
     if(mask[i] == oldIndex) 
      mask[i] = newIndex; 
    } 
} 

Ne yazık ki, hedef platformu için düşük performans göstermesi:

Özellikle ben maskeli endeksi değiştirir basit bir algoritma kullanır.

Optimize etmenin herhangi bir yolu var mı?

+1

değil daha hızlı olduğunu nasıl hemen açık - Eğer veriler hakkında daha fazla bilgi edinmek eğer hile olabilir - örneğin, içeren hücrelerin bir listesini olabilir 'X' değeri - ancak "isabet" sayısı oldukça düşük olduğunda bu gerçekten yararlıdır - eğer 'mask' eşleşen 'oldIndex'de çoğu girdiye isabet ediyorsanız, o zaman hızlanma olasılığı yoktur. Boyut nedir ve tablonun yüzde kaçının 'oldIndex 'değeri ortalamadadır? –

+0

Hangi derleyici seçeneklerini kullanıyorsunuz? NEON komutlarını ('-mfpu = neon-vfpv4', sanırım) kullanmak için talimat verdiğinizden emin olun, aksi halde NEON olmayan eski CPU'larla uyumlu kod üretiyor olabilirsiniz. – Gilles

+0

Ayrıca, üçlü operatör kullanılarak bir miktar hızlanma yapmalısınız: 'mask [i] = ([i] == oldIndex maskesi)? newIndex: mask [i]; ' – Miki

cevap

13

ARMv7 platformu, NEON adı verilen SIMD yönergelerini destekler. Bunların kullanımı ile Eğer daha hızlı kod yapabilirsiniz:

#include <arm_neon.h> 

void ChangeIndex(uint8_t * mask, size_t size, uint8_t oldIndex, uint8_t newIndex) 
{ 
    size_t alignedSize = size/16*16, i = 0; 

    uint8x16_t _oldIndex = vdupq_n_u8(oldIndex); 
    uint8x16_t _newIndex = vdupq_n_u8(newIndex); 

    for(; i < alignedSize; i += 16) 
    { 
     uint8x16_t oldMask = vld1q_u8(mask + i); // loading of 128-bit vector 
     uint8x16_t condition = vceqq_u8(oldMask, _oldIndex); // compare two 128-bit vectors 
     uint8x16_t newMask = vbslq_u8(condition, _newIndex, oldMask); // selective copying of 128-bit vector 
     vst1q_u8(mask + i, newMask); // saving of 128-bit vector 
    } 

    for(; i < size; ++i) 
    { 
     if(mask[i] == oldIndex) 
      mask[i] = newIndex; 
    } 
} 
+0

Algoritma sürümünüzü kontrol ettim. Orijinal versiyondan 5 kat daha hızlı çalışır. Bu harika! –

+0

"Maske + i" yerine "maske" işaretçisi ile doğrudan çalışarak daha küçük, hızlı bir gelişme elde edebilirsiniz. Önce uint8_t * maskEnd = mask + i; son noktanızı önceden hesaplayın, sonra döngüler için doğrudan işaretçinizle çalışacak şekilde değiştirin. 'için (; maske

+0

Muhtemelen Neon montajını doğrudan yazarak bunu daha da hızlandırabilirsiniz. IME GCC'nin Neon iç yapısı çok hızlı değil çünkü boru hattını durduran Neon ve ana siciller arasında eşya taşımaya devam ediyorlar. (Belki de onları en son kullandığımdan beri düzeltdiler.) –