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-03-02 16:00:03 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        40893 : MSEdgeControl::MSEdgeControl(const std::vector< MSEdge* >& edges)
      48        40893 :     : myEdges(edges),
      49        40893 :       myLanes(MSLane::dictSize()),
      50        40893 :       myWithVehicles2Integrate(MSGlobals::gNumSimThreads > 1),
      51        40893 :       myLastLaneChange(edges.size()),
      52        40893 :       myInactiveCheckCollisions(MSGlobals::gNumSimThreads > 1),
      53        40893 :       myMinLengthGeometryFactor(1.),
      54              : #ifdef THREAD_POOL
      55              :       myThreadPool(false, std::vector<int>(MSGlobals::gNumThreads, 0)),
      56              : #endif
      57        40893 :       myStopWatch(3) {
      58              :     // build the usage definitions for lanes
      59      1747749 :     for (MSEdge* const edge : myEdges) {
      60              :         const std::vector<MSLane*>& lanes = edge->getLanes();
      61      1706856 :         if (!edge->hasLaneChanger()) {
      62      1276102 :             const int pos = lanes.front()->getNumericalID();
      63      1276102 :             myLanes[pos].lane = lanes.front();
      64      1276102 :             myLanes[pos].amActive = false;
      65      1276102 :             myLanes[pos].haveNeighbors = false;
      66      2552204 :             myMinLengthGeometryFactor = MIN2(edge->getLengthGeometryFactor(), myMinLengthGeometryFactor);
      67              :         } else {
      68      1211360 :             for (MSLane* const l : lanes) {
      69              :                 const int pos = l->getNumericalID();
      70       780606 :                 myLanes[pos].lane = l;
      71       780606 :                 myLanes[pos].amActive = false;
      72       780606 :                 myLanes[pos].haveNeighbors = true;
      73      1536468 :                 myMinLengthGeometryFactor = MIN2(l->getLengthGeometryFactor(), myMinLengthGeometryFactor);
      74              :             }
      75       430754 :             myLastLaneChange[edge->getNumericalID()] = -1;
      76              :         }
      77              :     }
      78              : #ifndef THREAD_POOL
      79              : #ifdef HAVE_FOX
      80        40893 :     if (MSGlobals::gNumThreads > 1) {
      81        22265 :         while (myThreadPool.size() < MSGlobals::gNumThreads) {
      82        17796 :             new WorkerThread(myThreadPool);
      83              :         }
      84              :     }
      85              : #endif
      86              : #endif
      87        40893 : }
      88              : 
      89              : 
      90        40449 : MSEdgeControl::~MSEdgeControl() {
      91              : #ifndef THREAD_POOL
      92              : #ifdef HAVE_FOX
      93        40449 :     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       121347 : }
     108              : 
     109              : void
     110            8 : MSEdgeControl::setActiveLanes(std::list<MSLane*> lanes) {
     111            8 :     myActiveLanes = lanes;
     112           41 :     for (MSLane* lane : lanes) {
     113           33 :         myLanes[lane->getNumericalID()].amActive = true;
     114              :     }
     115            8 : }
     116              : 
     117              : void
     118     43951088 : MSEdgeControl::patchActiveLanes() {
     119     44605373 :     for (std::set<MSLane*, ComparatorNumericalIdLess>::iterator i = myChangedStateLanes.begin(); i != myChangedStateLanes.end(); ++i) {
     120       654285 :         LaneUsage& lu = myLanes[(*i)->getNumericalID()];
     121              :         // if the lane was inactive but is now...
     122       654285 :         if (!lu.amActive && (*i)->getVehicleNumber() > 0) {
     123              :             // ... add to active lanes and mark as such
     124       634792 :             if (lu.haveNeighbors) {
     125       503683 :                 myActiveLanes.push_front(*i);
     126              :             } else {
     127       131109 :                 myActiveLanes.push_back(*i);
     128              :             }
     129       634792 :             lu.amActive = true;
     130              :         }
     131              :     }
     132              :     myChangedStateLanes.clear();
     133     43951088 : }
     134              : 
     135              : 
     136              : void
     137     43951088 : 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    144488055 :     for (std::list<MSLane*>::iterator i = myActiveLanes.begin(); i != myActiveLanes.end();) {
     145    100536967 :         const int vehNum = (*i)->getVehicleNumber();
     146    100536967 :         if (vehNum == 0) {
     147       367485 :             myLanes[(*i)->getNumericalID()].amActive = false;
     148       367485 :             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    100169482 :             if (MSGlobals::gNumSimThreads > 1) {
     161     17593954 :                 myThreadPool.add((*i)->getPlanMoveTask(t), (*i)->getRNGIndex() % myThreadPool.size());
     162              :                 ++i;
     163     17593954 :                 continue;
     164              :             }
     165              : #endif
     166              : #endif
     167     82575528 :             (*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     43951088 :     if (MSGlobals::gNumSimThreads > 1) {
     178      8445821 :         myThreadPool.waitAll(false);
     179              :     }
     180              : #endif
     181              : #endif
     182              : #ifdef PARALLEL_STOPWATCH
     183              :     myStopWatch[0].stop();
     184              : #endif
     185     43951088 : }
     186              : 
     187              : 
     188              : void
     189     43951088 : MSEdgeControl::setJunctionApproaches() {
     190    144120570 :     for (MSLane* const lane : myActiveLanes) {
     191    100169482 :         lane->setJunctionApproaches();
     192              :     }
     193     43951088 : }
     194              : 
     195              : 
     196              : void
     197     43951088 : MSEdgeControl::executeMovements(SUMOTime t) {
     198              : #ifdef PARALLEL_STOPWATCH
     199              :     myStopWatch[1].start();
     200              : #endif
     201     43951088 :     std::vector<MSLane*> wasActive(myActiveLanes.begin(), myActiveLanes.end());
     202     43951088 :     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     43951088 :     if (MSGlobals::gNumSimThreads > 1) {
     216     26039775 :         for (MSLane* const lane : myActiveLanes) {
     217     17593954 :             myThreadPool.add(lane->getExecuteMoveTask(t), lane->getRNGIndex() % myThreadPool.size());
     218              :         }
     219      8445821 :         myThreadPool.waitAll(false);
     220              :     }
     221              : #endif
     222              : #endif
     223              : #endif
     224    144120567 :     for (std::list<MSLane*>::iterator i = myActiveLanes.begin(); i != myActiveLanes.end();) {
     225              :         if (
     226              : #ifdef PARALLEL_EXEC_MOVE
     227    100169482 :             MSGlobals::gNumSimThreads <= 1 &&
     228              : #endif
     229     82575528 :             (*i)->getVehicleNumber() > 0) {
     230     82575528 :             (*i)->executeMovements(t);
     231              :         }
     232    100169479 :         if ((*i)->getVehicleNumber() == 0) {
     233      8424248 :             myLanes[(*i)->getNumericalID()].amActive = false;
     234      8424248 :             i = myActiveLanes.erase(i);
     235              :         } else {
     236              :             ++i;
     237              :         }
     238              :     }
     239    144120564 :     for (MSLane* lane : wasActive) {
     240    100169479 :         lane->updateLengthSum();
     241              :     }
     242              :     // arrived vehicles should not influence lane changing
     243     43951085 :     MSNet::getInstance()->getVehicleControl().removePending();
     244              :     std::vector<MSLane*>& toIntegrate = myWithVehicles2Integrate.getContainer();
     245     43951085 :     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     78384617 :     for (MSLane* const lane : toIntegrate) {
     251              :         const bool wasInactive = lane->getVehicleNumber() == 0;
     252     34433532 :         lane->integrateNewVehicles();
     253     34433532 :         if (wasInactive && lane->getVehicleNumber() > 0) {
     254      7838412 :             LaneUsage& lu = myLanes[lane->getNumericalID()];
     255      7838412 :             if (!lu.amActive) {
     256      7838412 :                 if (lu.haveNeighbors) {
     257      3113234 :                     myActiveLanes.push_front(lane);
     258              :                 } else {
     259      4725178 :                     myActiveLanes.push_back(lane);
     260              :                 }
     261      7838412 :                 lu.amActive = true;
     262              :             }
     263              :         }
     264              :     }
     265              : #ifdef PARALLEL_STOPWATCH
     266              :     myStopWatch[1].stop();
     267              : #endif
     268     43951088 : }
     269              : 
     270              : 
     271              : void
     272     43951085 : MSEdgeControl::changeLanes(const SUMOTime t) {
     273              :     std::vector<MSLane*> toAdd;
     274              : #ifdef PARALLEL_CHANGE_LANES
     275              :     std::vector<const MSEdge*> recheckLaneUsage;
     276              : #endif
     277     43951085 :     MSGlobals::gComputeLC = true;
     278    101629743 :     for (const MSLane* const l : myActiveLanes) {
     279     73980199 :         if (myLanes[l->getNumericalID()].haveNeighbors) {
     280              :             const MSEdge& edge = l->getEdge();
     281     57678658 :             if (myLastLaneChange[edge.getNumericalID()] != t) {
     282     45861868 :                 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     45861868 :                     edge.changeLanes(t);
     291    136827294 :                     for (MSLane* const lane : edge.getLanes()) {
     292     90965426 :                         LaneUsage& lu = myLanes[lane->getNumericalID()];
     293              :                         //if ((*i)->getID() == "disabled") {
     294              :                         //    std::cout << SIMTIME << " vehicles=" << toString((*i)->getVehiclesSecure()) << "\n";
     295              :                         //    (*i)->releaseVehicles();
     296              :                         //}
     297     90965426 :                         if (lane->getVehicleNumber() > 0 && !lu.amActive) {
     298       335431 :                             toAdd.push_back(lane);
     299       335431 :                             lu.amActive = true;
     300              :                         }
     301     90965426 :                         if (MSGlobals::gLateralResolution > 0) {
     302     20003034 :                             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     43951085 :     MSGlobals::gComputeLC = false;
     333     44286516 :     for (std::vector<MSLane*>::iterator i = toAdd.begin(); i != toAdd.end(); ++i) {
     334       335431 :         myActiveLanes.push_front(*i);
     335              :     }
     336     43951085 : }
     337              : 
     338              : 
     339              : void
     340    175814402 : MSEdgeControl::detectCollisions(SUMOTime timestep, const std::string& stage) {
     341              :     // Detections is made by the edge's lanes, therefore hand over.
     342    575146986 :     for (MSLane* lane : myActiveLanes) {
     343    399332584 :         if (lane->needsCollisionCheck()) {
     344    107654940 :             lane->detectCollisions(timestep, stage);
     345              :         }
     346              :     }
     347    175814402 :     if (myInactiveCheckCollisions.size() > 0) {
     348       873047 :         for (MSLane* lane : myInactiveCheckCollisions.getContainer()) {
     349       548871 :             lane->detectCollisions(timestep, stage);
     350              :         }
     351       324176 :         myInactiveCheckCollisions.clear();
     352              :         myInactiveCheckCollisions.unlock();
     353              :     }
     354    175814402 : }
     355              : 
     356              : 
     357              : void
     358       654734 : MSEdgeControl::gotActive(MSLane* l) {
     359              :     myChangedStateLanes.insert(l);
     360       654734 : }
     361              : 
     362              : void
     363       549909 : MSEdgeControl::checkCollisionForInactive(MSLane* l) {
     364       549909 :     myInactiveCheckCollisions.insert(l);
     365       549909 : }
     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         5940 : MSEdgeControl::buildMesoSegments() {
     380         5940 :     const OptionsCont& oc = OptionsCont::getOptions();
     381       300141 :     for (MSEdge* edge : myEdges) {
     382       294201 :         if (!edge->getLanes().empty()) {
     383       294201 :             MSGlobals::gMesoNet->buildSegmentsFor(*edge, oc);
     384              :         }
     385              :     }
     386         5940 : }
     387              : 
     388              : void
     389            8 : MSEdgeControl::saveState(OutputDevice& out) {
     390            8 :     out.openTag(SUMO_TAG_EDGECONTROL);
     391            8 :     out.writeAttr(SUMO_ATTR_LANES, myActiveLanes);
     392            8 :     out.closeTag();
     393            8 : }
     394              : 
     395              : /****************************************************************************/
        

Generated by: LCOV version 2.0-1