Wednesday, November 26, 2008

SpringLobby release

A new version of SpringLobby has been released including a feature I made - as guest developer, you could say :-)

Besides the minimap (a picture of the map's texture), which has been present in Spring Lobbies practically forever, and the metalmap, which I added earlier to test a unitsync feature, you can now also view the heightmap.


As usual for SpringLobby, prebuilt packages are available on the site.

Have fun!

Gdb tricks

Yesterday I was debugging some curious bug in the Spring engine. I was playing a game of XTA and near the 51th minute the engine suddenly appeared to hang. So I fired up gdb, attached it to the process, and started to examine it. Now I wouldn't post here if I didn't learn some new things in gdb. That's what this post is about.


Static typing vs dynamic typing

By default, gdb uses some sort of static typing when examining data. If I point it at a memory location and tell it it contains a CObject pointer, then it will interpret it as a CObject pointer. Sometimes however, you have a list of polymorphous objects, and you want to know the actual type of the object being pointed to. This can be toggled on and off for all print commands using set print object on/off.

(gdb) p $99
$129 = (CObject *) 0xfe545f0
(gdb) set print object on
(gdb) p $99
$130 = (CUnit *) 0xfe545f0


Pretty printing


By default, gdb uses a very concise format for printing out objects. This may be good enough if you're looking at a tiny data structure, but for large structures it becomes illegible. You can, however, toggle pretty printing, which changes exactly this. Suddenly all members of a class are nicely indented, etc. Use set print pretty on/off for this.

Often when debugging, I find I'm absolutely not interested in the value of static members of classes. Even so, gdb still prints them out every time you print an instance of such class. This can be turned off using set print static on/off.


The poor man's loop applied to a linked list

I needed to go through a linked list yesterday, and was wondering how to do this without having to type a new print command every time. A little bit of googling brought me to this blog entry however, detailing how to loop through an array using the feature that pressing "return" on an empty line repeats the previous command. A similar thing can be done be used to loop through a linked list, in this example a std::list<CObject>. (Example is under the assumption of a 32 bit system.)

(gdb) set $node = 0x804a018
(gdb) p {CObject*} ($node + 8)
content of first node
(gdb) p {CObject*} (($node = *$node) + 8)
content of second node
(gdb)
content of third node
(gdb)
content of fourth node
...

I hope this helps you and I welcome all improvements and other tips!

Monday, November 24, 2008

Measure, measure, measure

(Skipping the introductory post for later - maybe.)

Today BrainDamage - developer of the SpringLobby client for the Spring Lobby - showed me some profiles of the Spring engine. Some interesting things can be observed in the profile. That is, if you are in some way involved with, or interested in, Spring engine development :-)


This is the big picture. The red blobs are the program entry point and related functions. From this the call graph branches into CGame::Update (left) and CGame::Draw (right). Let's zoom in to have a clearer picture of this.


Boring eh? Not much happening yet. The left branch (green) goes to CGame::Update, which then branches out to all - synchronized and unsynchronized - non-rendering logic. The right branch (also green) goes to CGame::Draw, which branches out to all rendering code. Update takes 38%, rendering 61%. Rendering is this high because the engine always tries to maintain an as high number of FPS as possible. In other words, all CPU time not spent on logic, is - by definition - spent on rendering. This also explains why it sums to 100% (approximately).


It gets interesting when we dive deeper inside the left part of the graph (click to enlarge). CGame::ClientReadNet is the sole method called by CGame::Update. Due to the networking model, this is the method calling the CGame::SimFrame method - the "main()" of the simulation - whenever a network message arrives instructing it to do so. This part of the tree as a whole took 38% of CPU time, so I'll normalize CPU percentages against this value.

We see a few methods taking single digit CPU percentages, but we see one taking 57% of the entire simulation: CUnitHandler::Update. This isn't too suprising. Lots of units involved in a real time strategy game. Let's see where this time is spent. About a third goes to CUnit::Update - called every frame for every unit. The rest goes to CUnit::SlowUpdate - called every sixteenth frame for every unit. The fact that the least called method of these two eats the most CPU may come as a surprise, but Spring unit simulation code was built taking into account that CPU intensive tasks are better not done every game frame for every unit. This is why SlowUpdate was invented: to perform the heavy tasks only once every few frames. (It's also spread out over all game frames, ie. one sixteenth of all units is SlowUpdated every frame.)


Here we see how CUnit::SlowUpdate spends it's time: it likes to call CAirMoveType::SlowUpdate. A movetype is an abstraction of the movement class of a unit. Each mobile unit has a movetype. Obviously, the CAirMoveType is used for airplanes. So airplanes take about 28% of total simulation time. Compare this to CGroundMoveType, which uses only 3%, even though BrainDamage ensured me he made more ground units then aircraft!

So what is burning the CPU inside CAirMoveType? It's the highlighted node: CLosHandler::MoveUnit. CLosHandler is the class that handles Line Of Sight calculations. Appararently over one third of all the simulation time is spent calculating whether units can see each other, while the other two thirds are fragmented over a lot of different methods.

This sounds like a bottleneck, and who knows, it might be optimizable. (To be continued?)

PS.: for those interested, here is the full graph.