Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

rewb0rn

Supermoderator

  • »rewb0rn« ist der Autor dieses Themas

Beiträge: 2 773

Wohnort: Berlin

Beruf: Indie Game Dev

  • Private Nachricht senden

1

12.06.2007, 15:46

Optimierung virtueller Funktionen

Ich hab letztens gelesen, dass virtuelle Funktionen einen signifikanten Geschwindigkeitsverlust in Spielen bedeuten können, wenn sie zu häufig aufgerufen werden. Mein Objektsystem besteht aus ca. 15 Klassen die mehrfach voneinander erben und es werden ~3 virtuelle Funktionen pro Frame aufgerufen. Ich glaube soweit sind die Geschwindigkeitseinbußen noch vertretbar, wenn überhaupt spürbar. Jetzt hab ich aber zB die Funktion FrameStarted(), und die soll je nach Bedarf auch noch die Versionen der Basisklassen aufrufen, also zB

C-/C++-Quelltext

1
2
3
4
void Derivation::FrameStarted(double TimePassed)
{
    inherited::FrameStarted(TimePassed);
}


Ist das auch ein virtueller Funktionsaufruf oder kann der Compiler da die direkte Adresse verwenden? (Würde also heißen, wenn eine Funktion virtuell ist, wäre es immer schlauer anstelle von Funktion() Klasse::Funktion() zu benutzen, wenn man weiß, dass es sowieso immer die bestimmte Version ist?

Und noch eine Frage zur Organisation:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Base
//...

void virtual FrameStarted();

class a : public virtual Base
//...

void virtual FrameStarted();

class b: public virtual Base
//...

void virtual FrameStarted();

class c: public virtual a, public virtual b
//

void virtual FrameStarted();


So jetzt soll in jedem Frame für ein Objekt vom Typ c jede Version der Funktion FrameStarted() genau einmal aufgerufen werden, ist dann das hier die intelligenteste Lösung?

C-/C++-Quelltext

1
2
3
4
5
6
7
c::_FrameStarted()
{
  Base::FrameStarted();
  a::FrameStarted();
  b::FrameStarted();
  c::FrameStarted();
}

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

2

12.06.2007, 17:17

Das virtuelle Methoden dein Programm signifikant verlangsamen halt ich für ein Gerücht. Was passiert denn bei einem Aufruf einer virtuellen Methode? Es wird die Funktionsadresse aus dem vtpl genommen und die Funktion wird aufgerufen, also passiert nicht wirklich mehr als bei einem normalen Funktionsaufruf. Das einzige was virtuelle Funktionen auslösen ist ein bisschen mehr Overhead der mit deinen Objekten hinzukommt.

Der Aufruf inherited::FrameStarted() gibt genau an welche Funktion aufgerufen werden soll. Darum ist der "Umweg" über die vtbl nicht notwendig und die Funktion kann direkt aufgerufen werden.

Zu deiner Organisation. Keine Ahnung was du mit b::Base::FrameStarted(); bezwecken willst.
@D13_Dreinig

rewb0rn

Supermoderator

  • »rewb0rn« ist der Autor dieses Themas

Beiträge: 2 773

Wohnort: Berlin

Beruf: Indie Game Dev

  • Private Nachricht senden

3

12.06.2007, 18:01

oh das war ein tippfehler

danke schonmal

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

4

12.06.2007, 21:03

Zitat von »"David_pb"«

Das virtuelle Methoden dein Programm signifikant verlangsamen halt ich für ein Gerücht. Was passiert denn bei einem Aufruf einer virtuellen Methode? Es wird die Funktionsadresse aus dem vtpl genommen und die Funktion wird aufgerufen, also passiert nicht wirklich mehr als bei einem normalen Funktionsaufruf. Das einzige was virtuelle Funktionen auslösen ist ein bisschen mehr Overhead der mit deinen Objekten hinzukommt.

Virtuelle Methoden kann der Compiler nicht inlinen.
Außerdem ist der Umweg über die Vtbl ungünstiger für den Prozessor als ein Funktionsaufruf, dessen Adresse von vornherein feststeht. Hier muss die Sprungvorhersage gut funktionieren, damit die Pipeline nicht leerläuft.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

5

12.06.2007, 21:18

Zitat von »"David Scherfgen"«

Virtuelle Methoden kann der Compiler nicht inlinen.


bist du dir da ganz sicher? generell hast du natürlich recht. aber ich denke nicht, dass es prinzipiell unmöglich ist. der compiler kann ja unter gewissen umständen (falls der dynamische typ zur compilezeit bekannt ist) virtuelle funktionsaufrufe eliminieren. ich sehe keinen grund warum er dann in einem solchen fall die funktion nicht inlinen können sollte (natürlich muss er die funktion sowieso instanzieren damit er eine adresse für die vtable hat, aber das stört ja keinen). ich denke auch nicht dass der C++ standard das verbietet (hab jetzt aber nicht nachgeschaut, also bitte bessert mich aus falls dem so wäre). natürlich kommt sowas selten vor und wird wenn überhaupt nur von wenigen compilern in sehr seltenen fällen gemacht werden.

EDIT: typo ausgebessert ;)

David Scherfgen

Administrator

Beiträge: 10 382

Wohnort: Hildesheim

Beruf: Wissenschaftlicher Mitarbeiter

  • Private Nachricht senden

6

12.06.2007, 21:25

OK, in speziellen Fällen, wenn der Typ zur Kompilierzeit bekannt ist, dann geht es natürlich schon (ob die Compiler das tun, müsste man mal testen).

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

7

12.06.2007, 21:43

Zitat von »"David Scherfgen"«

Zitat von »"David_pb"«

Das virtuelle Methoden dein Programm signifikant verlangsamen halt ich für ein Gerücht. Was passiert denn bei einem Aufruf einer virtuellen Methode? Es wird die Funktionsadresse aus dem vtpl genommen und die Funktion wird aufgerufen, also passiert nicht wirklich mehr als bei einem normalen Funktionsaufruf. Das einzige was virtuelle Funktionen auslösen ist ein bisschen mehr Overhead der mit deinen Objekten hinzukommt.

Virtuelle Methoden kann der Compiler nicht inlinen.
Außerdem ist der Umweg über die Vtbl ungünstiger für den Prozessor als ein Funktionsaufruf, dessen Adresse von vornherein feststeht. Hier muss die Sprungvorhersage gut funktionieren, damit die Pipeline nicht leerläuft.


Sicher ist es ein Mehraufwand. Aber einen signifikanten Geschwindigkeitsverlust, wie rewb0rn ihn beschrieb, wird es auf keinen Fall geben. Auch nicht bei häufiger Verwendung virtueller Funktionen.
@D13_Dreinig

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

8

12.06.2007, 21:46

doch. wie david schon geschreiben hat liegt das eigentliche problem nicht unbedingt an den 2 zusätzlichen indirektionen, sondern daran, dass sowas sehr ungünstig für die pipeline sein kann (außerdem hauts evtl. den instruction cache zusammen etc.)...

David_pb

Community-Fossil

Beiträge: 3 886

Beruf: 3D Graphics Programmer

  • Private Nachricht senden

9

12.06.2007, 21:51

Ja, wenns dumm läuft. Virtuelle Funktionen sind aber keine Garantie für einen enormen Speedverlust. Ansonsten könnte man bei Zeitauwendigen Anwendungen ein OOP Design komplett in die Tonne kloppen...
@D13_Dreinig

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

10

12.06.2007, 22:01

ja. wenn man virtual functions braucht, dann soll man sie imo ruhig verwenden. wenn man wirklich performance probleme bekommt, merkt mans eh. und das sollte eigentlich nur selten wirklich der fall sein.

Werbeanzeige