Change link graph join and compression times to use scaled tick counter

This commit is contained in:
Jonathan G Rennison
2024-02-15 02:05:27 +00:00
parent edbbaeb5d9
commit 1f5b35fac4
15 changed files with 90 additions and 109 deletions

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -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.

View File

@@ -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)
{

View File

@@ -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.

View File

@@ -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) {