PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Optimierung durch Compiler (g++)



SebastianKN
13-07-2007, 12:22
Hallo,

ich hab ein Stück Code geschrieben und frage mich aus Performancegründen was der Compiler daraus macht. Compiler ist g++ mit -O2 Flag.

Das ganze sind drei verschachtelte for-Schleifen (mit den Zählvariablen i, ii und iii). Der folgende Code ist die innerste Schleife. In dieser greife ich auf eine recht umfangreiche Datenstruktur zu, die aus mehreren std::vector besteht. Also nets, edges und points sind vectoren (aus #include <vector>).

Frage: Wird zur Laufzeit der Ausdruck layout->nets[i].edges[ii].path->points[iii] jedes mal neu ausgewertet, wird also jedes mal die Adresse von x bzw y berechnet und dann erst der Inhalt dem tmpPoint->x bzw y zugewiesen oder wird die Adresse von points[iii] einmal berechnet und in beiden Zuweisungen verwendet? Gibt es also einen Unterschied zwischen Code 1 und Code 2?

Code 1:


for( iii = 0; iii < layout->nets[i].edges[ii].path->points.size(); iii++ ) {
tmpPoint = new Point;
tmpPoint->x = layout->nets[i].edges[ii].path->points[iii].x;
tmpPoint->y = layout->nets[i].edges[ii].path->points[iii].y;

[ ... ]
}


Code 2:


for( iii = 0; iii < layout->nets[i].edges[ii].path->points.size(); iii++ ) {
Koord* p = &(layout->nets[i].edges[ii].path->points[iii]);
tmpPoint = new Point;
tmpPoint->x = p->x;
tmpPoint->y = p->y;

[ ... ]
}


Danke schon mal für eure Antworten!

Gruß
Sebastian

Boron
13-07-2007, 14:58
In dem Fall würde ich mir einfach mal den Assembler Code in einem Debugger anschauen.

Aber prinzipiell würde ich Variante 2 vorziehen, weil ich das schöner zu lesen finde Es wird ja nur einmalig die Koordinate bestimmt und dann x, bzw. y rausgezogen.
So ist es nämlich egal ob der Compiler die doppelte Adressbestimmung optimiert oder nicht, weil die Adressbestimmung nur ein mal stattfindet.

SebastianKN
13-07-2007, 16:12
finde die zweite Variante auch hübscher ;)

Hab mal Deinen Assembler-Tipp ausprobiert und beide Varianten einmal mit und einmal ohne Optimierung angeschaut:


Variante 1 / Code 1: NICHT OPTIMIERT



tmpPoint->x = layout->nets.edges[ii].path->points[iii].x;

0x080f57e8 <GARouter::getLinelist()+182>: mov 0xfffffff4(%ebp),%esi
0x080f57eb <GARouter::getLinelist()+185>: mov 0xfffffff0(%ebp),%ebx
0x080f57ee <GARouter::getLinelist()+188>: mov 0xffffffec(%ebp),%edx
0x080f57f1 <GARouter::getLinelist()+191>: mov 0x8(%ebp),%eax
0x080f57f4 <GARouter::getLinelist()+194>: mov 0x4(%eax),%eax
0x080f57f7 <GARouter::getLinelist()+197>: mov %edx,0x4(%esp)
0x080f57fb <GARouter::getLinelist()+201>: mov %eax,(%esp)
0x080f57fe <GARouter::getLinelist()+204>: call 0x80f5b92 <std::vector<GANet, std::allocator<GANet> >::operator[](unsigned int)>
0x080f5803 <GARouter::getLinelist()+209>: mov %ebx,0x4(%esp)
0x080f5807 <GARouter::getLinelist()+213>: mov %eax,(%esp)
0x080f580a <GARouter::getLinelist()+216>: call 0x80f5d52 <std::vector<GAEdge, std::allocator<GAEdge> >::operator[](unsigned int)>
0x080f580f <GARouter::getLinelist()+221>: mov (%eax),%eax
0x080f5811 <GARouter::getLinelist()+223>: mov %esi,0x4(%esp)
0x080f5815 <GARouter::getLinelist()+227>: mov %eax,(%esp)
0x080f5818 <GARouter::getLinelist()+230>: call 0x80f5f04 <std::vector<Koord, std::allocator<Koord> >::operator[](unsigned int)>
0x080f581d <GARouter::getLinelist()+235>: mov (%eax),%edx
0x080f581f <GARouter::getLinelist()+237>: mov 0xffffffe8(%ebp),%eax
0x080f5822 <GARouter::getLinelist()+240>: mov %edx,(%eax)


tmpPoint->y = layout->nets[i].edges[ii].path->points[iii].y;
0x080f5824 <GARouter::getLinelist()+242>: mov 0xfffffff4(%ebp),%esi
0x080f5827 <GARouter::getLinelist()+245>: mov 0xfffffff0(%ebp),%ebx
0x080f582a <GARouter::getLinelist()+248>: mov 0xffffffec(%ebp),%edx
0x080f582d <GARouter::getLinelist()+251>: mov 0x8(%ebp),%eax
0x080f5830 <GARouter::getLinelist()+254>: mov 0x4(%eax),%eax
0x080f5833 <GARouter::getLinelist()+257>: mov %edx,0x4(%esp)
0x080f5837 <GARouter::getLinelist()+261>: mov %eax,(%esp)
0x080f583a <GARouter::getLinelist()+264>: call 0x80f5b92 <std::vector<GANet, std::allocator<GANet> >::operator[](unsigned int)>
0x080f583f <GARouter::getLinelist()+269>: mov %ebx,0x4(%esp)
0x080f5843 <GARouter::getLinelist()+273>: mov %eax,(%esp)
0x080f5846 <GARouter::getLinelist()+276>: call 0x80f5d52 <std::vector<GAEdge, std::allocator<GAEdge> >::operator[](unsigned int)>
0x080f584b <GARouter::getLinelist()+281>: mov (%eax),%eax
0x080f584d <GARouter::getLinelist()+283>: mov %esi,0x4(%esp)
0x080f5851 <GARouter::getLinelist()+287>: mov %eax,(%esp)
0x080f5854 <GARouter::getLinelist()+290>: call 0x80f5f04 <std::vector<Koord, std::allocator<Koord> >::operator[](unsigned int)>
0x080f5859 <GARouter::getLinelist()+295>: mov 0x4(%eax),%edx
0x080f585c <GARouter::getLinelist()+298>: mov 0xffffffe8(%ebp),%eax
0x080f585f <GARouter::getLinelist()+301>: mov %edx,0x4(%eax)



Variante 1 / Code 1: OPTIMIERT



tmpPoint->x = layout->nets[i].edges[ii].path->points[iii].x;

0x080ee9d6 <GARouter::getLinelist()+246>: mov (%edx),%ecx
0x080ee9d8 <GARouter::getLinelist()+248>: mov %ecx,(%eax)

tmpPoint->x = layout->nets[i].edges[ii].path->points[iii].y;

0x080ee9da <GARouter::getLinelist()+250>: mov 0x4(%edx),%edx
0x080ee9dd <GARouter::getLinelist()+253>: mov %edx,0x4(%eax)


Wo genau die Adresse berechnet wird konnt ich nicht verfolgen. Der sprang da wie wild im Assemblercode herum...


Variante 2 / Code 2: NICHT OPTIMIERT



Koord* p = &(layout->nets[i].edges[ii].path->points[iii]);

0x080f57d6 <GARouter::getLinelist()+164>: mov 0xfffffff0(%ebp),%esi
0x080f57d9 <GARouter::getLinelist()+167>: mov 0xffffffec(%ebp),%ebx
0x080f57dc <GARouter::getLinelist()+170>: mov 0xffffffe8(%ebp),%edx
0x080f57df <GARouter::getLinelist()+173>: mov 0x8(%ebp),%eax
0x080f57e2 <GARouter::getLinelist()+176>: mov 0x4(%eax),%eax
0x080f57e5 <GARouter::getLinelist()+179>: mov %edx,0x4(%esp)
0x080f57e9 <GARouter::getLinelist()+183>: mov %eax,(%esp)
0x080f57ec <GARouter::getLinelist()+186>: call 0x80f5b64 <std::vector<GANet, std::allocator<GANet> >::operator[](unsigned int)>
0x080f57f1 <GARouter::getLinelist()+191>: mov %ebx,0x4(%esp)
0x080f57f5 <GARouter::getLinelist()+195>: mov %eax,(%esp)
0x080f57f8 <GARouter::getLinelist()+198>: call 0x80f5d24 <std::vector<GAEdge, std::allocator<GAEdge> >::operator[](unsigned int)>
0x080f57fd <GARouter::getLinelist()+203>: mov (%eax),%eax
0x080f57ff <GARouter::getLinelist()+205>: mov %esi,0x4(%esp)
0x080f5803 <GARouter::getLinelist()+209>: mov %eax,(%esp)
0x080f5806 <GARouter::getLinelist()+212>: call 0x80f5ed6 <std::vector<Koord, std::allocator<Koord> >::operator[](unsigned int)>
0x080f580b <GARouter::getLinelist()+217>: mov %eax,0xfffffff4(%ebp)

tmpPoint->x = p->x;

0x080f581d <GARouter::getLinelist()+235>: mov 0xfffffff4(%ebp),%eax
0x080f5820 <GARouter::getLinelist()+238>: mov (%eax),%edx
0x080f5822 <GARouter::getLinelist()+240>: mov 0xffffffe4(%ebp),%eax
0x080f5825 <GARouter::getLinelist()+243>: mov %edx,(%eax)

tmpPoint->y = p->y;

0x080f5827 <GARouter::getLinelist()+245>: mov 0xfffffff4(%ebp),%eax
0x080f582a <GARouter::getLinelist()+248>: mov 0x4(%eax),%edx
0x080f582d <GARouter::getLinelist()+251>: mov 0xffffffe4(%ebp),%eax
0x080f5830 <GARouter::getLinelist()+254>: mov %edx,0x4(%eax)


Variante 2 / Code 2: OPTIMIERT



Koord* p = &(layout->nets[i].edges[ii].path->points[iii]);

[I]Zeile wird nicht ausgeführt

tmpPoint->x = p->x;

0x080ee9b8 <GARouter::getLinelist()+216>: mov (%ebx),%edx
0x080ee9ba <GARouter::getLinelist()+218>: mov %edx,(%eax)

tmpPoint->y = p->y;

0x080ee9bc <GARouter::getLinelist()+220>: mov 0x4(%ebx),%edx
0x080ee9bf <GARouter::getLinelist()+223>: mov %edx,0x4(%eax)


Die Berechnung der Adresse wird wohl auch schon irgendwo vorher gemacht (hat breakpoint einfach übersprungen). Die benötigt er wohl schon für die Abbruchbedingung der Schleife.


Naja, im Endeffekt ist es wohl egal welche Variante man verwendet, da die Optimierung ganz gut zu sein scheint.

Gruß
Sebastian