Burada, std::copy
hafif, neredeyse algılanamayan bir performans kaybına sahip olacak genel bilgeliğe karşı çıkacağım. Sadece bir test yaptım ve yanlış olduğunu gördüm: Bir performans farkı fark ettim. Ancak kazanan oldu std::copy
.
Bir C ++ SHA-2 uygulaması yazdım. Testimde, dört SHA-2 sürümünü (224, 256, 384, 512) kullanarak 5 dize hash alıyorum ve 300 kez döngü yapıyorum. Boost.timer kullanarak zamanı ölçüyorum. Bu 300 loop sayacı sonuçlarımı tamamen stabilize etmek için yeterli. Testi, memcpy
sürüm ve sürüm arasında dönüşümlü olarak 5 kez çalıştırdım std::copy
. Kodum, verileri olabildiğince büyük yığınlardan yakalama avantajından yararlanır (diğer birçok uygulama char
/ ile çalışır char *
, oysa T
/ ile çalışırım T *
( T
kullanıcının uygulamasında doğru taşma davranışına sahip en büyük türdür), bu nedenle hızlı bellek erişimi yapabileceğim en büyük tipler algoritmamın performansında çok önemli.
SHA-2 testlerinin tamamlanma süresi (saniye olarak)
std::copy memcpy % increase
6.11 6.29 2.86%
6.09 6.28 3.03%
6.10 6.29 3.02%
6.08 6.27 3.03%
6.08 6.27 3.03%
Standart hızdaki ortalama ortalama artış :: memcpy üzerinden kopya:% 2.99
Derleyicim Fedora 16 x86_64 üzerinde gcc 4.6.3. Optimizasyon bayraklarım -Ofast -march=native -funsafe-loop-optimizations
.
SHA-2 uygulamalarım için kod.
MD5 uygulamam üzerinde de bir test yapmaya karar verdim. Sonuçlar çok daha az kararlıydı, bu yüzden 10 koşu yapmaya karar verdim. Ancak, ilk birkaç denememden sonra, bir koşudan diğerine çılgınca değişen sonuçlar aldım, bu yüzden bir tür işletim sistemi faaliyeti olduğunu tahmin ediyorum. Başlamaya karar verdim.
Aynı derleyici ayarları ve bayrakları. MD5'in yalnızca bir sürümü var ve SHA-2'den daha hızlı, bu yüzden benzer 5 test dizisi üzerinde 3000 döngü yaptım.
Bunlar benim son 10 sonuç:
MD5 testlerinin tamamlanma süresi (saniye olarak)
std::copy memcpy % difference
5.52 5.56 +0.72%
5.56 5.55 -0.18%
5.57 5.53 -0.72%
5.57 5.52 -0.91%
5.56 5.57 +0.18%
5.56 5.57 +0.18%
5.56 5.53 -0.54%
5.53 5.57 +0.72%
5.59 5.57 -0.36%
5.57 5.56 -0.18%
Standart hızdaki ortalama ortalama azalma :: memcpy üzerinden kopyalama:% 0.11
MD5 uygulamam için kod
Bu sonuçlar, std::copy
MD5 testlerimde kullanamadığım SHA-2 testlerimde kullanılan std :: copy'ın bazı optimizasyonları olduğunu göstermektedir . SHA-2 testlerinde, her iki dizi std::copy
/ adında aynı işlevle oluşturuldu memcpy
. MD5 testlerimde dizilerden biri işleve bir işlev parametresi olarak iletildi.
std::copy
Tekrar hızlandırmak için neler yapabileceğimi görmek için biraz daha test yaptım . Yanıtın basit olduğu ortaya çıktı: bağlantı süresi optimizasyonunu açın. Bunlar LTO açıkken sonuçlarım (gcc'de -flto seçeneği):
-Flto ile MD5 testlerinin tamamlanma süresi (saniye olarak)
std::copy memcpy % difference
5.54 5.57 +0.54%
5.50 5.53 +0.54%
5.54 5.58 +0.72%
5.50 5.57 +1.26%
5.54 5.58 +0.72%
5.54 5.57 +0.54%
5.54 5.56 +0.36%
5.54 5.58 +0.72%
5.51 5.58 +1.25%
5.54 5.57 +0.54%
Standart hızdaki ortalama ortalama artış :: Memcpy üzerinden kopyalama:% 0,72
Özetle, kullanım için bir performans cezası yok gibi görünüyor std::copy
. Aslında, bir performans kazancı var gibi görünüyor.
Sonuçların açıklaması
Öyleyse neden std::copy
performans artışı sağlayabilir ?
İlk olarak, satır içi optimizasyon açık olduğu sürece herhangi bir uygulama için daha yavaş olmasını beklemezdim. Tüm derleyiciler agresif olarak satır içi; diğer birçok optimizasyonu mümkün kıldığı için muhtemelen en önemli optimizasyondur. std::copy
argümanların önemsiz şekilde kopyalandığını ve belleğin sırayla düzenlendiğini tespit edebilir (ve tüm gerçek dünya uygulamalarından şüpheleniyorum). Bu, en kötü durumda, memcpy
yasal olduğunda , std::copy
daha kötü bir performans göstermemesi gerektiği anlamına gelir . Önemsiz uygulama std::copy
olduğunu ertelemektedir için memcpy
"her zaman satır içi bu hız veya boyut için optimize ederken" tutarındaki derleyici'nın kriterlerini karşılamalıdır.
Ancak, std::copy
daha fazla bilgi tutar. Aradığınızda std::copy
, işlev türleri sağlam tutar. memcpy
çalışır void *
hangi silip mevcut neredeyse tüm yararlı bilgiler. Örneğin, bir diziden std::uint64_t
geçersem, derleyici veya kütüphane uygulayıcısı 64 bit hizalamadan yararlanabilir std::copy
, ancak bunu yapmak daha zor olabilir memcpy
. Bunun gibi birçok algoritma uygulaması önce aralığın başında hizalanmamış kısım, daha sonra hizalanmış kısım, daha sonra sonda hizalanmamış kısım üzerinde çalışarak çalışır. Tümünün hizalanması garanti edilirse, kod daha basit ve daha hızlı hale gelir ve işlemcinizdeki dal öngörücüsünün doğru olması daha kolay hale gelir.
Erken optimizasyon?
std::copy
ilginç bir konumda. memcpy
Herhangi bir modern optimizasyon derleyici ile asla daha yavaş ve bazen daha hızlı olmasını bekliyorum . Üstelik yapabildiğiniz her şeyi memcpy
yapabilirsiniz std::copy
. memcpy
tamponlarda herhangi bir üst üste binmeye izin vermezken, std::copy
destekler bir yönde üst üste binmeyi destekler ( std::copy_backward
diğer üst üste binme yönüyle birlikte). memcpy
Yalnızca, işaretçiler çalışır std::copy
herhangi Yineleyicilerin çalışır ( std::map
, std::vector
, std::deque
, veya kendi özel tip). Başka bir deyişle, sadece std::copy
veri yığınlarını kopyalamanız gerektiğinde kullanmalısınız .
char
Uygulamaya bağlı olarak imzalı veya imzasız olabileceğini unutmayın . Bayt sayısı> = 128 ise,unsigned char
bayt dizileriniz için kullanın . ((int *)
Oyuncular da daha güvenli olurdu(unsigned int *)
.)