Brad Wardell's views about technology, politics, religion, world affairs, and all sorts of politically incorrect topics.
Faster..Faster..FASTER!
Published on January 20, 2006 By Draginol In GalCiv Journals

While beta testers seem pretty pleased with the performance, there is always room for improvement...A LOT OF ROOM.  Users with beta 5 will be astounded by the improvements in performance.  Game loading speeds cut by 90% over beta 5. Save game speeds cut to 30% the time of beta 5.  But there's still more. 

The key is profiling.  That is, you use tools that literally tell you how many ms the game spends in different areas.  The Green Reaper finally graduated this past year and has joined Stardock as a full time developer.  Having him is like having the first round draft choice of all developers worldwide for a given year.  As a teen, in his spare time, he reverse engineered the multiplayer server for The Corporate Machine and made a new one (That we still use today).  His primary project is working on our killer app for Windows Vista (which I can't talk about).  But for this month, I've tasked him with figuring out what is slow in GalCiv and how to fix it.  He is also doing the galactic empire map for the Metaverse which you'll hear more about soon.

Here are his findings (unedited):

Seemingly a big problem (this is where the std::tree stuff was coming on that I found with CodeAnalyst):

AIPlanningStrategy (60 million mcs total):
-classCivilization::AIActivateDomesticPolicy (17%, 392 calls)
--classCivilization::AIDesignShips (85%, 122 calls)
---classCivilization::AIDesignShipType (99%, 2,196 calls)
----CShipDesigner::LoadAvailableComponentsForPlayer (99%, 1,586 calls)
-----GetComponentDefsOfClass (79%, 14,274 calls)
------CPropertyBucket::GetIntProperty (47%, 4,140,224 calls) [due to: if(pComponent->GetIntProperty(COMPONENTCLASS, -1) == cc)]
-------CPropertyBucket::GetValue (53%, 4,207,204 calls)
--------std::tree::find
---------std::tree::_Lbound
---------std::basic_string::compare
--------std::tree::assign
-------_tstoi (30%, 4,182,617 calls)
------std::sort components (46%, 14,289 calls) [due to using CompDefGreater, which has a string comparison on the name]
-----classCivilization::MeetsTechRequirements (20%, 459,940 clalls)
------classGalaxy::FindTechByName (almost as many calls, making it an expensive function)
------CPropertyBucket::GetStringProperties (also lots of calls, and twice as expensive due to its resulting callees)
-classAICivilization_Diplomat::AISetSpendRatios (7%, but only because of the DebugMessage call)

I think four million calls anything is probably a bad idea.

LoadAvalableComponentsForPlayer looks like it needs to be cached, or one of the other methods above it needs to be trimmed down.

MeetsTechRequirements has similar issues, due in part to the cost of its callee methods (but also because it was called half a million times)

GetValue caused significant time use elsewhere, too. Perhaps there a more performant data type that could be used than the current one, or maybe values need to be cached.

Other biggies

RenderNode (63 million mcs total)
-CStarbox.Render (42%, 7,199 calls)

CShipGraphic::LoadConfiguration (43 million mcs)
-CShipGraphic::AddComponent (76%)
--CShipGraphic::LoadBumpAndLights (84%)
---CResourceManager::GetTexture
----LoadTexture (most?)
----GetFilename might be worth looking at, as it is called 150,000 times overall
-CShipGraphic::SetShipFile

On a second run:

UIUpdateGraphicMsg used significant CPU time in:

classGalaxy::FillMovableShipList (used by ::OnUpdate of CBegin[Player|AIPlayer]TurnProcess)
--classCivilization::AIAddShipsToFleets
---classGalaxy::AINewFleetFromStackedShips
----claasGalaxy::AddStackedShips
-----CFleet::UpdateFleet
------CFleet::GetTopShips
-------UIUpdateGraphicMsg (21 calls, comment for use: "update the fleet unit graphic" - resulted in almost all of the CPU use of the higher five methods)

..

Easy fruit: CMouseCursor::UpdateImage (59 million mcs, 13,636 calls) - the call to SetCursorProperties at the end of this method (that occurs in every pass through GameLoop) is not free! It results in constant calls to CreateDIBitmap, DestoryCursor and CreateIconIndirect, as well as critical section usage (and entering a critical section can be expensive on multiprocessor machines, I think including hyperthreaded ones). If it is possible to detect when it is and is not necessary to update the cursor then that would be good. SetCursorPosition should be used to move the cursor, not SetCursorProperties. See help for IDirect3DDevice9::SetCursorProperties.

AIDesignShips and (to a lesser extent) AICivilization_Diplomat::SetSpendRatios are using a bit on startup, the latter mostly because of a DebugMessage

CMidpointDisplacementHF::GenerateField uses up 27 million mcs, in part via this call path:

InitializeHiddenPlanetSurfaces
-classPalent::InitiPlanetSurfaces
--CPlanetSurface::InitSurface (252 calls, 40.9 million mcs)
---CPlanetSurface::generateHeightField (252 calls)
----CMidpointDisplacementHF::GenerateField (39 calls, self time 6.5 million mcs, total time 27.3 million

THis is due mainly to calls to CCoreRandomBase::RandFloat (6.8 million of them) and possibly double->float conversions relating to that. If this is being done on a background thread, it may not be that much of a problem.

EnterCriticalSection/LeaveCriticalSection can be a significant part of the screen update in GameLoop (10 million mcs verses the 42 million mcs of the Draw3D itself)

..

This particular performance run was done in a large galaxy with lots of planets. The previous notes about performance apply here as well.

CPlanetTerrainGraphic::calcTerrainColor used in CPlanetTerrainGraphic::CreateTexture was a significant use of time. It got called 2.3 million times and used up over the vast majority of the texture generation time, and seemingly around pmethe CPU cycles used to load the game in total. 21% of its use was encapsulated in CPlanetTerrainGraphic::GetNeightborBleed (which was also called in CreateTexture).

UIBeginGame (100%, 2 calls)
-CD3DWindow::InitGalaxyGfx (58.2%,, 2 calls)
--CD3DWindow::CreatePlanetGfx (86.0%, 84 calls)
---CPlanet3DWindow::CreatePlanetTexture (98.5%, 24 calls)
----CPlanetTerrainGraphic::CreateTexture (98.6%, 1,728 calls)
-----CPlanetTerrainGraphic::genTextures (99.9%, 1,728 calls)
------calcTerrainColor (69.2%, 1,769,472 calls)
------CPlanetTerrainGraphic::getNeighborBleed (22.7%, 1,916,928 calls)
-------calcTerrainColor (84.3%, 532,890 callls)
-------CPlanetSurface::GetTerrainType (12.1%, 532,890 calls)

--CD3DWindow::CreateShipGfx (6.3%)
--CD3DWindow::CreateAnomolyGfx (5.6%)
--CD3DWindow::CreateStarGfx (1.3%)

While the entire calcTerrainColour was expensive, particularly expensive was:
* Indirection of the CPlanetTerrainGraphic::tColorDefList::iterator defIt
* Comparison against colorSet.mDefaultColorList.end

Sections of interest were:
* The do loop following "// There's no override for this terrain type, so use the default straight up".
** Here the repeated indirection (*defIt) was costly, as was the call to lerp_color and the comparison "while ( defIt != colorSet.mDefaultColorList.end() );"

* the do loop following "// We may need to interpolate between the default and override schemes."
**Again, indirection caused the most expense here
**The code following "// See if we ran off the end of the list" was not executed. This *may* not be needed.

* The contents of the else labelled "// The texel falls within the override range"
** More indirection, more comparison against end

* The last line (call to lerp_color) was slightly expensive, but little compared to the first two

It would probably be worth trying to cache (*overIt) at the start of each loop iteration and use that within the loop. Of course, the compiler might be doing this. There appears to be an average of 40 indirections per call to calcTerrainColor

It might also be possible to cache some of the things like .begin and .end in calcTerrainColor.

Another big CPU user was classGalaxy::LoadBlock, which came back to the generation of large number of random numbers:

classGalaxy::LoadBlock (40.6 mcs, 2 calls)
-classPlanet::FromBlock (89%, 910 calls)
--CPlanetSurface::InitSurface (97.9%, 506 calls)
---CPlanetSurface::SeedSurfaceFromTerrain (98.3%, 506 calls)
----CPlanetSurface::generateHeightField (89%, 506 calls)
-----CMidpointDisplacementHF::GenerateField (97.3%, 70 calls)
------CCoreRandomBase::RandFloat (75.8%, 36,700,020 calls)
-------CCoreRandomMT::Rand32 (69.2%, 36,700,020 calls)
----CPlanetSurface::smoothSector (6.2%, 7,492 calls)

In generateHeightField (30 mcs including calls, 7mcs self time), the key lines were:

* The inner statement of the for loops *before* "Square step -", beginning "mpHeightField[mi+mj*rectWidth] (7.7 mcs taken by mRandGen.RandFloat)
* The line following "Calculate the square value for the top side of the rectangle" (10.4 mcs taken by mRandGen.RandFloat)
* The line right after that, "Calculate the square value for the left side of the rectangle" (4.9 mcs taken by mRandGen.RandFloat)

For loading, the main Lib3D usage (Which is not *too* big) appears to be:

CResourceManager::GetRootFrame
-CResourceManager::ComputeMeshTargets
--MeshMender::Mend
---MeshMender:rocessBinomials
---MeshMender:rocessTangents
----MeshMender::BuildGroups (used by both the above)
-----MeshMender::FindNeighbors

There is a thread that appears to spend a lot of its time looking at the foreground window. It sets an event. The call GetForegroundWindow in this thread is somewhat expensive, certainly in relation to the other calls in that thread procedure (like GetParent, IsWindow, GetWindowPlacement And GetWindowThreadProcID). If it's on a timer it might be good to reduce its frequency (if possible).

Analyis of long-running game. This game was one where I just stayed in the corner and did nothing, so it's mostly measuring the background processes like AI and ship building updates that always occur in a turn.

----

Large rendering costs:
CScene::Render (2,810 mcs, 19,151 calls)
-CShipGraphic::Render (1,169 mcs [89.6 mcs wait time], 84,874 calls)
-CPlanetoidGraphic::Render (1,028 mcs [873 mcs wait], 83,257 calls)
-COrbitingGraphic::Render (408 mcs [23.5 mcs wait], 16,594 calls)
-CStarbox::Render (113 mcs [36.1 mcs wait], 37,045 calls)
-CRingGRaphic::Render (20.8 mcs [1.26 mcs wait], 16,594 calls)
-CZOCGraphic::Render (16.8 mcs [3.01 mcs wait], 48,845 calls)
-CStarGraphic::Render (9.86 mcs [1.35 mcs wait], 16,726 calls)
-CFOWGraphic::Render (7.42 mcs [0.47 mcs wait], 61,069 calls)

* The large wait time on CPlanetoidGraphic is odd. Perhaps a large amount of processing is being done elsewhere each time it is called? IF so, perhaps this could be reduced somehow?

----

I think I've mentioned this one before, but UIUpdateGraphicMsg used up 424 mcs. 78.6% of the CPU time used by it was caused by classColony:;CompleteShip, a method which was responsible for 98% of the time used by classGalaxy::BeginTurn (this happens every turn via UpdateProcesses -> OnUpdate -> BeginTurn). Another 4.5% was caused by classStarShip::CompleteTradeRoute, 3.5% by GCObject::SetPosition and 3.3% by both classStarShip::UpdateFOW and CFleet::GetTopShips.

I think the large usage in CompleteShip is caused by:

// Joe 04/07/05 - There is a crash when an orbited ship is attacked.
//                In the case of a new ship, this was caused by
//                the ship not having a graphic node and not being added
//                to the sector node.
//                To fix the problem, I create the graphic and immediately
//                hide it. This ensures that all ships have graphics when
//                they are needed.
UIUpdateGraphicMsg(GCMSG_UPDATE_GFX, pshipBuilding->GetID(), pshipBuilding->GetType());
UIUpdateGraphicMsg(GCMSG_HIDE_GFX, pshipBuilding->GetID(), pshipBuilding->GetType());

* How many ships are created but just stay in orbit, or otherwise out of view? I wasn't exploring anywhere in this game - most things were hidden by the fog of war. It seems silly to have to spend time and memory making images for things that are never seen.

* It could well be worth seeing if there is another method of avoiding the crash that performs better and doesn't have side effects.

* I'm wondering if this is part of what is taking up memory later on in the game - how much memory is associated with a "graphic node"?

---

NtCreateFile was called 1,822,520 times, resulting in 246 mcs. I don't think GalCiv II has nearly 2 million files. Opening a file has significant cost even if the file data is in cache due to security checks etc.

Almost all of these calls were made by CResourceManager::GetTexture (via D3DXCreateTextureFromFile), which was itself called 3,250,089 times. CShipGraphic::LoadBumpAndLights took up this time, due to CShipGraphic::AddComponent.

of time taken by CShipGraphic::AddComponent ultimately almost all was used bysubmethods of CD3DWindow::CreateShipGfx in CD3DWindow::SceneGraphCallback:
-52.9% (155mcs, 45,784 calls) was caused by CShipGraphic::LoadConfiguration
-32.9% (96.4mcs, 7,220 calls) was caused by CShipGraphic::AutoPlaceModule
-9.5% (27.7mcs, 1,715 calls) was caused by CShipGraphic::AutoPlaceEngine
-4.6% (13.5mcs, 2,096 calls) was caused by CShipGraphic::AutoPlaceWeapon

Each call to GetTexture also caused a call to GetFilename, which is expensive (16.7 mcs) due to _splitpath/string assign/_makepath etc.

* Perhaps some kind of texture cache?
* Convert to using D3DXCreateTextureFromFileInMemory, perhaps with memory-mapped IO? That way the file handle creation is under our control. I am sure the vast majority of the calls were to the same files.

---

Saving a game could probably do with better memory allocation methods.

When saving the game 4 times:

classGalaxy::SaveBlock

MemBuffer::AddElement called MemBuffer::GrowIncrementally 1,273,720 times.

The largest causes of time were saving of planets and (especially) ships - I'm guessing ships are big?

MemBuffer::Grow had a large self time (probably due to copying data between allocated and freed blocks, and spent even more time in MemManager::Allocate and MemManager::Free themselves.

This can get a little annoying when you're playing the game and you have to wait for it to autosave. Only 6 saves occurred in the game but in total they took 67 mcs)

----

More fun with huge trees to iterate through (and do repeated string comparisons of elements).

CPlanetSurface::FindFirstImprovements was an expensive call, using 32.8 mcs. 80% of this was in CPlanetImprovement::GetInternalName, which suggests that improvements there would be a help. Perhaps the real issue was that it had to iterate over every improvement item and then get the string and do a case-insensitive compare on it. That's gotta cost.

It was used most by classStarShip::GetMaxHitPoints (54%) and classColony::CalcMorale (46%), 0.3% by classGalaxy::NewShip

* Checking for the OmegaDefenseSystem in classStarShip::GetMaxHitPoints(VOID) caused 18 mcs on its own:

IPlanetImprovement* pImp = pPlanet->GetPlanetSurface()->FindFirstImprovementByName( "OmegaDefenseSystem", IPlanetImprovement::kOperational );
This line was called 750,000 times. It found the defense system 23,562 times.

GetMaxHitPoints itself was called by a lot of things, most notably classStarShip::RepairShip (42.6%) but also classStarShip;:GetCurrHitPoints (18%), classCivilization::CalcMilitaryMight (12%) and UpdateAITurn (8)

* Similarly, checking for SecretPoliceCenter in classColony::CalcMorale caused 15 mcs:

classCivilization::CalculateMoraleMight was the most expensive by far of all the historical calculations. It was expensive because classCivilization::CalcApproval was expensive, due to classColony::CalcMorale . . . due to CPlanetSurface::FindFirstImprovement.

---

What takes time for the AI?

classStarShip::UpdateTurn was most used by UpdateAITurn (98%)

classStarShip::UpdateTurn (109,600 calls)
-classStarShip::RepairShip (48%, 108,577 calls)
--CShipDamageIndicator::RepairDamage (14.3%, 108,577 calls) - but almost all the time used by this is in getting the max hit points
--classStarShip::GetMaxHitPoints (84.7%, 688,745 calls)
---CPlanetSurface::FindFirstImprovementByName (94.8%, 373,090 calls)
-classStarShip::CalcTotalMoves (39.5%, 108,577 calls)
--classCivilization::GetTradeGood (82.8%, 97,264 calls)
---classGalaxy::findImprovementInLocatorMap (96%, 97,264 calls)
-classStarShip::GetMaxHitPoints (6.5%, 110,482 calls)
-classStarShip::CalculateSensorRange (4.1%, 108,577 calls)

The reason for GetMaxHitPoints using lots of time due to the check for the Omega Defense System has been covered above.

* The CPU usage in CalcTotalMoves is mostly due to checking for the trade good GravityAccelerators, which costs 6 mcs, although calculating the starbase speed bonus and penalty takes up a small amount of time.

---

Pathing and moving ships around takes a long time.

Profile of classGalaxy::MoveShip

classGalaxy::MoveShip (128.6 mcs total)
-classStarShip::QuickMove (55.6%, 117,918 calls)
--classStarShip::Teleport (46.6%, 84,954 calls)
---classStarShip::CheckForBlockedGoal (56.9%, 19,712 calls)
----classStarShip::CheckForBlockedGoal (97.8%, 87,016 calls)
-----CSectorMapper::HitCheckPlanets (65.9%, 171,970 calls)
-----CSectorMapper::HitCheckShips (28.9%, 42,353 calls)
-classStarShip::FindPath (41.6%, 118,397 calls)
--classStarShip::CalAStarPathToDest (99.8%, 81,055 calls)
---classStarShip::CalcAStarPath (68.9%, 80,588 calls)    - both of these
---classStarShip::CalcAStarTradeRoute (31%, 6,194 calls) - go to the folowing:
----classStarShip::CalcAStarPath (96.5%, 80,588 calls)
-----AStarShipMoveCostCallback (95.8%, 2,801,622 calls)
------classStarShip::CalcAStarMoveCost (100%, 2,801,622 calls)
-------CSectorMapper::HitCheckShips (67.1%, 2,594,057 calls)
-------CSectorMapper::HitCheckPlanets (21.7%, 2,714,842 calls)
-------CSectorMapper::HitCheckStars (5.8%, 2,529,019 calls)

For classStarShip::HitCheckShips
-GetDistanceInTiles (53.4%, 55,934,764 calls)
--GCObject::GetTileX (23.6%, 77,861,854 calls)
---CSectorMapper::WorldToTileX (31.5%, 77,861,854 calls)
--GCObject::GetTileY (23.0%, 77,861,854 calls)
---CSectorMapper::WorldToTileY (31.1%, 77,861,854 calls)
--CSectorMapper::WorldToTileX (7.9%, 77,861,854 calls)
--CSectorMapper::WorldToTileY (7.3%, 77,861,854 calls)
-ShipHit (21.8%, 364,205 calls)
-equal_range (4.0%, 2,638,080 calls)

CSectorMapper::HitCheckPlanets takes up 23.8mcs in classStarShip::CheckForBlockedGoal, and there is a comment there that suggests that it might not be necessary (don't know enough about it to be sure):

// I'm going to try to try checking planets first because there should be no ships under planets
// but if they are, chances are we want to be attacking the planet
pSectorMapper->HitCheckPlanets (this, v3Destination);

----

StaticText::RenderText takes 67 mcs and PushButton::RenderText takes 33mcs. They both create a new text sprite each time, which costs most of the time.

StaticText::RenderText (67 mcs, 333,484 calls)
-CreateClippedTextSprite (45.3%, 309,778 calls)
-DdEntry5 (18.5%, 8,346 calls)

* Could text sprites on static text and buttons be cached to avoid costs with sizing and rendering text, without going overboard on memory use?

----

The UIUpdateGraphicMsg at the end of classStarShip::AddStarbaseModel is expensive, costing 6.7mcs for just 193 calls. Added to the DestroyShip it means that starbase additions cost almost 10mcs.

----

And the part I was particularly interested -- AI performance.  The AI in GalCiv II (post beta 5) is radically improved but much more intensive since it's doing a LOT of analysis.  Here's some of the calls and what they're using.

AI planning focus.

Obvious issues:

* Biggest cost (as previously identified) is ship design - classCivilization::AIDesignShipType - due mostly to loading the available components for each player. There is a huge cost in iterating through the component hash_map and (to a lesser extent) matching tech requiements. It also sorts the hash_map in GetComponentDefsOfClass - is this even needed? It takes literally over half the time.

* In classCivilization::AIActivateMilitary, classAICivilization_Diplomat::AIFindConstructorDestination is the main expense due to calling classCivilization::AIFindStarbaseThatNeedsUpgrades, which calls classStarbase::GetModulesAvailable. In fact, looking at the code, it calls it three times in if()s just to check different return values! (eg: if(pShip->pStarbase->GetModulesAvailable() > 20) . . .). Iterating through the entire list of available modules and matching them to the current starbase state and available techs is very expensive.

* classAICivilization_Diplomat::AISetColonySocialProject could do with a less expensive way of figuring out what social projects it can/should build.

* classShipTypes::GetMaxCapacity has pCiv->CalcAbility( ABILITY_MINIATURIZATION );, which really seems too slow to be called so often.

* classCivilization::CalcApproval calls classColony::CalcMorale which spends a heck of a lot of time looking for the SecretPoliceCenter on every colony.

* There's various DebugMessages that need to be weeded out eventually, particularly the SetSpendRatios ones.

* Use of classCivilization::CalcAbility in classShipTypes::GetMaxCapacity == slowdown

* Generally speaking, CPropertyBucket methods are used in loops that end up being called often and deeply.

Planning call tree hotspots (methods not contributing significantly not included):

AIPlanningStrategy (577 mcs)
-AIActivateDomesticPolicy (75.8%, 437 mcs, 2,873 calls)
--classCivilization::AIDesignShips (88.9%, 390 mcs, 687 calls)
---classCivilization::AIDesignShipType (100%, 390 mcs, 12,364 calls)
----CShipDesigner::LoadAvailableComponentsForPlayer (96.9%, 377 mcs, 8,930 calls)
-----GetComponentDefsOfClass (82.8%, 312 mcs, 80,368 calls)
------std::sort of ComponentDefMap (52.0%, 162 mcs, 80,368 calls)
------CPropertyBucket::GetIntProperty (43.2%, 135 mcs, 31,775,109 calls)
-----classCivilization::MeetsTechRequirements (16.3%, 61.3 mcs)
------CPropertyBucket::GetStringProperties (59.6%, 36.7 mcs, 3,976,506 calls)
------classGalaxy::FindTechByName (22.5%, 13.8 mcs, 1,157,569 calls)
----CShipDesigner:esignShipType (2.7%, 10.5 mcs, 8,390 calls)
-----classShipTypes::AddComponent (51.0%, 5.4 mcs, 36,081 calls)
------classShipTypes::GetMaxCapacity (53.9%, 2.9 mcs, 36,081 calls)
-----classShipTypes::GetMaxCapacity (27.9%, 2.9 mcs, 59,224 calls)
------classCivilization::CalcAbility (97.7%, 6.0 mcs total, 97,314 calls)
--ClassCivilization::AISetSpendRatios (9.5%, 24 mcs, 1,400 calls)
---DebugMessage (53.8%, 10 mcs)
---classCivilization::CalcResearchMightRating (21.1%, 3.9 mcs, 461,686 calls)
---classCivilization::CalcTotalSpending (11.4%, 2 mcs, 201,548 calls)
---classCivilization::CalcApproval (6.8%, 1.3 mcs, 136,144 calls)
---classCivilization::CalcRevenueFromTrade (5.5%, 1.0 mcs, 132,695 calls)
--class[AI]Civilization::AIResearchTech (1.3%, 4 mcs)
---DebugMessage (90%, 3.5 mcs)
--classCivilization::AIBookeeping (0.1%, 0.5 mcs)
--classCivilization::CalcShipMaint (67.6%, 0.36 mcs)
--classCivilization::AIChooseGovernment (0.1%, 0.4 mcs, 41,032 calls)
---classCivilization::CalcApproval (92.0%, 0.4 mcs, 687 calls)
----classColony::CalcMorale (92.9%, 0.4 mcs, 15,071 calls)
-----CPlanetSurface::FindFirstImprovementByName
-classCivilization::AIActivateGovernors (12.2%, 70.2 mcs, 2,873 calls)
--classAICivilization_Diplomat::AISetColonySocialProject (70.5%, 49.5 mcs, 1,400 calls)
---CPlanetImpDBRecord::IsAvailable (57.8%, 28.6 mcs, 356,940 calls)
----CPlanetImpDBRecord::GetStringField (24.1%, 8.3 mcs, 481,131 calls)
----classCivilization::IsTechKnown (23.6%, 8.1 mcs, 423,300 calls)
----CPlanetImpDBRecord::GetImprovementType (17.8%, 6.1 mcs, 459,000 calls)
----classCivilization::GetSuperProject (10.8%, 3.7 mcs, 22,131 calls)
----CPlaentImpDBRecord::GetIntField (8.9%, 3.1 mcs, 918,000 calls)
----CPlanetSurface::IsImprovementRestricted (3.8%, 1.3 mcs, 63,546 calls)
----CPlanetImpDBRecord::GetField (3.2%, 1.1 mcs, 84,279 calls)
---classColony::GetNumberOfImpType (13.1%, 6.5 mcs, 42,245 calls)
----CPlanetImprovement::GetIntValue (71%, 5 mcs, ~1,000,000 calls)
-----CCorePropertyHolder::HasProperty (53.3%, 3 mcs)
-----CCorePropertyHolder::GetProperty (37.0%, 2 mcs)
----CPlanetSurface::GetCompletedImprovements (23%, 2.0 mcs, ~43,000 calls)
---classColony::CalcTurnsRequired (8.5%, 4.2 mcs, 42,245 calls)
---CPlanetSurface::CalcFoodProduction (3.8%, 1.9 mcs, 42,647 calls)
----CPlanetSurface::calcOperationalTotal (98.6%, 1.8 mcs, 42,647 calls)
-----CPlanetImprovement::GetIntValue (81.7%, 1.5 mcs, ~380,000 calls)
--classAICivilization_Drengin::AISetcolonySocialProject (21.4%, 15 mcs, 400 calls) [details as above]
--classAICivilization_General::AISetColonyMilitaryProject (7.3%, 5.1 mcs, 1,800 calls)
---classAICivilization_Diplomat::AISetColonyMilitaryProject (87.8%, 4.5 mcs, 2,222 calls)
----classAICivilization_Diplomat::AIIsColonyAdequatelyDefended (46.6%, 2.1 mcs, 2,222 calls)
-----classGalaxy::GetMostPowerfulOtherPlayer (50.0%, 1.0 mcs, 2,222 calls)
-----classCivilization::GetToughestShip (49.5%, 1.0 mcs, 2,222 calls)
----classCivilization::CalcColonyMaint (36.5%, 1.6 mcs, 2,222 calls)
----classColony::CalcColonyMaint (87.7%, 1.5 mcs, ~15,000 calls)
-----CPlanetImprovement::GetMaintenanceCost (58.4%, 0.9 mcs, ~100,000 calls)
-----CPlanetSurface::GetCompletedImprovements (33.2%, 0.5 mcs, ~16,000 calls)
---classAICivilization_Drengin::AISetColonyMilitaryProject (10.5%, 0.5 mcs, 661 calls)
-classGalaxy::NextTurnRequested (7.0%, 40.7 mcs [39 mcs wait], 193 calls) [I don't think this is real performance loss]
--UIHideTurnButton (70.5%, 28.7 mcs, 193 calls)
--UIRefresh (29.5%, 12.0 mcs, 193 calls)
-classCivilization::AIActivateMilitary (3.5%, 20.4 mcs, 2,873 calls)
--classAICivilization_General::AIExecuteShipAssignments (93.0%, 19.0 mcs, 2,672 calls)
---classAICivilization_Diplomat::AIFindConstructorDestination (54%, 10.2 mcs, 16,810 calls)
----classCivilization::AIFindStarbaseThatNeedsUpgrades (98%, 10.4 mcs, 581 calls)
-----classStarbase::GetModulesAvailable (97.2%, 10.0 mcs, ~20,000 calls)
------classCivilization::MeetsTechRequirements (63.8%, 6.5 mcs, ~600,000 calls)
------FindStarbaseModuleByID (30.5%, 2.9 mcs, ~2,400,000 calls)
---classCivilization::AIFindConstructorDestination (11.3%, 2.1 mcs, 2,959 calls)
----classCivilization::AIFindStarbaseThatNeedsUpgrades (98%, 2.0 mcs, 187 calls) [as above]
---classCivilization::AIFindMilitaryDestination (7.0%, 1.3 mcs, 46,005 calls)
----classCivilization::FindNearestRallyPoint (30.9%, 0.4 mcs, 64,750 calls)
---classCivilization::AIFindTransportDestination (5.4%, 1.0 mcs, 4,228 calls)
----classStarShip::FindClosestUndefendedEnemyPlanet (61.2%, 0.6 mcs, 3,695 calls)
----classCivilization::AIHostilesInSector (34.7%, 0.4 mcs, 3,680 calls)
---classCivilization::AIFindScoutDestination (4.9%, 0.9 mcs, 4,169 calls)
--classCivilization::AIBuildFleets (6.1%, 1.2 mcs, 2,873 calls)
---classStarShip::IsStarbase (30.2%, 0.4 mcs, 1,496,390 calls)
-classCivilization::AIActivateForeignPolicy (1.4%, 8.3 mcs, 2,873 calls)
--classCivilization::AIMananangeForeignRelations (88.3%, 7.3 mcs, 1,001 calls)
---classCivilization::AICalculatePrimaryEnemy (29.6%, 2.2 mcs, 1,001 calls)
----classCivilization::AIEvaluateProximityRelations (66.2%, 1.4 mcs, 2,817 calls)
-----classCivilization::GetToughestShip (65.5%)
-----classCivilization::GetRankedPlanet (29.8%)
----classCivilization::AIEvaluateTradeRelations (18.3%, 0.4 mcs, 2,817 calls)
---classCivilization::AICalculateRelationsWith (26.4%, 1.9 mcs, 1,704 calls)
----classCivilization::AIEvaluateProximityRelations (65.0%, 1.3 mcs, 1,790 calls)
---classCivilization::AITradeTechnologies (25.4%, 1.9 mcs, 3,020 calls)
----classCivilization::IsTechKnown (58.6%, 1.1 mcs, 352,445 calls)
----DebugMessage (37.6%, 0.7 mcs, 92 calls)
---classCivilization::AIMonitorGalaxy (11.4%, 0.8 mcs, 3,020 calls)
----classGalaxy::GetMostPowerfulPlayer (96.3%, 0.8 mcs, 1,608 calls)
--classCivilization::AIEvaluateOpponentDefenses (11.7%, 1.0 mcs, 1,001 calls)
---classCivilization::GetToughestShip (49.1%, 0.5 mcs, 780 calls)
---classGalaxy::GetMostPowerfulOtherPlayer (32.9%, 0.3 mcs, 702 calls)
---classCivilization::FidnMostLethalEnemy (16.5%, 0.2 mcs, 925 calls)

"
Comments
on Jan 20, 2006
number of calls from fanboys wondering is it done yet? = infinite

I don't envy what you are going through now, but good luck. Remember it's always darkest before dawn, and all this hard work will pay off. Thanks Stardock.
on Jan 21, 2006
grats on nabbing the badass programmer
on Jan 22, 2006
Great and insightful stufff.

Looks there's an ace on board.
on Jan 23, 2006
While beta testers seem pretty pleased with the performance
On a 3 GHz machine things look quite different as on a 500MHz machine. Keep up your good work. Even small issues are worth to look after them. Customers should spend their money for your software and not for new hardware
on Jan 23, 2006
I will be adding a small bottle of tylonel with the champagne.

W/R
Suralle