![]() |
User Manual, Developers Guide and API Documentation |
![]() |
00001 /******************************************************************************* 00002 * This file is part of openWNS (open Wireless Network Simulator) 00003 * _____________________________________________________________________________ 00004 * 00005 * Copyright (C) 2004-2007 00006 * Chair of Communication Networks (ComNets) 00007 * Kopernikusstr. 5, D-52074 Aachen, Germany 00008 * phone: ++49-241-80-27910, 00009 * fax: ++49-241-80-22242 00010 * email: info@openwns.org 00011 * www: http://www.openwns.org 00012 * _____________________________________________________________________________ 00013 * 00014 * openWNS is free software; you can redistribute it and/or modify it under the 00015 * terms of the GNU Lesser General Public License version 2 as published by the 00016 * Free Software Foundation; 00017 * 00018 * openWNS is distributed in the hope that it will be useful, but WITHOUT ANY 00019 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 00020 * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 00021 * details. 00022 * 00023 * You should have received a copy of the GNU Lesser General Public License 00024 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00025 * 00026 ******************************************************************************/ 00027 00028 #include <LTE/timing/ResourceScheduler.hpp> 00029 #include <LTE/controlplane/flowmanagement/FlowManager.hpp> 00030 00031 #include <LTE/macg/MACg.hpp> 00032 #include <LTE/rlc/RLCCommand.hpp> 00033 #include <LTE/macr/PhyUser.hpp> 00034 #include <LTE/controlplane/associationHandler/AssociationHandler.hpp> 00035 #include <LTE/timing/RegistryProxy.hpp> 00036 #include <LTE/timing/partitioning/PartitioningInfo.hpp> 00037 #include <LTE/helper/QueueProxy.hpp> 00038 00039 #include <WNS/ldk/helper/FakePDU.hpp> 00040 #include <WNS/probe/bus/ContextProviderCollection.hpp> 00041 #include <WNS/probe/bus/utils.hpp> 00042 00043 #include <boost/bind.hpp> 00044 00045 #include <fstream> 00046 00047 #define A2N(a) (((a).getInteger()>0) ? layer2->getStationManager()->getStationByMAC(a)->getName() : "DLL<0") 00048 00049 using namespace std; 00050 using namespace lte::timing; 00051 00052 00053 ResourceScheduler::ResourceScheduler(wns::ldk::fun::FUN* fun, const wns::pyconfig::View& config) : 00054 wns::ldk::CommandTypeSpecifier<SchedulerCommand>(fun), 00055 HasModeName(config), 00056 pyConfig(config), 00057 logger(config.get("logger")), 00058 layer2(NULL), 00059 associationService(NULL), 00060 friends(), 00061 colleagues(), 00062 framesPerSuperFrame(config.get<int>("framesPerSuperFrame")), 00063 slotDuration(config.get<simTimeType>("slotDuration")), // currently assumed constant for all timeSlots 00064 freqChannels(config.get<int>("freqChannels")), 00065 numberOfTimeSlots(config.get<int>("numberOfTimeSlots")), 00066 maxBeams(config.get<int>("maxBeams")), 00067 beamforming(config.get<bool>("grouper.beamforming")), 00068 partitionGroup(config.get<uint32_t>("group")), 00069 schedulingResultOfFrame(framesPerSuperFrame), // vector schedulingResultOfFrame[frameNr] 00070 scorer(mode,config), 00071 schedulerSpot(-1), // initialized to good value in setFriends 00072 IamUplinkMaster(config.get<bool>("uplinkMaster")), // uplink==true only for RS-RX 00073 writeMapOutput(config.get<bool>("writeMapOutput")), 00074 mapFile(NULL), 00075 transportBlockCounter(0), 00076 maxTxPower(config.get<wns::Power>("maxTxPower")) 00077 { 00078 MESSAGE_SINGLE(NORMAL, logger,"Constructor: Strategy="<<config.get<std::string>("strategy.nameInStrategyFactory")); 00079 if (writeMapOutput) 00080 { 00081 std::string outputDir = 00082 wns::simulator::getConfiguration().get<std::string>("outputDir"); 00083 mapOutputFileName = outputDir + "/" + config.get<std::string>("mapOutputFileName"); 00084 MESSAGE_SINGLE(NORMAL, logger,"writing maps to "<<mapOutputFileName); 00085 } // else they are None 00086 00087 colleagues.harq = STATIC_FACTORY_NEW_INSTANCE(wns::scheduler::harq::HARQInterface, wns::PyConfigViewCreator, pyConfig.get("harq"), pyConfig.get("harq")); 00088 assure(colleagues.harq, "HARQ creation failed"); 00089 00090 wns::probe::bus::ContextProviderCollection* cpcParent = &fun->getLayer()->getContextProviderCollection(); 00091 wns::probe::bus::ContextProviderCollection cpc(cpcParent); 00092 resUsageProbe_ = wns::probe::bus::collector(cpc, config, "resUsageProbeName"); 00093 00094 } // ResourceScheduler 00095 00096 00097 ResourceScheduler::~ResourceScheduler() 00098 { 00099 MESSAGE_SINGLE(VERBOSE, logger, "ResourceScheduler::~ResourceScheduler()"); 00100 if (colleagues.registry) delete colleagues.registry; colleagues.registry=NULL; 00101 if (colleagues.strategy) delete colleagues.strategy; colleagues.strategy=NULL; 00102 if (colleagues.grouper) delete colleagues.grouper; colleagues.grouper=NULL; 00103 if (colleagues.queueProxy) { 00104 delete colleagues.queueProxy; colleagues.queueProxy=NULL; 00105 } else { 00106 if (colleagues.queue) delete colleagues.queue; 00107 } 00108 for (int frame=0; frame<framesPerSuperFrame; ++frame) 00109 { 00110 schedulingResultOfFrame[frame] = wns::scheduler::strategy::StrategyResultPtr(); // empty 00111 } 00112 if (writeMapOutput) closeMapOutput(); 00113 MESSAGE_SINGLE(VERBOSE, logger, "ResourceScheduler::~ResourceScheduler() ready"); 00114 } // ~ResourceScheduler 00115 00116 // for MapHandler 00117 int 00118 lte::timing::ResourceScheduler::getPartitionGroup() 00119 { 00120 return partitionGroup; 00121 } 00122 00123 // this is called by ILayer2::onNodeCreated() via fun->onFUNCreated(); 00124 void 00125 ResourceScheduler::onFUNCreated() 00126 { 00127 MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFUNCreated()"); 00128 wns::ldk::fun::FUN* fun = getFUN(); 00129 assure(fun, "Could not get my FUN"); 00130 layer2 = fun->getLayer<dll::ILayer2*>(); 00131 assure(layer2, "could not get ILayer2 from FUN"); 00132 00133 std::string flowmanagername="FlowManager"; 00134 if (layer2->getStationType() == wns::service::dll::StationTypes::UE()) { 00135 flowmanagername += "UT"; 00136 } else if (layer2->getStationType() == wns::service::dll::StationTypes::FRS()) { 00137 flowmanagername += "RN"; 00138 } else { // BS 00139 flowmanagername += "BS"; 00140 } 00141 00142 // remember association service 00143 associationService = layer2->getControlService<dll::services::control::Association>("ASSOCIATION"+modeBase); 00144 // Register as Observer at the association Info providers 00145 dll::ILayer2::AssociationInfoContainer ais = layer2->getAssociationInfoProvider(mode); 00146 dll::ILayer2::AssociationInfoContainer::const_iterator iter = ais.begin(); 00147 for (; iter != ais.end(); ++iter) 00148 this->startObserving(*iter); 00149 00150 if (mode == modeBase) 00151 friends.macg = fun->findFriend<lte::macg::MACg*>("macg"); 00152 else 00153 friends.macg = fun->findFriend<lte::macg::MACg*>("macg"+separator+taskID); 00154 00155 friends.rlcReader = fun->getCommandReader("rlc"); 00156 friends.phyUser = fun->findFriend<lte::macr::PhyUser*>(modeBase+separator+"phyUser"); 00157 friends.mapHandler = fun->findFriend<lte::controlplane::IMapHandlerRS*>(mode+separator+"mapHandler"); 00158 friends.rrHandler = fun->findFriend<lte::controlplane::RRHandler*>(mode+separator+"RRHandler"); 00159 friends.timer = layer2->getManagementService<lte::timing::TimingScheduler>(mode+separator+"Timer"); 00160 friends.flowManager = layer2->getControlService<lte::controlplane::flowmanagement::FlowManager>(flowmanagername); 00161 friends.partitioningInfo = layer2->getControlService<lte::timing::partitioning::PartitioningInfo>("PARTITIONINGINFO"+modeBase); 00162 assure(friends.flowManager!=NULL,"friends.flowManager==NULL"); 00163 assure(friends.rrHandler!=NULL,"friends.rrHandler==NULL"); 00164 00165 // inform my scorer about things it needs to know 00166 scorer.setRLC(friends.rlcReader); 00167 scorer.setAssociationService(associationService); 00168 00169 std::string registryName = pyConfig.get<std::string>("registry.nameInRegistryProxyFactory"); 00170 std::string strategyName = pyConfig.get<std::string>("strategy.nameInStrategyFactory"); 00171 std::string grouperName = pyConfig.get<std::string>("grouper.nameInGrouperFactory"); 00172 00173 // the first thing to do is to set up the registry because other colleagues 00174 // may depend on it for their initialization 00175 wns::pyconfig::View registryView = pyConfig.get<wns::pyconfig::View>("registry"); 00176 wns::scheduler::RegistryCreator* registryCreator = wns::scheduler::RegistryFactory::creator(registryName); 00177 colleagues.registry = dynamic_cast<lte::timing::RegistryProxy*>(registryCreator->create(fun, registryView)); 00178 //registryInLte = colleagues.registry; 00179 assure(colleagues.registry, "Registry creation failed"); 00180 /* Registry= System specific proxy that forwards queries from generic scheduler 00181 * components to the system specific entities */ 00182 colleagues.registry->setFUN(fun); // ? rs: why again? fun is given with registryCreator->create(fun...) above 00183 colleagues.registry->setHARQ(colleagues.harq); 00184 00185 //lte::timing::RegistryProxy *registryInLte = 00186 // dynamic_cast<lte::timing::RegistryProxy*>(colleagues.registry); 00187 00188 //assure(registryInLte, "dynamic_cast failed when try to get registryInLte"); 00189 colleagues.registry->setAssociationHandler(fun->findFriend<lte::controlplane::associationHandler::AssociationHandler*>(mode+separator+ "associationHandler")); 00190 00191 // create the grouper 00192 wns::scheduler::grouper::SpatialGrouperCreator* grouperCreator = wns::scheduler::grouper::SpatialGrouperFactory::creator(grouperName); 00193 colleagues.grouper = grouperCreator->create(pyConfig.get<wns::pyconfig::View>("grouper")); 00194 assure(colleagues.grouper, "Grouper creation failed"); 00195 // tell the modules who their friends and colleagues are 00196 colleagues.grouper->setColleagues(colleagues.registry); 00197 00198 // create the scheduling strategy (subStrategies are set there) 00199 wns::scheduler::strategy::StrategyCreator* strategyCreator = wns::scheduler::strategy::StrategyFactory::creator(strategyName); 00200 colleagues.strategy = strategyCreator->create(pyConfig.get<wns::pyconfig::View>("strategy")); 00201 assure(colleagues.strategy, "Strategy module creation failed"); 00202 00203 if (IamUplinkMaster) { // RS-RX 00204 MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFUNCreated(): Strategy creation finished. Now init RS-RX (UL master) specific tasks."); 00205 // create the queueProxy 00206 // The queueProxy knows the real queue if available (Tx) or the RRHandler (Rx) 00207 // It can also imitate a "dynamic segmentation" by sending specific commands... 00208 std::string queueProxyName = pyConfig.get<std::string>("queueProxy.nameInQueueFactory"); 00209 MESSAGE_SINGLE(NORMAL, logger, "creating queueProxy of type "<<queueProxyName); 00210 wns::pyconfig::View queueProxyView = pyConfig.get<wns::pyconfig::View>("queueProxy"); 00211 wns::scheduler::queue::QueueCreator* queueProxyCreator = wns::scheduler::queue::QueueFactory::creator(queueProxyName); 00212 wns::scheduler::queue::QueueInterface* queueProxySimple = queueProxyCreator->create(NULL, queueProxyView); 00213 assure(queueProxySimple!=NULL, "QueueProxySimple creation failed"); 00214 colleagues.queue = queueProxySimple; // satisfy interfaces 00215 MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFUNCreated(): QueueProxy created"); 00216 colleagues.queueProxy = dynamic_cast<lte::helper::QueueProxy*>(queueProxySimple); 00217 assure(colleagues.queueProxy!=NULL, "QueueProxy creation failed"); 00218 //colleagues.queueProxy->setQueue(colleagues.queue); 00219 colleagues.queueProxy->setRRHandler(friends.rrHandler); 00220 friends.rrHandler->setColleagues(colleagues.registry); 00221 00222 // Create the HARQRetransmissionProxy for the uplink scheduler 00223 wns::scheduler::harq::HARQInterface* downlinkHARQ = NULL; 00224 downlinkHARQ = fun->findFriend<lte::timing::ResourceScheduler*>(pyConfig.get<std::string>("txSchedulerFUName"))->colleagues.harq; 00225 colleagues.harq->setDownlinkHARQ(downlinkHARQ); 00226 00227 colleagues.strategy->setColleagues(colleagues.queueProxy, // NEW[rs]: queueProxy instead of queue 00228 colleagues.grouper, 00229 colleagues.registry, 00230 colleagues.harq 00231 ); 00232 colleagues.queueProxy->setColleagues(colleagues.registry); 00233 } else { // RS-TX 00234 MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFUNCreated(): Strategy creation finished. Now init RS-TX specific tasks."); 00235 // create the queues 00236 std::string queueName = pyConfig.get<std::string>("queue.nameInQueueFactory"); 00237 MESSAGE_SINGLE(NORMAL, logger, "creating queue of type "<<queueName); 00238 wns::pyconfig::View queueView = pyConfig.get<wns::pyconfig::View>("queue"); 00239 wns::scheduler::queue::QueueCreator* queueCreator = wns::scheduler::queue::QueueFactory::creator(queueName); 00240 colleagues.queue = queueCreator->create(NULL, queueView); 00241 assure(colleagues.queue, "Queue creation failed"); 00242 00243 colleagues.strategy->setColleagues(colleagues.queue, 00244 colleagues.grouper, 00245 colleagues.registry, 00246 colleagues.harq 00247 ); 00248 } 00249 assure(colleagues.queue!=NULL,"colleagues.queue==NULL"); 00250 colleagues.queue->setColleagues(colleagues.registry); 00251 00252 if (writeMapOutput) prepareMapOutput(); 00253 MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFUNCreated() finished"); 00254 } // onFUNCreated 00255 00256 // called in ILayer2::onNodeCreated() to connect PHY service with spatial grouper 00257 void 00258 ResourceScheduler::onNodeCreated() 00259 { 00260 MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onNodeCreated()"); 00261 wns::service::phy::ofdma::DataTransmission* ofdmaProvider = friends.phyUser->getDataTransmissionService(); 00262 colleagues.grouper->setFriends(ofdmaProvider); 00263 colleagues.strategy->setFriends(ofdmaProvider); 00264 colleagues.queue->setFUN(getFUN()); 00265 schedulerSpot = colleagues.strategy->getSchedulerSpotType(); // first known after strategy->setFriends 00266 } // onNodeCreated(): setOFDMAService 00267 00268 void 00269 ResourceScheduler::onFlowReleased(wns::service::dll::FlowID flowId, wns::scheduler::UserID user /*nextHop!*/) 00270 { 00271 MESSAGE_SINGLE(NORMAL, logger, "ResourceScheduler::onFlowReleased("<<flowId<<")"); 00272 colleagues.queue->resetQueue(flowId); // cid=flowID 00273 colleagues.registry->deregisterCID(flowId, user); 00274 } 00275 00276 bool 00277 ResourceScheduler::doIsAccepting(const wns::ldk::CompoundPtr& compound) const 00278 { 00279 return true; 00280 //return colleagues.queue->isAccepting(compound); 00281 } // isAccepting 00282 00283 void 00284 ResourceScheduler::doSendData(const wns::ldk::CompoundPtr& compound) 00285 { 00286 assure(compound, "sendData called with an invalid compound."); 00287 colleagues.queue->put(compound); 00288 } // doSendData 00289 00290 void 00291 ResourceScheduler::deliverSchedulingTimeSlot( 00292 bool canBeDecoded, 00293 const wns::scheduler::SchedulingTimeSlotPtr& schedulingTimeSlot, 00294 wns::service::phy::power::PowerMeasurementPtr& phyMeasurement, 00295 int subband) 00296 { 00297 // Iterate over spatial domain 00298 for(wns::scheduler::PhysicalResourceBlockVector::iterator it = schedulingTimeSlot->physicalResources.begin(); 00299 it != schedulingTimeSlot->physicalResources.end(); 00300 ++it) 00301 { 00302 // Iterate over all contained compounds 00303 for (wns::scheduler::ScheduledCompoundsList::const_iterator compoundIt = it->scheduledCompoundsBegin(); 00304 compoundIt != it->scheduledCompoundsEnd(); 00305 ++compoundIt) 00306 { 00307 // There may be Non-HARQ transmissions in this SchedulingTimeSlot 00308 // For now these are error free and delivered regardless of canBeDecoded. 00309 // So: only check canBeDecoded flag for HARQ compounds 00310 // Do not deliver NON-HARQ compounds in a retry, they already have been 00311 // delivered. 00312 if ( (compoundIt->harqEnabled && (!canBeDecoded)) || 00313 (schedulingTimeSlot->harq.retryCounter > 0 && (!compoundIt->harqEnabled))) 00314 { 00315 continue; 00316 } 00317 00318 MESSAGE_BEGIN(NORMAL, logger, m, "onData: "); 00319 if(friends.rlcReader->commandIsActivated(compoundIt->compoundPtr->getCommandPool())) { 00320 lte::macg::MACgCommand* macgCommand = friends.macg->getCommand(compoundIt->compoundPtr->getCommandPool()); 00321 lte::rlc::RLCCommand* rlcCommand = friends.rlcReader->readCommand<lte::rlc::RLCCommand>(compoundIt->compoundPtr->getCommandPool()); 00322 m << "received PDU"; 00323 m << " from source " << A2N(rlcCommand->peer.source) 00324 << " via " << A2N(macgCommand->peer.source); 00325 } else { 00326 m << " rlcReader->commandIsActivated=false !!!"; 00327 } 00328 MESSAGE_END(); 00329 00330 if (!getFUN()->getProxy()->commandIsActivated(compoundIt->compoundPtr->getCommandPool(), this)) 00331 { 00332 this->activateCommand(compoundIt->compoundPtr->getCommandPool()); 00333 } 00334 SchedulerCommand* myCommand = this->getCommand(compoundIt->compoundPtr->getCommandPool()); 00335 myCommand->local.phyMeasurementPtr = phyMeasurement; 00336 myCommand->local.subBand = subband; 00337 00338 getDeliverer()->getAcceptor(compoundIt->compoundPtr)->onData(compoundIt->compoundPtr); 00339 } 00340 00341 it->clearScheduledCompounds(); 00342 } 00343 schedulingTimeSlot->physicalResources.clear(); 00344 } 00345 00346 void 00347 ResourceScheduler::deliverReceived() 00348 { 00349 wns::scheduler::harq::HARQInterface::DecodeStatusContainer::iterator it; 00350 00351 MESSAGE_SINGLE(NORMAL, logger, "Delivering " << receivedNonHARQTimeslots_.size() << " NON-HARQ transmissions"); 00352 00353 // First deliver all the non HARQ transmissions 00354 for (it = receivedNonHARQTimeslots_.begin(); 00355 it!= receivedNonHARQTimeslots_.end(); ++it) 00356 { 00357 MESSAGE_SINGLE(NORMAL, logger, "Delivering NON-HARQ timeslot " << it->first.getPtr()); 00358 deliverSchedulingTimeSlot(it->first->harq.successfullyDecoded, 00359 it->first, 00360 it->second.powerMeasurement_, 00361 it->second.sc_); 00362 } 00363 00364 // Clear the non HARQ buffer 00365 receivedNonHARQTimeslots_.clear(); 00366 00367 // Now proceed with all that HARQ was able to decode 00368 wns::scheduler::harq::HARQInterface::DecodeStatusContainer compounds = colleagues.harq->decode(); 00369 00370 MESSAGE_SINGLE(NORMAL, logger, "Delivering " << compounds.size() << " HARQ transmissions"); 00371 00372 for (it=compounds.begin(); it!=compounds.end();++it) 00373 { 00374 MESSAGE_SINGLE(NORMAL, logger, "Delivering HARQ timeslot " << it->first.getPtr()); 00375 00376 deliverSchedulingTimeSlot(it->first->harq.successfullyDecoded, 00377 it->first, 00378 it->second.powerMeasurement_, 00379 it->second.sc_); 00380 } 00381 } 00382 00383 // PDU or ResourceBlock from PHY came in ... just send up. Soneone else is responsible for the correct order (reordering). 00384 void 00385 ResourceScheduler::doOnData(const wns::ldk::CompoundPtr& compound) 00386 { 00387 SchedulerCommand* myCommand = this->getCommand(compound->getCommandPool()); 00388 lte::macr::PhyCommand* phyCommand = friends.phyUser->getCommand(compound->getCommandPool()); 00389 00390 wns::scheduler::SchedulingTimeSlotPtr ts = myCommand->magic.schedulingTimeSlotPtr; 00391 00392 MESSAGE_SINGLE(NORMAL, logger, "Received timeslot " << ts.getPtr()); 00393 00394 // after approx 3ms processing delay 00395 wns::simulator::getEventScheduler()->scheduleDelay( 00396 boost::bind(&ResourceScheduler::postDecoding, this, compound), 0.002999); 00397 } 00398 00399 void 00400 ResourceScheduler::postDecoding(const wns::ldk::CompoundPtr compound) 00401 { 00402 assure(compound, "onData called with an invalid compound."); 00403 00404 SchedulerCommand* myCommand = this->getCommand(compound->getCommandPool()); 00405 lte::macr::PhyCommand* phyCommand = friends.phyUser->getCommand(compound->getCommandPool()); 00406 00407 wns::scheduler::SchedulingTimeSlotPtr ts = myCommand->magic.schedulingTimeSlotPtr; 00408 00409 // A ResourceBlock has arrived (not a single compound/packet) 00410 if (ts != NULL) 00411 { 00412 MESSAGE_SINGLE(NORMAL, logger, "Received compound " << myCommand->magic.schedulingTimeSlotPtr->toString()); 00413 00414 wns::scheduler::harq::HARQInterface::TimeSlotInfo ti(phyCommand->local.rxPowerMeasurementPtr, 00415 phyCommand->local.subBand); 00416 // Process Non-HARQ protected compounds first 00417 if (!ts->isHARQEnabled()) 00418 { 00424 ts->harq.successfullyDecoded = true; 00425 wns::scheduler::harq::HARQInterface::DecodeStatusContainerEntry entry(ts, ti); 00426 receivedNonHARQTimeslots_.push_back(entry); 00427 00428 MESSAGE_SINGLE(NORMAL, logger, "Stored NON-HARQ " << ts.getPtr()); 00429 return; 00430 } 00431 else 00432 { 00433 if (colleagues.harq != NULL) 00434 { 00435 colleagues.harq->onTimeSlotReceived(ts, ti); 00436 } 00437 } 00438 } 00439 } // doOnData 00440 00441 void 00442 ResourceScheduler::doWakeup() 00443 {} // wakeup 00444 00445 // asked by MapHandler when it prepares the MAPs 00446 wns::scheduler::SchedulingMapPtr 00447 ResourceScheduler::getSchedulingMap(int frameNr) const 00448 { 00449 //return schedulingMapOfFrame[frameNr]; 00450 return schedulingResultOfFrame[frameNr]->schedulingMap; 00451 } 00452 00456 // triggered by TimingScheduler Event: 00457 void 00458 ResourceScheduler::startCollection(int frameNr /* for advance scheduling */, 00459 simTimeType _slotDuration) 00460 { 00461 MESSAGE_SINGLE(NORMAL, logger,"startCollection("<<wns::scheduler::SchedulerSpot::toString(schedulerSpot) 00462 <<": frameNr=" << frameNr << ", d="<< _slotDuration*1e6<<"us)"); 00463 assure(frameNr<framesPerSuperFrame,"invalid frameNr="<<frameNr); 00464 00465 // wakeup triggers the upper FU to send whatever is to be sent 00466 //getReceptor()->wakeup(); 00467 00468 // this is only required for "setAllStations" and "setRelaysOnly": 00469 lte::timing::RegistryProxy* registryInLte =colleagues.registry; //dynamic_cast<lte::timing::RegistryProxy*>(colleagues.registry); 00470 //assure(registryInLte, "RegistryProxy is not of the LTE type"); 00471 00472 // PREPARE STRATEGY INPUT NOW: 00473 // due to maxBeams, this is already "MIMO-ready" [rs] 00474 // generic call for master or slave scheduling 00475 wns::scheduler::strategy::StrategyInput strategyInput(freqChannels, double(_slotDuration), numberOfTimeSlots, maxBeams, NULL /*this/*callback*/); 00476 strategyInput.beamforming = beamforming; // bool 00477 strategyInput.setFrameNr(frameNr); 00478 00479 wns::scheduler::SchedulingMapPtr inputSchedulingMap; 00480 if (schedulerSpot==wns::scheduler::SchedulerSpot::ULSlave()) 00481 { 00482 colleagues.registry->setDL(false); 00483 // inputSchedulingMap should be a deep_copy of the original SchedulingMap from BS. 00484 // Currently it is not! 00485 // But it works well and this saves a lot of time. 00486 inputSchedulingMap = friends.mapHandler->getMasterMapForSlaveScheduling(frameNr); 00487 if (inputSchedulingMap == wns::scheduler::SchedulingMapPtr()) { 00488 MESSAGE_SINGLE(NORMAL, logger, "SlaveScheduling with null inputSchedulingMap: nothing to do"); 00489 return; 00490 } else if (inputSchedulingMap->isEmpty()) { // isEmpty is O(C*S) operation 00491 MESSAGE_SINGLE(NORMAL, logger, "SlaveScheduling with empty inputSchedulingMap: nothing to do"); 00492 return; 00493 } 00494 MESSAGE_SINGLE(NORMAL, logger, "SlaveScheduling with inputSchedulingMap="<<inputSchedulingMap.getPtr()); 00495 //<<"="<<inputSchedulingMap->toString()); 00496 assure(schedulingResultOfFrame[frameNr] == wns::scheduler::strategy::StrategyResultPtr(),"ULSlave must not have stored schedulingMaps"); 00497 // ^ this SchedulingMap counts as the "master mask" that the slave scheduler must obeye to. 00498 _slotDuration = inputSchedulingMap->getSlotLength(); // workaround for wrong slotDuration from Python 00499 } else if (schedulerSpot==wns::scheduler::SchedulerSpot::ULMaster()) { 00500 colleagues.registry->setDL(false); 00501 MESSAGE_SINGLE(NORMAL, logger, "MasterScheduling for UL"); 00502 } else if (schedulerSpot==wns::scheduler::SchedulerSpot::DLMaster()) { 00503 colleagues.registry->setDL(true); 00504 MESSAGE_SINGLE(NORMAL, logger, "MasterScheduling for DL"); 00505 } // switch(schedulerSpot) 00506 00507 // prepare INPUT schedulingMap; take care of previous results for this frame or UL-master-maps. 00508 if (schedulingResultOfFrame[frameNr] != wns::scheduler::strategy::StrategyResultPtr()) 00509 { // there already was a result of this frame (previous round or static allocation) 00510 // only possible in BS-RS-RX+TX (Master Scheduler) 00511 assure(schedulerSpot != wns::scheduler::SchedulerSpot::ULSlave(),"wrong schedulerSpot = "<<wns::scheduler::SchedulerSpot::toString(schedulerSpot)); 00512 MESSAGE_SINGLE(NORMAL, logger,"schedulingResultOfFrame[frameNr="<<frameNr<<"] is not empty"); 00513 // ^ if this frame was used in a previous round, it already contains the partitioning constraints 00514 inputSchedulingMap = schedulingResultOfFrame[frameNr]->schedulingMap; 00515 } else { // fresh new resource grid 00516 MESSAGE_SINGLE(NORMAL, logger,"schedulingResultOfFrame[frameNr="<<frameNr<<"] is empty. Creating new one."); 00517 if (schedulerSpot == wns::scheduler::SchedulerSpot::ULSlave()) // if I am slave (UT) 00518 { 00519 assure(schedulerSpot == wns::scheduler::SchedulerSpot::ULSlave(),"wrong schedulerSpot = "<<wns::scheduler::SchedulerSpot::toString(schedulerSpot)); 00520 assure(inputSchedulingMap != wns::scheduler::SchedulingMapPtr(),"inputSchedulingMap must not be empty in slave mode"); 00521 } else { // I am master (RAP) 00522 inputSchedulingMap = strategyInput.getEmptySchedulingMap(); 00523 int phaseNrAtFrameNr = friends.timer->phaseNumberAtFrame(frameNr); 00524 std::string resourceDedication = friends.partitioningInfo->getDedication(phaseNrAtFrameNr, partitionGroup); // string 00525 MESSAGE_SINGLE(NORMAL, logger,"Get partitioning: frameNr="<<frameNr<<", phaseNr="<<phaseNrAtFrameNr<<", d=\""<<resourceDedication<<"\""); 00526 // get partitioning (may depend on DL/UL), i.e. usable subchannels 00527 if (schedulerSpot==wns::scheduler::SchedulerSpot::ULMaster()) 00528 { // can be different for UL/DL 00529 wns::scheduler::UsableSubChannelVector usableSubChannels 00530 = friends.partitioningInfo->getUsableSubChannels(phaseNrAtFrameNr, partitionGroup); 00531 assure(usableSubChannels.size()>=freqChannels,"#usableSubChannels="<<usableSubChannels.size()); 00532 00533 MESSAGE_BEGIN(NORMAL, logger, m, "usableSubChannels: "); 00534 for (int ii=0; ii< usableSubChannels.size(); ++ii) 00535 { 00536 m << (usableSubChannels[ii] ? "1" : "0"); 00537 } 00538 MESSAGE_END() 00539 00540 inputSchedulingMap->maskOutSubChannels(usableSubChannels); // arg is just a const ref 00541 } 00542 else if (schedulerSpot==wns::scheduler::SchedulerSpot::DLMaster()) 00543 { // can be different for UL/DL 00544 const wns::scheduler::UsableSubChannelVector& usableSubChannels 00545 = friends.partitioningInfo->getUsableSubChannels(phaseNrAtFrameNr, partitionGroup); 00546 assure(usableSubChannels.size()>=freqChannels,"#usableSubChannels="<<usableSubChannels.size()); 00547 inputSchedulingMap->maskOutSubChannels(usableSubChannels); 00548 } // switch(schedulerSpot) 00549 if (resourceDedication == "Feeder") 00550 registryInLte->setRelaysOnly(); // used in filterReachable(), which must be changed anyway. 00551 } // if master/slave 00552 } // if empty/nonempty pre-scheduling input 00553 strategyInput.setInputSchedulingMap(inputSchedulingMap); 00554 00555 // DO THE SCHEDULING (CALL STRATEGY): 00556 wns::scheduler::strategy::StrategyResult strategyResult = // copy small container 00557 colleagues.strategy->startScheduling(strategyInput); 00558 MESSAGE_SINGLE(VERBOSE, logger, "strategyResult.schedulingMap " << strategyResult.schedulingMap->toString()); 00559 // we only user strategyResult.schedulingMap and not strategyResult.bursts anymore. 00560 00561 MESSAGE_SINGLE(NORMAL, logger, "startCollection finished"); 00562 00563 assure(_slotDuration == strategyResult.schedulingMap->getSlotLength(), 00564 "mismatch in slotLength: slotDuration="<<slotDuration<<" vs getSlotLength()="<<strategyResult.schedulingMap->getSlotLength()); 00565 00566 if (schedulerSpot==wns::scheduler::SchedulerSpot::ULMaster()) 00567 { 00568 MESSAGE_SINGLE(VERBOSE, logger, "deleteCompoundsInBursts()+deleteCompounds()"); 00569 strategyResult.deleteCompoundsInBursts(); // MapInfoCollection is not needed anymore 00570 strategyResult.schedulingMap->deleteCompounds(); // compounds are not needed anymore 00571 strategyResult.schedulingMap->grantFullResources(); // full time length on used subchannels (only for resourceUsage probe and plot) 00572 } 00573 00574 // save result per frame 00575 // perhaps more? TODO: antennaPatterns 00576 schedulingResultOfFrame[frameNr] = wns::scheduler::strategy::StrategyResultPtr(new wns::scheduler::strategy::StrategyResult(strategyResult)); // make SmartPtr 00577 00578 // adjustment for filterReachable in RegistyProxy: 00579 registryInLte->setAllStations(); // => relaysOnly = false; 00580 if (schedulerSpot == wns::scheduler::SchedulerSpot::DLMaster()) { 00581 friends.mapHandler->saveDLMap(frameNr,strategyResult.schedulingMap); // push 00582 } else if (schedulerSpot == wns::scheduler::SchedulerSpot::ULMaster()) { 00583 friends.mapHandler->saveULMap(frameNr,strategyResult.schedulingMap); // push 00584 } 00585 } // startCollection() 00586 00587 // called from rap::Events for RAP or ResourceSchedulerUT for UT: 00588 // this method means: really send out the packets to PhyUser... 00589 void 00590 ResourceScheduler::finishCollection(int frameNr, simTimeType _startTime) { 00591 // startTime is absolute time (==now) 00592 assure(frameNr<framesPerSuperFrame,"invalid frameNr="<<frameNr); 00593 transportBlockCounter++; 00594 if (transportBlockCounter == 0) 00595 { 00596 transportBlockCounter++; 00597 } 00598 00599 if (schedulingResultOfFrame[frameNr] == wns::scheduler::strategy::StrategyResultPtr()) 00600 { 00601 MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<", startTime="<<_startTime<<"): empty schedulingResult. nothing to do"); 00602 return; 00603 } 00604 assure(schedulingResultOfFrame[frameNr] != wns::scheduler::strategy::StrategyResultPtr(),"schedulingResultOfFrame[frameNr="<<frameNr<<"]==NULL"); 00605 wns::scheduler::SchedulingMapPtr schedulingMap = schedulingResultOfFrame[frameNr]->schedulingMap; 00606 double resourceUsage = schedulingMap->getResourceUsage(); 00607 MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<", startTime="<<_startTime<<"): " 00608 <<"schedulingMap="<<resourceUsage*100.0<<"% full"); 00609 00610 if(resUsageProbe_->hasObservers()) 00611 probeResourceUsage(schedulingMap); 00612 00613 wns::scheduler::UserID myOwnUserID = wns::scheduler::UserID(layer2->getNode()); 00614 if (schedulerSpot == wns::scheduler::SchedulerSpot::ULMaster()) 00615 { // only beamforming etc. 00616 // RS-RX does not need to transmit pdus 00617 wns::scheduler::GroupingPtr sdmaGrouping = schedulingResultOfFrame[frameNr]->sdmaGrouping; 00618 if (sdmaGrouping != wns::scheduler::GroupingPtr()) { 00619 MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<", startTime="<<_startTime<<"): setting antennaPatterns..."); 00620 wns::scheduler::AntennaPatternsPerUser& antennaPatternsPerUser = sdmaGrouping->patterns; 00621 // foreach user in sdmaGrouping: 00622 for (wns::scheduler::AntennaPatternsPerUser::const_iterator iter = antennaPatternsPerUser.begin(); iter != antennaPatternsPerUser.end(); ++iter) 00623 { 00624 wns::scheduler::UserID user = iter->first; 00625 wns::service::phy::ofdma::PatternPtr antennaPattern = iter->second; 00626 MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<"): setReceiveAntennaPattern(user="<<user.getName()<<")"); 00627 friends.phyUser->setReceiveAntennaPattern(user.getNode(), antennaPattern); 00628 } // foreach user in sdmaGrouping 00629 } else {// if not sdmaGrouping used 00630 MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<", startTime="<<_startTime<<"): nothing to do"); 00631 } 00632 } else { // RS-TX (BS-DL or UT-UL) 00633 if (colleagues.harq != NULL) 00634 { // process finished schedulingMap in order to store ResourceBlocks into HARQ processes... 00635 for (wns::scheduler::SubChannelVector::iterator iterSubChannel = schedulingMap->subChannels.begin(); iterSubChannel != schedulingMap->subChannels.end(); ++iterSubChannel) 00636 { 00637 wns::scheduler::SchedulingSubChannel& subChannel = *iterSubChannel; 00638 // TDMA can be easily supported... 00639 for (wns::scheduler::SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin(); 00640 iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot) 00641 { 00642 wns::scheduler::SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot; 00643 // for the UL slave it is not right to ask isEmpty, since all UL granted resources have isEmpty==false. 00644 //if (!timeSlotPtr->isEmpty()) 00645 if (timeSlotPtr->countScheduledCompounds()>0) 00646 { 00647 if (timeSlotPtr->harq.transportBlockID == 0) 00648 { 00649 timeSlotPtr->harq.transportBlockID = transportBlockCounter; 00650 } 00651 colleagues.harq->storeSchedulingTimeSlot(transportBlockCounter, timeSlotPtr); // store ResourceBlock 00652 } 00653 } 00654 } 00655 } // if HARQ 00656 00657 applyPowerLimitation(schedulingMap); 00658 00659 // currently the "SDMA antenna patterns" are set for each packet by bfTransmission->startTransmission() in PhyUser 00660 // but it would be more efficient to set it once, like this: 00661 // set SDMA antenna patterns first 00662 wns::scheduler::GroupingPtr sdmaGrouping = schedulingResultOfFrame[frameNr]->sdmaGrouping; 00663 wns::scheduler::AntennaPatternsPerUser* antennaPatternsPerUser=NULL; 00664 if (sdmaGrouping != wns::scheduler::GroupingPtr()) { 00665 antennaPatternsPerUser = &(sdmaGrouping->patterns); 00666 if (0) { // currently not needed because there's no support for that in PhyUser and OFDMAPhy 00667 // foreach user in sdmaGrouping: 00668 for (wns::scheduler::AntennaPatternsPerUser::const_iterator iter = antennaPatternsPerUser->begin(); iter != antennaPatternsPerUser->end(); ++iter) 00669 { 00670 wns::scheduler::UserID user = iter->first; 00671 wns::service::phy::ofdma::PatternPtr antennaPattern = iter->second; 00672 MESSAGE_SINGLE(NORMAL, logger,"finishCollection(frameNr="<<frameNr<<"): setTransmitAntennaPattern(user="<<user.getName()<<")"); 00673 //friends.phyUser->setTransmitAntennaPattern(user, antennaPattern); // There is currently no support for that in PhyUser and OFDMAPhy 00674 } // foreach user in sdmaGrouping 00675 } 00676 } // if sdmaGrouping used 00677 00678 if (writeMapOutput) 00679 { // write schedulingMap to file for visualization purposes: 00680 evaluateMap(schedulingMap,frameNr); 00681 } 00682 00683 // now send packets=pdus=compounds ... 00684 00685 // iterate over all compounds in schedulingMap 00686 // forall compounds in schedulingMap: 00687 wns::scheduler::SubChannelVector& subChannels = schedulingMap->subChannels; 00688 00689 double _slotDuration = schedulingMap->getSlotLength(); 00690 00691 for ( wns::scheduler::SubChannelVector::iterator iterSubChannel = subChannels.begin(); 00692 iterSubChannel != subChannels.end(); ++iterSubChannel) 00693 { 00694 wns::scheduler::SchedulingSubChannel& subChannel = *iterSubChannel; 00695 for ( wns::scheduler::SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin(); 00696 iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot) 00697 { 00698 wns::scheduler::SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot; 00699 00700 if (timeSlotPtr->isEmpty()) 00701 { 00702 // Skip empty time slots 00703 continue; 00704 } 00705 if (timeSlotPtr->countScheduledCompounds()==0) 00706 { 00707 MESSAGE_SINGLE(NORMAL, logger, "timeSlotPtr->countScheduledCompounds()==0"); 00708 // Skip if no compound inside 00709 continue; 00710 } 00711 assure(timeSlotPtr->physicalResources[0].hasScheduledCompounds()>0,"PRB[0] has zero compounds"); 00712 wns::scheduler::UserID TSuser = timeSlotPtr->getUserID(); 00713 wns::scheduler::UserID PRBuser = timeSlotPtr->physicalResources[0].getUserID(); 00714 assure( TSuser.isValid(), "Invalid TSuser=NULL"); 00715 assure( PRBuser.isValid(), "Invalid PRBuser=NULL"); 00716 assure(TSuser==PRBuser,"finishCollection("<<myOwnUserID.getName()<<"): PRB on subchannel="<<subChannel.subChannelIndex 00717 <<" has timeSlotPtr->getUserID()="<<TSuser.getName() 00718 <<" but physicalResources[0]->getUserID()="<<PRBuser.getName()); 00719 // ^ In the UT these TSuser and PRBuser are still the UT's name (myself) 00720 // That is important, because the libwns scheduler needs to know where it may put more compounds into; 00721 // it shall not use PRBs tagged for other UTs. IF ther would be an "BSx" tag, 00722 // then the UTs could not know which PRB is available for them. 00723 // Please keep it and don't think about changing this [rs]. 00724 wns::scheduler::UserID user = timeSlotPtr->physicalResources[0].getUserIDOfScheduledCompounds(); 00728 assure(user.isValid(), "Invalid !user.isValid()"); 00729 if ((schedulerSpot==wns::scheduler::SchedulerSpot::ULSlave()) // we are in UT 00730 //&&(user!=TSuser) // <- happens in UT 00731 && (TSuser != myOwnUserID)) 00732 { // this is not a resource I'm responsible for (other UT) 00733 // Skip wrong users (SchedulingMap still has them, because it is the same for all UTs) 00734 MESSAGE_SINGLE(NORMAL, logger, "skipping PRB on subchannel="<<subChannel.subChannelIndex 00735 <<" has timeSlotPtr->userID="<<TSuser.getName() 00736 <<" and PRB->userID="<<PRBuser.getName() 00737 <<" and compound->userID="<<user.getName()); 00738 continue; 00739 } else { 00740 MESSAGE_SINGLE(NORMAL, logger, "PRB on subchannel="<<subChannel.subChannelIndex 00741 <<" has timeSlotPtr->userID="<<TSuser.getName() 00742 <<" and PRB->userID="<<PRBuser.getName() 00743 <<" and compound->userID="<<user.getName()); 00744 } 00745 00746 int netDataBits = timeSlotPtr->getNetBlockSizeInBits(); 00747 // (this is one "resource block" for HARQ retransmission) 00748 wns::ldk::CompoundPtr containerPdu = wns::ldk::CompoundPtr( 00749 new wns::ldk::Compound(getFUN()->createCommandPool(), 00750 wns::ldk::helper::FakePDUPtr(new wns::ldk::helper::FakePDU(netDataBits)))); // magic "2" as marker? 00751 // set the scheduler command (contained in myPDU) 00752 SchedulerCommand* myCommand = this->activateCommand(containerPdu->getCommandPool()); 00753 if (timeSlotPtr->getTxPower() == wns::Power()) 00754 { 00755 MESSAGE_SINGLE(NORMAL, logger, "WARNING: 0 dBm transmit power. I will not send this"); 00756 continue; 00757 } 00758 myCommand->magic.schedulingTimeSlotPtr = wns::scheduler::SchedulingTimeSlotPtr(new wns::scheduler::SchedulingTimeSlot(*timeSlotPtr));; // SmartPtr 00759 00760 // Check for HARQ validity 00761 if (timeSlotPtr->isHARQEnabled()) 00762 { 00763 if (timeSlotPtr->harq.ackCallback.empty()) 00764 { 00765 std::cout << "Trying to retransmit resource block with empty ack callback in HARQUplinkSlaveRetransmission" << std::endl; 00766 exit(1); 00767 } 00768 00769 if (timeSlotPtr->harq.nackCallback.empty()) 00770 { 00771 std::cout << "Trying to retransmit resource block with empty nack callback in HARQUplinkSlaveRetransmission" << std::endl; 00772 exit(1); 00773 } 00774 } 00775 lte::macr::PhyCommand* phyCommand = dynamic_cast<lte::macr::PhyCommand*>( 00776 getFUN()->getProxy()->activateCommand( containerPdu->getCommandPool(), friends.phyUser )); 00777 assure(user!=myOwnUserID, "Invalid user="<<user.getName()); // don't send to myself. 00778 // currently assumed constant slotDuration for all timeSlots: 00779 // later TODO: sum (0..timeSlotPtr->timeSlotIndex) timeSlotPtr->slotLength 00780 simTimeType timeSlotOffset = (timeSlotPtr->timeSlotIndex * slotDuration); 00781 phyCommand->magic.source = myOwnUserID.getNode(); 00782 if (user.isBroadcast()) 00783 { 00784 phyCommand->magic.destination = NULL; 00785 } 00786 else 00787 { 00788 phyCommand->magic.destination = user.getNode(); 00789 } 00790 if(myCommand->magic.schedulingTimeSlotPtr->harq.retryCounter > 0 00791 && myCommand->magic.schedulingTimeSlotPtr->harq.NDI == false) 00792 { 00793 phyCommand->magic.isRetransmission = true; 00794 } 00795 else 00796 { 00797 phyCommand->magic.isRetransmission = false; 00798 } 00799 00800 phyCommand->magic.txp = timeSlotPtr->getTxPower(); // TxPower to use for sending 00801 00802 phyCommand->local.subBand = timeSlotPtr->subChannelIndex; 00803 phyCommand->local.phyModePtr = timeSlotPtr->physicalResources[0].getPhyMode(); // just as placeholder; the real phyModes are inside 00804 phyCommand->local.start = timeSlotOffset; // time relative to the start of the burst 00805 phyCommand->local.stop = timeSlotOffset + _slotDuration; // time relative to the start of the burst 00806 phyCommand->local.start += _startTime; 00807 phyCommand->local.stop += _startTime; 00808 phyCommand->local.stop -= wns::scheduler::slotLengthRoundingTolerance; // safety 00809 phyCommand->local.beam = 0; // beams are inside 00810 phyCommand->local.beamforming = beamforming; 00811 if (beamforming) { 00812 assure(antennaPatternsPerUser!=NULL,"antennaPatternsPerUser==NULL"); 00813 wns::service::phy::ofdma::PatternPtr antennaPattern = (*antennaPatternsPerUser)[user]; 00814 assure(antennaPattern != wns::service::phy::ofdma::PatternPtr(),"No Beamforming antennaPattern set."); 00815 phyCommand->local.pattern = antennaPattern; // see wns::service::phy::ofdma::PatternPtr() 00816 } 00817 00818 phyCommand->local.modeRxTx = lte::macr::PhyCommand::Tx; // Rx is obsolete. Maybe completely obsolete 00819 00820 MESSAGE_BEGIN(NORMAL, logger, m, "PRB for "); 00821 m << user.getName() << " scheduled on " 00822 <<"frame="<<frameNr<< ", subChannel="<<timeSlotPtr->subChannelIndex 00823 << ", T=["<<int(phyCommand->local.start*1e6+.5)<<"-"<<int(phyCommand->local.stop*1e6+.5)<<"us]"; 00824 //m <<", PHY="<<*phyCommand->local.phyModePtr; 00825 if (beamforming || (maxBeams>1)) { m << ", beam=" << phyCommand->local.beam; } 00826 //m << "\nEstimated: C=" << estimatedCandI.C << ", I=" << estimatedCandI.I; 00827 //m << ", SINR="<<estimatedCandI.toSINR(); 00828 m << ", TxP="<<phyCommand->magic.txp << ", TBC=" << myCommand->magic.schedulingTimeSlotPtr->harq.transportBlockID; 00829 m << ", netBits=" << netDataBits << "/" << containerPdu->getLengthInBits(); 00830 MESSAGE_END(); 00831 assure(phyCommand->local.subBand < freqChannels, "Invalid frequency channel "<<phyCommand->local.subBand); 00832 assure(phyCommand->local.stop > phyCommand->local.start, "stop-start = "<<phyCommand->local.stop<<" - "<< phyCommand->local.start); 00833 assure(phyCommand->local.phyModePtr->isValid(),"cannot work when !phyMode.isValid()"); 00834 assure(phyCommand->local.phyModePtr->dataRateIsValid(),"cannot work when !phyMode.dataRateIsValid()"); 00835 assure(colleagues.strategy->isTx(),"must be TxScheduler"); 00836 assure(getConnector()->hasAcceptor(containerPdu),"Lower FU is not accepting compound but is supposed to do so"); 00837 getConnector()->getAcceptor(containerPdu)->sendData(containerPdu); // to PhyUser or HARQ 00838 } // forall timeSlots 00839 } // forall subchannels 00840 } // TxScheduler 00841 schedulingResultOfFrame[frameNr] = wns::scheduler::strategy::StrategyResultPtr(); // clear result; not needed anymore; must be clean before next round 00842 } // finishCollection 00843 00844 void 00845 ResourceScheduler::probeResourceUsage(wns::scheduler::SchedulingMapPtr schedulingMap) 00846 { 00847 wns::scheduler::SubChannelVector& subChannels = schedulingMap->subChannels; 00848 00849 double _slotDuration = schedulingMap->getSlotLength(); 00850 00851 unsigned int numResources = 0; 00852 unsigned int usedResources = 0; 00853 00854 for ( wns::scheduler::SubChannelVector::iterator iterSubChannel = subChannels.begin(); 00855 iterSubChannel != subChannels.end(); ++iterSubChannel) 00856 { 00857 wns::scheduler::SchedulingSubChannel& subChannel = *iterSubChannel; 00858 for ( wns::scheduler::SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin(); 00859 iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot) 00860 { 00861 wns::scheduler::SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot; 00862 // Only count resources for this UT in ULSlave 00863 if(schedulerSpot == wns::scheduler::SchedulerSpot::ULSlave()) 00864 { 00865 wns::scheduler::UserID myOwnUserID = wns::scheduler::UserID(layer2->getNode()); 00866 if(timeSlotPtr->getUserID() == myOwnUserID) 00867 numResources++; 00868 } 00869 // Count all resources in master 00870 else 00871 { 00872 numResources++; 00873 } 00874 00875 if(!timeSlotPtr->isEmpty() && timeSlotPtr->countScheduledCompounds() > 0) 00876 usedResources++; 00877 } 00878 } 00879 resUsageProbe_->put(double(usedResources)/double(numResources), 00880 boost::make_tuple("SchedulerSpot", schedulerSpot)); 00881 } 00882 00883 void 00884 ResourceScheduler::applyPowerLimitation(wns::scheduler::SchedulingMapPtr schedulingMap) 00885 { 00886 // First pass: Find the sum TxPower 00887 wns::Power sum = wns::Power::from_mW(0.0); 00888 wns::scheduler::UserID myOwnUserID = wns::scheduler::UserID(layer2->getNode()); 00889 00890 for (wns::scheduler::SubChannelVector::iterator iterSubChannel = schedulingMap->subChannels.begin(); iterSubChannel != schedulingMap->subChannels.end(); ++iterSubChannel) 00891 { 00892 wns::scheduler::SchedulingSubChannel& subChannel = *iterSubChannel; 00893 for ( wns::scheduler::SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin(); 00894 iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot) 00895 { 00896 wns::scheduler::SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot; 00897 00898 if (schedulerSpot==wns::scheduler::SchedulerSpot::ULSlave()) 00899 { 00900 if (timeSlotPtr->getUserID() != myOwnUserID) 00901 { 00902 // Not my transmission. Belongs to another user 00903 continue; 00904 } 00905 } 00906 sum += timeSlotPtr->getTxPower(); 00907 } 00908 } 00909 00910 wns::Ratio downscale = wns::Ratio::from_factor(1.0); 00911 00912 if (sum > maxTxPower) 00913 { 00914 downscale = maxTxPower / sum; 00915 00916 MESSAGE_SINGLE(NORMAL, logger, "Power limitation reached, downscaling by " << downscale); 00917 00918 // Second pass: 00919 for (wns::scheduler::SubChannelVector::iterator iterSubChannel = schedulingMap->subChannels.begin(); iterSubChannel != schedulingMap->subChannels.end(); ++iterSubChannel) 00920 { 00921 wns::scheduler::SchedulingSubChannel& subChannel = *iterSubChannel; 00922 for ( wns::scheduler::SchedulingTimeSlotPtrVector::iterator iterTimeSlot = subChannel.temporalResources.begin(); 00923 iterTimeSlot != subChannel.temporalResources.end(); ++iterTimeSlot) 00924 { 00925 wns::scheduler::SchedulingTimeSlotPtr timeSlotPtr = *iterTimeSlot; 00926 00927 if (schedulerSpot==wns::scheduler::SchedulerSpot::ULSlave()) 00928 { 00929 if (timeSlotPtr->getUserID() != myOwnUserID) 00930 { 00931 // Not my transmission. Belongs to another user 00932 continue; 00933 } 00934 } 00935 00936 timeSlotPtr->setTxPower( timeSlotPtr->getTxPower() * downscale); 00937 } 00938 } 00939 } 00940 } 00941 00942 void 00943 ResourceScheduler::resetHARQScheduledPeerRetransmissions() 00944 { 00945 if(IamUplinkMaster) 00946 { 00947 //colleagues.harq->resetAllScheduledPeerRetransmissionCounters(); 00948 } 00949 } 00950 00951 void 00952 ResourceScheduler::sendPendingHARQFeedback() 00953 { 00954 colleagues.harq->sendPendingFeedback(); 00955 } 00956 00957 lte::helper::Route 00958 ResourceScheduler::score(const wns::ldk::CompoundPtr& compound) 00959 { 00960 return scorer.score(compound); 00961 } 00962 00963 00964 void 00965 ResourceScheduler::prepareMapOutput() 00966 { 00967 if (!writeMapOutput) return; // nothing to do 00968 MESSAGE_SINGLE(NORMAL, logger, "prepareMapOutput(): opening output file "<<mapOutputFileName); 00969 mapFile = new std::ofstream(mapOutputFileName.c_str()); 00970 assure(mapFile!=NULL,"cannot write to mapFile "<<mapOutputFileName); 00971 assure(mapFile->is_open(), "mapFile " << mapOutputFileName << " not open"); 00972 (*mapFile) << "# contents=\""<<logger.getLoggerName()<<" map\""<<std::endl; 00973 wns::scheduler::SchedulingMap::writeHeaderToFile(*mapFile); 00974 } 00975 00976 // analyze MAPs to get performance values from it. 00977 // Probe output and file output for Matlab 00978 void 00979 ResourceScheduler::evaluateMap(wns::scheduler::SchedulingMapPtr schedulingMap, int frameNr) 00980 { 00981 if (!writeMapOutput) return; // nothing to do 00982 MESSAGE_SINGLE(NORMAL, logger, "evaluateMap(): writing to "<<mapOutputFileName); 00983 assure(mapFile!=NULL,"cannot write to mapFile "<<mapOutputFileName); 00984 // write table output to file for postprocessing with Matlab/Gnuplot 00985 //friends.timer 00986 simTimeType now = wns::simulator::getEventScheduler()->getTime(); 00987 *mapFile << "# t="<<now<<", frameNr="<<frameNr<<std::endl; 00988 std::stringstream p; 00989 p << now << "\t"; 00990 schedulingMap->writeToFile(*mapFile,p.str()); 00991 // "ResourceUsage" probe is not written here but in finishCollection() 00992 } // evaluateMap 00993 00994 void 00995 ResourceScheduler::closeMapOutput() 00996 { 00997 if (!writeMapOutput) return; // nothing to do 00998 MESSAGE_SINGLE(NORMAL, logger, "closeMapOutput(): closing "<<mapOutputFileName); 00999 if (*mapFile) mapFile->close(); 01000 } 01001
1.5.5