mikrocontroller.net

Forum: Compiler & IDEs Cortex M4 interne Clock zum Cycles messen nutzen


Autor: Christopher S. (shalec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo allerseits,

ich habe auf Stackexchange diesen Vorgang gefunden. [1] "Number of 
Cycles"

Zunächst die erste Frage an die Profis: Macht der Kram exakt das, was er 
machen soll?


Nun zu meiner Beobachtung: Führe ich einfach folgendes aus:
reset_timer();
start_timer();
stop_timer();

und lasse mir das Ergebnis von getCycles() ausgeben, so erhalte ich die 
Zahl "35". Führe ich eine Multiplikation zweier 32-Bit Zahlen aus, 
erhalte ich ebenfalls 35.
Selbst bei 40k rekursiven Additionen wird mir der Wert 35 ausgegeben.

Führe ich eine selbstprogrammierte Operation (GF(p^16) Multiplikation) 
durch, erhalte ich einen von 35 abweichenden Wert. Aber die Anfängliche 
Ausgabe irritiert mich sehr und daher stelle ich Zweifel an diese 
Benchmarkingvorgehensweise.


Mein Board ist übrigens das Cortex M4: STM32F407VGT6 auf einem CJMCU 
Board.

[1] 
https://stackoverflow.com/questions/32610019/arm-m...



Edit: Vlt. hätte ich mir mal den Code genauer anschauen müssen. Dort 
wird ein Bit durch eine "Oder" Operation aktiviert.. das kann nicht 
klappen :D

Vorschlag:
void start_timer(){
    *DWT_CONTROL = *DWT_CONTROL | 1 ; // enable the counter
}

void stop_timer(){
    *DWT_CONTROL = *DWT_CONTROL & 0xFFFFFFFE ; // disable the counter    
}

und
void reset_timer(){
    DWT_CYCCNT   = (int *)0xE0001004; //address of the register
    DWT_CONTROL  = (int *)0xE0001000; //address of the register
    SCB_DEMCR    = (int *)0xE000EDFC; //address of the register
    *SCB_DEMCR   = *SCB_DEMCR | 0x01000000;
    *DWT_CYCCNT  = 0; // reset the counter
    *DWT_CONTROL = 0; 
}


Diese "Vorschläge" führen nun dazu, dass eine Ausgabe ohne Operationen 
"19" und eine Multiplikation "uint32_t c = 0xFF*0xFFFF" 18 "cycles" 
braucht. Da stimmt also immer noch was nicht ;)

: Bearbeitet durch User
Autor: Vincent Hamp (vinci)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja das funktioniert einwandfrei. Ich hab zwar mittlerweile eine Klasse 
dafür, aber das C-äquivalent wär in etwa das hier:
#define CORE_DWT_CYCCNT_EN()    *((volatile uint32_t*)0xE0001000) = 0x40000001  //!< Enable CYCCNT register
#define CORE_DWT_CYCCNT_DIS()   *((volatile uint32_t*)0xE0001000) = 0x40000000  //!< Disable CYCCNT register
#define CORE_DWT_CYCCNT_GET()   *((volatile uint32_t*)0xE0001004)               //!< Get value from CYCCNT register


Und folgendermaßen zu nutzen:
uint32_t it1, it2;                                              
float f = 1.01f;                                                
CORE_DWT_CYCCNT_EN();                                          
it1 = CORE_DWT_CYCCNT_GET();
float f2 = f * 2.29f;
it2 = CORE_DWT_CYCCNT_GET() - it1;                             
CORE_DWT_CYCCNT_DIS();

Laut meinen Notizen braucht die Subtraktion und der Store nach "it2" 
selbst 6 Zyklen... aber das weiß ich grad ehrlich gesagt nicht 
auswendig, also bitte selbst nachschaun.

Autor: Ruediger Asche (Firma: keine) (rac)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Doch doch, die DWT funktioniert. Allerdings kann es sein, dass dein 
Debugger sie mit nutzt, also asynchron auf 0 setzt.

Du brauchst auch kein stop_timer(), sondern kannst jederzeit den cycle 
count auslesen. Mglw. setzt das Stoppen implizit den Counter zurück, und 
die 35 Zyklen sind genau das Delta zwischen stop_timer() und 
get_cycles(). Ich würde auch die Abstraktionen nicht nutzen, sondern die 
Registeroperation auf die DWT inline im Code machen, weil Du sonst immer 
um die Zyklen verfälscht bist, die der Aufruf in die Unterfunktion 
verbrät.

Autor: Christopher S. (shalec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einen Debugger habe ich nicht angeschlossen. Mein Programmaufbau ist so:
reset_timer();
start_timer();
stop_timer();
print_int(getCycles());

print_int() sendet über USART einen String, der den Count enthält. 
Ausgelesen wird in Ubuntu im Terminal. Ausgabe ist an dieser Stelle 19.
reset_timer();
start_timer();
stop_timer();
uint32_t c= 0xFF*0xFFFF;
print_int(getCycles());
Output: 18

Autor: RAc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
was willst Du damit messen? Du stoppst den Timer, bevor Du die 
Multiplikation machst?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Christopher S. schrieb:
> stop_timer();
> uint32_t c= 0xFF*0xFFFF;

Compiler sind manchmal komisch, sie führen Sachen in der Reihenfolge 
aus, wie man sie hinschreibt.
Und oft sind sie faul, sie rechnen Konstanten aus und schreiben das 
Ergebnis direkt hin.

Autor: Christopher S. (shalec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ehm.. Hab es falsch zusammenkopiert. Tatsächlich wird erst multipliziert 
und dann gestoppt. Sry, ich hätte etwas aufmerksamer sein sollen.

Ich habe übrigens aktuell die Version mit meinen Änderungen aktiv. Waren 
die Änderungen sinnvoll? Ich habe praktisch das |1 gegen & 0xFFFFFFFE 
getauscht. Auch gucke ich grade nach, ob die Adressen alle korrekt für 
den M4 sind.

Autor: Markus F. (mfro)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christopher S. schrieb:
> Tatsächlich wird erst multipliziert

Zumindest in deinem Beispiel wird überhaupt nix multipliziert (s. zwei 
Beiträge weiter oben).

Autor: Christopher S. (shalec)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ah, dann berechnet der Compiler den Kram vorher? Müsste ich dann a=0xFF, 
b=0xFFFF; und dann entsprechend c=a*b; berechnen? Oder wie sieht das 
dann aus? Theoretisch sind ja a*b dann während der Compilierung bekannt.

Gut, vielen Dank für die Hilfe. Den Rest werde ich mir jetzt wohl 
anlesen können :)

: Bearbeitet durch User
Autor: Markus F. (mfro)
Datum:

Bewertung
3 lesenswert
nicht lesenswert
Der Compiler erkennt, daß sich an der Multiplikation nie was ändert, 
berechnet das Ergebnis entsprechend bereits beim Compilieren und 
schreibt eine Konstante.

Anschliessend erkennt er, daß sich niemand für diese Konstante 
interessiert (sie wird ja nirgends verwendet) und optimiert sie deshalb 
gleich komplett weg.

Um tatsächlich etwas zu berechnen, musst Du schon noch etwas kreativer 
werden ;)

Autor: Nico W. (nico_w)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn man davon ausgeht, dass zumindest der cmsis-core_cm4.h mit 
eingebunden wird, geht das alles auch noch ein wenig schöner.
void init_debug_counter(void) {
  CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
}

void start_debug_counter(void) {
  DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
}

void end_debug_counter(void) {
  DWT->CTRL &= ~(DWT_CTRL_CYCCNTENA_Msk);
}

uint32_t get_debug_counter(void) {
  return DWT->CYCCNT;
}

Das ganze kann man ggf. noch in Macros verpacken.

Autor: Root (Gast)
Datum:

Bewertung
1 lesenswert
nicht lesenswert
Nico W. schrieb:
> Das ganze kann man ggf. noch in Macros verpacken

function like macro = inline
inline = schöner

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.