Czy można monitorować blok kodu i określić liczbę cykli zegara procesora, które kod wziął na procesorze ATMU Arduino i / lub AVR? czy powinienem raczej monitorować mikrosekundy przed i po uruchomieniu kodu? Uwaga: nie interesuje mnie czas rzeczywisty (jak w, ile rzeczywistych sekund minęło), a nie „ile cykli zegara wymaga tego kodu od procesora”
Obecne rozwiązanie, które mogę wymyślić, pochodzi z time.c:
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
wiring.c dodaje:
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
Za pomocą tego konta mogłem obliczyć cykle zegara przekazane przez monitorowanie minionych mikrosekund, a następnie przekazać je do microsecondsToClockCycles (). Moje pytanie brzmi, czy jest lepszy sposób?
sidenote: czy istnieją dobre zasoby do monitorowania wydajności AVR. Wyszukiwania w witrynie lmgtfy.com i na różnych forach nie przynoszą żadnych oczywistych wyników poza eksploracją liczników czasu
dzięki
Co rozumiesz przez „monitor”?
Liczenie cykli zegara dla AVR nie powinno być trudne dla małych fragmentów kodu asemblera.
Możesz także ustawić port przed wykonaniem kodu i zresetować go później, a także monitorować go za pomocą analizatora logicznego lub oszilloskopu, aby uzyskać czas.
Możesz też odczytywać czas z szybko działającego timera, jak mówisz.
źródło
To jest przykład Arduino używającego funkcji clockCyclesPerMicrosecond () do obliczania upływających zegarów. Ten kod będzie czekać 4 sekundy, a następnie wydrukuje czas, jaki upłynął od uruchomienia programu. Lewe 3 wartości to całkowity czas (mikrosekundy, milisekundy, całkowite cykle zegara), a prawe 3 najbardziej upłynęły czasy:
Wynik:
Jestem pewien, że istnieje uzasadnione wytłumaczenie, dlaczego pierwsze pętle miały krótsze cykle zegara niż większość i dlaczego wszystkie inne pętle przełączają się między dwiema długościami cykli zegara.
Kod:
Uwaga: jeśli usuniesz 4-sekundowe opóźnienie, zaczniesz widzieć efekty Serial.print () znacznie wyraźniej. Uwaga: tutaj porównywane są 2 przebiegi. Uwzględniłem tylko 4 próbki blisko siebie z odpowiednich dzienników.
Uruchom 1:
Uruchom 2:
Upływający czas zwiększa się w stosunku do całkowitego czasu pracy. Po upływie sekundy zegary zwiększają się średnio z 40 tys. Do 44 tys. Dzieje się to konsekwentnie kilka milisekund po 1 sekundzie, a upływające zegary pozostają około 44k przez co najmniej kolejne 10 sekund (nie testowałem tego dalej). Dlatego monitorowanie jest przydatne lub potrzebne. Być może zmniejszona wydajność ma związek z konfiguracją lub błędami szeregowymi? A może kod nie używa pamięci poprawnie i ma wyciek, który wpływa na wydajność itp.
źródło
Ponieważ każdy wiersz kodu dodany do źródła będzie miał wpływ na wydajność i może zmienić zastosowane optymalizacje. Zmiany powinny stanowić minimum wymagane do wykonania zadania.
Właśnie znalazłem wtyczkę Atmel Studio o nazwie „Debugger pliku z adnotacjami”. http://www.atmel.com/webdoc/aafdebugger/pr01.html Wygląda na to, że przechodzisz przez faktycznie wygenerowany język asemblera, podczas gdy prawdopodobnie żmudne pokaże ci dokładnie, co się dzieje. Być może nadal będziesz musiał zdekodować liczbę cykli potrzebnych dla każdej instrukcji, ale zbliżyłoby się to znacznie bardziej niż niektóre inne opublikowane opcje.
Dla tych, którzy nie wiedzą w folderze Output twojego projektu jest plik z rozszerzeniem LSS. Ten plik zawiera cały oryginalny kod źródłowy w postaci komentarzy, a pod każdym wierszem znajduje się język asemblera, który został wygenerowany na podstawie tego wiersza kodu. Generowanie pliku LSS można wyłączyć, dlatego sprawdź następujące ustawienie.
Właściwości projektu | Toolchain | AVR / GNU Common | OutputFiles
Pole wyboru „.lss (Wygeneruj plik lss)
źródło
Możesz użyć jednego z wbudowanych timerów. Przygotuj wszystko dla prescaller = 1 i TCNT = 0 przed blokiem. Następnie włącz licznik czasu na linii przed blokiem i wyłącz go na linii po bloku. TCNT będzie teraz przechowywał liczbę cykli, które wziął blok, pomniejszoną o ustalone cykle dla kodu włączania i wyłączania.
Należy zauważyć, że TNCT przepełni się po 65535 cyklach zegara na 16-bitowym zegarze. Możesz użyć flagi przepełnienia, aby podwoić czas działania. Jeśli nadal potrzebujesz dłużej, możesz użyć preskalera, ale uzyska on mniejszą rozdzielczość.
źródło