Burada, std::copyhafif, 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, memcpysü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 *( Tkullanı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::copyMD5 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::copyTekrar 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::copyperformans 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::copyargü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, memcpyyasal olduğunda , std::copydaha kötü bir performans göstermemesi gerektiği anlamına gelir . Önemsiz uygulama std::copyolduğ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::copydaha 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_tgeç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::copyilginç bir konumda. memcpyHerhangi bir modern optimizasyon derleyici ile asla daha yavaş ve bazen daha hızlı olmasını bekliyorum . Üstelik yapabildiğiniz her şeyi memcpyyapabilirsiniz std::copy. memcpytamponlarda herhangi bir üst üste binmeye izin vermezken, std::copydestekler bir yönde üst üste binmeyi destekler ( std::copy_backwarddiğer üst üste binme yönüyle birlikte). memcpyYalnızca, işaretçiler çalışır std::copyherhangi Yineleyicilerin çalışır ( std::map, std::vector, std::deque, veya kendi özel tip). Başka bir deyişle, sadece std::copyveri yığınlarını kopyalamanız gerektiğinde kullanmalısınız .
charUygulamaya bağlı olarak imzalı veya imzasız olabileceğini unutmayın . Bayt sayısı> = 128 ise,unsigned charbayt dizileriniz için kullanın . ((int *)Oyuncular da daha güvenli olurdu(unsigned int *).)