OpenTTD Source: src/linkgraph/linkgraphschedule.cpp Source File

OpenTTD Source 15.0-RC2

linkgraphschedule.cpp
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
10#include "../stdafx.h"
11#include "linkgraphschedule.h"
12#include "init.h"
13#include "demands.h"
14#include "mcf.h"
15#include "flowmapper.h"
16#include "../framerate_type.h"
17#include "../command_func.h"
18#include "../network/network.h"
19#include "../misc_cmd.h"
20
21#include "../safeguards.h"
22
28/* static */ LinkGraphSchedule LinkGraphSchedule::instance;
29
33 void LinkGraphSchedule::SpawnNext()
34{
35 if (this->schedule.empty()) return;
36 LinkGraph *next = this->schedule.front();
37 LinkGraph *first = next;
38 while (next->Size() < 2) {
39 this->schedule.splice(this->schedule.end(), this->schedule, this->schedule.begin());
40 next = this->schedule.front();
41 if (next == first) return;
42 }
43 assert(next == LinkGraph::Get(next->index));
44 this->schedule.pop_front();
45 if (LinkGraphJob::CanAllocateItem()) {
46 LinkGraphJob *job = new LinkGraphJob(*next);
47 job->SpawnThread();
48 this->running.push_back(job);
49 } else {
50 NOT_REACHED();
51 }
52}
53
58 bool LinkGraphSchedule::IsJoinWithUnfinishedJobDue() const
59{
60 if (this->running.empty()) return false;
61 const LinkGraphJob *next = this->running.front();
62 return next->IsScheduledToBeJoined() && !next->IsJobCompleted();
63}
64
68 void LinkGraphSchedule::JoinNext()
69{
70 if (this->running.empty()) return;
71 LinkGraphJob *next = this->running.front();
72 if (!next->IsScheduledToBeJoined()) return;
73 this->running.pop_front();
74 LinkGraphID id = next->LinkGraphIndex();
75 delete next; // implicitly joins the thread
76 if (LinkGraph::IsValidID(id)) {
77 LinkGraph *lg = LinkGraph::Get(id);
78 this->Dequeue(lg); // Dequeue to avoid double-queueing recycled IDs.
79 this->Queue(lg);
80 }
81}
82
87/* static */ void LinkGraphSchedule::Run(LinkGraphJob *job)
88{
89 for (const auto &handler : instance.handlers) {
90 if (job->IsJobAborted()) return;
91 handler->Run(*job);
92 }
93
94 /*
95 * Readers of this variable in another thread may see an out of date value.
96 * However this is OK as this will only happen just as a job is completing,
97 * and the real synchronisation is provided by the thread join operation.
98 * In the worst case the main thread will be paused for longer than
99 * strictly necessary before joining.
100 * This is just a hint variable to avoid performing the join excessively
101 * early and blocking the main thread.
102 */
103
104 job->job_completed.store(true, std::memory_order_release);
105}
106
111 void LinkGraphSchedule::SpawnAll()
112{
113 for (auto &it : this->running) {
114 it->SpawnThread();
115 }
116}
117
121/* static */ void LinkGraphSchedule::Clear()
122{
123 for (auto &it : instance.running) {
124 it->AbortJob();
125 }
126 instance.running.clear();
127 instance.schedule.clear();
128}
129
135 void LinkGraphSchedule::ShiftDates(TimerGameEconomy::Date interval)
136{
137 for (LinkGraph *lg : LinkGraph::Iterate()) lg->ShiftDates(interval);
138 for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) lgj->ShiftJoinDate(interval);
139}
140
144LinkGraphSchedule::LinkGraphSchedule()
145{
146 this->handlers[0] = std::make_unique<InitHandler>();
147 this->handlers[1] = std::make_unique<DemandHandler>();
148 this->handlers[2] = std::make_unique<MCFHandler<MCF1stPass>>();
149 this->handlers[3] = std::make_unique<FlowMapper>(false);
150 this->handlers[4] = std::make_unique<MCFHandler<MCF2ndPass>>();
151 this->handlers[5] = std::make_unique<FlowMapper>(true);
152}
153
157LinkGraphSchedule::~LinkGraphSchedule()
158{
159 this->Clear();
160}
161
169 void StateGameLoop_LinkGraphPauseControl()
170{
171 if (_pause_mode.Test(PauseMode::LinkGraph)) {
172 /* We are paused waiting on a job, check the job every tick. */
173 if (!LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
174 Command<CMD_PAUSE>::Post(PauseMode::LinkGraph, false);
175 }
176 } else if (_pause_mode.None() &&
177 TimerGameEconomy::date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK - 2 &&
178 TimerGameEconomy::date.base() % (_settings_game.linkgraph.recalc_interval / EconomyTime::SECONDS_PER_DAY) == (_settings_game.linkgraph.recalc_interval / EconomyTime::SECONDS_PER_DAY) / 2 &&
179 LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
180 /* Perform check two TimerGameEconomy::date_fract ticks before we would join, to make
181 * sure it also works in multiplayer. */
182 Command<CMD_PAUSE>::Post(PauseMode::LinkGraph, true);
183 }
184}
185
191 void AfterLoad_LinkGraphPauseControl()
192{
193 if (LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
194 _pause_mode.Set(PauseMode::LinkGraph);
195 }
196}
197
202 void OnTick_LinkGraph()
203{
204 if (TimerGameEconomy::date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
205 TimerGameEconomy::Date offset{TimerGameEconomy::date.base() % (_settings_game.linkgraph.recalc_interval / EconomyTime::SECONDS_PER_DAY)};
206 if (offset == 0) {
207 LinkGraphSchedule::instance.SpawnNext();
208 } else if (offset == (_settings_game.linkgraph.recalc_interval / EconomyTime::SECONDS_PER_DAY) / 2) {
209 if (!_networking || _network_server) {
210 PerformanceMeasurer::SetInactive(PFE_GL_LINKGRAPH);
211 LinkGraphSchedule::instance.JoinNext();
212 } else {
213 PerformanceMeasurer framerate(PFE_GL_LINKGRAPH);
214 LinkGraphSchedule::instance.JoinNext();
215 }
216 }
217}
218
219
BaseBitSet::Test
constexpr bool Test(Tvalue_type value) const
Test if the value-th bit is set.
Definition base_bitset_type.hpp:141
BaseBitSet::None
constexpr bool None() const
Test if none of the values are set.
Definition base_bitset_type.hpp:188
BaseBitSet::Set
constexpr Timpl & Set()
Set all bits.
Definition base_bitset_type.hpp:40
LinkGraphJob
Class for calculation jobs to be run on link graphs.
Definition linkgraphjob.h:29
LinkGraphJob::job_completed
std::atomic< bool > job_completed
Is the job still running. This is accessed by multiple threads and reads may be stale.
Definition linkgraphjob.h:167
LinkGraphJob::LinkGraphIndex
LinkGraphID LinkGraphIndex() const
Get the ID of the underlying link graph.
Definition linkgraphjob.h:261
LinkGraphJob::IsJobAborted
bool IsJobAborted() const
Check if job has been aborted.
Definition linkgraphjob.h:198
LinkGraphJob::SpawnThread
void SpawnThread()
Spawn a thread if possible and run the link graph job in the thread.
Definition linkgraphjob.cpp:59
LinkGraphJob::IsScheduledToBeJoined
bool IsScheduledToBeJoined() const
Check if job is supposed to be finished.
Definition linkgraphjob.h:212
LinkGraphJob::IsJobCompleted
bool IsJobCompleted() const
Check if job has actually finished.
Definition linkgraphjob.h:191
LinkGraphSchedule
Definition linkgraphschedule.h:36
LinkGraphSchedule::LinkGraphSchedule
LinkGraphSchedule()
Create a link graph schedule and initialize its handlers.
Definition linkgraphschedule.cpp:144
LinkGraphSchedule::schedule
GraphList schedule
Queue for new jobs.
Definition linkgraphschedule.h:46
LinkGraphSchedule::SpawnNext
void SpawnNext()
Start the next job in the schedule.
Definition linkgraphschedule.cpp:33
LinkGraphSchedule::instance
static LinkGraphSchedule instance
Static instance of LinkGraphSchedule.
Definition linkgraphschedule.h:52
LinkGraphSchedule::Clear
static void Clear()
Clear all link graphs and jobs from the schedule.
Definition linkgraphschedule.cpp:121
LinkGraphSchedule::ShiftDates
void ShiftDates(TimerGameEconomy::Date interval)
Shift all dates (join dates and edge annotations) of link graphs and link graph jobs by the number of...
Definition linkgraphschedule.cpp:135
LinkGraphSchedule::~LinkGraphSchedule
~LinkGraphSchedule()
Delete a link graph schedule and its handlers.
Definition linkgraphschedule.cpp:157
LinkGraphSchedule::IsJoinWithUnfinishedJobDue
bool IsJoinWithUnfinishedJobDue() const
Check if the next job is supposed to be finished, but has not yet completed.
Definition linkgraphschedule.cpp:58
LinkGraphSchedule::SPAWN_JOIN_TICK
static const uint SPAWN_JOIN_TICK
Tick when jobs are spawned or joined every day.
Definition linkgraphschedule.h:51
LinkGraphSchedule::Queue
void Queue(LinkGraph *lg)
Queue a link graph for execution.
Definition linkgraphschedule.h:67
LinkGraphSchedule::Run
static void Run(LinkGraphJob *job)
Run all handlers for the given Job.
Definition linkgraphschedule.cpp:87
LinkGraphSchedule::JoinNext
void JoinNext()
Join the next finished job, if available.
Definition linkgraphschedule.cpp:68
LinkGraphSchedule::Dequeue
void Dequeue(LinkGraph *lg)
Remove a link graph from the execution queue.
Definition linkgraphschedule.h:77
LinkGraphSchedule::handlers
std::array< std::unique_ptr< ComponentHandler >, 6 > handlers
Handlers to be run for each job.
Definition linkgraphschedule.h:45
LinkGraphSchedule::running
JobList running
Currently running jobs.
Definition linkgraphschedule.h:47
LinkGraphSchedule::SpawnAll
void SpawnAll()
Start all threads in the running list.
Definition linkgraphschedule.cpp:111
LinkGraph
A connected component of a link graph.
Definition linkgraph.h:37
LinkGraph::Size
NodeID Size() const
Get the current size of the component.
Definition linkgraph.h:230
PerformanceMeasurer
RAII class for measuring simple elements of performance.
Definition framerate_type.h:91
PerformanceMeasurer::SetInactive
static void SetInactive(PerformanceElement elem)
Mark a performance element as not currently in use.
Definition framerate_gui.cpp:291
TimerGameConst< struct Economy >::SECONDS_PER_DAY
static constexpr int SECONDS_PER_DAY
approximate seconds per day, not for precise calculations
Definition timer_game_common.h:153
TimerGameEconomy::date
static Date date
Current date in days (day counter).
Definition timer_game_economy.h:38
TimerGameEconomy::date_fract
static DateFract date_fract
Fractional part of the day.
Definition timer_game_economy.h:39
demands.h
Declaration of demand calculating link graph handler.
flowmapper.h
Declaration of flow mapper; maps paths into flows at nodes.
PFE_GL_LINKGRAPH
@ PFE_GL_LINKGRAPH
Time spent waiting for link graph background jobs.
Definition framerate_type.h:55
_pause_mode
PauseModes _pause_mode
The current pause mode.
Definition gfx.cpp:50
init.h
Declaration of initializing link graph handler.
OnTick_LinkGraph
void OnTick_LinkGraph()
Spawn or join a link graph job or compress a link graph if any link graph is due to do so.
Definition linkgraphschedule.cpp:202
StateGameLoop_LinkGraphPauseControl
void StateGameLoop_LinkGraphPauseControl()
Pause the game if in 2 TimerGameEconomy::date_fract ticks, we would do a join with the next link grap...
Definition linkgraphschedule.cpp:169
AfterLoad_LinkGraphPauseControl
void AfterLoad_LinkGraphPauseControl()
Pause the game on load if we would do a join with the next link graph job, but it is still running,...
Definition linkgraphschedule.cpp:191
linkgraphschedule.h
Declaration of link graph schedule used for cargo distribution.
mcf.h
Declaration of Multi-Commodity-Flow solver.
_networking
bool _networking
are we in networking mode?
Definition network.cpp:66
_network_server
bool _network_server
network-server is active
Definition network.cpp:67
PauseMode::LinkGraph
@ LinkGraph
A game paused due to the link graph schedule lagging.
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition settings.cpp:61
CommandHelper
Definition command_func.h:83
GameSettings::linkgraph
LinkGraphSettings linkgraph
settings for link graph calculations
Definition settings_type.h:643
LinkGraphSettings::recalc_interval
uint16_t recalc_interval
time (in days) between subsequent checks for link graphs to be calculated.
Definition settings_type.h:572
PoolID< uint16_t, struct LinkGraphIDTag, 0xFFFF, 0xFFFF >
Pool::PoolItem<&_link_graph_pool >::Iterate
static Pool::IterateWrapper< Titem > Iterate(size_t from=0)
Returns an iterable ensemble of all valid Titem.
Definition pool_type.hpp:436
Pool::PoolItem<&_link_graph_pool >::Get
static Titem * Get(auto index)
Returns Titem with given index.
Definition pool_type.hpp:387
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition pool_type.hpp:286
Pool::PoolItem<&_link_graph_job_pool >::CanAllocateItem
static bool CanAllocateItem(size_t n=1)
Helper functions so we can use PoolItem::Function() instead of _poolitem_pool.Function()
Definition pool_type.hpp:357
Pool::PoolItem<&_link_graph_pool >::IsValidID
static bool IsValidID(auto index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition pool_type.hpp:376
StrongType::Typedef
Templated helper to make a type-safe 'typedef' representing a single POD value.
Definition strong_typedef_type.hpp:130