webForumDet fria alternativet

Optimerings fråga

4 svar · 210 visningar · startad av Viktor

ViktorMedlem sedan aug. 20021 752 inlägg
#1

Tänkte höra om det är någon prestanda skilnad mellan att skriva såhär,

if((!(pCond->buttons & CONT_DPAD_UP))&&((pGame->GetPlayer(iPlayer)->ButtonInfo.frmctrUp+20)<frmctr))
{
	pGame->GetMainMenu()->SelectPrev();
	pGame->GetPlayer(iPlayer)->ButtonInfo.frmctrUp=frmctr;
}

Jag upprepar denna if för varje knapp, 9 knappar, det är samma ButtonInfo strukt för alla.
Structen för ButtonInfo serut såhär,

struct button_info
{
	cont_cond_t cond;
	long frmctrX;
	long frmctrY;
	long frmctrA;
	long frmctrB;
	long frmctrDown;
	long frmctrUp;
	long frmctrLeft;
	long frmctrRight;
	long frmctrStart;
};

Går det snabbare om jag skriver,

button_info *button=pGame->GetPlayer(iPlayer)->GetButtonInfo();
if((!(pCond->buttons & CONT_DPAD_UP))&&((button->frmctrUp+20)<frmctr))
{
	pGame->GetMainMenu()->SelectPrev();
	button->frmctrUp=frmctr;
}

Tjänar man något på det?
Detta är ett konkret exempel men jag tänker även rent allmänt, hur mycket påvärkas prestandan av att peka på många objekt i en lång kedja?

/Viktor

developerMedlem sedan aug. 2001458 inlägg
#2

Rent allmänt när det gäller optimering är det något som ska göras på kod man vet är en flaskhals i programmet. Att spendera en timme på att optimera något som tar en promille av programmets hela exekveringstid är slöseri. Så börja med att ta reda på vad som är flaskhalsarna i ditt program och sen betar du av och optimerar dessa i tur och ordning. Ett bra sätt att leta flaskhalsar är med en profiler, exempelvis: http://www.compuware.com/products/devpartner/profiler/

Sedan är det förstås bra att aldrig skriva flaskhalsar :), och man lär sig med tiden vad som är bra och dåligt.

Generellt kan man säga att optimeringen som görs av kompilatorer är mycket bra i moderna kompilatorer. Riktigt bra länkare klarar även att optimera över flera objektfiler, vilket gör att man (i princip) aldrig vinner på att sitta och handjaga exempelvis assembler-kod (tvärtom förstör man då ofta möjligheten till optimering för kompilator/länkare). Den stora vinsta man kan göra själv är att välja smarta algoritmer och datastrukturer.

Men det var inget svar på frågan du ställde. Det är några olika saker du visar, vi tittar på de olika exemplen:

GetPlayer(iPlayer)

Här måste man veta vad GetPlayer(iPlayer) innebär. För en tung sökning som har sidoeffekter kan det löna sig att hämta bara göra ett anrop istället för två, annars inte.

Du använder i första fallet ButtonInfo direkt, medan du i andra fallet använder GetButtonInfo()-metoden. Jag förmoder att det är samma sak (?), dvs GetButtonInfo() är bara en accessmetod för ButtonInfo-structen. Det är mycket elegantare att anropa accessmetoden än att direkt komma åt medlemsvariabler i klassen. Rätt skriven är skillnaden obefintlig. Med rätt skriven menar jag ungefär såhär:

class Foo {
    //...
public:
    button_info ButtonInfo;
    button_info& GetButtonInfo() {
        return ButttonInfo;
    }
    //...
};

och detta måste ligga "inline" i klassen (i header-filen), eftersom det är enda tillfället då man garanteras att metoden inline:as (vilket man bara ska göra för väldigt korta metoder, typiskt 1-raders accessmetoder).

En annan sak att fundera på är hur ofta if-satsen blir sann. Om den blir sann "sällan", drar du ju bara nytta av optimeringen "sällan".

Jag tycker personligen inte om att ha structar där man pillar på enskilda variabler som du gör (frmctr), utan brukar lägga variablerna privata och använda accessmetoder. Det är ingen som helst prestandaskillnad på detta om alla access-metoder är inline och 1-raders.

ViktorMedlem sedan aug. 20021 752 inlägg
#3

Tack för svaret :)

En liten följdfråga, inline metoder, är de snabbare än vanliga funktioner som man lägger i en cpp fil?

/Viktor

developerMedlem sedan aug. 2001458 inlägg
#4

det beror på.

Att inline:a en metod "M" innebär att man istället för att göra ett funktionsanrop för att köra koden lägger en kopia av "M" där den ska köras. Så om "M" anropas från 10 ställen, kommer det finnas 10 kopior av "M", medan om "M" inte inline:ats hade det funnits 1 kopia, och man hade fått göra ett funktionsanrop från varje ställe den skulle användas.

Det innebär ett visst jobb att göra ett funktionsanrop (man lägger argument och returadress på stacken, gör anropet till funktionen som lyfter bort argument från stacken, kör funktionen, och returnerar), och det går därför fortare med en inline:ad metod då funktionsanropet inte behövs.

Men kan man inte alltid inline:a allt? Nej, det är riktigt dåligt, eftersom man får många kopior av samma kod. Det ger en större binärkod, vilket gör att man får fler cache-missar (långsamt). Men att inline:a en kort metod innebär inte fler instruktioner än vad funktionsanropet hade kostat.

Dessutom, för små korta metoder är kostnaden relativt stor för ett funktionsanrop (kanske åtgår fler instruktioner för att göra funktionsanropet än att köra själva funktionen), men för en lång metod är den förstås relativt liten. Så det är för små metoder man drar verklig nytta av inline:ing.

Nu känner jag att det här med inline:ing fick lite större betydelse här än vad det egentligen kanske är värt, men det kan ju vara bra att veta hur det fungerar.

ViktorMedlem sedan aug. 20021 752 inlägg
#5

developer skrev:

Nu känner jag att det här med inline:ing fick lite större betydelse här än vad det egentligen kanske är värt, men det kan ju vara bra att veta hur det fungerar.

Gör inget, alltid roligt att lärasig något nytt.

/Viktor

137 ms totalt · 3 externa anrop · v20260731065814-full.30151723
0 ms — hämta forumlista (cache)
0 ms — hämta statistik (cache)
135 ms — hämta tråd, inlägg och bilagor (db)