DLL interfacing performance

Started by
3 comments, last by spek 9 years, 2 months ago

Actually 2 questions, but let's start with the more global one; is it a good idea to put math functionality in a separate library (Windows DLL) - performance wise?

I'm trying to split up my huge game application into smaller chunks, DLL's. One of those chunks would be a generic math library, with mainly vector functions. Now normally I don't care tóóó much about performance, but vector-functions are called LOT's of times each cycle. And if I remember well -but correct me if I'm wrong!- calling a function from an external library adds a little bit overhead.

So Instead of calling DLL functions, I could just as well just attach the code files to my other libraries that make use of it, if performance is really an issue. But I found the DLL way more elegant. The smaller each library, the better maintainable. Any idea how modern game engines handle this?

For the info- I'm making this math library with either native C++ or Pascal (Delphi XE). Thus not .NET or the likes.

Second, and this might be a bit C++ or Delphi specific, I'd like to keep things OOP. Now with .NET you can import a DLL and use its classes. But if I'm right this is not (directly) possible with C++ or Delphi based libraries. AFAIK, you can only export functions, structs (with functions / operator overloading??), and "Interfaces".

The latter, Interfaces, would more or less allow to export an "object" with functions. But yet again, I'm not sure if this is wise to do, when caring about performance. A typical example would be sharing "Entities" amongst multiple DLL's. An entity could be a game object, such as the player, a lightsource, or a crate. Several DLL's could be interested in using (read looping through / reading / writing / calling a lot) these entities. AI, Rendering, Physics, Game-rules , ...

Advertisement
Personally, I'm a big fan of modularization. However, I would consider actual DLLs as the last alternative for that. Static libraries are almost always doing a much better job with less headache. If you have megabytes of shared code between executables used next to each other, then yes, DLLs might be something for you if it outweighs the problems (see below).

There is no problem using classes across DLL boundaries (extremely important detail: if you know exactly what you are doing). For a start, name mangling across different C++ compilers will in general not be the same. So using C++ code (that's not just about classes, it's about anything not marked as pure C) across different compilers (or even different versions of the same compiler) will not work correctly for the simple reason they cannot find the functions they expect to find. Just because one compiler put an 'int myFunc(char*)' into the DLL does not mean another compiler can even find it. If you build both the DLLs and the executables using it with the same compiler (and the same build settings), you are clear though.

That's one part of the problem. Another problem is that you need to take care about where something was allocated and where it is freed. If the DLL newed something it can hand out that pointer to another DLL or the executable where it can be used. You are not allowed to just free that pointer in another module though. This can be worked around if both modules use a runtime which explicitly allows that (like /MD for MSVC). This is the reason why libraries generally offer a CreateXXX/DestroyXXX pair of functions for XXX you can create. Take note that if the runtime is updated you might have to ensure both executables and DLLs are all rebuilt and deployed using the same version of the runtime. I'm not sure how frequent that is but it happened to me at least once for MSVC 2005 or 2008 and missing an executable or DLL in a deployment can lead to highly annoying and difficult to track down bugs.

As a side effect of the above paragraphs, unless you can make sure you are using the exact same compilers and the exact same build settings standard library containers (including, say, std::string) are usually out for the public DLL interface. I say 'build settings' because that's not just about the runtime library used. For example MSVC allows to configure (among other things) iterator debugging at compile time using defines. If these defines are not identical extremely bad stuff will happen.

In summary, I'd like to reiterate once again: if all you are after is a bit of organization and modularization, forget about DLLs. Static libraries do that job wonderfully without any of the problems. If you really, absolutely need DLL functionality treat carefully and expect problems while you learn the ropes.

First of all, thanks for your time! Second, what exactly do you mean with a "Static library"? I know the term, but since its used in so many (slight) different ways. I suppose you mean the code from libraryX (a *.lib file? or *.a in Linux?) is actually "baked" into the "host" executable (thus no DLL or other files that are linked after starting the EXE). Basically just one big program? Never really tried that for some reason, but it makes perfect sense.

As for the same compilers, most likely that will be the case. The whole game/engine is made in Delphi7 (including a couple of DLL's written in Delphi7 and C++/VS2008). Delphi7 is ancient though, so I'll have to migrate sooner or later. Likely DelphiXE will give me a smoother transition, otherwise I would have to rewrite the whole thing in C++. Then again splitting up in modules and doing a big clean sweep won't hurt.

I've been using DLL's written in various languages quite some time, but not really consequently game-engine wise. Re-usability of code is nice, but splitting up in libraries/modules or whatever is especially nice as it *forces* you to think (better) about the design and architecture. When dealing with one huge program, roles and functionality often get blurry after a while. Who does what, what is depending on which...

Memory management is always a b*tch. I'm trying to avoid creating and destroying "stuff" on the fly as much as possible. Instead of building everything on demand whenever needed, I try to provide a collection of available objects. And yeah, you're right; if programA desroys stuff while DLL-X is still expecting it, errors get nasty. And probably it gets even worse when involving multi-threading and such.

Putting math into a DLL is a bad idea. It defeats any ability for your compiler to optimize the math code in use sites. The overhead of the DLL bounary aside, your compiler can do some pretty magical things with your math functions when it's allowed to inline and reorder their internals at the call site.

Modularizing a big code base into multiple libraries is a good idea, but math is the kind of thing that should be put into a static library and linked into each DLL or EXE that needs it. There are very good reasons to put certain kinds of things into DLLs (e.g. hot reloading, improved compile/link times, etc.) but math code is not one of those things. The same goes for other small, performance-sensitive modules like your string and containers code (if you have any).

Sean Middleditch – Game Systems Engineer – Join my team!

Thanks again!

Usually there are a thousand ways to Rome, but judging on your anwers (which make perfect sense), Static Libraries will be the way for me then.

This topic is closed to new replies.

Advertisement