Arduino / AVR'daki kod için saat döngülerini izleyin?


11

Bir kod bloğunu izlemek ve bir Arduino ve / veya AVR atmel işlemcisinde kodun aldığı işlemci saat döngülerinin sayısını belirlemek mümkün müdür? veya kod çalıştırmadan önce ve sonra geçen mikrosaniyeleri izlemeli miyim? Not: "Bu kodun CPU'dan kaç saat döngüsü gerektirdiği" kadar gerçek zamanlı (kaç gerçek saniye geçtiği gibi) ile ilgilenmiyorum

Ben gelebilir mevcut çözüm zaman c.

#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )

wiring.c ekler:

#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )

Bu hesap ile geçen mikrosaniye izleyerek geçen saat cyles hesaplamak ve daha sonra bu microsecondsToClockCycles () iletmek olabilir. Sorum şu, daha iyi bir yol var mı?

Sidenote: AVR'nin performans izlemesi için iyi kaynaklar var mı? lmgtfy.com ve çeşitli forum aramaları zamanlayıcıların keşfi dışında belirgin sonuçlar vermez

Teşekkürler

Yanıtlar:


6

En basit yöntem, kodunuzun zamanlamak istediğiniz kodu çalıştırmadan önce bir miktar yukarı çekmesini ve her şeyi bitirdikten sonra alçalmasını sağlamaktır. Daha sonra kod döngüsünü yapın (veya tek çekim modunda hafızalı dijital osiloskop kullanın) ve sadece kapsam yapın ve sabitleyin. Nabzın uzunluğu, kod parçasının ve bir saat döngüsünün pim durumunu değiştirmesinin ne kadar sürdüğünü gösterir (sanırım bir döngü alır,% 100 emin değilim).


Teşekkürler. Evet, bunun muhtemelen en doğru çözüm olduğunu görebiliyorum. Hala bana kod içinde genel döngü kullanımı analizi bile verecek kod uzakta chucking. Bazı test araçları oluşturmak için bunu kullanacağım ve kodun ne kadar verimli bir şekilde çalıştığına bağlı olarak maksimum izin verilen çalışma süresi gibi parametreler için üst sınırlarımı ayarlamak iyi olurdu. kullanımı
cyphunk

4

"Monitör" ile ne demek istiyorsun?

Küçük montaj kodu parçaları için AVR için saat döngülerini saymak zor olmamalıdır.

Ayrıca kod yürütülmeden önce bir bağlantı noktası ayarlayabilir ve daha sonra sıfırlayabilir ve zamanlamayı almak için bir mantık analizörü veya bir oszilloskop ile izleyebilirsiniz.

Ayrıca, söylediğiniz gibi, hızlı çalışan bir zamanlayıcıdan zamanı da okuyabilirsiniz.


Monitöre göre, kod tarafından kullanılan döngü sayısını belirler. gibi bir şey (not, kodun biçimlendirilmesi muhtemelen yorum motoru tarafından düzleştirilecektir): clocks = startCountingAtmegaClocks (); for ... {for ... {digitalRead ...}} Seri.print ("kullanılan döngü sayısı:"); Serial.print (currentCountingAtmegaClocks () - saatler, DEC);
cyphunk

Ama evet, cevabınız seçeneklerim olduğunu düşündüğüm şey. Sanırım, montajcının elle alacağı saat döngülerini hesaplayabiliyorsam, belki de birisinin bunu zaten programlı olarak yapmak için bazı güzel kodlar
yazdığını varsayabilirim

3

Bu, geçen saatleri hesaplamak için clockCyclesPerMicrosecond () işlevini kullanan Arduino için bir örnektir. Bu kod 4 saniye bekleyecek, ardından programın başlamasından bu yana geçen süreyi yazdıracaktır. Sol 3 değerleri toplam süredir (mikrosaniye, milisaniye, toplam saat çevrimi) ve en sağdaki 3 geçen süredir:

Çıktı:

clocks for 1us:16
runtime us, ms, ck :: elapsed tme us, ms ck
4003236 4002	64051776	::	4003236	4002	64051760
8006668 8006	128106688	::	4003432	4004	64054912
12010508    12010	192168128	::	4003840	4004	64061440
16014348    16014	256229568	::	4003840	4004	64061440
20018188    20018	320291008	::	4003840	4004	64061440
24022028    24022	384352448	::	4003840	4004	64061440
28026892    28026	448430272	::	4004864	4004	64077824
32030732    32030	512491712	::	4003840	4004	64061440
36034572    36034	576553152	::	4003840	4004	64061440
40038412    40038	640614592	::	4003840	4004	64061440
44042252    44042	704676032	::	4003840	4004	64061440
48046092    48046	768737472	::	4003840	4004	64061440
52050956    52050	832815296	::	4004864	4004	64077824

İlk döngülerin neden daha uzun süren saat döngülerine sahip olduğuna ve diğer tüm döngülerin iki saat döngü döngüsü arasında neden geçiş yaptığına dair makul bir açıklama olduğundan eminim.

Kod:

unsigned long us, ms, ck;
unsigned long _us, _ms, _ck;
unsigned long __us, __ms, __ck;
void setup() {
        Serial.begin(9600);
}
boolean firstloop=1;
void loop() { 
        delay(4000);

        if (firstloop) {
                Serial.print("clocks for 1us:");
                ck=microsecondsToClockCycles(1);
                Serial.println(ck,DEC);
                firstloop--;
                Serial.println("runtime us, ms, ck :: elapsed tme us, ms ck");
        }

        _us=us;
        _ms=ms;
        _ck=ck;

        us=micros(); // us since program start
        ms=millis();
        //ms=us/1000;
        ck=microsecondsToClockCycles(us);
        Serial.print(us,DEC);
        Serial.print("\t");
        Serial.print(ms,DEC);
        Serial.print("\t");
        Serial.print(ck,DEC);     
        Serial.print("\t::\t");

        __us = us - _us;
        __ms = ms - _ms;
        __ck = ck - _ck;
        Serial.print(__us,DEC);
        Serial.print("\t");
        Serial.print(__ms,DEC);
        Serial.print("\t");
        Serial.println(__ck,DEC);     

}

Sidenote: 4 saniyelik gecikmeyi kaldırırsanız, Serial.print () etkilerini çok daha net görmeye başlayacaksınız. Burada 2 çalışma karşılaştırılmıştır. Sadece kendi günlüklerinden 4 tane örnek ekledim.

Çalışma 1:

5000604 5000	80009664	::	2516	2	40256
6001424 6001	96022784	::	2520	3	40320
7002184 7002	112034944	::	2600	3	41600
8001292 8001	128020672	::	2600	3	41600

2. Yarış:

5002460 5002	80039360	::	2524	3	40384
6000728 6000	96011648	::	2520	2	40320
7001452 7001	112023232	::	2600	3	41600
8000552 8000	128008832	::	2604	3	41664

Geçen süre toplam çalışma süresi boyunca artar. Bir saniye geçtikten sonra saatler ortalama 40k'dan 44k'ye yükselir. Bu, 1 saniye sonra sürekli olarak birkaç milisaniye olur ve geçen saatler en az sonraki 10 saniye boyunca 44k civarında kalır (daha fazla test etmedim). Bu nedenle izleme yararlı veya gereklidir. Belki de azalan verimlilik, seri yapılandırma veya hatalarla ilgilidir? Belki de kod belleği düzgün kullanmıyor ve performansı etkileyen bir sızıntıya sahip.


yıllar sonra, hala kodları (osiloskopta olduğu gibi) kodla daha doğru gösteren bir şey istiyorum. Ben de 16MHZ ve 8MHZ bir digitalWrite () için gerekli saat döngü sayısını belirlemeye çalışıyorum. 16MHZ'de 8us / 64clk alıyorum. Ama 8MHZ'de 0us / 0clk alıyorum.
cyphunk

1

Kaynağınıza eklenen her kod satırının performans üzerinde etkisi olacağından ve uygulanan optimizasyonları değiştirebileceğinden. Değişiklikler görevi gerçekleştirmek için gereken minimum değer olmalıdır.

Az önce "Annotated Assembly File Debugger" adlı bir Atmel Studio eklentisi buldum. http://www.atmel.com/webdoc/aafdebugger/pr01.html Muhtemelen sıkıcı olan şey size tam olarak ne olduğunu gösterecekken, üretilen gerçek montaj dilini adımlamak gibi görünüyor. Her bir talimat için kaç döngü sürdüğünü çözmek zorunda kalabilirsiniz, ancak diğer yayınlanan seçeneklerden çok daha yakın olacaktır.

Projenizin Çıktı klasöründe bilmeyenler için LSS uzantılı bir dosyadır. Bu dosya orijinal kaynak kodunuzun tamamını yorum olarak içerir ve her satırın altında o kod satırına göre oluşturulan montaj dili bulunur. LSS dosyasının oluşturulması kapatılabilir, bu nedenle aşağıdaki ayarı kontrol edin.

Proje Özellikleri | Takım Zinciri | AVR / GNU Ortak | OutputFiles

Onay kutusu ".lss (lss dosyası oluştur)


1

Dahili zamanlayıcılardan birini kullanabilirsiniz. Bloktan önce ön ölçekleyici = 1 ve TCNT = 0 için ayarlanan her şeyi alın. Ardından bloktan önceki satırda zamanlayıcıyı etkinleştirin ve bloktan sonraki satırda devre dışı bırakın. TCNT şimdi bloğun aldığı döngü sayısını, etkinleştirme ve devre dışı bırakma kodu için sabit döngüleri daha az tutacaktır.

TNCT'nin 16 bitlik bir zamanlayıcıda 65535 saat çevriminden sonra taşacağını unutmayın. Taşma bayrağını iki kat çalışma süresi için kullanabilirsiniz. Hâlâ daha uzun süreye ihtiyacınız varsa, bir ön ölçekleyici kullanabilirsiniz, ancak daha az çözünürlük elde edersiniz.

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.