Sida 1 av 1
Optimera C-kod för GCC
Postat: 28 juli 2005, 03:50:55
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
Postat: 28 juli 2005, 07:33:38
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.
Postat: 28 juli 2005, 09:02:52
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.
Postat: 28 juli 2005, 11:24:07
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å.
Postat: 28 juli 2005, 13:35:55
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.
Postat: 28 juli 2005, 13:45:18
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
Postat: 28 juli 2005, 15:53:54
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.
Postat: 28 juli 2005, 17:17:43
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!
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).