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