Daha hızlı işlemciler / saatler daha fazla kod yürütebilir mi?


9

16Mhz'de çalışan bir ATmega 328 üzerinde çalışacak bir program yazıyorum (eğer bunları biliyorsanız bir Arduino Duemilanove, bir AVR yongası).

Her 100 mikrosaniyede bir kesinti sürecim var. 100 mikrosaniyelik bir döngüde ne kadar "kod" çalıştırabileceğinizi söylemek imkansızdır (muhtemelen C'ye yazıyorum ki montajdan sonra ikili bir görüntüye dönüştürülüyor mu?).

Ayrıca bu, kodun karmaşıklığına da bağlıdır (dev bir astar, örneğin birkaç kısa satırdan daha yavaş çalışabilir).

Anladığım doğru mu, saat hızı veya 16Mhz olan işlemcimin saniyede 16 milyon döngü gerçekleştirmesi (mikrosaniye başına 16 döngü 16.000.000 / 1.000 / 1.000 anlamına gelir); Ve böylece, 100 mikrosaniye döngümde daha fazlasını yapmak istersem, 72Mhz sürümü gibi daha hızlı bir model satın almak bana mikrosaniye başına 72 döngü (72.000.000 / 1.000 / 1.000) verir mi?

Şu anda biraz fazla yavaş çalışıyor, yani döngüyü yapmak için 100 mikrosaniyeden biraz daha uzun sürüyor (tam olarak ne kadar uzun olduğunu söylemek zor, ama kademeli olarak geride kalıyor) ve biraz daha fazlasını yapmak istiyorum, Bu daha hızlı bir çip almak aklı başında bir yaklaşım mı yoksa delirdim mi?


.... ATmega328 bir ARM yongası DEĞİLDİR. Bu bir AVR.
vicatcu

Şerefe, düzeltildi!
jwbensley

Yanıtlar:


9

Genel olarak, cihazın saniyede gerçekleştirebileceği montaj talimatı sayısı, talimat karışımına ve her talimat tipinin kaç döngüde (CPI) yürüteceğine bağlı olacaktır. Teorik döngüde, demonte asm dosyasına bakarak ve endişelendiğiniz işleve bakarak, içindeki tüm farklı talimat türlerini sayarak ve hedef işlemcinizin veri sayfasından döngü sayılarına bakarak kodunuzu sayabilirsiniz.

Saniyede etkili talimat sayısını belirleme problemi, daha karmaşık işlemcilerde boru hatlarına sahip olmaları ve önbelleklere sahip olmaları ve neyin olmaması nedeniyle daha da artmaktadır. Bu, uçuş işlemcisinde tek bir talimat olan ATMega328 gibi basit bir cihaz için geçerli değildir.

Pratik konulara gelince, bir AVR gibi basit bir cihaz için cevabım aşağı yukarı "evet" olacaktır. Saat hızınızı ikiye katlamak, verilen herhangi bir işlevin yürütme süresinin yarısı kadar olmalıdır. Bununla birlikte, bir AVR için, 20MHz'den daha hızlı çalışmazlar, bu nedenle Arduino'nuzu sadece başka bir 4MHz ile "overclock edebilirsiniz".

Bu tavsiye etmez değil daha gelişmiş özelliklere sahip bir işlemciye genelleme. Intel işlemcinizde saat hızını ikiye katlamak, pratikte saniyede yürüttüğü komut sayısını iki katına çıkarmayacaktır (şube yanlış tahminleri, önbellek özledikleri vb. Nedeniyle).


Merhaba, bilgilendirici yanıtınız için teşekkürler! Bunlardan birini gördüm ( coolcomponents.co.uk/catalog/product_info.php?products_id=808 ), bir AVR'nin 20Mhz'den daha hızlı gidemeyeceğini söylediniz, neden bu? Yukarıdaki tahtadaki çip ( uk.farnell.com/stmicroelectronics/stm32f103rbt6/… ) 72Mhz ARM, yukarıda açıkladığım şekilde bundan makul bir performans artışı bekleyebilir miyim?
jwbensley

2
İşleme hızı iki katına olmayabilir Eğer talimatlar flaş getirilen olabilir hızını aşması başlayabilir olarak üretilen iş sizin talimat artırır. Bu noktada, komutun flaştan gelmesini beklerken CPU'nun durakladığı yerde "Flaş bekleme durumlarına" basmaya başlarsınız. Bazı mikro denetleyiciler, FLASH'dan çok daha hızlı olan RAM'den kod yürütmenize izin vererek bunu tamamlar.
Majenko

@Majenko: komik, ikimiz de aynı noktayı aynı anda yaptık.
Jason S

Bu olur ... seninki benimkinden daha iyi :)
Majenko

1
Tamam, Vicatcu'nun cevabını "cevap" olarak işaretledim. Performansla ilgili orijinal hız sorunum için en uygun olduğunu düşünüyorum, ancak tüm cevaplar harika ve herkesin cevaplarından gerçekten memnunum. Bana bunun ilk fark ettiğimden daha geniş bir konu olduğunu gösterdiler ve bu yüzden hepsi bana çok şey öğretiyor ve bana araştırmaya çok şey
veriyorlar

8

@ vicatcu'nun cevabı oldukça kapsamlı. Dikkat edilmesi gereken bir diğer şey, CPU'nun program ve veri belleği de dahil olmak üzere G / Ç'ye erişirken bekleme durumlarına (durmuş CPU döngüleri) girebilmesidir .

Örneğin, bir TI F28335 DSP kullanıyoruz; RAM'in bazı alanları program ve veri belleği için 0-bekleme durumudur, bu nedenle RAM'de kod çalıştırdığınızda, komut başına 1 döngüde çalışır (1 döngüden fazla süren talimatlar hariç). Ancak FLASH bellekten (dahili EEPROM, daha fazla veya daha az) kod çalıştırdığınızda, tam 150MHz'de çalışamaz ve birkaç kat daha yavaştır.


Yüksek hızlı kesme koduyla ilgili olarak, bir dizi şey öğrenmelisiniz.

İlk olarak, derleyicinize çok aşina olun. Derleyici iyi bir iş çıkarıyorsa, çoğu şey için elle kodlanmış montajdan çok daha yavaş olmamalıdır. (burada "çok daha yavaş": 2 faktörü benim için uygun olurdu; 10 faktörü kabul edilemez olacaktır) Derleyici optimizasyon bayraklarını nasıl (ve ne zaman) kullanacağınızı ve arada bir bakmanız gerekir nasıl olduğunu görmek için derleyicinin çıktısında.

Kodu hızlandırmak için derleyicinin yapabileceği diğer bazı şeyler:

  • satır içi işlevleri kullanın (C'nin bunu destekleyip desteklemediğini veya yalnızca bir C ++ - ism olup olmadığını hatırlayamayın), hem küçük işlevler hem de yalnızca bir veya iki kez yürütülecek işlevler için. Dezavantajı, özellikle derleyici optimizasyonu açıksa satır içi işlevlerin hatalarını ayıklamak zordur. Ancak, özellikle "işlev" soyutlaması kod uygulaması yerine kavramsal tasarım amaçları içinse, gereksiz çağrı / dönüş dizilerini kurtarırlar.

  • Kendine özgü işlevlere sahip olup olmadığını görmek için derleyicinizin kılavuzuna bakın - bunlar doğrudan işlemcinin montaj talimatlarıyla eşleşen derleyiciye bağlı yerleşik işlevlerdir; bazı işlemciler, min / max / bit ters gibi faydalı şeyler yapan montaj talimatlarına sahiptir ve bunu yaparken zaman kazanabilirsiniz.

  • Sayısal hesaplama yapıyorsanız, matematik kitaplığı işlevlerini gereksiz yere çağırmamaya dikkat edin. Kodun y = (y+1) % 44 periyodu olan bir sayaç için olduğu gibi bir derleyici vardı, derleyicinin modulo 4'ü bitsel-AND olarak uygulamasını bekliyor. Bunun yerine matematik kütüphanesini çağırdı. Böylece y = (y+1) & 3istediğimizi yapmak için yerini aldık.

  • Biraz dönen hackler sayfasına aşina olun . Bunlardan en az birini sık sık kullanacağınızı garanti ederim.

Kod yürütme süresini ölçmek için CPU'nuzun zamanlayıcı çevre birimlerini de kullanmalısınız - çoğunda CPU saat frekansında çalışacak şekilde ayarlanabilen bir zamanlayıcı / sayaç vardır. Kritik kodunuzun başında ve sonunda sayacın bir kopyasını yakalayın ve ne kadar sürdüğünü görebilirsiniz. Bunu yapamazsanız, başka bir alternatif kodunuzun başlangıcında bir çıkış pinini düşürmek ve sonunda yükseltmek ve yürütmeyi zamanlamak için bir osiloskopta bu çıkışa bakmaktır. Her bir yaklaşım için dengesizlikler vardır: dahili zamanlayıcı / sayaç daha esnektir (birkaç şeyi zamanlayabilirsiniz), ancak bilgiyi elde etmek daha zordur, oysa bir çıkış pimini ayarlamak / silmek bir kapsamda hemen görülebilir ve istatistikleri yakalayabilirsiniz, ancak birden fazla olayı ayırt etmek zor.

Son olarak, hem genel hem de özel işlemci / derleyici kombinasyonları ile deneyim ile gelen çok önemli bir beceri vardır: ne zaman ve ne zaman optimize edilmeyeceğini bilmek . Genel olarak cevap optimize etmektir. Donald Knuth alıntısı StackOverflow'da sıklıkla yayınlanır (genellikle sadece son kısım):

Zamanın yaklaşık% 97'sini küçük verimlilikleri unutmalıyız: erken optimizasyon tüm kötülüklerin köküdür

Ancak, bir çeşit optimizasyon yapmanız gerektiğini bildiğiniz bir durumdasınız, bu yüzden mermiyi ısırmanın ve optimize etmenin (veya daha hızlı bir işlemcinin veya her ikisinin birden) zamanı. Do DEĞİL montaj içinde tüm ISR yazın. Bu neredeyse garantili bir felaket - bunu yaparsanız, aylar veya haftalar içinde yaptığınız şeyin ve nedeninin parçalarını unutacaksınız ve kodun çok kırılgan ve değiştirilmesi zor olacak. Ancak, kodunuzun bölümlerini olması muhtemeldir vardır vardır montaj için iyi bir aday.

Kodunuzun bazı bölümlerinin montaj kodlaması için uygun olduğunu gösteren işaretler:

  • iyi etkilenmeyen, iyi tanımlanmış küçük rutinleri içeren işlevler
  • belirli montaj talimatlarını kullanabilen fonksiyonlar (min / maks / sağ kaydırma / vb.)
  • defalarca çağrılan işlevler (sizi çarpanı alır: her çağrıda 0,5usec kaydederseniz ve 10 kez çağrılırsanız, bu da sizin durumunuzda önemli olan 5 usec tasarruf sağlar)

Derleyicinizin işlev çağırma kurallarını (örneğin, bağımsız değişkenleri kayıtlara koyduğu yeri ve hangi kayıtları kaydettiğini / geri yüklediğini) öğrenin, böylece C tarafından çağrılabilir montaj yordamları yazabilirsiniz.

Mevcut projemde, 10kHz'lik bir kesmede (100usec - ses tanıdık?) Çalıştırılması gereken kritik kodlu oldukça büyük bir kod tabanına sahibiz ve montajda yazılmış pek çok işlev yok. Bunlar, CRC hesaplaması, yazılım kuyrukları, ADC kazanç / ofset telafisi gibi şeylerdir.

İyi şanslar!


yürütme süresi ölçüm teknikleri hakkında iyi tavsiyeler
vicatcu

Sorum için bir başka harika cevap, bu harika bilgi yığını için çok teşekkürler Jason S! Bunu okuduktan sonra görünen iki şey; İlk olarak, kodun yürütülmesi için daha fazla zaman vermek için her 100uS'den 500uS'ye kadar olan kesmeyi artırabilirim, şimdi bunun bu kadar hızlı olmama gerçekten fayda sağlamadığını anlıyorum. İkincisi, benim kod belki çok verimsiz düşünüyorum, daha uzun kesme süresi ve daha iyi kod ile tüm iyi olabilir. Stackoverflow kodu göndermek için daha iyi bir yer, bu yüzden orada bir mesaj ve burada bir bağlantı koymak, kimse bir göz atın ve herhangi bir öneri yapmak istiyorsa lütfen yapın: D
jwbensley

5

Dikkat edilmesi gereken başka bir şey - muhtemelen kodunuzu daha verimli hale getirmek için yapabileceğiniz bazı optimizasyonlar vardır.

Örneğin - bir zamanlayıcı kesintisi içinde çalışan bir rutin var. Rutin 52µS içinde tamamlanmalı ve bunu yaparken büyük miktarda hafızadan geçmelidir.

Ana sayaç değişkenini bir sicile kilitleyerek (µC ve derleyicimde - sizinki için farklı) büyük bir hız artışı başardım:

register unsigned int pointer asm("W9");

Derleyicinizin biçimini bilmiyorum - RTFM, ancak montaja geçmek zorunda kalmadan rutininizi daha hızlı hale getirmek için yapabileceğiniz bir şey olacak.

Bunu söyledikten sonra, rutininizi derleyiciden daha iyi hale getirmede çok daha iyi bir iş yapabilirsiniz, bu yüzden montaja geçmek size bazı büyük hız artışları sağlayabilir.


lol ben "aynı anda" montajcı ayarlama ve kayıt tahsisi hakkında kendi cevabımı yorumladı :)
vicatcu

16 MHz'lik bir işlemcide 100us kullanıyorsa - açıkçası oldukça büyük, bu yüzden optimize etmek için bir sürü kod var. Bugün derleyicilerin elle optimize edilmiş montajdan yaklaşık 1.1 kat daha fazla kod ürettiğini duydum. Tamamen böyle büyük bir rutin için buna değer değil. 6 satır fonksiyonunda% 20 tıraş için, belki de ...
DefenestrationDay

1
Mutlaka değil ... Bir döngüde sadece 5 satır kod olabilir. Kod boyutu değil, kod verimliliği ile ilgili . Kodu farklı şekilde yazarak daha hızlı çalışmasını sağlayabilirsiniz. Kesinti rutinim için biliyorum. Örneğin, hız için büyüklükten ödün vermek. Aynı kodu 10 kez sırayla çalıştırarak, döngü ve ilişkili sayaç değişkenleri için kod alma zamanından tasarruf edersiniz. Evet, kod 10 kat daha uzun, ancak daha hızlı çalışıyor.
Majenko

Merhaba Majenko, montajı bilmiyorum ama öğrenmeyi düşünüyordum ve Arduino'nun masaüstü bilgisayarımdan daha az karmaşık olacağını düşünüyordum, bu yüzden özellikle öğrenmek istediğim gibi öğrenmek için iyi bir zaman olabilir olup bitenler hakkında daha fazla bilgi ve daha düşük bir seviye. Diğerlerinin söylediği gibi, her şeyi sadece belirli bölümlere yeniden yazmam. Anladığım kadarıyla, C içinde ASM'ye girip çıkabiliyorum, bu doğru mu? Genel bir fikirden hemen sonra, ayrıntılar için stackoverflow'da yayınlayacağım.
jwbensley

@javano: Evet. C içinde ASM'ye girip çıkabilirsiniz. Birçok gömülü sistem - C ve montaj karışımında - böyle yazılmıştır, çünkü esas olarak mevcut ilkel C derleyicilerinde yapılamayan birkaç şey vardı. saati. Bununla birlikte, gcc (Arduino tarafından kullanılan derleyici) gibi modern C derleyicileri artık montaj dilini gerektiren şeylerin çoğunu ve çoğu durumda işliyor.
davidcary
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.