Counter Geschwindigkeit

Gast #1334838
Lesenswert?

Na ihr,

Die Verpackung verspricht ja im Normalfall viel mehr als wirklich 
geleistet wird.
Heute habe ich mal aus reiner Neugierde ausgetestet, ob das auch für 
einen AVR(oder bzw den verwendeten Quarz) zutrifft.

Folgendes Programm soll einfach zählen und nach jedem Zählvorgang eine 
Led ein/ausschalten:
1
...
2
long i;
3
while (1){
4
    for(i=0;i<=6000000;i++){}   
5
    if(PINC.0==1) PORTC.0=0;
6
    else    PORTC.0=1;
7
};
8
...

Der "geht mir aufn Sac*"-Teil:
Diese Schleife sollte wie man sieht bis 6000000(6Millionen) zählen. 
Dazu(also für eine Periode) benötigt mein ATMEGA32 mit 16MHZ Quarz etwa 
20 sekunden.
-> Rechnen: 6000000/20=300000HZ=300KHZ
-> lol, nen ATMEGA mit 16MHZ-Quarz kann nicht schneller als mit 300KHZ 
zählen??
Das ist wohl oder übel ein Verhältniss von 1/53.

mfg Renato
Gast #1334852
Lesenswert?

Hab auch ne 8Bit und 16Bit Addition versucht. Die Unterschiede liegen 
unterhalb des Sekundenbereichs.

Hab mir fast gedacht dass jetzt gleich Assembler erwähnt wird. :D
Na dann lern ich jetzt mal Assembler Programmieren.(Dieser Schritt 
musste ja irgendwann mal kommen ^^)



Schon mal irgendwer ausprobiert wie schnell man mit Assembler nen 
Counter hinkriegt?(Also verhältnis zwischen Clock und tatsächlicher 
Zählgeschwindigkeit)

mfg
#1334869
Lesenswert?

Renato P. schrieb:
>>Nein? Counter sollte man generell vermeiden.
>>Es kommt immer nur Schrott dabei raus. Volldepp!
>
> Vermeiden? Was soll ich denn Vermeiden?
> Ich will nur sehen wie schnell der Zählen tut und wenn möglich ne
> schnellere Methode als meine finden.
> Du verstehst wohl den Sinn des Topics nicht? :)

und du nicht die funktionsweise von mcu, compiler & co...
nachdem du dich durch die tuts hier durchgearbeitet hast reden wir 
weiter ;)
#1334872
Lesenswert?

Renato P. schrieb:
> Ich will nur sehen wie schnell der Zählen tut und wenn möglich ne
> schnellere Methode als meine finden.

Und was soll das für einen Sinn haben?

Wenn Du schnell zählen willst, nimm nen Timer.
Dann kannst Du nebenbei noch andere Sachen machen.


53 Zyklen kann hinkommen, immerhin hast Du ja die Optimierung 
ausgeschaltet. Mit Optimierung wird diese Schleife nämlich in 0µs 
ausgeführt.

Und kein 8-Bitter macht 32Bit-Operationen in einem Takt, er muß sie aus 
mehreren 8Bit-Operationen zusammensetzen.


> Du verstehst wohl den Sinn des Topics nicht? :)

Den versteht wohl keiner.


Peter
#1334883
Lesenswert?

Andi D. schrieb:
> Renato P. schrieb:
>>>Nein? Counter sollte man generell vermeiden.
>>>Es kommt immer nur Schrott dabei raus. Volldepp!
>>
>> Vermeiden? Was soll ich denn Vermeiden?
>> Ich will nur sehen wie schnell der Zählen tut und wenn möglich ne
>> schnellere Methode als meine finden.
>> Du verstehst wohl den Sinn des Topics nicht? :)
>
> und du nicht die funktionsweise von mcu, compiler & co...

Jo, hab mich nicht besonders mit der Funktionsweise beschäftigt.
Ich habe mich ausserdem nicht mit der Funktionsweise eines PC's 
beschäftigt.
Für meine Anwendungen war/ist das (noch) nicht notwendig.

>nachdem du dich durch die tuts hier durchgearbeitet hast reden wir
>weiter ;)
Jo mach ma ;)
#1334888
Lesenswert?

Peter Dannegger schrieb:
> Renato P. schrieb:
>> Ich will nur sehen wie schnell der Zählen tut und wenn möglich ne
>> schnellere Methode als meine finden.
>
> Und was soll das für einen Sinn haben?

Tja das ist eine wirklich triviale Frage!

Ich teste und lerne!

Hast du schon mal eine Led aus/eingeschaltet? Wahrscheinlich ja! Hat das 
etwa als selbstständige Funktion einen Sinn(ausser wenns mal dunkel is 
;))?

Man entdeckt Funktionen, die man später zu einem Sinnvollen Projekt 
kombiniert.
#1334889
Lesenswert?

Renato P. schrieb:
> Ich teste und lerne!

Trial & Error ist keine gute Lernmethode.
Man wiederholt nur alle die Fehler, die andere längst gemacht haben.

Deutlich effektiver ist es, sich Tutorials, Examples, FAQs, Lib-Manuals 
usw. anzusehen.

Dann fällt einem z.B. beim AVR-GCC eine delay.h auf.
Die macht genau das, was Du willst und auf den Takt genau.


Scheinbar sind bei vielen C-Installation die Include-, Doc- und 
Example-Verzeichnisse gegen auslesen geschützt und  nur mit 
Administratorrechten einsehbar.


Peter
#1335014
Lesenswert?

Hallo,

so zum Spaß:

8Bit:
1
  ldi r16,wert
2

3
loop:
4
  dec r16           ; 1 Takt
5
  brne loop         ; 2 Takte - 1 Takt wenn nicht gesprungen wird

16Bit:
1
  ldi ZH,high(wert)
2
  ldi ZL,low(wert)
3

4
loop:
5
  sbiw Z,1         ; 2 Takte
6
  brne loop        ; 2 Takte - 1 Takt wenn nicht gesprungen wird

32Bit:
1
  ldi YH,byte4(wert)
2
  ldi YL,byte3(wert)
3
  ldi ZH,high(wert)
4
  ldi ZL,low(wert)
5

6
loop:
7
  sbiw Z,1         ; 2 Takte 
8
  brne loop        ; 2 Takte - 1 Takt wenn nicht gesprungen wird
9
 
10
  sbiw Y,1         ; 2 Takte 
11
  brne loop        ; 2 Takte - 1 Takt wenn nicht gesprungen wird

Da kannst Du dann im .lss vergleichen, was jeweils der Compiler draus 
macht.

Gruß aus Berlin
Michael
#1335093
Lesenswert?

Michael U. schrieb:
> 32Bit:
> ...
> Da kannst Du dann im .lss vergleichen, was jeweils der Compiler draus
> macht.


Der GCC braucht je Runde 5 Takte:
1
void bad_style_delay( void )
2
{
3
  7a:   80 ec           ldi     r24, 0xC0       ; 192
4
  7c:   97 e2           ldi     r25, 0x27       ; 39
5
  7e:   a9 e0           ldi     r26, 0x09       ; 9
6
  80:   b0 e0           ldi     r27, 0x00       ; 0
7
  for( uint32_t i = 600000L; i; i-- )
8
  82:   01 97           sbiw    r24, 0x01       ; 1
9
  84:   a1 09           sbc     r26, r1
10
  86:   b1 09           sbc     r27, r1
11
  88:   e1 f7           brne    .-8             ; 0x82 <count+0x8>
12
    asm volatile("");
13
}
14
  8a:   08 95           ret

Und ohne das asm volatile("") 0 Takte.

Aber wie gesagt, sowas ist unter C bad style.
Nimm die delay.h.


Peter
#1335195
Lesenswert?

Herbert schrieb:
>>lol, nen ATMEGA mit 16MHZ-Quarz kann nicht schneller als mit 300KHZ
>>zählen??
>
> Selber lol. Er kann natürlich mit 16MHZ zählen, wenn man ihn richtig
> programmiert. Aber dazu muss man natürlich erstmal das Datenblatt lesen
> um überhaupt zu wissen was man tun muss. Von nichts kommt halt nichts.

Jo da hab ich mich falsch ausgedrückt. Das war eher auf das zählen 
mittels C-Programm bezogen. Natürlich kann ders schneller wenn man weiß 
wie.

>-> lol, nen ATMEGA mit 16MHZ-Quarz kann nicht schneller als mit 300KHZ
>zählen??
>Das ist wohl oder übel ein Verhältniss von 1/53.

Was hast Du denn erwartet? 1/10? 1/2?

Unter C hab ich mir erhofft dass ich zumindest 1/10 hinkrieg ^^
Gast #1335223
Lesenswert?

>Unter C hab ich mir erhofft dass ich zumindest 1/10 hinkrieg ^^
auf welcher grundlage hast du denn gehofft?

wie ein prozessor funktioniert ist besonders bei so zeitkritischen 
sachen interessant und sollte unbedingt als grundwissen beim 
µC-programmieren vorhanden sein.

besonders wenn ich mit der ausführungsgeschwindigkeit in den bereich der 
taktfrequenz des prozessors komme (ich sag mal über 1/100 der 
taktfrequenz ) wird es wichtig für welche befehle wieviel tacktzyklen 
gebraucht werden und wie man da optimieren kann etc.

der simulator gibt einem da einen ganz guten eindruck, der zählt einem 
nämlich die tacktzyklen vor. und dort kann man auch nach belieben die 
ganze geschichte in assambler bestaunen.
#1335877
Lesenswert?

Hallo,

Karl heinz Buchegger schrieb:
> Wie PeDa weiter oben schon gezeigt hat kommt man auf ca. 1/5. Also rund
> 3.2Mhz
>
> Für 32Bit-Arithmetik ist das gar kein so schlechtes Ergebnis für einen
> C-Compiler.

Kann ich nur zustimmen. Ich bin eigentlich recht positiv überrascht vom 
GGC.
Einige Sachen sollte man aber nicht machen, z.B.

 uint64_t test = 1;
 test = test << 1;

 ;-))

Gruß aus Berlin
Michael
#1335910
Lesenswert?

Hi!

Diskussion um Compileroptimierung hin oder her,
a) ich verstehe den zweck nicht, wozu man so einen zähler als Schleife 
überhaupt sinnvoll einsetzen soll (ausser delay und dabei wäre die 
zaehlgeschwindigkeit sowieso völlig egal)
b) will mir nicht in den kopp, wieso man die Ausführungsgeschwindigkeit 
eines codes MESSEN muss, wenn alle Faktoren bekannt sind (Taktfrequenz 
und benötigte Taktzyklen für die einzelnen Befehle). Das hat man sogar 
mit Taschenrechner suchen schneller ausgerechnet als der Lötkolben zum 
heizen braucht.

Aber ansonsten recht amüsant der Thread hier :)

Gruss, Malte
#1336335
Lesenswert?

Malte Bayer schrieb:

> Diskussion um Compileroptimierung hin oder her,
> a) ich verstehe den zweck nicht, wozu man so einen zähler als Schleife
> überhaupt sinnvoll einsetzen soll (ausser delay und dabei wäre die
> zaehlgeschwindigkeit sowieso völlig egal)

Naja ich wollte nur allgemein mal wissen wie schnell der µC die 
C-Befehle abarbeitet. Das Beispiel mit dem Zähler is mir dazu rein 
zufällig als erstes eingefallen.
Es ist ja allgemein bekannt das Assembler schneller is als C, nur um 
wieviel hab ich noch nie irgendwo gelesen.
Der enorme Geschwindigkeitsverlust bei meinem Programm hat mich total 
verblüfft und somit hab ich mal einfach ein Topic aufgemacht.

Und was passiert als erstes? Na klar, jemand schnauzt mich an, weil er 
denkt ich will nen Timer oder ne delay proggen. ^^
sorry deswegen...

> b) will mir nicht in den kopp, wieso man die Ausführungsgeschwindigkeit
> eines codes MESSEN muss, wenn alle Faktoren bekannt sind (Taktfrequenz
> und benötigte Taktzyklen für die einzelnen Befehle). Das hat man sogar
> mit Taschenrechner suchen schneller ausgerechnet als der Lötkolben zum
> heizen braucht.

Ach, für C-Befehle gibts auch irgendwo die Zyklenzeit-Liste?(danke, ich 
schau gleich mal nach deswegen). Ich bin wohl Totalnoob...
Auf dem Datenblatt sah ich immer nur die Assembler-Zyklenzeiten und aus 
der Schule kenn ich auch nur die Assembler-Zyklenzeit-Rechnungen.

> Aber ansonsten recht amüsant der Thread hier :)
Na das is schön zu hören :P :)
#1336358
Lesenswert?

Renato P. schrieb:
> Naja ich wollte nur allgemein mal wissen wie schnell der µC die
> C-Befehle abarbeitet.

Der arbeitet die überhaupt nicht ab.

Sondern der C-Compiler übersetzt die 'C-Befehle' in Maschinensprache (im 
weitesten Sinne ist es genau das was du programmierst, wenn du Assembler 
programmierst)

> Es ist ja allgemein bekannt das Assembler schneller is als C, nur um
> wieviel hab ich noch nie irgendwo gelesen.

Nein, das ist nicht Allgemein bekannt.
Auf vielen Architekturen ist es mitlerweile so, dass der C-Compiler in 
der Lage ist, mindestens 80% aller Assembler-Programmierer bei 
durchschnittlichen Programmen zu schlagen.

> Der enorme Geschwindigkeitsverlust bei meinem Programm hat mich total
> verblüfft und somit hab ich mal einfach ein Topic aufgemacht.

Der enorme Geschwindigkeitsverlust resultiert daraus, dass du mit deinem 
Werkzeug, dem C-Compiler, noch nicht umgehen kannst. Du hast ihn ganz 
einfach 'mit angezogener Handbremse' arbeiten lassen. Da fährt dann auch 
ein Ferrari nicht schneller als 30km/h

> Ach, für C-Befehle gibts auch irgendwo die Zyklenzeit-Liste?

Nein, die gibt es nicht.
Es hängt immer davon ab, wie der Compiler bestimmte Konstrukte umsetzt. 
Und das wiederrum hängt von vielen Faktoren ab.
#1336440
Lesenswert?

Hi Renato,

Karl trifft es auf den Punkt,
damit jetzt vielleicht alle Klarheiten beseitigt werden:

Der AVR uC arbeitet die befehle die er versteht (diese sind im 
Datenblatt ersichtlich) ab.
Für das Ausführen eines jeden Befehls benötigt er eine Gewisse Menge 
Taktzyklen (für die meisten Befehle einen, aber auch zb mal zwei takte 
für einen befehl).

Das hat erstmal garnichts mit der verwendeten Programmiersprache zu tun.

In deinem Ursprungspost vermittelst du mir den Eindruck, als ob du davon 
ausgehst, dass eine Zählschleife ohne weiteren Inhalt aus einem Befehl 
bestünde.
A bissl naiv. Für dich sieht es in C so aus, da es ja nur das for() 
konstrukt ist. Der Controller muss aber viel mehr tun:
- zähler addieren (und das nicht nur 1x, da er nur mit 8bit arbeitet)
- vergleichen ob das schleifenende erreicht ist
- schleifensprung

Meine orredner haben dir das ja bereits am entsprechenden Assemblercode 
versucht zu erklären.

Es gibt deshalb keine Tabelle mit Befehlszeiten für C-Befehle, weil die 
Compiler alle unterschiedliche Befehlskonstrukte für die Controller 
daraus produzieren. Zudem hängt das ja auch noch von dem verwendeten 
Controller ab.
So zum beispiel können manche AVR hardwareseitige Multiplikation, können 
sie dies nicht, so müssen viel mehr Taktzyklen aufgewendet werden um die 
Multiplikation auf herkömmlichen Weg zu berechnen.

Was du dir also ganz klar vor Augen halten musst ist: ZÄHLEN kann ein 
AVR eine 8bit Zahl mit fOSC/2.
Nämlich
1
 Loop:
2
  INC r16
3
  RJMP Loop
Dabei benötigt das Erhöhen und der Rücksprung jeweils einen Taktzyklus.

Das ganze natürlich wenn du den Zähler auch so programmierst.
Ich kann mir gut vorstellen, dass aus
1
for(i=0;i<=255;i++){}
etwas ähnlich Schlankes wird (ich weiss es nicht genau, weil ich avr 
"nur" in assembler programmiere). Logischerweise nicht obiges 
Assemblerbeispiel, weil dies ja eine Endlosschleife darstellt.

JS says: "Klar soweit?"

Gruss, Malte
#1336688
Lesenswert?

Malte Bayer schrieb:
> Ich kann mir gut vorstellen, dass aus
>
1
for(i=0;i<=255;i++){}
> etwas ähnlich Schlankes wird (ich weiss es nicht genau, weil ich avr
> "nur" in assembler programmiere).

Diese Schleife wird denk ich mal ziemlich sicher auch mehr 40 Taktzyklen 
pro Zählererhöhung brauchen(zumindest wenn ichs in meinen obigen 
Codeausschnitt einfüge).
Dat ist ja was mich wundert. Ich ging beim programmieren der Schleife 
davon aus, dass der höchstens 10 Taktzyklen für einen Zähldurchgang 
braucht, aber weit über 40 für eine einfache for-Schleife fand ich 
heftig(ich bin aber auch nen bisschen noob in Sachen Taktzyklen).

Klar verlangsamt die while Schleife das ein bisschen. Aber schau mal:
Die While Schleife fängt an, dann sollte die for-Schleife in Ruhe(sie 
tut ja nix anderes als zu zählen) bis 6Millionen zählen können und dann 
schaltet er den Port um.
Das währen 6Millionen Zählvorgänge, dann 2if's und 1while, dann wieder 
6Millionen Zählvorgänge.
Die while-Schleife und die ifs Scheinen mir da vernächlässigbar 
klein(sind ja nur 6Befehle die nach den 6Millionen Befehlen kommen).
-> Ich komm halt zum Schluss, dass diese 50 Taktzyklen die der µC bei 
mir pro Zählererhöhung gebraucht hat, fast allein an der for-Schleife 
liegen
und ps: long in int umgewandelt erhöht die Schleife nur um 
milisekunden(habs probiert).

Verstehst was ich meine? Also kurz nochmal heißt das folgendes:
1
for(i=0;i<=1;i++){} //also i um 1 erhöhen
Diese Schleife würde 52Taktzyklen verbraten.
Hingegen:
1
INC r16
nur 1 Taktzyklus

Ich mit meinem ungeschulten Auge finde das schon heftig...
Persönliche Seite #1336750
Lesenswert?

So.
1
#include <avr/io.h>
2

3
int main()
4
{
5
  long i;
6

7
  while (1)
8
  {
9

10
      for(i=0;i<=6000000;i++)
11
    {
12
      asm volatile("");
13
    } 
14

15
    if(PINC & 0x01) 
16
      PORTC = 0x00;
17
    else
18
        PORTC = 0x01;
19
  }
20

21
  return 0;
22
}

(Ich hoffe das jetzt so richtig korrigiert zu haben)
Macht:
1
  while (1)
2
  {
3

4
      for(i=0;i<=6000000;i++)
5
  94:  01 96         adiw  r24, 0x01  ; 1
6
  96:  a1 1d         adc  r26, r1
7
  98:  b1 1d         adc  r27, r1
8
  9a:  81 38         cpi  r24, 0x81  ; 129
9
  9c:  3d e8         ldi  r19, 0x8D  ; 141
10
  9e:  93 07         cpc  r25, r19
11
  a0:  3b e5         ldi  r19, 0x5B  ; 91
12
  a2:  a3 07         cpc  r26, r19
13
  a4:  30 e0         ldi  r19, 0x00  ; 0
14
  a6:  b3 07         cpc  r27, r19
15
  a8:  ac f3         brlt  .-22       ; 0x94 <main+0xc>
16
    {
17
      asm volatile("");
18
    } 
19

20
    if(PINC & 0x01) 
21
  aa:  30 9b         sbis  0x06, 0  ; 6
22
  ac:  02 c0         rjmp  .+4        ; 0xb2 <main+0x2a>
23
      PORTC = 0x00;
24
  ae:  18 b8         out  0x08, r1  ; 8
25
  b0:  01 c0         rjmp  .+2        ; 0xb4 <main+0x2c>
26
    else
27
        PORTC = 0x01;
28
  b2:  28 b9         out  0x08, r18  ; 8
29
  b4:  80 e0         ldi  r24, 0x00  ; 0
30
  b6:  90 e0         ldi  r25, 0x00  ; 0
31
  b8:  a0 e0         ldi  r26, 0x00  ; 0
32
  ba:  b0 e0         ldi  r27, 0x00  ; 0
33
  bc:  ee cf         rjmp  .-36       ; 0x9a <main+0x12>

Kommandozeile:
avr-gcc  -mmcu=atmega644 -Wall -gdwarf-2 -std=gnu99   -DF_CPU=1000000UL 
-Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -MD 
-MP -MT test.o -MF dep/test.o.d  -c  ../test.c

Da benötigt die For-Schleife 13 us, bzw. 13 Takte bei 1MHz pro 
Durchlauf.
Persönliche Seite #1336762
Lesenswert?

Mit folgenden Einstellung braucht die For-Schleife für einen Durchlauf 
37 Takte:

avr-gcc  -mmcu=atmega644 -Wall -gdwarf-2 -std=gnu99 
-DF_CPU=1000000UL -O0 -funsigned-char -funsigned-bitfields -fpack-struct 
-fshort-enums -MD -MP -MT test.o -MF dep/test.o.d  -c  ../test.c

Optimierung ausgeschaltet.

Der Code sieht mehr oder weniger grausam aus (Ich poste nur die for 
Schleife):
1
      for(i=0;i<=6000000;i++)
2
  94:  19 82         std  Y+1, r1  ; 0x01
3
  96:  1a 82         std  Y+2, r1  ; 0x02
4
  98:  1b 82         std  Y+3, r1  ; 0x03
5
  9a:  1c 82         std  Y+4, r1  ; 0x04
6
  9c:  0b c0         rjmp  .+22       ; 0xb4 <main+0x2c>
7
  9e:  89 81         ldd  r24, Y+1  ; 0x01
8
  a0:  9a 81         ldd  r25, Y+2  ; 0x02
9
  a2:  ab 81         ldd  r26, Y+3  ; 0x03
10
  a4:  bc 81         ldd  r27, Y+4  ; 0x04
11
  a6:  01 96         adiw  r24, 0x01  ; 1
12
  a8:  a1 1d         adc  r26, r1
13
  aa:  b1 1d         adc  r27, r1
14
  ac:  89 83         std  Y+1, r24  ; 0x01
15
  ae:  9a 83         std  Y+2, r25  ; 0x02
16
  b0:  ab 83         std  Y+3, r26  ; 0x03
17
  b2:  bc 83         std  Y+4, r27  ; 0x04
18
  b4:  89 81         ldd  r24, Y+1  ; 0x01
19
  b6:  9a 81         ldd  r25, Y+2  ; 0x02
20
  b8:  ab 81         ldd  r26, Y+3  ; 0x03
21
  ba:  bc 81         ldd  r27, Y+4  ; 0x04
22
  bc:  81 38         cpi  r24, 0x81  ; 129
23
  be:  2d e8         ldi  r18, 0x8D  ; 141
24
  c0:  92 07         cpc  r25, r18
25
  c2:  2b e5         ldi  r18, 0x5B  ; 91
26
  c4:  a2 07         cpc  r26, r18
27
  c6:  20 e0         ldi  r18, 0x00  ; 0
28
  c8:  b2 07         cpc  r27, r18
29
  ca:  4c f3         brlt  .-46       ; 0x9e <main+0x16>
30
    {
31
      asm volatile("");
32
    }
#1336773
Lesenswert?

Renato P. schrieb:
> Malte Bayer schrieb:
>> Ich kann mir gut vorstellen, dass aus
>>
1
for(i=0;i<=255;i++){}
>> etwas ähnlich Schlankes wird (ich weiss es nicht genau, weil ich avr
>> "nur" in assembler programmiere).
>
> Diese Schleife wird denk ich mal ziemlich sicher auch mehr 40 Taktzyklen
> pro Zählererhöhung brauchen(zumindest wenn ichs in meinen obigen
> Codeausschnitt einfüge).

Wie kommst du denn auf diesen Blödsinn?
Persönliche Seite #1336774
Lesenswert?

Folgendes Programm
1
#include <avr/io.h>
2

3
int main()
4
{
5
  uint8_t i;
6

7
  for(i=0;i<10;i++)
8
  {
9
    PORTC = i;    
10
  } 
11

12
  return 0;
13
}

übersetzt sich so:
1
00000088 <main>:
2
  88:  80 e0         ldi  r24, 0x00  ; 0
3
  8a:  88 b9         out  0x08, r24  ; 8
4
  8c:  8f 5f         subi  r24, 0xFF  ; 255
5
  8e:  8a 30         cpi  r24, 0x0A  ; 10
6
  90:  e1 f7         brne  .-8        ; 0x8a <main+0x2>
7
  92:  80 e0         ldi  r24, 0x00  ; 0
8
  94:  90 e0         ldi  r25, 0x00  ; 0
9
  96:  08 95         ret

Bei Kommandozeile:
avr-gcc  -mmcu=atmega644 -Wall -std=gnu99 -DF_CPU=1000000UL -Os 
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums  -MD 
-MP -MT test.o -MF dep/test.o.d  -c  ../test.c

Ich hab mal die Debugsachen rausgeschmissen, die haben ohnehin keinen 
Sinn mehr ergeben bei so guter Optimierung.
#1336814
Lesenswert?

Danke für die Posts Leute. Hat sehr geholfen :)

Da ich eure AVRGCC-Codes gleich ausprobieren wollte, hab ich jetzt mal 
AVR-Studio heruntergeladen.
Es stimmt, es geht nun 3 mal schneller als vorher.
:D Nur wieso das so ist, hab ich keinen Dunst.

2 eigentlich völlig identische Codes:
1
// AVRGCC mit AVRStudio        //CodeVisionAVR's Compiler
2
#include <avr/io.h>            #include <mega32.h>
3
int main(){                    void main(void){
4
  DDRC=0x01;                     long i;
5
  long i;                        DDRC=0xFF;
6
  while (1){                     while (1){
7
      for(i=0;i<=6000000;i++){}    for(i=0;i<=6000000;i++){}               
8
    if(PINC&0x01)   PORTC=0x00;    if(PINC.0==1) PORTC=0;
9
    else            PORTC=0x01;    else          PORTC=255;
10
  }                              };
11
}                              }
Der linke 4 mal schneller :D

Wenn mir den Grund hierfür auch nochmal einer erklären kann, dann bin 
ich Glücklich ;)

Arbeitet hier überhaupt einer mit CodeVisionAVR? Vielleicht sollt ich ja 
nen umstieg auf AVRStudio wagen.
#1336822
Lesenswert?

Renato P. schrieb:

> Wenn mir den Grund hierfür auch nochmal einer erklären kann, dann bin
> ich Glücklich ;)

Der wahrscheinliche Grund dafür wurde dir jetzt schon ein paar mal 
gesagt:
Es hängt davon ab, welche Einstellung du für den Optimizer hast.

Je nachdem wie agressiv der Optimizer optimieren darf, kommt 
unterschiedlicher Code heraus.
#1336826
Lesenswert?

Renato P. schrieb:
> Simon K. schrieb:
>> Renato P. schrieb:
>>> Diese Schleife wird denk ich mal ziemlich sicher auch mehr 40 Taktzyklen
>>> pro Zählererhöhung brauchen(zumindest wenn ichs in meinen obigen
>>> Codeausschnitt einfüge).
>>
>> Schalt halt endlich mal den Optimierer ein du Held!
>
> Meine IDE erkennt den Befehl asm volatile(""); nicht.

Deiner IDE ist das "asm volatile("");" aber sowas von egal.

Dir fehlt es hinten und vorne an Grundlagen und trotzdem stellst du dich 
hier hin und ziehst über Compiler her? Dein Selbstvertrauen möchte ich 
haben! Schon mal eine Karriere in der Poltik oder als Konzernmanager ins 
Auge gefasst?
Gast #1336828
Lesenswert?

@renato
du solltest versuchen zu begreifen was eine höhere programmiersprache 
ist.
C ist eine höhere Programmiersprache.
Assembler ist eine "niedere"

Assemblerbefehle stehen immer für einen maschinenbefehl, die der 
Prozessor versteht, man spricht schon mit dem Ausdruck, den der 
prozessor versteht ... da müssen dann nur das Wort (MOV RJMP etc) durch 
das byte, welches diesen befehl für den Prozessor darstellt ausgetauscht 
werden ... fertig.

C-Befehle und Programme versteht der Prozessor nicht. Deswegen müssen 
C-Programme erst von einem Compiler übersetzt werden, einige C-Befehle 
werden in eine ganze reihe von maschinenbefehlen übersetzt.
besonders wenn es sich um datentypen handelt, die größer sind als die 
register des Prozessors, braucht der plötzlich viel mehr Anweisungen, 
als man annehmen würde.

die kleinen AVR's haben nur 8bit große Register ... um eine 8 bit zahl 
zu inkrementieren braucht er die zahl blos aus dem ram (wozu er eine 16 
bit adresse in die adressregister schreiben muss etc)  in ein register 
legen um 1 erhöhen und zurück in den ram schreiben ...
einige compiler optimieren aber auch indem sie die 8 bit variable gleich 
im register lassen und gar nicht im ram ablegen.
bei einer 32 oder 64 bit zahl aber wahrscheinlich nicht. denn da braucht 
der prozessor ja 4 oder 8 8bit-register.
deswegen werden um eine 64 bit zahl um eins zu erhöhen erst die 
niedriegsten 8 bit aus dem ram in ein register geschrieben um eins 
erhöht und wieder zurückgeschrieben, gab es nun einen übertrag auf die 
nächsten 8 bit (255 -> 256) dann muss er die nächsten 8 bit aus dem ram 
holen usw.

Wie du siehst artet dann so ein einfaches Inkrement in eine ziemliche 
Arbeit für den Prozessor aus.

Deswegen sollte man schon aus Gründen der effizienten Programmierung auf 
solch große Datentypen verzichten. Damit sind Aufgabengebiete wie das 
bis-6-Millionen-Zählen alles andere als performant.
#1336835
Lesenswert?

Renato P. schrieb:
> Arbeitet hier überhaupt einer mit CodeVisionAVR? Vielleicht sollt ich ja
> nen umstieg auf AVRStudio wagen.

Zumindest erheblich weniger als mit dem AVR-GCC (WINAVR, AVRStudio).

Sachen, die nicht im C-Standard festgelegt sind, behandelt jeder 
Compiler unterschiedlich, z.B. Inline-Assembler, Interrupthandler.
Und die Compileroptionen (Optimierungs-Level) werden warscheinlich auch 
anders eingestellt.

Daher kannst Du die AVR-GCC Tips nicht wörtlich übernehmen, sondern nur 
sinngemäß.

Ich benutze auch den AVR-GCC. Da muß man sich nicht mit irgendwelchem 
Lizenzgeraffel rumärgern, wenn man an mehreren PCs arbeitet.


Peter
#1336859
Lesenswert?

Karl heinz Buchegger schrieb:
> Renato P. schrieb:
>> Simon K. schrieb:
>>> Renato P. schrieb:
>>>> Diese Schleife wird denk ich mal ziemlich sicher auch mehr 40 Taktzyklen
>>>> pro Zählererhöhung brauchen(zumindest wenn ichs in meinen obigen
>>>> Codeausschnitt einfüge).
>>>
>>> Schalt halt endlich mal den Optimierer ein du Held!
>>
>> Meine IDE erkennt den Befehl asm volatile(""); nicht.
>
> Deiner IDE ist das "asm volatile("");" aber sowas von egal.

Mir kommt vor ich hab vorher grad wo gelesen, dass dieses asm 
volatile(""); die optimierung sein soll.
Hab ich mich wohl verlesen oder?
#1336886
Lesenswert?

Renato P. schrieb:
> Karl heinz Buchegger schrieb:
>> Renato P. schrieb:
>>> Simon K. schrieb:
>>>> Renato P. schrieb:
>>>>> Diese Schleife wird denk ich mal ziemlich sicher auch mehr 40 Taktzyklen
>>>>> pro Zählererhöhung brauchen(zumindest wenn ichs in meinen obigen
>>>>> Codeausschnitt einfüge).
>>>>
>>>> Schalt halt endlich mal den Optimierer ein du Held!
>>>
>>> Meine IDE erkennt den Befehl asm volatile(""); nicht.
>>
>> Deiner IDE ist das "asm volatile("");" aber sowas von egal.
>
> Mir kommt vor ich hab vorher grad wo gelesen, dass dieses asm
> volatile(""); die optimierung sein soll.
> Hab ich mich wohl verlesen oder?

Gaaaaaaaanz von vorne.

Wenn dein Compiler sich einen C-Quellcode vornimmt, dann kann er den 
ziemlich naiv übersetzen.

zb übersetzt er
1
    i = 5;
2
    i = 7;

zu
1
   lade ein Register mit dem Wert 5
2
   Speichere den Reigsterinhalt im Speicher ab, wo die Variable i liegt
3
   lade ein Register mit dem Wert 7
4
   Speichere den Reigsterinhalt im Speicher ab, wo die Variable i liegt

ziemlich offensichtlich, dass der ganze Teil mit laden von 5 und 
speichern unsinnig ist, da diese 5 sowieso mit einer 7 überschrieben 
werden.

Nun, das hilft dem Compiler aber nichts. Der Programmierer hat das so 
geschrieben und dieses Geschriebene ist für den Compiler erst mal 
Gesetz.

Es sei denn der Programmierer erlaubt dem Compiler zu optimieren. Die 
Datenflussanalyse findet raus, dass diese erste Zuweisung für die Katz 
ist und schmeisst sie ganz einfach raus.

Das entstehende Programm ist damit zwar auf Detailebene nicht mehr 
identisch mit dem was der Programmierer geschrieben hat, aber im 
Endeffekt ändert sich nichts. Wenn die komplette Sequenz durchgelaufen 
ist, ist das Endergebnis vom ursprünglichen Endergebnis nicht zu 
unterscheiden.

Und so wie es hier eine ziemlich offensichtiche Optimierung gibt, gibt 
es noch eine Unzahl anderer möglicher Optimierungen die letztendlich 
dazu führen, dass das Programm entweder schneller läuft oder weniger 
Platz benötigt oder beides gleichzeitig. Allen gemeinsam ist allerdings, 
dass das entstehende Programm nicht mehr ein 1:1 Abbild dessen ist, was 
der Programmierer geschrieben hat. Es verhält sich nur noch gleich, aber 
die 1:1 Entsprechung auf Quellcode-Ebene ist verschwunden.


Dazu muss dem Compiler aber erlaubt werden zu optimieren. Und man 
erlaubt ihm dieses, indem man ein Schalter umlegt. Dieser Schalter ist 
ein Commandline-switch oder es findet sich irgendwo in deiner IDE eine 
entsprechende Checkbox oder sonstige Einstellung dafür

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren