• Advertisement
Sign in to follow this  

Virtual still the bad way ?

This topic is 1876 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,
Using virtual on console dev is the bad way to have good perf when used on renderer.
The concept is to have IRenderer and have inherited class by API.
My question is quite simple : Is virtual still bad on both console ?

Thanks

Share this post


Link to post
Share on other sites
Advertisement
Even if the user would like to use a different renderer at compile/linkage time, wouldn't the use of a interface class with virtual methods would still be required, to avoid changing client code to use one renderer or another?? Edited by Burnt_Fyr

Share this post


Link to post
Share on other sites
Why do you think that requires virtual lookup? Virtual lookup is for runtime decisions.

Which API does this use:
[code]
class CircleRenderer {
public:
Renderer();
~Renderer();

void begin();
void circle(float x, float y, float r);
void end();
private:
// Omitted...
};
[/code]
What client changes are required if the implementation was switched from/to OpenGL/Direct3D/Software? Edited by rip-off
Wrong tags

Share this post


Link to post
Share on other sites
[quote name='Alundra' timestamp='1352902141' post='5000913']
My question is quite simple : Is virtual still bad on both console ?
[/quote]

The answer is really quite simple, independent of the platform:
If you do not need the decision at runtime, you do not need virtual or other decision structures and their performance cost and vice versa.

Share this post


Link to post
Share on other sites
If you want multiple switchable renderers at run time and not suffer so "much" (?) performance loss, i guess you could just move the "virtual interface" to a higher level which would reduce calls but increase the size of the executable.

Not sure how to do that properly, perhaps pass the renderer as a template instead of as a pointer that has virtual methods... (and instead make the temolate class have virtual methods)

feels messy though.

Share this post


Link to post
Share on other sites
Virtual functions are the bedrock of modern, object-oriented C++, and are unlikely to be a significant performance bottleneck on today's relatively fast processors. I recommend you proceed with using them. If at some point in the future, as a result of performance profiling, you do identify a virtual function or two that are slowing your code down (perhaps used very often in a tight loop), then address the problem locally at that time.

Good luck!
Geoff

Share this post


Link to post
Share on other sites
Virtual functions are fine... the overhead that they incur negligible in most cases when you consider the benefits. That being said, like anything in C++ it can get out of hand - virtual functions are a tool, and should be used when they're needed and they fit your design pattern.

Share this post


Link to post
Share on other sites
[quote name='Hodgman' timestamp='1352955900' post='5001111']
[quote name='gdunbar' timestamp='1352923413' post='5000997']Virtual functions are the bedrock of modern, object-oriented C++, and are unlikely to be a significant performance bottleneck on today's relatively fast processors.[/quote]FWIW, the [font=courier new,courier,monospace]class[/font] is the bedrock of C++ OOP, and [font=courier new,courier,monospace]virtual[/font] is an add-on for the [b]rare[/b] cases where you need runtime polymorphism.
[/quote]
IMO, [font=courier new,courier,monospace]class[/font] is the bedrock of most Object Based languages.
Object Oriented languages imply the availability of [font=courier new,courier,monospace]virtual[/font], as it allows for inheritance in addition to extension and aggregation...

...Perhaps it's more reasonable for us to define what [u][font=courier new,courier,monospace]bedrock[/font][/u] means in programming. :D

I just discovered that my real time script processing module uses virtual for its nodes in its intermediate representaion.
- Might be a good idea to change that... (Thanks Swiftcoder for the example on dealing with many virtual function calls) Edited by SuperVGA

Share this post


Link to post
Share on other sites
[quote name='gdunbar' timestamp='1352923413' post='5000997']
today's relatively fast processors
[/quote]

I don't know about you, but I find that processors are never quite fast enough! ;)

Share this post


Link to post
Share on other sites
[quote name='SuperVGA' timestamp='1352963167' post='5001125']Object Oriented languages imply the availability of virtual, as it allows for inheritance in addition to extension and aggregation...[/quote]Yeah, I just meant to imply that inheritance and polymorphism aren't the main/most-important/most-common parts of OOP, and are actually quite rare compared to, e.g. the use of composition or encapsulation.

Share this post


Link to post
Share on other sites
OK, OK, maybe I went too far with "bedrock". "Indispensable", maybe? C++ certainly wouldn't be much of an object-oriented language without virtual functions!

In any case, my true point stands: Use virtual functions. Don't worry about it. Then, if at some point in the future you have performance issues or otherwise want to optimize performance, you should measure performance. In the event that you find that you are calling a virtual function in a tight loop or something, you should be able to target a fix there; it is _extremely_ unlikely any type of major architectural change will be needed. swiftcoder's method of moving the function call to surround the loop (instead of the other way) is certainly an excellent option.

Good luck,
Geoff Edited by gdunbar

Share this post


Link to post
Share on other sites
[quote name='gdunbar' timestamp='1353091710' post='5001602']
OK, OK, maybe I went too far with "bedrock". "Indispensable", maybe? C++ certainly wouldn't be much of an object-oriented language without virtual functions!

In any case, my true point stands: Use virtual functions. Don't worry about it. Then, if at some point in the future you have performance issues or otherwise want to optimize performance, you should measure performance. In the event that you find that you are calling a virtual function in a tight loop or something, you should be able to target a fix there; it is _extremely_ unlikely any type of major architectural change will be needed. swiftcoder's method of moving the function call to surround the loop (instead of the other way) is certainly an excellent option.

Good luck,
Geoff
[/quote]
Use virtual functions if you need polymorphism. If you don't need, don't default to using virtual functions. Using of virtual functions is a design decision about where you want your abstractions to be. They should be used wisely or they will complicate whole code base. It is much easier to introduce virtual functions later on, than it is to get rid of them.

My answer to the OP is, the console is not going to change rendering API on runtime. Thus, it shouldn't be runtime polymorphic. Edited by Codarki

Share this post


Link to post
Share on other sites
In most cases, IMHO, virtual methods are better replaced with a plug-in system providing dependency inversion rather than concretet dependency, since its more amenable to automated unit testing and mocking. Dependency inversion allows the assembly of the class functions at runtime without implying any specific hierarchy.

As an example; a pseudo logging class using inheritence -

Class SystemLog : FileWriter
{
public WriteLog(string comment) : base(comment);
}

Using dependency injection

Class SystemLog
{
public IWriteDestination WriterStream {get;set;}
public WriteLog(string comment)
{
this.WriterStream.Write(comment);
}

}

The first example requires a class called FileWriter whose functionality is expressly built into the class hierarchy, but the second does not need this dependency; its entirely ignorant of how the functionality on which it depends is provided. The first example has the class "knowing" at design time about which class it will use to implement its features, but the second example has the class being ignorant of what other class will provide this function (allowing for a test framework to provide a replacement implementation without affecting the calling class).

Although polymorphism is a solid OO concept, anything but the simplist inheritence hierarchy requires a lot of design level decisions which could reasonably be left until runtime.

So - in short; Virtual generally is better replaced by a

public MyProvider : IProviderClass
{
get;set;
}

Phillip

Share this post


Link to post
Share on other sites
[quote name='PhillipHamlyn' timestamp='1353103516' post='5001649']
...
[/quote]
You introduce an indirection which adds an extra method call in means of performance.
Furthermore not using Polymorphism where it is appropriate will increase code size dramatically.

For testing this should imo not be a runtime decision, but a decision at build time.
In C++ you can easily swap in mockup classes in a type hierarchy with #ifdefs or by including different directories for unit/integration tests.
Not sure about C# though.

Share this post


Link to post
Share on other sites
[quote name='myro' timestamp='1353192309' post='5001865']
[quote name='PhillipHamlyn' timestamp='1353103516' post='5001649']
...
[/quote]
You introduce an indirection which adds an extra method call in means of performance.
Furthermore not using Polymorphism where it is appropriate will increase code size dramatically.

For testing this should imo not be a runtime decision, but a decision at build time.
In C++ you can easily swap in mockup classes in a type hierarchy with #ifdefs or by including different directories for unit/integration tests.
Not sure about C# though.
[/quote]

But inheritence uses a virtual method lookup anyway, so no net loss ?
Dont agree with the code size argument - I dont see a difference in code size either way. Same logic; same compiler.
Agreed you can use Mocking, but inheritence concepts indicate that the inheritor "is interested in" or "knows" about the implementation details of the inherited class and extends that [i]implementation[/i], Mocking replaces the implementation with a different one and therefore invalidates the assumptions on which the inheritence contract was originally made. With a dependency inversion approach, no assumptions are made about the implementation because these are interfaced away leaving only the calling contract.

Share this post


Link to post
Share on other sites
If you have legitimate reason to be worried about the performance costs of run time polymorphism, Agner Fog has a section in his free guide to [url="http://www.agner.org/optimize/optimizing_cpp.pdf"]Optimizing C++[/url] that describes how to do compile time polymorphism. You sacrifice a bit of readability for that possible benefit in performance though. Section 7.28 - "Templates" describes this. That pdf is an interesting thing to read if you ever have bits of free time scattered through your day that you need to make use of.

Share this post


Link to post
Share on other sites
I just want to say, each and every person so far has posted "true" statements ... but most of the posters have made a simple scientific / engineering question into a religious idea when it has no reason to be.

1. A language without "virtual" would not be very good for OO. I agree with this, on the grounds that dynamic dispatch / run-time polymorphism is one of the key ideas for the standard type of OO programming practiced today, from Smalltalk based roots. There are however other types of "OO", including the template / compile time version used in Advanced Template Metaprogramming and Modern C++ Design.

More people need to realize that programming languages exist to make life easier for the programmer to express a desire at programming time ... not to make any certain set of things happen at run-time unless they are needed to accomplish the desired result. Hence the rise of declarative concepts in recent years, which make the compiler and run-time work harder for the programmer.

2. Use virtual when you want run-time polymorphism or dispatch. Absolutely agree. This very useful keyword exist almost exclusively for this very purpose. When this is what you want, only very specialized alternatives can give any increased performance over the very simple virtual table. Examples of slightly "specialized" optimizations were already mentioned earlier in this thread ... such as polymorphic / virtual factories, which then do NOT use virtual method invocations internally ... so you pay the cost only during initialization (where it doesn't matter and isn't repeated), instead of during every method call of every object in your game loops.

3. The cost of virtual is "just" an extra indirection - function lookup. True. But "just" can be misleading. It is no more, nor less than this.

4. The cost of virtual is insignificant. Not always true. If you are trying to write a modern game engine, you simply cannot afford the cost of virtual function call on every function. It would be impossible to write a highly oo, completely dynamic game engine which tens-of-thousands of object running every frame with uncessary indirections at every level. When used "correctly" or at least either "when necessary", "when appropriate" or "sparingly" ... then virtual is great. When used for "no reason", "by default", "without consideration" or "excessively" ... virtual function call costs can actually account for a large percentage of your total performance cost - especially if also mixed with deep abstract object trees.

4. Inheritance implies virtual functions. Not at all true. virtual functions imply inheritance but NOT the other way around. Many many programming problems use inheiritance, but not run-time polymorphism.

I don't advocate avoiding virtual. In fact I use it quite heavily. And when prototyping I actual apply it "by default" on my prototype classes. But as your design solidifies, you realize a large set of methods has no reason to be virtual - UNLESS you are releasing BINARY class libraries to be consumed in unexpected ways by THIRD PARTIES who do NOT have access to your source code. That is the ONLY case where unknown use-cases dictate extra virtuals where not "needed" by existing client code.

Even more than virtuals I do most my programming in C# / .NET with all of its costs ... but when I have to tune the performance of an audio mixing library, or reduce the footprint / performance profile of some asynchronous networking code - I go to C++, and I use a "proper" design for the problem ... not just throw abstractions and features at it and hope performance just happens to be "good enough".

Share this post


Link to post
Share on other sites
You just have to understand what you are doing.
For a render you will not be passing the data directly to the functions, you will be passing pointers if-not handles to the methods.
So structured-coding overhead is guaranteed.
If you start creating function-pointers to code something up, you may-as-well have just used virtual functions.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement