Change link graph join and compression times to use scaled tick counter
This commit is contained in:
@@ -53,7 +53,7 @@ void FlowMapper::Run(LinkGraphJob &job) const
|
||||
/* Scale by time the graph has been running without being compressed. Add 1 to avoid
|
||||
* division by 0 if spawn date == last compression date. This matches
|
||||
* LinkGraph::Monthly(). */
|
||||
uint runtime = (uint)Clamp<StateTicksDelta>(DateTicksToStateTicks(job.StartDateTicks()) - job.LastCompression() + 1, 1, UINT32_MAX).base();
|
||||
uint runtime = (uint)Clamp<ScaledTickCounter>(job.StartTick() - job.LastCompression() + 1, 1, UINT32_MAX);
|
||||
for (auto &it : flows) {
|
||||
it.ScaleToMonthly(runtime);
|
||||
}
|
||||
|
@@ -54,7 +54,7 @@ void LinkGraph::ShiftDates(DateDelta interval)
|
||||
|
||||
void LinkGraph::Compress()
|
||||
{
|
||||
this->last_compression = (_state_ticks.base() + this->last_compression.base()) / 2;
|
||||
this->last_compression = (_scaled_tick_counter + this->last_compression) / 2;
|
||||
for (NodeID node1 = 0; node1 < this->Size(); ++node1) {
|
||||
this->nodes[node1].supply /= 2;
|
||||
}
|
||||
@@ -79,8 +79,8 @@ void LinkGraph::Compress()
|
||||
*/
|
||||
void LinkGraph::Merge(LinkGraph *other)
|
||||
{
|
||||
uint32_t age = ClampTo<uint32_t>(CeilDivT<int64_t>(_state_ticks.base() - this->last_compression.base() + 1, DAY_TICKS));
|
||||
uint32_t other_age = ClampTo<uint32_t>(CeilDivT<int64_t>(_state_ticks.base() - other->last_compression.base() + 1, DAY_TICKS));
|
||||
uint32_t age = ClampTo<uint32_t>(CeilDivT<int64_t>(_scaled_tick_counter - this->last_compression + 1, DAY_TICKS));
|
||||
uint32_t other_age = ClampTo<uint32_t>(CeilDivT<int64_t>(_scaled_tick_counter - other->last_compression + 1, DAY_TICKS));
|
||||
NodeID first = this->Size();
|
||||
this->nodes.reserve(first + other->Size());
|
||||
for (NodeID node1 = 0; node1 < other->Size(); ++node1) {
|
||||
@@ -266,23 +266,26 @@ void LinkGraph::Init(uint size)
|
||||
this->nodes.resize(size);
|
||||
}
|
||||
|
||||
void AdjustLinkGraphStateTicksBase(StateTicksDelta delta)
|
||||
{
|
||||
for (LinkGraph *lg : LinkGraph::Iterate()) lg->last_compression += delta;
|
||||
|
||||
for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) {
|
||||
LinkGraph *lg = &(const_cast<LinkGraph &>(lgj->Graph()));
|
||||
lg->last_compression += delta;
|
||||
}
|
||||
}
|
||||
|
||||
void LinkGraphFixupLastCompressionAfterLoad()
|
||||
void LinkGraphFixupAfterLoad(bool compression_was_date)
|
||||
{
|
||||
/* last_compression was previously a Date, change it to a StateTicks */
|
||||
for (LinkGraph *lg : LinkGraph::Iterate()) lg->last_compression = DateToStateTicks((EconTime::Date)lg->last_compression.base());
|
||||
for (LinkGraph *lg : LinkGraph::Iterate()) {
|
||||
if (compression_was_date) lg->last_compression = DateToStateTicks((EconTime::Date)lg->last_compression).base();
|
||||
lg->last_compression -= _state_ticks.base();
|
||||
lg->last_compression += _scaled_tick_counter;
|
||||
}
|
||||
|
||||
for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) {
|
||||
LinkGraph *lg = &(const_cast<LinkGraph &>(lgj->Graph()));
|
||||
lg->last_compression = DateToStateTicks((EconTime::Date)lg->last_compression.base());
|
||||
if (compression_was_date) lg->last_compression = DateToStateTicks((EconTime::Date)lg->last_compression).base();
|
||||
lg->last_compression -= _state_ticks.base();
|
||||
lg->last_compression += _scaled_tick_counter;
|
||||
|
||||
/* Change start and join ticks from DateTicks to ScaledTickCounter */
|
||||
auto convert = [&](ScaledTickCounter &tick) {
|
||||
tick = (uint64_t)(std::max<int64_t>(0, _scaled_tick_counter + (DateTicksToStateTicks((EconTime::DateTicks)tick) - _state_ticks).base()));
|
||||
};
|
||||
convert(lgj->join_tick);
|
||||
convert(lgj->start_tick);
|
||||
}
|
||||
}
|
||||
|
@@ -290,7 +290,7 @@ public:
|
||||
static constexpr DateDelta STALE_LINK_DEPOT_TIMEOUT = 1024;
|
||||
|
||||
/** Minimum number of ticks between subsequent compressions of a LG. */
|
||||
static constexpr StateTicksDelta COMPRESSION_INTERVAL = 256 * DAY_TICKS;
|
||||
static constexpr ScaledTickCounter COMPRESSION_INTERVAL = 256 * DAY_TICKS;
|
||||
|
||||
/**
|
||||
* Scale a value from a link graph of age orig_age for usage in one of age
|
||||
@@ -311,7 +311,7 @@ public:
|
||||
* Real constructor.
|
||||
* @param cargo Cargo the link graph is about.
|
||||
*/
|
||||
LinkGraph(CargoID cargo) : cargo(cargo), last_compression(_state_ticks) {}
|
||||
LinkGraph(CargoID cargo) : cargo(cargo), last_compression(_scaled_tick_counter) {}
|
||||
|
||||
void Init(uint size);
|
||||
void ShiftDates(DateDelta interval);
|
||||
@@ -350,7 +350,7 @@ public:
|
||||
* Get date of last compression.
|
||||
* @return Date of last compression.
|
||||
*/
|
||||
inline StateTicks LastCompression() const { return this->last_compression; }
|
||||
inline ScaledTickCounter LastCompression() const { return this->last_compression; }
|
||||
|
||||
/**
|
||||
* Get the cargo ID this component's link graph refers to.
|
||||
@@ -365,7 +365,7 @@ public:
|
||||
*/
|
||||
inline uint Monthly(uint base) const
|
||||
{
|
||||
return (uint)((static_cast<uint64_t>(base) * 30 * DAY_TICKS * DayLengthFactor()) / std::max<uint64_t>((_state_ticks - this->last_compression).base(), DAY_TICKS));
|
||||
return (uint)((static_cast<uint64_t>(base) * 30 * DAY_TICKS * DayLengthFactor()) / std::max<uint64_t>(_scaled_tick_counter - this->last_compression, DAY_TICKS));
|
||||
}
|
||||
|
||||
NodeID AddNode(const Station *st);
|
||||
@@ -392,11 +392,10 @@ protected:
|
||||
friend upstream_sl::SlLinkgraphNode;
|
||||
friend upstream_sl::SlLinkgraphEdge;
|
||||
|
||||
friend void AdjustLinkGraphStateTicksBase(StateTicksDelta delta);
|
||||
friend void LinkGraphFixupLastCompressionAfterLoad();
|
||||
friend void LinkGraphFixupAfterLoad(bool compression_was_date);
|
||||
|
||||
CargoID cargo; ///< Cargo of this component's link graph.
|
||||
StateTicks last_compression; ///< Last time the capacities and supplies were compressed.
|
||||
ScaledTickCounter last_compression; ///< Last time the capacities and supplies were compressed.
|
||||
NodeVector nodes; ///< Nodes in the component.
|
||||
EdgeMatrix edges; ///< Edges in the component.
|
||||
|
||||
|
@@ -26,10 +26,10 @@ INSTANTIATE_POOL_METHODS(LinkGraphJob)
|
||||
*/
|
||||
/* static */ Path *Path::invalid_path = new Path(INVALID_NODE, true);
|
||||
|
||||
static EconTime::DateTicks GetLinkGraphJobJoinDateTicks(uint duration_multiplier)
|
||||
static ScaledTickCounter GetLinkGraphJobJoinTick(uint duration_multiplier)
|
||||
{
|
||||
DateTicksDelta ticks = (_settings_game.linkgraph.recalc_time * DAY_TICKS * duration_multiplier) / (SECONDS_PER_DAY * _settings_game.economy.day_length_factor);
|
||||
return ticks + EconTime::CurDateTicks();
|
||||
ScaledTickCounter ticks = (_settings_game.linkgraph.recalc_time * DAY_TICKS * duration_multiplier) / SECONDS_PER_DAY;
|
||||
return ticks + _scaled_tick_counter;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,8 +43,8 @@ LinkGraphJob::LinkGraphJob(const LinkGraph &orig, uint duration_multiplier) :
|
||||
* This is on purpose. */
|
||||
link_graph(orig),
|
||||
settings(_settings_game.linkgraph),
|
||||
join_date_ticks(GetLinkGraphJobJoinDateTicks(duration_multiplier)),
|
||||
start_date_ticks(EconTime::CurDateTicks()),
|
||||
join_tick(GetLinkGraphJobJoinTick(duration_multiplier)),
|
||||
start_tick(_scaled_tick_counter),
|
||||
job_completed(false),
|
||||
job_aborted(false)
|
||||
{
|
||||
|
@@ -131,6 +131,7 @@ private:
|
||||
friend SaveLoadTable GetLinkGraphJobDesc();
|
||||
friend upstream_sl::SaveLoadTable upstream_sl::GetLinkGraphJobDesc();
|
||||
friend void GetLinkGraphJobDayLengthScaleAfterLoad(LinkGraphJob *lgj);
|
||||
friend void LinkGraphFixupAfterLoad(bool compression_was_date);
|
||||
friend class LinkGraphSchedule;
|
||||
friend class LinkGraphJobGroup;
|
||||
|
||||
@@ -139,8 +140,8 @@ protected:
|
||||
|
||||
std::shared_ptr<LinkGraphJobGroup> group; ///< Job group thread the job is running in or nullptr if it's running in the main thread.
|
||||
const LinkGraphSettings settings; ///< Copy of _settings_game.linkgraph at spawn time.
|
||||
EconTime::DateTicks join_date_ticks; ///< Date when the job is to be joined.
|
||||
EconTime::DateTicks start_date_ticks; ///< Date when the job was started.
|
||||
ScaledTickCounter join_tick; ///< Tick when the job is to be joined.
|
||||
ScaledTickCounter start_tick; ///< Tick when the job was started.
|
||||
NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation.
|
||||
EdgeAnnotationVector edges; ///< Edge data necessary for link graph calculation.
|
||||
std::atomic<bool> job_completed; ///< Is the job still running. This is accessed by multiple threads and reads may be stale.
|
||||
@@ -263,7 +264,7 @@ public:
|
||||
* settings have to be brutally const-casted in order to populate them.
|
||||
*/
|
||||
LinkGraphJob() : settings(_settings_game.linkgraph),
|
||||
join_date_ticks(EconTime::INVALID_DATE_TICKS), start_date_ticks(EconTime::INVALID_DATE_TICKS), job_completed(false), job_aborted(false) {}
|
||||
join_tick(0), start_tick(0), job_completed(false), job_aborted(false) {}
|
||||
|
||||
LinkGraphJob(const LinkGraph &orig, uint duration_multiplier);
|
||||
~LinkGraphJob();
|
||||
@@ -298,29 +299,25 @@ public:
|
||||
* @param tick_offset Optional number of ticks to add to the current date
|
||||
* @return True if job should be finished by now, false if not.
|
||||
*/
|
||||
inline bool IsScheduledToBeJoined(int tick_offset = 0) const { return this->join_date_ticks <= EconTime::CurDateTicks() + tick_offset; }
|
||||
inline bool IsScheduledToBeJoined(int tick_offset = 0) const { return this->join_tick <= _scaled_tick_counter + tick_offset; }
|
||||
|
||||
/**
|
||||
* Get the date when the job should be finished.
|
||||
* Get the tick when the job should be finished.
|
||||
* @return Join date.
|
||||
*/
|
||||
inline EconTime::DateTicks JoinDateTicks() const { return join_date_ticks; }
|
||||
inline ScaledTickCounter JoinTick() const { return this->join_tick; }
|
||||
|
||||
/**
|
||||
* Get the date when the job was started.
|
||||
* Get the tick when the job was started.
|
||||
* @return Start date.
|
||||
*/
|
||||
inline EconTime::DateTicks StartDateTicks() const { return start_date_ticks; }
|
||||
inline ScaledTickCounter StartTick() const { return this->start_tick; }
|
||||
|
||||
/**
|
||||
* Change the start and join dates on date cheating.
|
||||
* @param interval Number of days to add.
|
||||
* Set the tick when the job should be joined.
|
||||
* @return Start date.
|
||||
*/
|
||||
inline void ShiftJoinDate(DateDelta interval)
|
||||
{
|
||||
this->join_date_ticks += DateDeltaToDateTicksDelta(interval);
|
||||
this->start_date_ticks += DateDeltaToDateTicksDelta(interval);
|
||||
}
|
||||
inline void SetJoinTick(ScaledTickCounter tick) { this->join_tick = tick; }
|
||||
|
||||
/**
|
||||
* Get the link graph settings for this component.
|
||||
@@ -351,7 +348,7 @@ public:
|
||||
* Get the state tick when the underlying link graph was last compressed.
|
||||
* @return Compression date.
|
||||
*/
|
||||
inline StateTicks LastCompression() const { return this->link_graph.LastCompression(); }
|
||||
inline ScaledTickCounter LastCompression() const { return this->link_graph.LastCompression(); }
|
||||
|
||||
/**
|
||||
* Get the ID of the underlying link graph.
|
||||
|
@@ -81,14 +81,14 @@ void LinkGraphSchedule::SpawnNext()
|
||||
uint duration_multiplier = CeilDivT<uint64_t>(lg->Size(), 75);
|
||||
std::unique_ptr<LinkGraphJob> job(new LinkGraphJob(*lg, duration_multiplier));
|
||||
jobs_to_execute.emplace_back(job.get(), cost);
|
||||
if (this->running.empty() || job->JoinDateTicks() >= this->running.back()->JoinDateTicks()) {
|
||||
if (this->running.empty() || job->JoinTick() >= this->running.back()->JoinTick()) {
|
||||
this->running.push_back(std::move(job));
|
||||
DEBUG(linkgraph, 3, "LinkGraphSchedule::SpawnNext(): Running job: id: %u, nodes: %u, cost: " OTTD_PRINTF64U ", duration_multiplier: %u",
|
||||
lg->index, lg->Size(), cost, duration_multiplier);
|
||||
} else {
|
||||
// find right place to insert
|
||||
auto iter = std::upper_bound(this->running.begin(), this->running.end(), job->JoinDateTicks(), [](EconTime::DateTicks a, const std::unique_ptr<LinkGraphJob> &b) {
|
||||
return a < b->JoinDateTicks();
|
||||
auto iter = std::upper_bound(this->running.begin(), this->running.end(), job->JoinTick(), [](ScaledTickCounter a, const std::unique_ptr<LinkGraphJob> &b) {
|
||||
return a < b->JoinTick();
|
||||
});
|
||||
this->running.insert(iter, std::move(job));
|
||||
DEBUG(linkgraph, 3, "LinkGraphSchedule::SpawnNext(): Running job (re-ordering): id: %u, nodes: %u, cost: " OTTD_PRINTF64U ", duration_multiplier: %u",
|
||||
@@ -203,7 +203,6 @@ void LinkGraphSchedule::SpawnAll()
|
||||
void LinkGraphSchedule::ShiftDates(DateDelta interval)
|
||||
{
|
||||
for (LinkGraph *lg : LinkGraph::Iterate()) lg->ShiftDates(interval);
|
||||
for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) lgj->ShiftJoinDate(interval);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -276,16 +275,16 @@ void LinkGraphJobGroup::JoinThread()
|
||||
const uint thread_budget = 200000;
|
||||
|
||||
std::sort(jobs.begin(), jobs.end(), [](const JobInfo &a, const JobInfo &b) {
|
||||
return std::make_pair(a.job->JoinDateTicks(), a.cost_estimate) < std::make_pair(b.job->JoinDateTicks(), b.cost_estimate);
|
||||
return std::make_pair(a.job->JoinTick(), a.cost_estimate) < std::make_pair(b.job->JoinTick(), b.cost_estimate);
|
||||
});
|
||||
|
||||
std::vector<LinkGraphJob *> bucket;
|
||||
uint bucket_cost = 0;
|
||||
EconTime::DateTicks bucket_join_date = 0;
|
||||
ScaledTickCounter bucket_join_tick = 0;
|
||||
auto flush_bucket = [&]() {
|
||||
if (!bucket_cost) return;
|
||||
DEBUG(linkgraph, 2, "LinkGraphJobGroup::ExecuteJobSet: Creating Job Group: jobs: " PRINTF_SIZE ", cost: %u, join after: " OTTD_PRINTF64,
|
||||
bucket.size(), bucket_cost, (bucket_join_date - EconTime::CurDateTicks()).base());
|
||||
bucket.size(), bucket_cost, bucket_join_tick - _scaled_tick_counter);
|
||||
auto group = std::make_shared<LinkGraphJobGroup>(constructor_token(), std::move(bucket));
|
||||
group->SpawnThread();
|
||||
bucket_cost = 0;
|
||||
@@ -293,8 +292,8 @@ void LinkGraphJobGroup::JoinThread()
|
||||
};
|
||||
|
||||
for (JobInfo &it : jobs) {
|
||||
if (bucket_cost && (bucket_join_date != it.job->JoinDateTicks() || (bucket_cost + it.cost_estimate > thread_budget))) flush_bucket();
|
||||
bucket_join_date = it.job->JoinDateTicks();
|
||||
if (bucket_cost && (bucket_join_tick != it.job->JoinTick() || (bucket_cost + it.cost_estimate > thread_budget))) flush_bucket();
|
||||
bucket_join_tick = it.job->JoinTick();
|
||||
bucket.push_back(it.job);
|
||||
bucket_cost += it.cost_estimate;
|
||||
}
|
||||
@@ -305,10 +304,10 @@ LinkGraphJobGroup::JobInfo::JobInfo(LinkGraphJob *job) :
|
||||
job(job), cost_estimate(job->Graph().CalculateCostEstimate()) { }
|
||||
|
||||
/**
|
||||
* Pause the game if in 2 _date_fract ticks, we would do a join with the next
|
||||
* Pause the game if in 2 ticks, we would do a join with the next
|
||||
* link graph job, but it is still running.
|
||||
* The check is done 2 _date_fract ticks early instead of 1, as in multiplayer
|
||||
* calls to DoCommandP are executed after a delay of 1 _date_fract tick.
|
||||
* The check is done 2 ticks early instead of 1, as in multiplayer
|
||||
* calls to DoCommandP are executed after a delay of 1 tick.
|
||||
* If we previously paused, unpause if the job is now ready to be joined with.
|
||||
*/
|
||||
void StateGameLoop_LinkGraphPauseControl()
|
||||
@@ -318,19 +317,14 @@ void StateGameLoop_LinkGraphPauseControl()
|
||||
if (!LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
|
||||
DoCommandP(0, PM_PAUSED_LINK_GRAPH, 0, CMD_PAUSE);
|
||||
}
|
||||
} else if (_pause_mode == PM_UNPAUSED && TickSkipCounter() == 0) {
|
||||
if (DayLengthFactor() == 1) {
|
||||
if (EconTime::CurDateFract() != LinkGraphSchedule::SPAWN_JOIN_TICK - 2) return;
|
||||
if (EconTime::CurDate().base() % _settings_game.linkgraph.recalc_interval != (_settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY) / 2) return;
|
||||
} else {
|
||||
int date_ticks = (EconTime::CurDateTicks() - (LinkGraphSchedule::SPAWN_JOIN_TICK - 2)).base();
|
||||
int interval = std::max<int>(2, (_settings_game.linkgraph.recalc_interval * DAY_TICKS / (SECONDS_PER_DAY * DayLengthFactor())));
|
||||
if (date_ticks % interval != interval / 2) return;
|
||||
}
|
||||
|
||||
/* perform check one _date_fract tick before we would join */
|
||||
if (LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
|
||||
DoCommandP(0, PM_PAUSED_LINK_GRAPH, 1, CMD_PAUSE);
|
||||
} else if (_pause_mode == PM_UNPAUSED) {
|
||||
int interval = _settings_game.linkgraph.recalc_interval * DAY_TICKS / SECONDS_PER_DAY;
|
||||
int offset = _scaled_tick_counter % interval;
|
||||
if (offset == (interval / 2) - 2) {
|
||||
/* perform check 2 ticks before we would join */
|
||||
if (LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
|
||||
DoCommandP(0, PM_PAUSED_LINK_GRAPH, 1, CMD_PAUSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -353,16 +347,8 @@ void AfterLoad_LinkGraphPauseControl()
|
||||
*/
|
||||
void OnTick_LinkGraph()
|
||||
{
|
||||
int offset;
|
||||
int interval;
|
||||
if (DayLengthFactor() == 1) {
|
||||
if (EconTime::CurDateFract() != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
|
||||
interval = _settings_game.linkgraph.recalc_interval / SECONDS_PER_DAY;
|
||||
offset = EconTime::CurDate().base() % interval;
|
||||
} else {
|
||||
interval = std::max<int>(2, (_settings_game.linkgraph.recalc_interval * DAY_TICKS / (SECONDS_PER_DAY * DayLengthFactor())));
|
||||
offset = (EconTime::CurDateTicks() - LinkGraphSchedule::SPAWN_JOIN_TICK).base() % interval;
|
||||
}
|
||||
int interval = _settings_game.linkgraph.recalc_interval * DAY_TICKS / SECONDS_PER_DAY;
|
||||
int offset = _scaled_tick_counter % interval;
|
||||
if (offset == 0) {
|
||||
LinkGraphSchedule::instance.SpawnNext();
|
||||
} else if (offset == interval / 2) {
|
||||
|
Reference in New Issue
Block a user