1
0
mirror of https://github.com/vcmi/vcmi.git synced 2025-01-26 03:52:01 +02:00

Nullkiller: async hero chain calculation

This commit is contained in:
Andrii Danylchenko 2021-05-16 15:08:49 +03:00 committed by Andrii Danylchenko
parent 0265de77fa
commit 66843b22d3
3 changed files with 149 additions and 68 deletions

View File

@ -401,11 +401,12 @@ private:
int heroChainTurn; int heroChainTurn;
std::vector<CGPathNode *> heroChain; std::vector<CGPathNode *> heroChain;
const std::vector<int3> & tiles; const std::vector<int3> & tiles;
std::vector<DelayedWork> delayedWork;
public: public:
HeroChainCalculationTask( HeroChainCalculationTask(
AINodeStorage & storage, AISharedStorage & nodes, const std::vector<int3> & tiles, uint64_t chainMask, int heroChainTurn) AINodeStorage & storage, AISharedStorage & nodes, const std::vector<int3> & tiles, uint64_t chainMask, int heroChainTurn)
:existingChains(), newChains(), nodes(nodes), storage(storage), chainMask(chainMask), heroChainTurn(heroChainTurn), heroChain(), tiles(tiles) :existingChains(), newChains(), delayedWork(), nodes(nodes), storage(storage), chainMask(chainMask), heroChainTurn(heroChainTurn), heroChain(), tiles(tiles)
{ {
existingChains.reserve(NUM_CHAINS); existingChains.reserve(NUM_CHAINS);
newChains.reserve(NUM_CHAINS); newChains.reserve(NUM_CHAINS);
@ -444,6 +445,22 @@ public:
} }
} }
for(auto delayed = delayedWork.begin(); delayed != delayedWork.end();)
{
auto newActor = delayed->carrier->actor->tryExchangeNoLock(delayed->other->actor);
if(!newActor.lockAcquired) continue;
if(newActor.actor)
{
newChains.push_back(calculateExchange(newActor.actor, delayed->carrier, delayed->other));
}
delayed++;
}
delayedWork.clear();
cleanupInefectiveChains(newChains); cleanupInefectiveChains(newChains);
addHeroChain(newChains); addHeroChain(newChains);
} }
@ -483,11 +500,34 @@ bool AINodeStorage::calculateHeroChain()
CCreature::DisableChildLinkage = true; CCreature::DisableChildLinkage = true;
auto r = blocked_range<size_t>(0, data.size()); if(data.size() > 100)
HeroChainCalculationTask task(*this, nodes, data, chainMask, heroChainTurn); {
std::mutex resultMutex;
task.execute(r); std::random_shuffle(data.begin(), data.end());
task.flushResult(heroChain);
parallel_for(blocked_range<size_t>(0, data.size()), [&](const blocked_range<size_t>& r)
{
//auto r = blocked_range<size_t>(0, data.size());
HeroChainCalculationTask task(*this, nodes, data, chainMask, heroChainTurn);
task.execute(r);
{
std::lock_guard<std::mutex> resultLock(resultMutex);
task.flushResult(heroChain);
}
});
}
else
{
auto r = blocked_range<size_t>(0, data.size());
HeroChainCalculationTask task(*this, nodes, data, chainMask, heroChainTurn);
task.execute(r);
task.flushResult(heroChain);\
}
CCreature::DisableChildLinkage = false; CCreature::DisableChildLinkage = false;
@ -666,9 +706,10 @@ void HeroChainCalculationTask::calculateHeroChain(
} }
} }
auto newActor = carrier->actor->tryExchange(other->actor); auto newActor = carrier->actor->tryExchangeNoLock(other->actor);
if(newActor) result.push_back(calculateExchange(newActor, carrier, other)); if(!newActor.lockAcquired) delayedWork.push_back(DelayedWork(carrier, other));
if(newActor.actor) result.push_back(calculateExchange(newActor.actor, carrier, other));
} }
} }

View File

@ -145,11 +145,11 @@ void HeroActor::setupSpecialActors()
} }
} }
ChainActor * ChainActor::tryExchange(const ChainActor * specialActor, const ChainActor * other) const ExchangeResult ChainActor::tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const
{ {
if(!isMovable) return nullptr; if(!isMovable) return ExchangeResult();
return baseActor->tryExchange(specialActor, other); return baseActor->tryExchangeNoLock(specialActor, other);
} }
namespace vstd namespace vstd
@ -169,12 +169,12 @@ namespace vstd
} }
} }
ChainActor * HeroActor::tryExchange(const ChainActor * specialActor, const ChainActor * other) const ExchangeResult HeroActor::tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const
{ {
const ChainActor * otherBase = other->baseActor; const ChainActor * otherBase = other->baseActor;
HeroActor * result = exchangeMap->tryExchange(otherBase); ExchangeResult result = exchangeMap->tryExchangeNoLock(otherBase);
if(!result) return nullptr; if(!result.actor || !result.lockAcquired) return result;
if(specialActor == this) if(specialActor == this)
return result; return result;
@ -184,7 +184,9 @@ ChainActor * HeroActor::tryExchange(const ChainActor * specialActor, const Chain
return &actor == specialActor; return &actor == specialActor;
}); });
return &result->specialActors[index]; result.actor = &(dynamic_cast<HeroActor *>(result.actor)->specialActors[index]);
return result;
} }
HeroExchangeMap::HeroExchangeMap(const HeroActor * actor, const Nullkiller * ai) HeroExchangeMap::HeroExchangeMap(const HeroActor * actor, const Nullkiller * ai)
@ -205,40 +207,67 @@ HeroExchangeMap::~HeroExchangeMap()
exchangeMap.clear(); exchangeMap.clear();
} }
HeroActor * HeroExchangeMap::tryExchange(const ChainActor * other) ExchangeResult HeroExchangeMap::tryExchangeNoLock(const ChainActor * other)
{ {
auto position = exchangeMap.find(other); ExchangeResult result;
if(position != exchangeMap.end())
{ {
return position->second; boost::shared_lock<boost::shared_mutex> lock(sync, boost::try_to_lock);
if(!lock.owns_lock())
{
result.lockAcquired = false;
return result;
}
auto position = exchangeMap.find(other);
if(position != exchangeMap.end())
{
result.actor = position->second;
return result;
}
} }
auto inserted = exchangeMap.insert(std::pair<const ChainActor *, HeroActor *>(other, nullptr));
if(!inserted.second)
{ {
return inserted.first->second; // already inserted boost::unique_lock<boost::shared_mutex> uniqueLock(sync, boost::try_to_lock);
}
position = inserted.first; if(!uniqueLock.owns_lock())
{
result.lockAcquired = false;
auto differentMasks = (actor->chainMask & other->chainMask) == 0; return result;
}
if(!differentMasks) return nullptr; auto inserted = exchangeMap.insert(std::pair<const ChainActor *, HeroActor *>(other, nullptr));
TResources resources = ai->cb->getResourceAmount(); if(!inserted.second)
{
result.actor = inserted.first->second;
if(!resources.canAfford(actor->armyCost + other->armyCost)) return result; // already inserted
{ }
auto position = inserted.first;
auto differentMasks = (actor->chainMask & other->chainMask) == 0;
if(!differentMasks) return result;
TResources resources = ai->cb->getResourceAmount();
if(!resources.canAfford(actor->armyCost + other->armyCost))
{
#if PATHFINDER_TRACE_LEVEL >= 2 #if PATHFINDER_TRACE_LEVEL >= 2
logAi->trace( logAi->trace(
"Can not afford exchange because of total cost %s but we have %s", "Can not afford exchange because of total cost %s but we have %s",
(actor->armyCost + other->armyCost).toString(), (actor->armyCost + other->armyCost).toString(),
resources.toString()); resources.toString());
#endif #endif
return nullptr; return result;
} }
if(other->isMovable && other->armyValue <= actor->armyValue / 10 && other->armyValue < MIN_ARMY_STRENGTH_FOR_CHAIN) if(other->isMovable && other->armyValue <= actor->armyValue / 10 && other->armyValue < MIN_ARMY_STRENGTH_FOR_CHAIN)
return nullptr; return nullptr;
@ -247,52 +276,54 @@ HeroActor * HeroExchangeMap::tryExchange(const ChainActor * other)
HeroExchangeArmy * upgradedInitialArmy = tryUpgrade(actor->creatureSet, other->getActorObject(), availableResources); HeroExchangeArmy * upgradedInitialArmy = tryUpgrade(actor->creatureSet, other->getActorObject(), availableResources);
HeroExchangeArmy * newArmy; HeroExchangeArmy * newArmy;
if(other->creatureSet->Slots().size()) if(other->creatureSet->Slots().size())
{
if(upgradedInitialArmy)
{ {
newArmy = pickBestCreatures(upgradedInitialArmy, other->creatureSet); if(upgradedInitialArmy)
newArmy->armyCost = upgradedInitialArmy->armyCost; {
newArmy->requireBuyArmy = upgradedInitialArmy->requireBuyArmy; newArmy = pickBestCreatures(upgradedInitialArmy, other->creatureSet);
newArmy->armyCost = upgradedInitialArmy->armyCost;
newArmy->requireBuyArmy = upgradedInitialArmy->requireBuyArmy;
delete upgradedInitialArmy; delete upgradedInitialArmy;
}
else
{
newArmy = pickBestCreatures(actor->creatureSet, other->creatureSet);
}
} }
else else
{ {
newArmy = pickBestCreatures(actor->creatureSet, other->creatureSet); newArmy = upgradedInitialArmy;
} }
}
else
{
newArmy = upgradedInitialArmy;
}
if(!newArmy) return nullptr; if(!newArmy) return result;
auto reinforcement = newArmy->getArmyStrength() - actor->creatureSet->getArmyStrength(); auto reinforcement = newArmy->getArmyStrength() - actor->creatureSet->getArmyStrength();
#if PATHFINDER_TRACE_LEVEL >= 2 #if PATHFINDER_TRACE_LEVEL >= 2
logAi->trace( logAi->trace(
"Exchange %s->%s reinforcement: %d, %f%%", "Exchange %s->%s reinforcement: %d, %f%%",
actor->toString(), actor->toString(),
other->toString(), other->toString(),
reinforcement, reinforcement,
100.0f * reinforcement / actor->armyValue); 100.0f * reinforcement / actor->armyValue);
#endif #endif
if(reinforcement <= actor->armyValue / 10 && reinforcement < MIN_ARMY_STRENGTH_FOR_CHAIN) if(reinforcement <= actor->armyValue / 10 && reinforcement < MIN_ARMY_STRENGTH_FOR_CHAIN)
{ {
delete newArmy; delete newArmy;
return nullptr; return result;
}
HeroActor * exchanged = new HeroActor(actor, other, newArmy, ai);
exchanged->armyCost += newArmy->armyCost;
result.actor = exchanged;
exchangeMap[other] = exchanged;
return result;
} }
HeroActor * exchanged = new HeroActor(actor, other, newArmy, ai);
exchanged->armyCost += newArmy->armyCost;
position->second = exchanged;
return exchanged;
} }
HeroExchangeArmy * HeroExchangeMap::tryUpgrade( HeroExchangeArmy * HeroExchangeMap::tryUpgrade(

View File

@ -17,6 +17,7 @@
extern const uint64_t MIN_ARMY_STRENGTH_FOR_CHAIN; extern const uint64_t MIN_ARMY_STRENGTH_FOR_CHAIN;
class ChainActor;
class HeroActor; class HeroActor;
class Nullkiller; class Nullkiller;
@ -33,6 +34,14 @@ public:
} }
}; };
struct ExchangeResult
{
bool lockAcquired;
ChainActor * actor;
ExchangeResult() : lockAcquired(true), actor(nullptr) {}
};
class ChainActor class ChainActor
{ {
protected: protected:
@ -68,12 +77,12 @@ public:
ChainActor(){} ChainActor(){}
virtual std::string toString() const; virtual std::string toString() const;
ChainActor * tryExchange(const ChainActor * other) const { return tryExchange(this, other); } ExchangeResult tryExchangeNoLock(const ChainActor * other) const { return tryExchangeNoLock(this, other); }
void setBaseActor(HeroActor * base); void setBaseActor(HeroActor * base);
virtual const CGObjectInstance * getActorObject() const { return hero; } virtual const CGObjectInstance * getActorObject() const { return hero; }
protected: protected:
virtual ChainActor * tryExchange(const ChainActor * specialActor, const ChainActor * other) const; virtual ExchangeResult tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const;
}; };
class HeroExchangeMap class HeroExchangeMap
@ -88,7 +97,7 @@ public:
HeroExchangeMap(const HeroActor * actor, const Nullkiller * ai); HeroExchangeMap(const HeroActor * actor, const Nullkiller * ai);
~HeroExchangeMap(); ~HeroExchangeMap();
HeroActor * tryExchange(const ChainActor * other); ExchangeResult tryExchangeNoLock(const ChainActor * other);
private: private:
HeroExchangeArmy * pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const; HeroExchangeArmy * pickBestCreatures(const CCreatureSet * army1, const CCreatureSet * army2) const;
@ -114,7 +123,7 @@ public:
HeroActor(const ChainActor * carrier, const ChainActor * other, const HeroExchangeArmy * army, const Nullkiller * ai); HeroActor(const ChainActor * carrier, const ChainActor * other, const HeroExchangeArmy * army, const Nullkiller * ai);
protected: protected:
virtual ChainActor * tryExchange(const ChainActor * specialActor, const ChainActor * other) const override; virtual ExchangeResult tryExchangeNoLock(const ChainActor * specialActor, const ChainActor * other) const override;
}; };
class ObjectActor : public ChainActor class ObjectActor : public ChainActor