From c63da54bbdcfba84a443ce50609e2d363ec7e0a7 Mon Sep 17 00:00:00 2001 From: Mark Vejvoda Date: Fri, 22 Feb 2013 06:52:51 +0000 Subject: [PATCH] - attempt to improve performance when units are blocked badly (this is not backwards compatible with other builds, will create out of synch) --- source/glest_game/ai/path_finder.cpp | 28 +++++- source/glest_game/ai/path_finder.h | 2 + source/glest_game/type_instances/unit.cpp | 14 ++- source/glest_game/type_instances/unit.h | 2 +- source/glest_game/world/unit_updater.cpp | 7 +- source/glest_game/world/unit_updater.h | 2 +- source/glest_game/world/world.cpp | 105 +++++++++++++++++++++- 7 files changed, 152 insertions(+), 8 deletions(-) diff --git a/source/glest_game/ai/path_finder.cpp b/source/glest_game/ai/path_finder.cpp index 99cf6b66..cde7a82e 100644 --- a/source/glest_game/ai/path_finder.cpp +++ b/source/glest_game/ai/path_finder.cpp @@ -218,7 +218,8 @@ TravelState PathFinder::findPath(Unit *unit, const Vec2i &finalPos, bool *wasStu } } - if(path->isStuck() == true && unit->getLastStuckPos() == finalPos && + if(path->isStuck() == true && + (unit->getLastStuckPos() == finalPos || path->getBlockCount() > 500) && unit->isLastStuckFrameWithinCurrentFrameTolerance() == true) { //printf("$$$$ Unit STILL BLOCKED for [%d - %s]\n",unit->getId(),unit->getFullName().c_str()); @@ -1418,6 +1419,31 @@ int PathFinder::findNodeIndex(Node *node, std::vector &nodeList) { return index; } +bool PathFinder::unitCannotMove(Unit *unit) { + bool unitImmediatelyBlocked = false; + + // First check if unit currently blocked all around them, if so don't try to pathfind + const bool showConsoleDebugInfo = Config::getInstance().getBool("EnablePathfinderDistanceOutput","false"); + const Vec2i unitPos = unit->getPos(); + int failureCount = 0; + int cellCount = 0; + + for(int i = -1; i <= 1; ++i) { + for(int j = -1; j <= 1; ++j) { + Vec2i pos = unitPos + Vec2i(i, j); + if(pos != unitPos) { + bool canUnitMoveToCell = map->aproxCanMove(unit, unitPos, pos); + if(canUnitMoveToCell == false) { + failureCount++; + } + cellCount++; + } + } + } + unitImmediatelyBlocked = (failureCount == cellCount); + return unitImmediatelyBlocked; +} + void PathFinder::saveGame(XmlNode *rootNode) { std::map mapTagReplacements; XmlNode *pathfinderNode = rootNode->addChild("PathFinder"); diff --git a/source/glest_game/ai/path_finder.h b/source/glest_game/ai/path_finder.h index 68d854e6..1cc4c72f 100644 --- a/source/glest_game/ai/path_finder.h +++ b/source/glest_game/ai/path_finder.h @@ -164,6 +164,8 @@ public: void removeUnitPrecache(Unit *unit); void clearCaches(); + bool unitCannotMove(Unit *unit); + int findNodeIndex(Node *node, Nodes &nodeList); int findNodeIndex(Node *node, std::vector &nodeList); diff --git a/source/glest_game/type_instances/unit.cpp b/source/glest_game/type_instances/unit.cpp index 37e0518f..9d045574 100644 --- a/source/glest_game/type_instances/unit.cpp +++ b/source/glest_game/type_instances/unit.cpp @@ -3672,9 +3672,17 @@ void Unit::setLastStuckFrameToCurrentFrame() { lastStuckFrame = getFrameCount(); } -bool Unit::isLastStuckFrameWithinCurrentFrameTolerance() const { - const int MIN_FRAME_ELAPSED_RETRY = 300; - bool result (getFrameCount() - lastStuckFrame <= MIN_FRAME_ELAPSED_RETRY); +bool Unit::isLastStuckFrameWithinCurrentFrameTolerance() { + //const int MIN_FRAME_ELAPSED_RETRY = 300; + const int MAX_BLOCKED_FRAME_THRESHOLD = 25000; + int MIN_FRAME_ELAPSED_RETRY = 6; + if(lastStuckFrame < MAX_BLOCKED_FRAME_THRESHOLD) { + MIN_FRAME_ELAPSED_RETRY = random.randRange(2,6); + } + else { + MIN_FRAME_ELAPSED_RETRY = random.randRange(6,8); + } + bool result (getFrameCount() - lastStuckFrame <= (MIN_FRAME_ELAPSED_RETRY * 100)); return result; } diff --git a/source/glest_game/type_instances/unit.h b/source/glest_game/type_instances/unit.h index 9660ffb5..86190ac0 100644 --- a/source/glest_game/type_instances/unit.h +++ b/source/glest_game/type_instances/unit.h @@ -722,7 +722,7 @@ public: std::string toString() const; bool needToUpdate(); - bool isLastStuckFrameWithinCurrentFrameTolerance() const; + bool isLastStuckFrameWithinCurrentFrameTolerance(); inline uint32 getLastStuckFrame() const { return lastStuckFrame; } inline void setLastStuckFrame(uint32 value) { lastStuckFrame = value; } void setLastStuckFrameToCurrentFrame(); diff --git a/source/glest_game/world/unit_updater.cpp b/source/glest_game/world/unit_updater.cpp index 66507af4..bb80ffb4 100644 --- a/source/glest_game/world/unit_updater.cpp +++ b/source/glest_game/world/unit_updater.cpp @@ -106,7 +106,9 @@ UnitUpdater::~UnitUpdater() { // ==================== progress skills ==================== //skill dependent actions -void UnitUpdater::updateUnit(Unit *unit) { +bool UnitUpdater::updateUnit(Unit *unit) { + bool processUnitCommand = false; + Chrono chrono; if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled) chrono.start(); @@ -153,6 +155,7 @@ void UnitUpdater::updateUnit(Unit *unit) { if(update == true) { //SystemFlags::OutputDebug(SystemFlags::debugSystem,"In [%s::%s Line: %d]\n",__FILE__,__FUNCTION__,__LINE__); + processUnitCommand = true; updateUnitCommand(unit,-1); if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld [after updateUnitCommand()]\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); @@ -282,6 +285,8 @@ void UnitUpdater::updateUnit(Unit *unit) { } if(SystemFlags::getSystemSettingType(SystemFlags::debugPerformance).enabled && chrono.getMillis() > 0) SystemFlags::OutputDebug(SystemFlags::debugPerformance,"In [%s::%s] Line: %d took msecs: %lld --------------------------- [END OF METHOD] ---------------------------\n",__FILE__,__FUNCTION__,__LINE__,chrono.getMillis()); + + return processUnitCommand; } // ==================== progress commands ==================== diff --git a/source/glest_game/world/unit_updater.h b/source/glest_game/world/unit_updater.h index 8953f802..784d2ce7 100644 --- a/source/glest_game/world/unit_updater.h +++ b/source/glest_game/world/unit_updater.h @@ -102,7 +102,7 @@ public: ~UnitUpdater(); //update skills - void updateUnit(Unit *unit); + bool updateUnit(Unit *unit); //update commands void updateUnitCommand(Unit *unit, int frameIndex); diff --git a/source/glest_game/world/world.cpp b/source/glest_game/world/world.cpp index 0029056f..f424c7ea 100644 --- a/source/glest_game/world/world.cpp +++ b/source/glest_game/world/world.cpp @@ -462,6 +462,12 @@ void World::updateAllTilesetObjects() { } void World::updateAllFactionUnits() { + bool showPerfStats = Config::getInstance().getBool("ShowPerfStats","false"); + Chrono chronoPerf; + if(showPerfStats) chronoPerf.start(); + char perfBuf[8096]=""; + std::vector perfList; + scriptManager->onTimerTriggerEvent(); // Prioritize grouped command units so closest units to target go first @@ -491,6 +497,11 @@ void World::updateAllFactionUnits() { faction->clearAproxCanMoveSoonCached(); } + if(showPerfStats) { + sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); + perfList.push_back(perfBuf); + } + Chrono chrono; chrono.start(); @@ -500,6 +511,12 @@ void World::updateAllFactionUnits() { bool slavesCompleted = masterController.waitTillSlavesTrigger(20000); if(SystemFlags::VERBOSE_MODE_ENABLED && chrono.getMillis() >= 10) printf("In [%s::%s Line: %d] *** Faction thread preprocessing took [%lld] msecs for %d factions for frameCount = %d slavesCompleted = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),factionCount,frameCount,slavesCompleted); + + if(showPerfStats) { + sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); + perfList.push_back(perfBuf); + } + } else { // Signal the faction threads to do any pre-processing @@ -508,6 +525,11 @@ void World::updateAllFactionUnits() { faction->signalWorkerThread(frameCount); } + if(showPerfStats) { + sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); + perfList.push_back(perfBuf); + } + bool workThreadsFinished = false; Chrono chrono; chrono.start(); @@ -527,14 +549,32 @@ void World::updateAllFactionUnits() { } } + if(showPerfStats) { + sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); + perfList.push_back(perfBuf); + } + if(SystemFlags::VERBOSE_MODE_ENABLED && chrono.getMillis() >= 10) printf("In [%s::%s Line: %d] *** Faction thread preprocessing took [%lld] msecs for %d factions for frameCount = %d.\n",__FILE__,__FUNCTION__,__LINE__,(long long int)chrono.getMillis(),factionCount,frameCount); } + if(showPerfStats) { + sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER "\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis()); + perfList.push_back(perfBuf); + } + //units + Chrono chronoPerfUnit; + int totalUnitsChecked = 0; + int totalUnitsProcessed = 0; for(int i = 0; i < factionCount; ++i) { Faction *faction = getFaction(i); faction->clearUnitsPathfinding(); + std::map mapCommandCount; + std::map mapSkillCount; + int unitCountStuck = 0; + int unitCountUpdated = 0; + int unitCount = faction->getUnitCount(); for(int j = 0; j < unitCount; ++j) { Unit *unit = faction->getUnit(j); @@ -542,7 +582,70 @@ void World::updateAllFactionUnits() { throw megaglest_runtime_error("unit == NULL"); } - unitUpdater.updateUnit(unit); + CommandClass unitCommandClass = ccCount; + if(unit->getCurrCommand() != NULL) { + unitCommandClass = unit->getCurrCommand()->getCommandType()->getClass(); + } + + SkillClass unitSkillClass = scCount; + if(unit->getCurrSkill() != NULL) { + unitSkillClass = unit->getCurrSkill()->getClass(); + } + + if(showPerfStats) chronoPerfUnit.start(); + + int unitBlockCount = unit->getPath()->getBlockCount(); + bool isStuck = unit->getPath()->isStuck(); + bool isStuckWithinTolerance = unit->isLastStuckFrameWithinCurrentFrameTolerance(); + uint32 lastStuckFrame = unit->getLastStuckFrame(); + + if(unitUpdater.updateUnit(unit) == true) { + unitCountUpdated++; + + if(unit->getLastStuckFrame() == frameCount) { + unitCountStuck++; + } + mapCommandCount[unitCommandClass] = mapCommandCount[unitCommandClass] + 1; + mapSkillCount[unitSkillClass] = mapSkillCount[unitSkillClass] + 1; + } + totalUnitsChecked++; + + if(showPerfStats && chronoPerfUnit.getMillis() >= 10) { + sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER " stuck: %d [%d] for unit:\n%sBEFORE unitBlockCount = %d, AFTER = %d, BEFORE lastStuckFrame = %u, AFTER: %u\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerfUnit.getMillis(),isStuck,isStuckWithinTolerance,unit->toString().c_str(),unitBlockCount,unit->getPath()->getBlockCount(),lastStuckFrame,unit->getLastStuckFrame()); + perfList.push_back(perfBuf); + } + + } + totalUnitsProcessed += unitCountUpdated; + + if(showPerfStats) { + sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER " faction: %d / %d unitCount = %d unitCountUpdated = %d unitCountStuck = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis(),i+1,factionCount,unitCount,unitCountUpdated,unitCountStuck); + perfList.push_back(perfBuf); + + for(std::map::iterator iterMap = mapCommandCount.begin(); + iterMap != mapCommandCount.end(); ++iterMap) { + + sprintf(perfBuf,"Command class = %d, count = %d\n",iterMap->first,iterMap->second); + perfList.push_back(perfBuf); + } + + for(std::map::iterator iterMap = mapSkillCount.begin(); + iterMap != mapSkillCount.end(); ++iterMap) { + + sprintf(perfBuf,"Skill class = %d, count = %d\n",iterMap->first,iterMap->second); + perfList.push_back(perfBuf); + } + } + } + + if(showPerfStats) { + sprintf(perfBuf,"In [%s::%s] Line: %d took msecs: " MG_I64_SPECIFIER " totalUnitsProcessed = %d\n",extractFileFromDirectoryPath(__FILE__).c_str(),__FUNCTION__,__LINE__,chronoPerf.getMillis(),totalUnitsProcessed); + perfList.push_back(perfBuf); + } + + if(showPerfStats && chronoPerf.getMillis() >= 50) { + for(unsigned int x = 0; x < perfList.size(); ++x) { + printf("%s",perfList[x].c_str()); } }