Optimera C-kod för GCC

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Användarvisningsbild
strombom
Inlägg: 3305
Blev medlem: 27 maj 2003, 10:50:20
Ort: Västra Götaland
Kontakt:

Optimera C-kod för GCC

Inlägg av strombom »

Hejsan

Jag funderar lite över hur man bäst optimerar sin C-kod i GCC. Finns det någon guide eller liknande? Plattformen är en ARM7...

Är det någon skillnad i prestanda mellan:

var *= 2;
var = var<<1;


Är dubbelarrayer snabba?
for(a=0;...) {
for(b=0;...) {
var[a] = tjohej;
}}

eller bör jag optimera så att jag med en endimensionell array räknar upp den lite manuellt ?
for(a=0;...) {
tmp=a*8;
for(b=0;...) {
var[tmp++] = tjohej;
}}

Är det snabbast att använda unsigned int eller vanlig int ?

Slöar det ner att använda char istället för int på en 32-bitarsplattform, är char kanske snabbare ändå, eller är de rentav lika snabba ?

Sen har jag fått för mig att int är 32-bitarstal på GCC för ARM, vad är då long, 64 bitar ?

/Johan
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Jag vet att jag läst en application note eller dyl. från atmel ang. det där.
Hittar den inte direkt nu och måste rusa till tåget, men kan kolla i em. om du inte redan hittat något.
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Oftast anpassar kompilern själv optimeringen men såklart kan man lösa vissa funktioner på ett snabbare och/eller enklare sätt.

Jag vet att kompilern just med 2D variabler gör om den till 1D variabler som den indexerar i och jag tror att den gör det indexeringen snabbare själv.

Vad angår variablernas storlek är det inte så mycket man kan göra förutom att tänka till iblant. I "de gamla dagar" var en 'int' 16 bit lång och nu, då PC'n har kommit till 32 bit/64 bit i standart-ord är en 'int' just den storlek men bara 15 bit + signbit används. Likaså är det med de andra variabelstorleker: det finns en standart som följs men iblant tas det i, på PC (Borland C Builder) är en 'int' 32 bit stor, ganska enkelt för att det är den 'snabbaste' storlek.

Som jag har förstådd det är 'int' den "mest optimerade" vcariabel att använda från och med 16-bits system och uppåt men det beror mycket på arkitekturen osv. PÅ den Fujitsu jag använder flitigt betyder 'byte'-värden ofta att minnet läsas, de höga 8 bit sätts till noll och sen utförs uträkningen, vid att välja en 'int' till den variabel kan jag alltså spara 1 operation.

Den verkliga prestandaskillnad kan hittas vid att minimera loopar: det är långt mer lönt att ta bort 1 instruktion i en loop som utförs 10000 gånger per cyklus än en som utförs 2 gånger per cyklus.

Kod: Markera allt

A = uppmätt tid (t.ex)
B = Referens (t.ex.)
#define D_ARRAY_SIZE 10000
int X;
int Y[D_ARRAY_SIZE];
for(X = 0;X < D_ARRAY_SIZE;X++)
  {
  Y[X] += (A - B);
  }

går en "hel" del långsammare än:

A = uppmätt tid (t.ex)
B = Referens (t.ex.)
#define D_ARRAY_SIZE 10000
int X, Diff;
int Y[D_ARRAY_SIZE];
Diff = A - B;
for(X = 0;X < D_ARRAY_SIZE;X++)
  {
  Y[X] += Diff;
  }
Som så ofta förut: kan man sin maskinkod kan man optimera långt bättre.
Användarvisningsbild
strombom
Inlägg: 3305
Blev medlem: 27 maj 2003, 10:50:20
Ort: Västra Götaland
Kontakt:

Inlägg av strombom »

Tack, det var mycket tänkvärt. Jag borde nog sätta in mig mer i arkitekturen som du säger. Ska kolla lite på appnotes också.
frejo
Inlägg: 496
Blev medlem: 21 april 2004, 21:43:01
Ort: Linköping

Inlägg av frejo »

Den appnoten jag tänkte på var visst för AVR...

AVR035: Efficient C Coding for AVR
http://www.atmel.com/dyn/resources/prod ... oc1497.pdf

Men det går nog att lära sig något även från den.
Rymdninja
Inlägg: 330
Blev medlem: 15 december 2003, 13:41:25
Ort: Göteborg

Inlägg av Rymdninja »

Huruvida 1d arrayer är snabbare än 2d arrayer beror på hur ramminnet accessas. I en "pagead" minnesmiljö är det alltid snabbare med 1d eftersom man får färst (alltså som i färre) page-swaps. Och säkerligen som Icecap säger så görs de juh om till 1d arrayer av kompilatorn, men det man ska vara noga med är då hur man indexerar elementet rad/col eller col/rad (kommer aldrig ihåg hur den lagrar sina arrayer, det kanske tom är olika beroende på kompilator).

Sen tror jag faktiskt att konstanta uttryck inuti loopar omptimeras bort ganska bra...men jag är inte helt säker...

peace
Användarvisningsbild
Icecap
Inlägg: 26647
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Inlägg av Icecap »

Hur bra optimeringen är beror till stor del på hur duktig kompilerkonstruktören har varit.

Jag hade stor framgång då jag skulle kopiera en minnesblock, med memcpy() gick det snabbt men inte snabbt nog så jag gjorde en MemCpyW() som flyttade integers, samma data annrs som memcpy(). Det gjorde susen, jag fick kraftigt förbättret prestanda på hela lösningen, enkom för att denna rutin var så mycket snabbare och det var ju trevlig.

Exemplet jag gav förut var bara en klen beskrivning men faktum kvarstår: man kan spara 10000 instruktioner om man kan banta bort 1 i en cykel som upprepas 10000 gånger, att pilla bort 1 instruktion i något som utförs lite då och då är nära nog bortkastat tid.

Man kan även tänka på funktionen i helhet: ska man göra en LED-snurrar t.ex. kan man göra utläsningen så att man gör skickar ut styrningen av LED'en och därefter förbereder nästa dataklump så den ligger redo till nästa gång. Detta kan ge mycket bra realtidsprestanda men kräver såklart att datan kan förutsägas så att säga.
cyr
Inlägg: 2712
Blev medlem: 27 maj 2003, 16:02:39
Ort: linköping
Kontakt:

Inlägg av cyr »

När det gäller GCC behöver man nog inte bekymra sig speciellt mycket om hur man skriver koden, enligt min erfarenhet är den väldigt bra på att optimera. Flytta ut konstanta beräkningar ur loopar gör den nog garanterat, och den tar även bort "meningslösa" loopar (som man skrivit för att göra en kort delay eller testa minnesbandbredden) helt och hållet! :lol:

Stor skillnad jämfört med t.ex. LCC som är det enda jag har till en processor. Den kan skapa riktigt hemsk kod ibland, med helt överflödiga load/store och move mellan register i onödan osv.

När det gäller storlek på typer så är det praktiskt taget alltid såhär:

char 8bit
short 16bit
long 32bit
long long 64bit

int = 32bit på 32bits processor, 16bit på 16bits processor, och på 8bits system kan faktiskt int vara 8bit också (fast det går emot standarden).

long long stöds inte av alla (men GCC gör det).
Skriv svar