Eclipse SUMO - Simulation of Urban MObility
MSEdgeControl.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2020 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
21 // Stores edges and lanes, performs moving of vehicle
22 /****************************************************************************/
23 #include <config.h>
24 
25 #include <iostream>
26 #include <queue>
27 #include <vector>
28 #include "MSEdgeControl.h"
29 #include "MSVehicleControl.h"
30 #include "MSGlobals.h"
31 #include "MSEdge.h"
32 #include "MSLane.h"
33 #include "MSVehicle.h"
34 
35 #define PARALLEL_PLAN_MOVE
36 #define PARALLEL_EXEC_MOVE
37 //#define PARALLEL_CHANGE_LANES
38 //#define LOAD_BALANCING
39 
40 //#define PARALLEL_STOPWATCH
41 
42 // ===========================================================================
43 // member method definitions
44 // ===========================================================================
45 MSEdgeControl::MSEdgeControl(const std::vector< MSEdge* >& edges)
46  : myEdges(edges),
47  myLanes(MSLane::dictSize()),
48  myWithVehicles2Integrate(MSGlobals::gNumSimThreads > 1),
49  myLastLaneChange(MSEdge::dictSize()),
50  myInactiveCheckCollisions(MSGlobals::gNumSimThreads > 1),
51  myMinLengthGeometryFactor(1.),
52 #ifdef THREAD_POOL
53  myThreadPool(false, std::vector<int>(MSGlobals::gNumThreads, 0)),
54 #endif
55  myStopWatch(3) {
56  // build the usage definitions for lanes
57  for (MSEdge* const edge : myEdges) {
58  const std::vector<MSLane*>& lanes = edge->getLanes();
59  if (!edge->hasLaneChanger()) {
60  const int pos = lanes.front()->getNumericalID();
61  myLanes[pos].lane = lanes.front();
62  myLanes[pos].amActive = false;
63  myLanes[pos].haveNeighbors = false;
64  myMinLengthGeometryFactor = MIN2(edge->getLengthGeometryFactor(), myMinLengthGeometryFactor);
65  } else {
66  for (MSLane* const l : lanes) {
67  const int pos = l->getNumericalID();
68  myLanes[pos].lane = l;
69  myLanes[pos].amActive = false;
70  myLanes[pos].haveNeighbors = true;
71  myMinLengthGeometryFactor = MIN2(l->getLengthGeometryFactor(), myMinLengthGeometryFactor);
72  }
73  myLastLaneChange[edge->getNumericalID()] = -1;
74  }
75  }
76 #ifndef THREAD_POOL
77 #ifdef HAVE_FOX
78  if (MSGlobals::gNumThreads > 1) {
79  while (myThreadPool.size() < MSGlobals::gNumThreads) {
80  new WorkerThread(myThreadPool);
81  }
82  }
83 #endif
84 #endif
85 }
86 
87 
89 #ifndef THREAD_POOL
90 #ifdef HAVE_FOX
91  myThreadPool.clear();
92 #endif
93 #endif
94 #ifdef PARALLEL_STOPWATCH
96  for (MSEdge* const edge : myEdges) {
97  for (MSLane* const l : edge->getLanes()) {
98  wPlan.add(l->getStopWatch()[0]);
99  }
100  }
101  std::cout << wPlan.getHistory().size() << " lane planmove calls, average " << wPlan.getAverage() << " ns, total " << wPlan.getTotal() / double(1e9) << " s" << std::endl;
102  std::cout << myStopWatch[0].getHistory().size() << " planmove calls, average " << myStopWatch[0].getAverage() << " ns, total " << myStopWatch[0].getTotal() / double(1e9) << " s" << std::endl;
103  std::cout << myStopWatch[1].getHistory().size() << " execmove calls, average " << myStopWatch[1].getAverage() << " ns, total " << myStopWatch[1].getTotal() / double(1e9) << " s" << std::endl;
104 #endif
105 }
106 
107 
108 void
110  for (std::set<MSLane*, ComparatorNumericalIdLess>::iterator i = myChangedStateLanes.begin(); i != myChangedStateLanes.end(); ++i) {
111  LaneUsage& lu = myLanes[(*i)->getNumericalID()];
112  // if the lane was inactive but is now...
113  if (!lu.amActive && (*i)->getVehicleNumber() > 0) {
114  // ... add to active lanes and mark as such
115  if (lu.haveNeighbors) {
116  myActiveLanes.push_front(*i);
117  } else {
118  myActiveLanes.push_back(*i);
119  }
120  lu.amActive = true;
121  }
122  }
123  myChangedStateLanes.clear();
124 }
125 
126 
127 void
129 #ifdef PARALLEL_STOPWATCH
130  myStopWatch[0].start();
131 #endif
132 #ifdef THREAD_POOL
133  std::vector<std::future<void>> results;
134 #endif
135  for (std::list<MSLane*>::iterator i = myActiveLanes.begin(); i != myActiveLanes.end();) {
136  const int vehNum = (*i)->getVehicleNumber();
137  if (vehNum == 0) {
138  myLanes[(*i)->getNumericalID()].amActive = false;
139  i = myActiveLanes.erase(i);
140  } else {
141 #ifdef THREAD_POOL
142  if (MSGlobals::gNumSimThreads > 1) {
143  results.push_back(myThreadPool.executeAsync([i, t](int) {
144  (*i)->planMovements(t);
145  }, (*i)->getRNGIndex() % MSGlobals::gNumSimThreads));
146  ++i;
147  continue;
148  }
149 #else
150 #ifdef HAVE_FOX
151  if (MSGlobals::gNumSimThreads > 1) {
152  myThreadPool.add((*i)->getPlanMoveTask(t), (*i)->getRNGIndex() % myThreadPool.size());
153  ++i;
154  continue;
155  }
156 #endif
157 #endif
158  (*i)->planMovements(t);
159  ++i;
160  }
161  }
162 #ifdef THREAD_POOL
163  for (auto& r : results) {
164  r.wait();
165  }
166 #else
167 #ifdef HAVE_FOX
168  if (MSGlobals::gNumSimThreads > 1) {
169  myThreadPool.waitAll(false);
170  }
171 #endif
172 #endif
173 #ifdef PARALLEL_STOPWATCH
174  myStopWatch[0].stop();
175 #endif
176 }
177 
178 
179 void
181  for (MSLane* const lane : myActiveLanes) {
182  lane->setJunctionApproaches(t);
183  }
184 }
185 
186 
187 void
189 #ifdef PARALLEL_STOPWATCH
190  myStopWatch[1].start();
191 #endif
192  std::vector<MSLane*> wasActive(myActiveLanes.begin(), myActiveLanes.end());
194 #ifdef PARALLEL_EXEC_MOVE
195 #ifdef THREAD_POOL
196  if (MSGlobals::gNumSimThreads > 1) {
197  for (MSLane* const lane : myActiveLanes) {
198  myThreadPool.executeAsync([lane, t](int) {
199  lane->executeMovements(t);
200  }, lane->getRNGIndex() % MSGlobals::gNumSimThreads);
201  }
202  myThreadPool.waitAll();
203  }
204 #else
205 #ifdef HAVE_FOX
206  if (MSGlobals::gNumSimThreads > 1) {
207  for (MSLane* const lane : myActiveLanes) {
208  myThreadPool.add(lane->getExecuteMoveTask(t), lane->getRNGIndex() % myThreadPool.size());
209  }
210  myThreadPool.waitAll(false);
211  }
212 #endif
213 #endif
214 #endif
215  for (std::list<MSLane*>::iterator i = myActiveLanes.begin(); i != myActiveLanes.end();) {
216  if (
217 #ifdef PARALLEL_EXEC_MOVE
219 #endif
220  (*i)->getVehicleNumber() > 0) {
221  (*i)->executeMovements(t);
222  }
223  if ((*i)->getVehicleNumber() == 0) {
224  myLanes[(*i)->getNumericalID()].amActive = false;
225  i = myActiveLanes.erase(i);
226  } else {
227  ++i;
228  }
229  }
230  for (MSLane* lane : wasActive) {
231  lane->updateLengthSum();
232  }
234  std::vector<MSLane*>& toIntegrate = myWithVehicles2Integrate.getContainer();
235  std::sort(toIntegrate.begin(), toIntegrate.end(), ComparatorIdLess());
237  //This should disappear when parallelization is working. Until then it would
238  //be better to use ComparatorNumericalIdLess instead of ComparatorIdLess
240  for (MSLane* const lane : toIntegrate) {
241  const bool wasInactive = lane->getVehicleNumber() == 0;
242  lane->integrateNewVehicles();
243  if (wasInactive && lane->getVehicleNumber() > 0) {
244  LaneUsage& lu = myLanes[lane->getNumericalID()];
245  if (!lu.amActive) {
246  if (lu.haveNeighbors) {
247  myActiveLanes.push_front(lane);
248  } else {
249  myActiveLanes.push_back(lane);
250  }
251  lu.amActive = true;
252  }
253  }
254  }
255 #ifdef PARALLEL_STOPWATCH
256  myStopWatch[1].stop();
257 #endif
258 }
259 
260 
261 void
263  std::vector<MSLane*> toAdd;
264 #ifdef PARALLEL_CHANGE_LANES
265  std::vector<const MSEdge*> recheckLaneUsage;
266 #endif
267  MSGlobals::gComputeLC = true;
268  for (const MSLane* const l : myActiveLanes) {
269  if (myLanes[l->getNumericalID()].haveNeighbors) {
270  const MSEdge& edge = l->getEdge();
271  if (myLastLaneChange[edge.getNumericalID()] != t) {
272  myLastLaneChange[edge.getNumericalID()] = t;
273 #ifdef PARALLEL_CHANGE_LANES
274  if (MSGlobals::gNumSimThreads > 1) {
275  MSLane* lane = edge.getLanes()[0];
276  myThreadPool.add(lane->getLaneChangeTask(t), lane->getRNGIndex() % myThreadPool.size());
277  recheckLaneUsage.push_back(&edge);
278  } else {
279 #endif
280  edge.changeLanes(t);
281  for (MSLane* const lane : edge.getLanes()) {
282  LaneUsage& lu = myLanes[lane->getNumericalID()];
283  //if ((*i)->getID() == "disabled") {
284  // std::cout << SIMTIME << " vehicles=" << toString((*i)->getVehiclesSecure()) << "\n";
285  // (*i)->releaseVehicles();
286  //}
287  if (lane->getVehicleNumber() > 0 && !lu.amActive) {
288  toAdd.push_back(lane);
289  lu.amActive = true;
290  }
291  }
292 #ifdef PARALLEL_CHANGE_LANES
293  }
294 #endif
295  }
296  } else {
297  break;
298  }
299  }
300 
301 #ifdef PARALLEL_CHANGE_LANES
302  if (MSGlobals::gNumSimThreads > 1) {
303  myThreadPool.waitAll(false);
304  for (const MSEdge* e : recheckLaneUsage) {
305  for (MSLane* const l : e->getLanes()) {
306  LaneUsage& lu = myLanes[l->getNumericalID()];
307  if (l->getVehicleNumber() > 0 && !lu.amActive) {
308  toAdd.push_back(l);
309  lu.amActive = true;
310  }
311  }
312  }
313  }
314 #endif
315 
316  MSGlobals::gComputeLC = false;
317  for (std::vector<MSLane*>::iterator i = toAdd.begin(); i != toAdd.end(); ++i) {
318  myActiveLanes.push_front(*i);
319  }
321  // sort maneuver reservations
322  for (LaneUsageVector::iterator it = myLanes.begin(); it != myLanes.end(); ++it) {
323  (*it).lane->sortManeuverReservations();
324  }
325  }
326 }
327 
328 
329 void
330 MSEdgeControl::detectCollisions(SUMOTime timestep, const std::string& stage) {
331  // Detections is made by the edge's lanes, therefore hand over.
332  for (MSLane* lane : myActiveLanes) {
333  if (lane->needsCollisionCheck()) {
334  lane->detectCollisions(timestep, stage);
335  }
336  }
337  if (myInactiveCheckCollisions.size() > 0) {
339  lane->detectCollisions(timestep, stage);
340  }
343  }
344 }
345 
346 
347 void
349  myChangedStateLanes.insert(l);
350 }
351 
352 void
355 }
356 
357 void
359  for (MSEdgeVector::const_iterator i = myEdges.begin(); i != myEdges.end(); ++i) {
360  const std::vector<MSLane*>& lanes = (*i)->getLanes();
361  for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
362  (*j)->initRestrictions();
363  }
364  }
365 }
366 
367 void
369  for (MSEdge* edge : myEdges) {
370  edge->updateMesoType();
371  }
372 }
373 
374 
375 /****************************************************************************/
#define PARALLEL_EXEC_MOVE
long long int SUMOTime
Definition: SUMOTime.h:31
T MIN2(T a, T b)
Definition: StdDefs.h:73
void unlock()
Definition: FXSynchQue.h:100
Container & getContainer()
Definition: FXSynchQue.h:85
void clear()
Definition: FXSynchQue.h:143
Container & getContainer()
Definition: FXSynchSet.h:54
void insert(T what)
Definition: FXSynchSet.h:83
void unlock()
Definition: FXSynchSet.h:69
size_t size() const
Definition: FXSynchSet.h:126
void clear()
Definition: FXSynchSet.h:112
void patchActiveLanes()
Resets information whether a lane is active for all lanes.
std::vector< StopWatch< std::chrono::nanoseconds > > myStopWatch
~MSEdgeControl()
Destructor.
void setMesoTypes()
update meso edge type parameters
void setAdditionalRestrictions()
apply additional restrictions
FXSynchSet< MSLane *, std::set< MSLane *, ComparatorNumericalIdLess > > myInactiveCheckCollisions
Additional lanes for which collision checking must be performed.
std::list< MSLane * > myActiveLanes
The list of active (not empty) lanes.
void detectCollisions(SUMOTime timestep, const std::string &stage)
Detect collisions.
MSEdgeVector myEdges
Loaded edges.
void setJunctionApproaches(SUMOTime t)
Register junction approaches for all vehicles after velocities have been planned. This is a prerequis...
void executeMovements(SUMOTime t)
Executes planned vehicle movements with regards to right-of-way.
LaneUsageVector myLanes
Information about lanes' number of vehicles and neighbors.
void gotActive(MSLane *l)
Informs the control that the given lane got active.
void checkCollisionForInactive(MSLane *l)
trigger collision checking for inactive lane
std::vector< SUMOTime > myLastLaneChange
The list of active (not empty) lanes.
std::set< MSLane *, ComparatorNumericalIdLess > myChangedStateLanes
Lanes which changed the state without informing the control.
void planMovements(SUMOTime t)
Compute safe velocities for all vehicles based on positions and speeds from the last time step....
FXSynchQue< MSLane *, std::vector< MSLane * > > myWithVehicles2Integrate
A storage for lanes which shall be integrated because vehicles have moved onto them.
void changeLanes(const SUMOTime t)
Moves (precomputes) critical vehicles.
MSEdgeControl(const std::vector< MSEdge * > &edges)
Constructor.
double myMinLengthGeometryFactor
A road/street connecting two junctions.
Definition: MSEdge.h:77
void changeLanes(SUMOTime t) const
Performs lane changing on this edge.
Definition: MSEdge.cpp:682
const std::vector< MSLane * > & getLanes() const
Returns this edge's lanes.
Definition: MSEdge.h:166
int getNumericalID() const
Returns the numerical id of the edge.
Definition: MSEdge.h:294
static double gLateralResolution
Definition: MSGlobals.h:82
static bool gComputeLC
whether the simulationLoop is in the lane changing phase
Definition: MSGlobals.h:112
static int gNumSimThreads
how many threads to use for simulation
Definition: MSGlobals.h:115
static int gNumThreads
how many threads to use
Definition: MSGlobals.h:118
Representation of a lane in the micro simulation.
Definition: MSLane.h:82
int getRNGIndex() const
returns the associated RNG index
Definition: MSLane.h:210
static MSNet * getInstance()
Returns the pointer to the unique instance of MSNet (singleton).
Definition: MSNet.cpp:171
MSVehicleControl & getVehicleControl()
Returns the vehicle control.
Definition: MSNet.h:371
void removePending()
Removes a vehicle after it has ended.
const std::vector< TimeT > & getHistory() const
Definition: StopWatch.h:66
long long int getTotal() const
Definition: StopWatch.h:74
long long int getAverage() const
Definition: StopWatch.h:70
void add(const StopWatch< TimeT, ClockT > &other)
Definition: StopWatch.h:62
Function-object for stable sorting of objects acting like Named without being derived (SUMOVehicle)
Definition: Named.h:29
A structure holding some basic information about a simulated lane.
bool amActive
Information whether this lane is active.
bool haveNeighbors
Information whether this lane belongs to a multi-lane edge.