views:

1478

answers:

12

In the name of efficiency in game programming, some programmers do not trust several C++ features. One of my friends claims to understand how game industry works, and would come up with the following remarks:

  • Do not use smart pointers. Nobody in games does.
  • Exceptions should not be (and is usually not) used in game programming for memory and speed.

How much of these statements are true? C++ features have been designed keeping efficiency in mind. Is that efficiency not sufficient for game programming? For 97% of game programming?

The C-way-of-thinking still seems to have a good grasp on the game development community. Is this true?

I watched another video of a talk on multi-core programming in GDC 2009. His talk was almost exclusively oriented towards Cell Programming, where DMA transfer is needed before processing (simple pointer access won't work with the SPE of Cell). He discouraged the use of polymorphism as the pointer has to be "re-based" for DMA transfer. How sad. It is like going back to the square one. I don't know if there is an elegant solution to program C++ polymorphism on the Cell. The topic of DMA transfer is esoteric and I do not have much background here.

I agree that C++ has also not been very nice to programmers who want a small language to hack with, and not read stacks of books. Templates have also scared the hell out of debugging. Do you agree that C++ is too much feared by the gaming community?

+30  A: 

Look, most everything you hear anyone say about efficiency in programming is magical thinking and superstition. Smart pointers do have a performance cost; especially if you're doing a lot of fancy pointer manipulations in an inner loop, it could make a difference.

Maybe.

But when people say things like that, it's usually the result of someone who told them long ago that X was true, without anything but intuition behind it. Now, the Cell/polymorphism issue sounds plausible — and I bet it did to the first guy who said it. But I haven't verified it.

You'll hear the very same things said about C++ for operating systems: that it is too slow, that it does things you want to do well, badly.

None the less we built OS/400 (from v3r6 forward) entirely in C++, bare-metal on up, and got a code base that was fast, efficient, and small. It took some work; especially working from bare metal, there are some bootstrapping issues, use of placement new, that kind of thing.

C++ can be a problem just because it's too damn big: I'm rereading Stroustrup's wristbreaker right now, and it's pretty intimidating. But I don't think there's anything inherent that says you can't use C++ in an effective way in game programming.

Charlie Martin
I bet that's the first time anyone's said the words 'game' and 'OS/400' in the same sentence. Kudos for writing such a good OS though.
gbjbaanb
+1 for a really good answer. The only thing to add is to profile in case that something is to slow and then address the "real" culprit found by profiling. Let's not forget what Don Knuth told us: "We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil."
lothar
Quite a number of engineers say that C++ is not for embedded systems. I work as an embedded systems engineer and use C++ whenever possible and the result is higher quality code, which is more compact, easier to maintain and requires less debug. Probably most of those who believe this falacy are those who think C++ C with a few extensions. I have yet to see code with speed problems because it's coded in C++ instead of C. Also, modern C++ compilers do a very good job, and the result is usually as efficient as with C.
piotr
There's a reason the C++ commitee wrote a TR (Technical Report) on the use of C++ in embedded systems - there's too much myth. The TR is available for free from the ISO C++ website.
MSalters
Game developers have very good performance analysis tools. So usually when I hear someone say how smart pointers doing extra work on dereference or virtual calls taking up a lot of time, it's because they saw it in one of their profiling tools. We work with embedded platforms and they all have their own performance idiosyncrasies, so I find it a bit offensive that you assume we're all optimizing our games based on myths and assumptions when you aren't familiar with the platforms we use.
Dan Olson
@Dan, I'm sorry you find it offensive. That doesn't mean it doesn't match my experience, though.
Charlie Martin
@Dan: Amen to that.
kotlinski
+2  A: 

It really depends on the type of game too. If it's a processor-light game (like an asteroids clone) or pretty much anything in 2d, you can get away with more. Sure, smart pointers cost more than regular pointers, but if some people are writing games in C# then smart pointers are definitely not going to be a problem. And exceptions not being used in games is probably true, but many people misuse exceptions anyways. Exceptions should only be used for exceptional circumstances..not expected errors.

ryeguy
yeah you prob want to stay away smart pointers and exceptions on really big games. IE AAA titles where there's a lot of code and it has to be as fast as possible (crysis/gow).
Annerajb
And even then, I wish you wouldn't. Too many AAA games are buggy as hell.. Id much prefer the game running a few frames per second slower (and lets face it, micro-optimizations like this will rarely gain you more than a few additional frames) than having the thing leak memory, glitch or crash. Too many AAA games do and I bet its because the programmers worried about shit like this :'(
Dan
+4  A: 

Lots of people make absolute statements about things, because they don't actually think. They'd rather just apply a rule, making things more tedious, but requiring less design and forethought. I'd rather have a bit of hard thinking now and then when I'm doing something hairy, and abstract away the tedium, but I guess not everyone thinks that way. Sure, smart pointers have a performance cost. So do exceptions. That just means there may be some small portions of your code where you shouldn't use them. But you should profile first and make sure that's actually what the problem is.

Disclaimer: I've never done any game programming.

Adam Jaskiewicz
+8  A: 

If you or your friend are really paranoid about performance, then go read the Intel manuals on optimization. Fun.

Otherwise, go for correctness, reliability and maintainability every time. I'd rather have a game that ran a bit slowly than one that crashed. If/when you notice that you have performance issues, PROFILE and then optimize. You will likely find that theres some hotspot piece of code which can possibly be made more efficient by using a more efficient data structure or algorithm. Only bother about these silly little mico-optimization when profiling shows that they're the only way you can get a worthwhile speedup.

So:

  1. Write code to be clear and correct
  2. Profile
  3. PROFILE
  4. Can you use more efficient data structures or algorithms to speed up the bottleneck?
  5. Use micro-optimizations as a last resort and only where profiling showed it would help

PS: A lot of modern C++ compilers provide an exception handling mechanism which adds zero execution overhead UNLESS an exception is thrown. That is, performance is only reduced when an exception is actually thrown. As long as exceptions are only used for exceptional circumstances, then theres no good reason not to use them.

Dan
+1 for repeating "Profile".
Joe White
PROFILE DAMMIT! :D
Dan
+35  A: 

The last game I worked on was Heavenly Sword on the PS3 and that was written in C++, even the cell code. Before that, I did some PS2 games and PC games and they were C++ as well. Non of the projects used smart pointers. Not because of any efficency issues but because they were generally not needed. Games, especially console games, do not do dynamic memory allocation using the standard memory managers during normal play. If there are dynamic objects (missiles, enemies, etc) then they are usually pre-allocated and re-used as required. Each type of object would have an upper limit on the number of instancies the game can cope with. These upper limits would be defined by the amount of processing required (too many and the game slows to a crawl) or the amount of RAM present (too much and you could start frequently paging to disk which would seriously degrade performance).

Games generally don't use exceptions because, well, games shouldn't have bugs and therefore not be capable of generating exceptions. This is especially true of console games where games are tested by the console manufacturer, although recent platforms like 360 and PS3 do appear to have a few games that can crash. To be honest, I've not read anything online about what the actual cost of having exceptions enabled is. If the cost is incurred only when an exception is thrown then there is no reason not to use them in games, but I don't know for sure and it's probably dependant on the compiler used. Generally, game programmers know when problems can occur that would be handled using an exception in a business application (things like IO and initialisation) and handle them without the use of exceptions (it is possible!).

But then, in the global scale, C++ is slowly decreasing as a language for game development. Flash and Java probably have a much bigger slice of market and they do have exceptions and smart pointers (in the form of managed objects).

As for the Cell pointer access, the problems arise when the code is being DMA'd into the Cell at an arbitrary base addresses. In this instance, any pointers in the code need to be 'fixed up' with the new base address, this includes v-tables, and you don't really want to do this for every object you load into the Cell. If the code is always loaded at a fixed address, then there is never a need to fix-up the pointers. You lose a bit of flexibility though as you're limiting where code can be stored. On a PC, the code never moves during execution so pointer fix-up at runtime is never needed.

I really don't think anyone 'distrusts' C++ features - not trusting the compiler is something else entirely and quite often new, esoteric archetectures like the Cell tend to get robust C compilers before C++ ones because a C compiler is much easier to make than a C++ one.

Skizz

Skizz
Good points. +1 for giving a honest answer, also because it comes from someone who has experience in writing games
Edison Gustavo Muenz
"Games generally don't use exceptions because, well, games shouldn't have bugs"Software in general shouldn't have bugs, but it ends up having. Carefully using exceptions is a good way to handle errors without cluttering the code with a lot of error handling.
piotr
@Skizz: The main argument for using smart pointers would be exception safety (using RAII, it is possible to design smart pointer on the line of scoped_ptr serving your use case of placement new and delete/replacement of object). But since you do not care about exceptions, smart pointers won't be needed. However exceptions like "out of memory" or network disconnect can happen. Probably you use error codes? The other case when smart pointer is needed is reference counting, which is avoidable in most cases using exclusive ownership, which probably suffices for most parts of games, as you say.
Amit Kumar
With regards to the above: Console games are tested quite thoroughly by the manufacturer and any failure means not being allowed to publish the game, which means not getting any revenue from sales. So games are generally bug free. The testing covers all known failure modes, such as network disconnect for networked games, controller removal, memory card removal and so on. Out of memory should never happen - (XBox aside) consoles have a known, fixed amount of RAM and it is carefully budgeted to various aspects of the game during development (audio, graphics, AI, etc).
Skizz
@Skizz: Possibly Amit disagrees with the assumption inherent in "games shouldn't have bugs and therefore not be capable of generating exceptions". Some programmers use exceptions in non-bug situations (especially if they're from Java), for example to unwind the stack if your network connection drops deep in some socket-using code. It would be interesting to know why games choose not to do this, even if the answer is just "because we, unlike certain other C++ programmers, prefer to return error codes rather than throw exceptions".
Steve Jessop
Also, -fno-exceptions can result in smaller code, which may be justification enough on its own if you had no particular plans to use them, and want to squeeze more into your icache.
Steve Jessop
Your network connection dropping is exceptional behavior, if you ask me, and a perfectly valid use of exceptions. Its not like you expect this to happen every frame of your game and most good compilers have no speed overheads unless an exception is thrown.
Dan
Come on. A network connection dropping is not an exceptional behavior. It's normal.
kotlinski
From the codes point of view, it is. The normal behaviour ehre is that the connection is up and working.
Dan
maybe this is another myth, but the performance of exception handling in realtime systems in C++ has a reputation of being slow. It's more efficient to deal with return values than to rely of C++ exceptions. Does anyone know if this is really true?
sean riley
@Dan: which code? maybe in the application code layer that is true, but not in the network layer.
sean riley
For the exception bit, I think it's important to consider how games differ from other applications: Something that would throw an exception generally translates into the game should crash anyways, so why deal with the (admittedly often slight) overhead? If you unexpectedly fail to load a file, can't acquire some resource, etc., almost always the exception is just going to go to the top anyways, so just call "exit()", free your resources, and get it over with. Granted, it depends on what's viewed as "exceptional", but in games "exceptional" generally equals "crash" no matter how it's handled.
Tyler Millican
Tyler: but the overhead of C++ exceptions only comes into play when an exception is actually thrown - this is known as zero overhead exception handling - in which case you said the code should crash. Personally, I HATE when my games crash, I'd much rather get a message telling me why so I can fix it and play my game. Or better yet, it recovers and lets me continue playing. Slight performance hit when an error occurs vs crash.. I think I know which I prefer.
Dan
+5  A: 

Regarding the Cell architecture: it has an incoherent cache. Each SPE has its own local store of 256 KB. The SPEs can only access this memory; any other memory, such as the 512 MB of main memory or the local store of another SPE, has to be accessed with DMA. You perform the DMA manually and copy the memory into your local store by explicitly initiating a DMA transfer. This makes synchronization a huge pain.

Alternatively, you actually can access other memory. Main memory and each SPE's local store is mapped to a certain section of the 64-bit virtual address space. If you access data through the right pointers, the DMA happens behind the scenes, and it all looks like one giant shared memory space. The problem? Huge performance hit. Every time you access one of these pointers, the SPE stalls while the DMA occurs. This is slow, and it's not something you want to do in performance-critical code (i.e. a game).

This brings us to Skizz's point about vtables and pointer fixups. If you're blindly copying around vtable pointers between SPEs, you're going to incur a huge performance hit if you don't fix up your pointers, and you're also going to incur a huge performance hit if you do fix up your pointers and download the virtual function code to the SPEs.

Adam Rosenfield
+4  A: 

I have written small games in the past with C++ and use C++ currently for other high performance applications. There is no need to use every single C++ feature throughout the whole code base.

Because C++ is (pretty much, minus a few things) a superset of C, you can write C style code where required, while taking advantage of the extra C++ features where appropriate.

Given a decent compiler, C++ can be just as quick as C because you can write "C" code in C++.

And as always, profile the code. Algorithms and memory management generally have a greater impact on performance than using some C++ feature.

Many games also embed Lua or some other scripting language into the game engine, so obviously maximum performance isn't required for every single line of code.

I have never programmed or used a Cell so that may have further restrictions etc.

Steven
"Given a decent compiler, C++ can be just as quick as C because you can write "C" code in C++." -- The author of blitz++ library would say "C++ can be faster than C because you can write C++, the features not in C"
Amit Kumar
+2  A: 

C++ is not feared by the gaming community. Having worked on an open-world game engine selling millions, I can say the people in the business are extremely skilled and knowledgable.

The fact that shared_ptr isn't used extensively is partly because there is a real cost to it, but more importantly because ownership isn't very clear. Ownership and resource management is one of the most important and hardest things to get right. Partly because resources are still scarce on console, but also since most difficult bugs tend to be related to unclear resource management (e.g. who and what controls the lifetime of an object). IMHO shared_ptr doesn't help with that the least.

There is an added cost to exception handling, which makes it just not worthwhile. In the final game, no exceptions should be thrown anyway - it's better to just crash than to throw an exception. Plus, it's really hard to ensure exception safety in C++ anyway.

But there are many other parts of C++ that are used extensively in the gaming business. Inside EA, EASTL is an amazing remake of STL that is very adapted for high performance and scarce resources.

kotlinski
+1  A: 

Kevin Frei wrote an interesting document, “How much does Exception Handling cost, really?”.

Luc Hermitte
+1  A: 

There is an old saying about Generals being fully prepared to fight the last war not the next.

Something similar is true about most advice on performance. It usually relates to the software and hardware that was availbale five years ago.

James Anderson
A: 

I also heard it before I joined the game industry, but something I've found is that the compilers for specialized game hardware are sometimes... subpar. (I've personally only worked with the major consoles, but I'm sure it's even more true for devices like cell phones and the like.) Obviously this isn't really a huge issue if you're developing for PC, where the compilers are tried, true, and abundant in variety, but if you want to develop a game for the Wii, PS3, or X360, guess how many options you have and how well tested they are versus your Windows/Unix compiler of choice.

This isn't to say that the tools are necessarily awful, of course, but they're only guaranteed to work if your code is simple -- in essence, if you program in C. This doesn't mean that you can't use a class or create a RAII-using smart pointer, but the further from that "guaranteed" functionality you get, the shakier the support for the standard becomes. I've personally written a line of code using some templates that compiled for one platform but not on another -- one of them simply didn't support some fringe case in the C++ standard properly.

Some of it is undoubtedly game programmer folklore, but chances are it came from somewhere: Some old compiler unwound the stack strangely when exceptions were thrown, so we don't use exceptions; A certain platform didn't play with templates well, so we only use them in trivial cases; etc. Unfortunately the problem cases and where they occurred never seem to be written down anywhere (and the cases are frequently esoteric and were a pain to track down when they first occurred), so there's no easy way to verify if it's still an issue or not except to try and hope you don't get hurt as a result. Needless to say, this is easier said than done, so the hesitance continues.

Tyler Millican
+1  A: 

I ran across an excellent presentation by Sony called "Pitfalls of Object Oriented Programming". This generation of console hardware has really made a number of people take a second look at the OO aspects of C++ and start asking questions about whether it's really the best way forward.

You can find the presentation here (direct link here). Maybe you'll find the example a bit contrived, but hopefully you'll see that this dislike of highly abstracted object oriented designs isn't always based on myth and superstition.

Dan Olson
+1 The presentation was quite nice.
Amit Kumar