LCOV - code coverage report
Current view: top level - src/microsim - MSEdgeControl.cpp (source / functions) Coverage Total Hit
Test: lcov.info Lines: 100.0 % 136 136
Test Date: 2026-04-16 16:39:47 Functions: 100.0 % 14 14

            Line data    Source code
       1              : /****************************************************************************/
       2              : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
       3              : // Copyright (C) 2001-2026 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              : /****************************************************************************/
      14              : /// @file    MSEdgeControl.cpp
      15              : /// @author  Christian Roessel
      16              : /// @author  Daniel Krajzewicz
      17              : /// @author  Jakob Erdmann
      18              : /// @author  Michael Behrisch
      19              : /// @date    Mon, 09 Apr 2001
      20              : ///
      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 <utils/options/OptionsCont.h>
      29              : #include <mesosim/MELoop.h>
      30              : #include "MSEdgeControl.h"
      31              : #include "MSVehicleControl.h"
      32              : #include "MSGlobals.h"
      33              : #include "MSEdge.h"
      34              : #include "MSLane.h"
      35              : #include "MSVehicle.h"
      36              : 
      37              : #define PARALLEL_PLAN_MOVE
      38              : #define PARALLEL_EXEC_MOVE
      39              : //#define PARALLEL_CHANGE_LANES
      40              : //#define LOAD_BALANCING
      41              : 
      42              : //#define PARALLEL_STOPWATCH
      43              : 
      44              : // ===========================================================================
      45              : // member method definitions
      46              : // ===========================================================================
      47        41436 : MSEdgeControl::MSEdgeControl(const std::vector< MSEdge* >& edges)
      48        41436 :     : myEdges(edges),
      49        41436 :       myLanes(MSLane::dictSize()),
      50        41436 :       myWithVehicles2Integrate(MSGlobals::gNumSimThreads > 1),
      51        41436 :       myLastLaneChange(edges.size()),
      52        41436 :       myInactiveCheckCollisions(MSGlobals::gNumSimThreads > 1),
      53        41436 :       myMinLengthGeometryFactor(1.),
      54              : #ifdef THREAD_POOL
      55              :       myThreadPool(false, std::vector<int>(MSGlobals::gNumThreads, 0)),
      56              : #endif
      57        41436 :       myStopWatch(3) {
      58              :     // build the usage definitions for lanes
      59      1788420 :     for (MSEdge* const edge : myEdges) {
      60              :         const std::vector<MSLane*>& lanes = edge->getLanes();
      61      1746984 :         if (!edge->hasLaneChanger()) {
      62      1312128 :             const int pos = lanes.front()->getNumericalID();
      63      1312128 :             myLanes[pos].lane = lanes.front();
      64      1312128 :             myLanes[pos].amActive = false;
      65      1312128 :             myLanes[pos].haveNeighbors = false;
      66      2624256 :             myMinLengthGeometryFactor = MIN2(edge->getLengthGeometryFactor(), myMinLengthGeometryFactor);
      67              :         } else {
      68      1223517 :             for (MSLane* const l : lanes) {
      69              :                 const int pos = l->getNumericalID();
      70       788661 :                 myLanes[pos].lane = l;
      71       788661 :                 myLanes[pos].amActive = false;
      72       788661 :                 myLanes[pos].haveNeighbors = true;
      73      1552271 :                 myMinLengthGeometryFactor = MIN2(l->getLengthGeometryFactor(), myMinLengthGeometryFactor);
      74              :             }
      75       434856 :             myLastLaneChange[edge->getNumericalID()] = -1;
      76              :         }
      77              :     }
      78              : #ifndef THREAD_POOL
      79              : #ifdef HAVE_FOX
      80        41436 :     if (MSGlobals::gNumThreads > 1) {
      81        22495 :         while (myThreadPool.size() < MSGlobals::gNumThreads) {
      82        17980 :             new WorkerThread(myThreadPool);
      83              :         }
      84              :     }
      85              : #endif
      86              : #endif
      87        41436 : }
      88              : 
      89              : 
      90        40993 : MSEdgeControl::~MSEdgeControl() {
      91              : #ifndef THREAD_POOL
      92              : #ifdef HAVE_FOX
      93        40993 :     myThreadPool.clear();
      94              : #endif
      95              : #endif
      96              : #ifdef PARALLEL_STOPWATCH
      97              :     StopWatch<std::chrono::nanoseconds> wPlan;
      98              :     for (MSEdge* const edge : myEdges) {
      99              :         for (MSLane* const l : edge->getLanes()) {
     100              :             wPlan.add(l->getStopWatch()[0]);
     101              :         }
     102              :     }
     103              :     std::cout << wPlan.getHistory().size() << " lane planmove calls, average " << wPlan.getAverage() << " ns, total " << wPlan.getTotal() / double(1e9) << " s" << std::endl;
     104              :     std::cout << myStopWatch[0].getHistory().size() << " planmove calls, average " << myStopWatch[0].getAverage() << " ns, total " << myStopWatch[0].getTotal() / double(1e9) << " s" << std::endl;
     105              :     std::cout << myStopWatch[1].getHistory().size() << " execmove calls, average " << myStopWatch[1].getAverage() << " ns, total " << myStopWatch[1].getTotal() / double(1e9) << " s" << std::endl;
     106              : #endif
     107       122979 : }
     108              : 
     109              : void
     110           13 : MSEdgeControl::setActiveLanes(std::list<MSLane*> lanes) {
     111           13 :     myActiveLanes = lanes;
     112           51 :     for (MSLane* lane : lanes) {
     113           38 :         myLanes[lane->getNumericalID()].amActive = true;
     114              :     }
     115           13 : }
     116              : 
     117              : void
     118     40788936 : MSEdgeControl::patchActiveLanes() {
     119     41441447 :     for (std::set<MSLane*, ComparatorNumericalIdLess>::iterator i = myChangedStateLanes.begin(); i != myChangedStateLanes.end(); ++i) {
     120       652511 :         LaneUsage& lu = myLanes[(*i)->getNumericalID()];
     121              :         // if the lane was inactive but is now...
     122       652511 :         if (!lu.amActive && (*i)->getVehicleNumber() > 0) {
     123              :             // ... add to active lanes and mark as such
     124       633139 :             if (lu.haveNeighbors) {
     125       500072 :                 myActiveLanes.push_front(*i);
     126              :             } else {
     127       133067 :                 myActiveLanes.push_back(*i);
     128              :             }
     129       633139 :             lu.amActive = true;
     130              :         }
     131              :     }
     132              :     myChangedStateLanes.clear();
     133     40788936 : }
     134              : 
     135              : 
     136              : void
     137     40788936 : MSEdgeControl::planMovements(SUMOTime t) {
     138              : #ifdef PARALLEL_STOPWATCH
     139              :     myStopWatch[0].start();
     140              : #endif
     141              : #ifdef THREAD_POOL
     142              :     std::vector<std::future<void>> results;
     143              : #endif
     144    135321281 :     for (std::list<MSLane*>::iterator i = myActiveLanes.begin(); i != myActiveLanes.end();) {
     145     94532345 :         const int vehNum = (*i)->getVehicleNumber();
     146     94532345 :         if (vehNum == 0) {
     147       361120 :             myLanes[(*i)->getNumericalID()].amActive = false;
     148       361120 :             i = myActiveLanes.erase(i);
     149              :         } else {
     150              : #ifdef THREAD_POOL
     151              :             if (MSGlobals::gNumSimThreads > 1) {
     152              :                 results.push_back(myThreadPool.executeAsync([i, t](int) {
     153              :                     (*i)->planMovements(t);
     154              :                 }, (*i)->getRNGIndex() % MSGlobals::gNumSimThreads));
     155              :                 ++i;
     156              :                 continue;
     157              :             }
     158              : #else
     159              : #ifdef HAVE_FOX
     160     94171225 :             if (MSGlobals::gNumSimThreads > 1) {
     161     15421747 :                 myThreadPool.add((*i)->getPlanMoveTask(t), (*i)->getRNGIndex() % myThreadPool.size());
     162              :                 ++i;
     163     15421747 :                 continue;
     164              :             }
     165              : #endif
     166              : #endif
     167     78749478 :             (*i)->planMovements(t);
     168              :             ++i;
     169              :         }
     170              :     }
     171              : #ifdef THREAD_POOL
     172              :     for (auto& r : results) {
     173              :         r.wait();
     174              :     }
     175              : #else
     176              : #ifdef HAVE_FOX
     177     40788936 :     if (MSGlobals::gNumSimThreads > 1) {
     178      6293436 :         myThreadPool.waitAll(false);
     179              :     }
     180              : #endif
     181              : #endif
     182              : #ifdef PARALLEL_STOPWATCH
     183              :     myStopWatch[0].stop();
     184              : #endif
     185     40788936 : }
     186              : 
     187              : 
     188              : void
     189     40788936 : MSEdgeControl::setJunctionApproaches() {
     190    134960161 :     for (MSLane* const lane : myActiveLanes) {
     191     94171225 :         lane->setJunctionApproaches();
     192              :     }
     193     40788936 : }
     194              : 
     195              : 
     196              : void
     197     40788936 : MSEdgeControl::executeMovements(SUMOTime t) {
     198              : #ifdef PARALLEL_STOPWATCH
     199              :     myStopWatch[1].start();
     200              : #endif
     201     40788936 :     std::vector<MSLane*> wasActive(myActiveLanes.begin(), myActiveLanes.end());
     202     40788936 :     myWithVehicles2Integrate.clear();
     203              : #ifdef PARALLEL_EXEC_MOVE
     204              : #ifdef THREAD_POOL
     205              :     if (MSGlobals::gNumSimThreads > 1) {
     206              :         for (MSLane* const lane : myActiveLanes) {
     207              :             myThreadPool.executeAsync([lane, t](int) {
     208              :                 lane->executeMovements(t);
     209              :             }, lane->getRNGIndex() % MSGlobals::gNumSimThreads);
     210              :         }
     211              :         myThreadPool.waitAll();
     212              :     }
     213              : #else
     214              : #ifdef HAVE_FOX
     215     40788936 :     if (MSGlobals::gNumSimThreads > 1) {
     216     21715183 :         for (MSLane* const lane : myActiveLanes) {
     217     15421747 :             myThreadPool.add(lane->getExecuteMoveTask(t), lane->getRNGIndex() % myThreadPool.size());
     218              :         }
     219      6293436 :         myThreadPool.waitAll(false);
     220              :     }
     221              : #endif
     222              : #endif
     223              : #endif
     224    134960158 :     for (std::list<MSLane*>::iterator i = myActiveLanes.begin(); i != myActiveLanes.end();) {
     225              :         if (
     226              : #ifdef PARALLEL_EXEC_MOVE
     227     94171225 :             MSGlobals::gNumSimThreads <= 1 &&
     228              : #endif
     229     78749478 :             (*i)->getVehicleNumber() > 0) {
     230     78749478 :             (*i)->executeMovements(t);
     231              :         }
     232     94171222 :         if ((*i)->getVehicleNumber() == 0) {
     233      7740479 :             myLanes[(*i)->getNumericalID()].amActive = false;
     234      7740479 :             i = myActiveLanes.erase(i);
     235              :         } else {
     236              :             ++i;
     237              :         }
     238              :     }
     239    134960155 :     for (MSLane* lane : wasActive) {
     240     94171222 :         lane->updateLengthSum();
     241              :     }
     242              :     // arrived vehicles should not influence lane changing
     243     40788933 :     MSNet::getInstance()->getVehicleControl().removePending();
     244              :     std::vector<MSLane*>& toIntegrate = myWithVehicles2Integrate.getContainer();
     245     40788933 :     std::sort(toIntegrate.begin(), toIntegrate.end(), ComparatorIdLess());
     246              :     /// @todo: sorting only needed to account for lane-ordering dependencies.
     247              :     //This should disappear when parallelization is working. Until then it would
     248              :     //be better to use ComparatorNumericalIdLess instead of ComparatorIdLess
     249              :     myWithVehicles2Integrate.unlock();
     250     74256310 :     for (MSLane* const lane : toIntegrate) {
     251              :         const bool wasInactive = lane->getVehicleNumber() == 0;
     252     33467377 :         lane->integrateNewVehicles();
     253     33467377 :         if (wasInactive && lane->getVehicleNumber() > 0) {
     254      7156839 :             LaneUsage& lu = myLanes[lane->getNumericalID()];
     255      7156839 :             if (!lu.amActive) {
     256      7156839 :                 if (lu.haveNeighbors) {
     257      2944655 :                     myActiveLanes.push_front(lane);
     258              :                 } else {
     259      4212184 :                     myActiveLanes.push_back(lane);
     260              :                 }
     261      7156839 :                 lu.amActive = true;
     262              :             }
     263              :         }
     264              :     }
     265              : #ifdef PARALLEL_STOPWATCH
     266              :     myStopWatch[1].stop();
     267              : #endif
     268     40788936 : }
     269              : 
     270              : 
     271              : void
     272     40788933 : MSEdgeControl::changeLanes(const SUMOTime t) {
     273              :     std::vector<MSLane*> toAdd;
     274              : #ifdef PARALLEL_CHANGE_LANES
     275              :     std::vector<const MSEdge*> recheckLaneUsage;
     276              : #endif
     277     40788933 :     MSGlobals::gComputeLC = true;
     278     94857670 :     for (const MSLane* const l : myActiveLanes) {
     279     67865850 :         if (myLanes[l->getNumericalID()].haveNeighbors) {
     280              :             const MSEdge& edge = l->getEdge();
     281     54068737 :             if (myLastLaneChange[edge.getNumericalID()] != t) {
     282     42064392 :                 myLastLaneChange[edge.getNumericalID()] = t;
     283              : #ifdef PARALLEL_CHANGE_LANES
     284              :                 if (MSGlobals::gNumSimThreads > 1) {
     285              :                     MSLane* lane = edge.getLanes()[0];
     286              :                     myThreadPool.add(lane->getLaneChangeTask(t), lane->getRNGIndex() % myThreadPool.size());
     287              :                     recheckLaneUsage.push_back(&edge);
     288              :                 } else {
     289              : #endif
     290     42064392 :                     edge.changeLanes(t);
     291    125593511 :                     for (MSLane* const lane : edge.getLanes()) {
     292     83529119 :                         LaneUsage& lu = myLanes[lane->getNumericalID()];
     293              :                         //if ((*i)->getID() == "disabled") {
     294              :                         //    std::cout << SIMTIME << " vehicles=" << toString((*i)->getVehiclesSecure()) << "\n";
     295              :                         //    (*i)->releaseVehicles();
     296              :                         //}
     297     83529119 :                         if (lane->getVehicleNumber() > 0 && !lu.amActive) {
     298       329614 :                             toAdd.push_back(lane);
     299       329614 :                             lu.amActive = true;
     300              :                         }
     301     83529119 :                         if (MSGlobals::gLateralResolution > 0) {
     302     19985800 :                             lane->sortManeuverReservations();
     303              :                         }
     304              :                     }
     305              : #ifdef PARALLEL_CHANGE_LANES
     306              :                 }
     307              : #endif
     308              :             }
     309              :         } else {
     310              :             break;
     311              :         }
     312              :     }
     313              : 
     314              : #ifdef PARALLEL_CHANGE_LANES
     315              :     if (MSGlobals::gNumSimThreads > 1) {
     316              :         myThreadPool.waitAll(false);
     317              :         for (const MSEdge* e : recheckLaneUsage) {
     318              :             for (MSLane* const l : e->getLanes()) {
     319              :                 LaneUsage& lu = myLanes[l->getNumericalID()];
     320              :                 if (l->getVehicleNumber() > 0 && !lu.amActive) {
     321              :                     toAdd.push_back(l);
     322              :                     lu.amActive = true;
     323              :                 }
     324              :                 if (MSGlobals::gLateralResolution > 0) {
     325              :                     l->sortManeuverReservations();
     326              :                 }
     327              :             }
     328              :         }
     329              :     }
     330              : #endif
     331              : 
     332     40788933 :     MSGlobals::gComputeLC = false;
     333     41118547 :     for (std::vector<MSLane*>::iterator i = toAdd.begin(); i != toAdd.end(); ++i) {
     334       329614 :         myActiveLanes.push_front(*i);
     335              :     }
     336     40788933 : }
     337              : 
     338              : 
     339              : void
     340    165083758 : MSEdgeControl::detectCollisions(SUMOTime timestep, const std::string& stage) {
     341              :     // Detections is made by the edge's lanes, therefore hand over.
     342    540412366 :     for (MSLane* lane : myActiveLanes) {
     343    375328608 :         if (lane->needsCollisionCheck()) {
     344    101394894 :             lane->detectCollisions(timestep, stage);
     345              :         }
     346              :     }
     347    165083758 :     if (myInactiveCheckCollisions.size() > 0) {
     348       912539 :         for (MSLane* lane : myInactiveCheckCollisions.getContainer()) {
     349       575261 :             lane->detectCollisions(timestep, stage);
     350              :         }
     351       337278 :         myInactiveCheckCollisions.clear();
     352              :         myInactiveCheckCollisions.unlock();
     353              :     }
     354    165083758 : }
     355              : 
     356              : 
     357              : void
     358       652938 : MSEdgeControl::gotActive(MSLane* l) {
     359              :     myChangedStateLanes.insert(l);
     360       652938 : }
     361              : 
     362              : void
     363       576299 : MSEdgeControl::checkCollisionForInactive(MSLane* l) {
     364       576299 :     myInactiveCheckCollisions.insert(l);
     365       576299 : }
     366              : 
     367              : void
     368           65 : MSEdgeControl::setAdditionalRestrictions() {
     369         2163 :     for (MSEdge* e : myEdges) {
     370         2098 :         e->inferEdgeType();
     371              :         const std::vector<MSLane*>& lanes = e->getLanes();
     372         4762 :         for (std::vector<MSLane*>::const_iterator j = lanes.begin(); j != lanes.end(); ++j) {
     373         2664 :             (*j)->initRestrictions();
     374              :         }
     375              :     }
     376           65 : }
     377              : 
     378              : void
     379         6427 : MSEdgeControl::buildMesoSegments() {
     380         6427 :     const OptionsCont& oc = OptionsCont::getOptions();
     381       331945 :     for (MSEdge* edge : myEdges) {
     382       325518 :         if (!edge->getLanes().empty()) {
     383       325518 :             MSGlobals::gMesoNet->buildSegmentsFor(*edge, oc);
     384              :         }
     385              :     }
     386         6427 : }
     387              : 
     388              : void
     389           13 : MSEdgeControl::saveState(OutputDevice& out) {
     390           13 :     out.openTag(SUMO_TAG_EDGECONTROL);
     391           13 :     out.writeAttr(SUMO_ATTR_LANES, myActiveLanes);
     392           13 :     out.closeTag();
     393           13 : }
     394              : 
     395              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1