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

OpenTTD Source 1.11.0-RC1

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 <http://www.gnu.org/licenses/>.
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
20 #include "../safeguards.h"
21
27 /* static */ LinkGraphSchedule LinkGraphSchedule::instance;
28
32 void LinkGraphSchedule::SpawnNext()
33 {
34 if (this->schedule.empty()) return;
35 LinkGraph *next = this->schedule.front();
36 LinkGraph *first = next;
37 while (next->Size() < 2) {
38 this->schedule.splice(this->schedule.end(), this->schedule, this->schedule.begin());
39 next = this->schedule.front();
40 if (next == first) return;
41 }
42 assert(next == LinkGraph::Get(next->index));
43 this->schedule.pop_front();
44 if (LinkGraphJob::CanAllocateItem()) {
45 LinkGraphJob *job = new LinkGraphJob(*next);
46 job->SpawnThread();
47 this->running.push_back(job);
48 } else {
49 NOT_REACHED();
50 }
51 }
52
57 bool LinkGraphSchedule::IsJoinWithUnfinishedJobDue() const
58 {
59 if (this->running.empty()) return false;
60 const LinkGraphJob *next = this->running.front();
61 return next->IsScheduledToBeJoined() && !next->IsJobCompleted();
62 }
63
67 void LinkGraphSchedule::JoinNext()
68 {
69 if (this->running.empty()) return;
70 LinkGraphJob *next = this->running.front();
71 if (!next->IsScheduledToBeJoined()) return;
72 this->running.pop_front();
73 LinkGraphID id = next->LinkGraphIndex();
74 delete next; // implicitly joins the thread
75 if (LinkGraph::IsValidID(id)) {
76 LinkGraph *lg = LinkGraph::Get(id);
77 this->Unqueue(lg); // Unqueue to avoid double-queueing recycled IDs.
78 this->Queue(lg);
79 }
80 }
81
86 /* static */ void LinkGraphSchedule::Run(LinkGraphJob *job)
87 {
88 for (uint i = 0; i < lengthof(instance.handlers); ++i) {
89 if (job->IsJobAborted()) return;
90 instance.handlers[i]->Run(*job);
91 }
92
93 /*
94 * Readers of this variable in another thread may see an out of date value.
95 * However this is OK as this will only happen just as a job is completing,
96 * and the real synchronisation is provided by the thread join operation.
97 * In the worst case the main thread will be paused for longer than
98 * strictly necessary before joining.
99 * This is just a hint variable to avoid performing the join excessively
100 * early and blocking the main thread.
101 */
102
103 job->job_completed.store(true, std::memory_order_release);
104 }
105
110 void LinkGraphSchedule::SpawnAll()
111 {
112 for (JobList::iterator i = this->running.begin(); i != this->running.end(); ++i) {
113 (*i)->SpawnThread();
114 }
115 }
116
120 /* static */ void LinkGraphSchedule::Clear()
121 {
122 for (JobList::iterator i(instance.running.begin()); i != instance.running.end(); ++i) {
123 (*i)->AbortJob();
124 }
125 instance.running.clear();
126 instance.schedule.clear();
127 }
128
134 void LinkGraphSchedule::ShiftDates(int interval)
135 {
136 for (LinkGraph *lg : LinkGraph::Iterate()) lg->ShiftDates(interval);
137 for (LinkGraphJob *lgj : LinkGraphJob::Iterate()) lgj->ShiftJoinDate(interval);
138 }
139
143 LinkGraphSchedule::LinkGraphSchedule()
144 {
145 this->handlers[0] = new InitHandler;
146 this->handlers[1] = new DemandHandler;
147 this->handlers[2] = new MCFHandler<MCF1stPass>;
148 this->handlers[3] = new FlowMapper(false);
149 this->handlers[4] = new MCFHandler<MCF2ndPass>;
150 this->handlers[5] = new FlowMapper(true);
151 }
152
156 LinkGraphSchedule::~LinkGraphSchedule()
157 {
158 this->Clear();
159 for (uint i = 0; i < lengthof(this->handlers); ++i) {
160 delete this->handlers[i];
161 }
162 }
163
171 void StateGameLoop_LinkGraphPauseControl()
172 {
173 if (_pause_mode & PM_PAUSED_LINK_GRAPH) {
174 /* We are paused waiting on a job, check the job every tick. */
175 if (!LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
176 DoCommandP(0, PM_PAUSED_LINK_GRAPH, 0, CMD_PAUSE);
177 }
178 } else if (_pause_mode == PM_UNPAUSED &&
179 _date_fract == LinkGraphSchedule::SPAWN_JOIN_TICK - 2 &&
180 _date % _settings_game.linkgraph.recalc_interval == _settings_game.linkgraph.recalc_interval / 2 &&
181 LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
182 /* Perform check two _date_fract ticks before we would join, to make
183 * sure it also works in multiplayer. */
184 DoCommandP(0, PM_PAUSED_LINK_GRAPH, 1, CMD_PAUSE);
185 }
186 }
187
193 void AfterLoad_LinkGraphPauseControl()
194 {
195 if (LinkGraphSchedule::instance.IsJoinWithUnfinishedJobDue()) {
196 _pause_mode |= PM_PAUSED_LINK_GRAPH;
197 }
198 }
199
204 void OnTick_LinkGraph()
205 {
206 if (_date_fract != LinkGraphSchedule::SPAWN_JOIN_TICK) return;
207 Date offset = _date % _settings_game.linkgraph.recalc_interval;
208 if (offset == 0) {
209 LinkGraphSchedule::instance.SpawnNext();
210 } else if (offset == _settings_game.linkgraph.recalc_interval / 2) {
211 if (!_networking || _network_server) {
212 PerformanceMeasurer::SetInactive(PFE_GL_LINKGRAPH);
213 LinkGraphSchedule::instance.JoinNext();
214 } else {
215 PerformanceMeasurer framerate(PFE_GL_LINKGRAPH);
216 LinkGraphSchedule::instance.JoinNext();
217 }
218 }
219 }
220
221
LinkGraphSchedule::Clear
static void Clear()
Clear all link graphs and jobs from the schedule.
Definition: linkgraphschedule.cpp:120
mcf.h
Pool::PoolItem<&_link_graph_pool >::Get
static Titem * Get(size_t index)
Returns Titem with given index.
Definition: pool_type.hpp:329
LinkGraphSchedule::JoinNext
void JoinNext()
Join the next finished job, if available.
Definition: linkgraphschedule.cpp:67
LinkGraph
A connected component of a link graph.
Definition: linkgraph.h:39
DemandHandler
Stateless, thread safe demand handler.
Definition: demands.h:28
LinkGraphSchedule::ShiftDates
void ShiftDates(int interval)
Shift all dates (join dates and edge annotations) of link graphs and link graph jobs by the number of...
Definition: linkgraphschedule.cpp:134
LinkGraphSchedule::SPAWN_JOIN_TICK
static const uint SPAWN_JOIN_TICK
Tick when jobs are spawned or joined every day.
Definition: linkgraphschedule.h:51
LinkGraphJob
Class for calculation jobs to be run on link graphs.
Definition: linkgraphjob.h:30
_date_fract
DateFract _date_fract
Fractional part of the day.
Definition: date.cpp:29
LinkGraphSchedule::running
JobList running
Currently running jobs.
Definition: linkgraphschedule.h:47
_network_server
bool _network_server
network-server is active
Definition: network.cpp:53
LinkGraphSchedule
Definition: linkgraphschedule.h:36
LinkGraphJob::IsJobCompleted
bool IsJobCompleted() const
Check if job has actually finished.
Definition: linkgraphjob.h:283
LinkGraphSchedule::instance
static LinkGraphSchedule instance
Static instance of LinkGraphSchedule.
Definition: linkgraphschedule.h:52
Pool::PoolItem::index
Tindex index
Index of this pool item.
Definition: pool_type.hpp:227
demands.h
PerformanceMeasurer
RAII class for measuring simple elements of performance.
Definition: framerate_type.h:92
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:65
PFE_GL_LINKGRAPH
@ PFE_GL_LINKGRAPH
Time spent waiting for link graph background jobs.
Definition: framerate_type.h:56
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:193
LinkGraphSchedule::SpawnAll
void SpawnAll()
Start all threads in the running list.
Definition: linkgraphschedule.cpp:110
PerformanceMeasurer::SetInactive
static void SetInactive(PerformanceElement elem)
Mark a performance element as not currently in use.
Definition: framerate_gui.cpp:264
LinkGraphJob::LinkGraphIndex
LinkGraphID LinkGraphIndex() const
Get the ID of the underlying link graph.
Definition: linkgraphjob.h:353
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:204
PM_UNPAUSED
@ PM_UNPAUSED
A normal unpaused game.
Definition: openttd.h:59
LinkGraphSchedule::Queue
void Queue(LinkGraph *lg)
Queue a link graph for execution.
Definition: linkgraphschedule.h:67
_date
Date _date
Current date in days (day counter)
Definition: date.cpp:28
LinkGraphJob::SpawnThread
void SpawnThread()
Spawn a thread if possible and run the link graph job in the thread.
Definition: linkgraphjob.cpp:61
ComponentHandler::Run
virtual void Run(LinkGraphJob &job) const =0
Run the handler.
DoCommandP
bool DoCommandP(const CommandContainer *container, bool my_cmd)
Shortcut for the long DoCommandP when having a container with the data.
Definition: command.cpp:541
CMD_PAUSE
@ CMD_PAUSE
pause the game
Definition: command_type.h:256
LinkGraphJob::IsScheduledToBeJoined
bool IsScheduledToBeJoined() const
Check if job is supposed to be finished.
Definition: linkgraphjob.h:304
Date
int32 Date
The type to store our dates in.
Definition: date_type.h:14
init.h
LinkGraph::Size
uint Size() const
Get the current size of the component.
Definition: linkgraph.h:498
_pause_mode
PauseMode _pause_mode
The current pause mode.
Definition: gfx.cpp:47
_settings_game
GameSettings _settings_game
Game settings of a running game or the scenario editor.
Definition: settings.cpp:80
LinkGraphSchedule::SpawnNext
void SpawnNext()
Start the next job in the schedule.
Definition: linkgraphschedule.cpp:32
_networking
bool _networking
are we in networking mode?
Definition: network.cpp:52
LinkGraphSchedule::LinkGraphSchedule
LinkGraphSchedule()
Create a link graph schedule and initialize its handlers.
Definition: linkgraphschedule.cpp:143
GameSettings::linkgraph
LinkGraphSettings linkgraph
settings for link graph calculations
Definition: settings_type.h:570
LinkGraphSchedule::schedule
GraphList schedule
Queue for new jobs.
Definition: linkgraphschedule.h:46
linkgraphschedule.h
FlowMapper
Map the path trees generated by the MCF solver into flows.
Definition: flowmapper.h:22
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:378
LinkGraphSettings::recalc_interval
uint16 recalc_interval
time (in days) between subsequent checks for link graphs to be calculated.
Definition: settings_type.h:511
LinkGraphJob::IsJobAborted
bool IsJobAborted() const
Check if job has been aborted.
Definition: linkgraphjob.h:290
LinkGraphSchedule::IsJoinWithUnfinishedJobDue
bool IsJoinWithUnfinishedJobDue() const
Check if the next job is supposed to be finished, but has not yet completed.
Definition: linkgraphschedule.cpp:57
MCFHandler
Link graph handler for MCF.
Definition: mcf.h:77
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:299
PM_PAUSED_LINK_GRAPH
@ PM_PAUSED_LINK_GRAPH
A game paused due to the link graph schedule lagging.
Definition: openttd.h:66
lengthof
#define lengthof(x)
Return the length of an fixed size array.
Definition: stdafx.h:367
LinkGraphSchedule::Run
static void Run(LinkGraphJob *job)
Run all handlers for the given Job.
Definition: linkgraphschedule.cpp:86
LinkGraphSchedule::handlers
ComponentHandler * handlers[6]
Handlers to be run for each job.
Definition: linkgraphschedule.h:45
LinkGraphSchedule::Unqueue
void Unqueue(LinkGraph *lg)
Remove a link graph from the execution queue.
Definition: linkgraphschedule.h:77
Pool::PoolItem<&_link_graph_pool >::IsValidID
static bool IsValidID(size_t index)
Tests whether given index can be used to get valid (non-nullptr) Titem.
Definition: pool_type.hpp:318
flowmapper.h
LinkGraphSchedule::~LinkGraphSchedule
~LinkGraphSchedule()
Delete a link graph schedule and its handlers.
Definition: linkgraphschedule.cpp:156
InitHandler
Stateless, thread safe initialization handler.
Definition: init.h:12
StateGameLoop_LinkGraphPauseControl
void StateGameLoop_LinkGraphPauseControl()
Pause the game if in 2 _date_fract ticks, we would do a join with the next link graph job,...
Definition: linkgraphschedule.cpp:171