SORU
2 Aralık 2010, PERŞEMBE


C standart iostreams için düşük performans görevi yapar, ya da sadece kötü bir uygulama ile ilgili muyum?

Her zaman C standart kütüphane iostreams yavaş performans bahsettiğim, güvensizlik dalgası ile bir araya geldi. Henüz var profiler sonuçları gösteren büyük miktarda zaman harcanır iostream Kütüphanesi kod (tam derleyici en iyi duruma getirme) ve geçiş yapmasını iostreams OS-özel G/Ç API ve özel arabellek yönetimi yok ver bir sipariş büyüklüğü iyileştirme.

Ne ekstra işi C standart kütüphane yapıyor, bu standart tarafından gerekli ve pratikte işe yarar mı? Ya da bazı Derleyiciler manuel tampon yönetimi ile rekabetçi iostreams uygulamaları sağlar mı?

Kriterler

Önemli olan hareket etmek, kısa programlar birkaç iostreams iç tampon egzersiz için yazdım:

ostringstream stringbuf sürümleri çok daha yavaş oldukları için daha az tekrar çalıştırmak unutmayın.

İdeone, ostringstream * *12std:copy *11, *'den yaklaşık 3 kat daha yavaş ve ham bir tampona memcpy göre yaklaşık 15 kat daha yavaştır. Bu öncesi-sonrası özel tamponlama için benim gerçek uygulama açıldığında profil ile tutarlı hissediyor.

Bunlar tüm bellek arabellekleri, yani yavaşlık iostreams olamaz suçladı yavaş disk I/O, çok fazla kızarma, senkronizasyon istasyonu. ya da başka şeyler insanları kullanmak için bahane gözlenen yavaşlık C standart kütüphane iostream.

Olacağını görmek güzel kriterler diğer sistemleri ve yorum şeylere ortak uygulamaları yapmak (gibi gds'ler, kütüphanenin , Visual C , Intel C ) ve ne kadar yükü ise zorunlu standart.

Bu test için gerekçe

Bir kaç kişi doğru iostreams daha yaygın olarak biçimlendirilmiş çıkış için kullanılan işaret ettiler. Ancak, aynı zamanda sadece modern API ikili dosya erişimi için C standardı tarafından sağlanır. Ama gerçek nedeni için yaptığımız performans testlerinde iç tamponlama için geçerlidir tipik biçimlendirilmiş I/O: eğer iostreams alamazsınız disk denetleyicisi sağlanan ham veri, nasıl onlar muhtemelen takip zaman onlar sorumlu biçimlendirme de?

Kriter Zamanlama

Tüm bunlar (k) dış döngünün her yineleme için.

Üzerinde ideone (gcc-4.3.4, bilinmeyen OS ve donanım):

  • ostringstream: 53 milisaniye
  • stringbuf: 27 ms
  • vector<char> back_inserter: ile 17,6 ms
  • Sıradan yineleyici vector<char>: 10.6 ms
  • vector<char> yineleyici ve sınırları kontrol: 11.4 ms
  • char[]: 3.7 ms

Benim laptop (2010 86, cl /Ox /EHsc Windows 7 Ultimate 64-bit, Intel Core i7, 8 GB RAM, Visual C):

  • ostringstream:, 71.6 ms 73.4 milisaniye
  • stringbuf: 21.7 ms, ms 21.3
  • vector<char> back_inserter: 34, 6 ' lık ms, ms 34.4
  • Sıradan yineleyici vector<char>: 1.10 ms, ms tarafından 1,04
  • vector<char> ve kontrol yineleyici sınırları: 1.11 ms, 0.87, 1.12, 0.89, 1.02, 1.14 ms ms ms ms ms
  • char[]: 1.48 ms, ms 1.57

Visual C Profil-Güdümlü Optimizasyonu*, link /ltcg:pgi, *30 çalışacak, link /ltcg:pgo ölçü: 2010 86,

  • ostringstream: 61.2 ms, ms 60.5
  • Sıradan yineleyici ile vector<char>: tarafından 1,04 ms, ms 1.03

Aynı laptop, aynı OS, 4.3.4 g -O3: özellik listesi gcc kullanarak

  • ostringstream: 62.7 ms, ms 60.5
  • stringbuf: üzere 44, 4 ms, ms 44.5
  • vector<char> back_inserter: 13.5 ms, ms-13, 6 gibi
  • Sıradan yineleyici vector<char>:, 3.9 ms ms 4.1
  • vector<char> yineleyici ve sınırları kontrol: 4.0, ms, ms 4.0
  • char[]: 3.57 ms, ms 3.75

Aynı laptop, C 2008 SP1, cl /Ox /EHsc: Görsel

  • ostringstream: 88.7 ms, ms 87.6
  • stringbuf: ms 23.3, 23.4 ms
  • vector<char> back_inserter: 26.1 ms, ms 24.5
  • Sıradan yineleyici vector<char>: 3.13 ms, ms 2.48
  • vector<char> yineleyici ve sınırları kontrol: 2.97 ms, ms 2.53
  • char[]:, 1.25 ms ms 1.52

Aynı laptop, C 2010 64-bit derleyici: Visual

  • ostringstream: 48.6 ms, ms 45.0
  • stringbuf: 16.2 ms, ms 16.0
  • vector<char> back_inserter: 26.3 ms, ms 26,5 iken
  • Sıradan yineleyici vector<char>: 0.87 ms, ms 0.89
  • vector<char> yineleyici ve sınırları kontrol: 0.99 ms, ms 0.99
  • char[]: 1.25 ms, ms 1.24

EDİT: iki kere nasıl tutarlı sonuçlar olduğunu görmek için Koştu. Oldukça tutarlı IMO.

Benim laptop, ideone izin verdiğinden daha fazla CPU zaman ayırabilirim beri, tüm yöntemleri için 1000 tekrarlanma sayısını ayarlayın. NOT: Bu ostringstream ve sadece ilk geçişte yer alan 59 ** tahsisat, nihai sonuçlar üzerinde çok az etkisi olması gerektiği anlamına gelir.

DÜZENLEME: Oops, yineleyici gelişmiş değildi ve çok fazla önbellek isabet vardı bu nedenle vector--sıradan-yineleyici ile bir hata buldu. vector<char> char[] iyi performans nasıl diye merak etmiştim. , vector<char> hala char[] altında VC 2010 daha hızlı olmasına rağmen pek bir fark yoktu.

Sonuç

Çıkış akışları tampon saat veri eklenir her üç adım gerektirir:

  • Gelen blok kullanılabilir arabellek alanı uygun olduğunu kontrol edin.
  • Gelen blok kopyalayın.
  • -Uç veri işaretçisi güncelleştirin.

En son kod parçacığını ben, "vector<char> yineleyici basit artı" sadece bu, aynı zamanda ek alan ayırır ve gelen blok uymazsa, mevcut veri taşır. kontrol sınırları gönderildi Clifford belirttiği gibi, O sınıf/dosya tampon, sadece geçerli arabelleği temizleme ve yeniden o işi olmaz. Bu bir üst tampon çıkış maliyeti bağlı olmalı. Ve bellek içi çalışan bir tampon yapmak için gereken tam olarak bu.

Neden onu test ettiğimde ideone stringbuf 2.5 x daha yavaş, ve en az 10 kat daha yavaş? Bunu açıklamıyor bu yüzden bu basit polymorphically mikro kriter kullanılmasını değil.

CEVAP
2 Aralık 2010, PERŞEMBE


Sorunuzu başlık olarak çok ayrıntıya cevap: 2006 Technical Report on C Performance İOStreams (s.ilginç bir bölüm vardır 68). Sorunuza en uygun Bölüm 6.1.2 ("") Yürütme Hızı:

İOStreams işleme bazı yönlerini beri birden fazla yönü üzerinde dağıtılmış, Standart bir görev gibi görünüyor verimsiz bir uygulama. Bu ama — bazı formunu kullanarak değil önişleme, işi çok olabilir Kaçınılması. Biraz daha akıllı olan tipik olarak kullanılır Daha linker, mümkün bunlardan bazıları kaldırmak için verimsizlikleri. Bu tartışılan bir konu §6.2.3 ve madde 6.2.5.

Rapor 2006 yılında yazılmış bu yana tek tavsiyelerin çoğu mevcut Derleyiciler dahil olurdu umarım olur, ama belki de bu durum böyle değil.

Sizin de belirttiğiniz gibi, yönü write() (ama bu körü körüne kabul etmem) özelliği olmayabilir. Ne özelliği? ostringstream kodu GCC ile derlenmiş GProf çalışan verir aşağıdaki arıza:

  • std::basic_streambuf<char>::xsputn(char const*, int) 44.23%
  • std::ostream::write(char const*, int) 34.62%
  • main 12.50%
  • std::ostream::sentry::sentry(std::ostream&) 6.73%
  • std::string::_M_replace_safe(unsigned int, unsigned int, char const*, unsigned int) 0.96%
  • std::basic_ostringstream<char>::basic_ostringstream(std::_Ios_Openmode) 0.96%
  • std::fpos<int>::fpos(long long) 0.00%

Bu yüzden toplu zaman geçirdi xsputn hangi sonunda aramalar std::copy() sonra bir sürü kontrol ve güncelleme imleç pozisyonları ve tamponlar (bir bak c \bits\streambuf.tcc ayrıntılar).

Bu benim en kötü durum durum odaklanmış. Gerçekleştirilen tüm kontrol verileri oldukça büyük parçalar ile ilgili toplam işin küçük bir kısmı bitmiş olur. Ama kodu aynı anda dört bayt veri değiştirme, ve tüm ekstra maliyetleri her zaman erişebilirsiniz. Belli ki önlemek böylece gerçek bir durum düşünün ne kadar önemsiz cezası olurdu write adlı bir dizinin 1m in yerine 1 milyon kez bir int. Ve gerçek bir durumda bir çok İOStreams, yani bellek için güvenli ve emniyetli tip tasarımının önemli özellikleri seviniriz. Bu faydalar bir fiyata geliyor, ve bu maliyetler yürütme zamanı hakim kılan bir test yazdım.

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

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • Awesomesauce Network

    Awesomesauce

    4 EKİM 2012
  • GoogleTechTalks

    GoogleTechTa

    15 AĞUSTOS 2007
  • segtlim

    segtlim

    21 EKİM 2008