![]() |
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-2009 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 <WNS/scheduler/CallBackInterface.hpp> 00029 #include <WNS/scheduler/RegistryProxyInterface.hpp> 00030 #include <WNS/scheduler/strategy/Strategy.hpp> 00031 #include <WNS/scheduler/strategy/StrategyInterface.hpp> 00032 #include <WNS/PowerRatio.hpp> 00033 00034 using namespace wns::scheduler; 00035 using namespace wns::scheduler::strategy; 00036 00037 Strategy::Strategy(const wns::pyconfig::View& config) 00038 : colleagues(), 00039 friends(), 00040 pyConfig(config), 00041 logger(config.get("logger")) 00042 { 00043 simTimeType symbolDuration = config.get<double>("symbolDuration"); 00044 bool txMode = config.get<bool>("txMode"); // Python parameter 00045 bool excludeTooLowSINR = config.get<bool>("excludeTooLowSINR"); 00046 bool powerControlSlave = config.get<bool>("powerControlSlave"); 00047 PowerControlType powerControlType; 00048 00049 MESSAGE_SINGLE(NORMAL, logger,"Strategy=" 00050 << config.get<std::string>("nameInStrategyFactory")); 00051 00052 // there are three positions for the scheduler... 00053 if (txMode && !powerControlSlave) 00054 { 00055 // 1.) BS.Tx (DL) -> power from Python (myself) 00056 powerControlType = PowerControlDLMaster; 00057 } 00058 else if(!txMode && !powerControlSlave) 00059 { 00060 // 2.) BS.Rx (UL) -> power from Python (user) 00061 powerControlType = PowerControlULMaster; 00062 } 00063 else if(txMode && powerControlSlave) 00064 { 00065 // 3.) UT.Tx (UL) -> power from masterBurst 00066 powerControlType = PowerControlULSlave; 00067 } 00068 else 00069 { 00070 assure(0,"invalid case for powerControlType: txMode=" 00071 << txMode <<", powerControlSlave=" << powerControlSlave); 00072 throw wns::Exception("invalid case for powerControlType"); 00073 } 00074 getNewSchedulerState(); 00075 schedulerState->symbolDuration = symbolDuration; 00076 schedulerState->isTx = txMode; 00077 schedulerState->powerControlType = powerControlType; 00078 schedulerState->excludeTooLowSINR = excludeTooLowSINR; 00079 } 00080 00081 Strategy::~Strategy() 00082 { 00083 if (colleagues.apcstrategy) 00084 delete colleagues.apcstrategy; 00085 if (colleagues.dsastrategy) 00086 delete colleagues.dsastrategy; 00087 if (colleagues.dsafbstrategy) 00088 delete colleagues.dsafbstrategy; 00089 00090 // delete SchedulerState: 00091 if (schedulerState) 00092 { 00093 if (schedulerState->currentState) 00094 { 00095 schedulerState->clearMap(); 00096 if (schedulerState->currentState->strategyInput) 00097 { 00098 schedulerState->currentState->strategyInput = NULL; 00099 } 00100 if (schedulerState->currentState->channelQualitiesOfAllUsers) 00101 { 00102 schedulerState->currentState->channelQualitiesOfAllUsers = ChannelQualitiesOfAllUsersPtr(); 00103 } 00104 if (schedulerState->currentState->schedulingMap) 00105 { 00106 schedulerState->currentState->schedulingMap = SchedulingMapPtr(); 00107 } 00108 if (schedulerState->currentState->bursts) 00109 { 00110 schedulerState->currentState->bursts = MapInfoCollectionPtr(); 00111 } 00112 schedulerState->currentState->strategyInput = NULL; 00113 schedulerState->currentState = RevolvingStatePtr(); 00114 } 00115 schedulerState = SchedulerStatePtr(); 00116 } 00117 } 00118 00119 void 00120 Strategy::setColleagues(queue::QueueInterface* _queue, 00121 grouper::GroupingProviderInterface* _grouper, 00122 RegistryProxyInterface* _registry, 00123 wns::scheduler::harq::HARQInterface* _harq 00124 ) 00125 { 00126 MESSAGE_SINGLE(NORMAL, logger,"Strategy::setColleagues(): creating DSA/APC strategies..."); 00127 colleagues.queue = _queue; 00128 colleagues.grouper = _grouper; 00129 colleagues.registry = _registry; 00130 colleagues.harq = _harq; 00131 00132 assure(dynamic_cast<queue::QueueInterface*>(colleagues.queue), "Need access to the queue"); 00133 assure(dynamic_cast<grouper::GroupingProviderInterface*>(colleagues.grouper), "Need access to the grouper"); 00134 assure(dynamic_cast<RegistryProxyInterface*>(colleagues.registry), "Need access to the registry"); 00135 00136 std::string apcstrategyName = pyConfig.get<std::string>("apcstrategy.nameInAPCStrategyFactory"); 00137 std::string dsastrategyName = pyConfig.get<std::string>("dsastrategy.nameInDSAStrategyFactory"); 00138 std::string dsafbstrategyName = pyConfig.get<std::string>("dsafbstrategy.nameInDSAStrategyFactory"); 00139 00140 MESSAGE_SINGLE(NORMAL, logger,"dsastrategy = "<<dsastrategyName); 00141 MESSAGE_SINGLE(NORMAL, logger,"dsafbstrategy = "<<dsafbstrategyName); 00142 MESSAGE_SINGLE(NORMAL, logger,"apcstrategy = "<<apcstrategyName); 00143 00144 // create the scheduling dsastrategy 00145 wns::scheduler::strategy::dsastrategy::DSAStrategyCreator* dsastrategyCreator; 00146 dsastrategyCreator = wns::scheduler::strategy::dsastrategy::DSAStrategyFactory::creator(dsastrategyName); 00147 colleagues.dsastrategy = dsastrategyCreator->create(pyConfig.get<wns::pyconfig::View>("dsastrategy")); 00148 assure(colleagues.dsastrategy, "DSAStrategy module creation failed"); 00149 00150 // create the scheduling dsafallbackstrategy 00151 wns::scheduler::strategy::dsastrategy::DSAStrategyCreator* dsafbstrategyCreator; 00152 dsafbstrategyCreator = wns::scheduler::strategy::dsastrategy::DSAStrategyFactory::creator(dsafbstrategyName); 00153 colleagues.dsafbstrategy = dsafbstrategyCreator->create(pyConfig.get<wns::pyconfig::View>("dsafbstrategy")); 00154 assure(colleagues.dsafbstrategy, "DSAfbStrategy module creation failed"); 00155 00156 // create the scheduling apcstrategy 00157 wns::scheduler::strategy::apcstrategy::APCStrategyCreator* apcstrategyCreator; 00158 apcstrategyCreator = wns::scheduler::strategy::apcstrategy::APCStrategyFactory::creator(apcstrategyName); 00159 colleagues.apcstrategy = apcstrategyCreator->create(pyConfig.get<wns::pyconfig::View>("apcstrategy")); 00160 assure(colleagues.apcstrategy, "APCStrategy module creation failed"); 00161 00162 assure(colleagues.dsastrategy != NULL, "dsastrategy = NULL"); 00163 assure(colleagues.dsafbstrategy != NULL, "dsafbstrategy = NULL"); 00164 assure(colleagues.apcstrategy != NULL, "apcstrategy = NULL"); 00165 00166 colleagues.dsastrategy->setColleagues(colleagues.registry); 00167 colleagues.dsafbstrategy->setColleagues(colleagues.registry); 00168 colleagues.apcstrategy->setColleagues(colleagues.registry); 00169 00170 assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid"); 00171 bool useCQI = colleagues.registry->getCQIAvailable(); 00172 schedulerState->useCQI = useCQI; 00173 schedulerState->myUserID = colleagues.registry->getMyUserID(); 00174 00175 assure(!colleagues.dsafbstrategy->requiresCQI(),"dsafbstrategy must never require CQI"); 00176 assure(useCQI || !colleagues.dsastrategy->requiresCQI(),"dsastrategy requires CQI"); 00177 assure(useCQI || !colleagues.apcstrategy->requiresCQI(),"apcstrategy requires CQI"); 00178 00179 // calls method of derived class for initialization 00180 this->onColleaguesKnown(); 00181 } // setColleagues 00182 00183 void 00184 Strategy::onColleaguesKnown() 00185 { 00186 MESSAGE_SINGLE(NORMAL, logger,"Strategy::onColleaguesKnown()"); 00187 } 00188 00189 void 00190 Strategy::setFriends(wns::service::phy::ofdma::BFInterface* _ofdmaProvider) 00191 { 00192 friends.ofdmaProvider = _ofdmaProvider; 00193 assure(friends.ofdmaProvider != NULL, "ofdmaProvider==NULL => eirpLimited undefined"); 00194 assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid"); 00195 00196 bool eirpLimited = friends.ofdmaProvider->isEIRPLimited(); 00197 schedulerState->eirpLimited = eirpLimited; 00198 00199 assure(colleagues.registry!=NULL,"colleagues.registry==NULL"); 00200 00201 bool isDL = colleagues.registry->getDL(); 00202 if ((isDL == true) && (schedulerState->isTx == false)) 00203 { 00204 MESSAGE_SINGLE(NORMAL, logger,"Strategy::setFriends(): misconfiguration: isDL=" 00205 << isDL << ", isTx=" << schedulerState->isTx); 00206 00207 // workaround for WiMAC where registry->getDL() is not implemented 00208 isDL = false; 00209 } 00210 schedulerState->isDL = isDL; 00211 assure((isDL && (schedulerState->powerControlType == PowerControlDLMaster)) || !isDL, 00212 logger.getLoggerName() << ": invalid: powerControlType=" 00213 << schedulerState->powerControlType 00214 << ",isDL=" << isDL << ",isTx=" 00215 << schedulerState->isTx); 00216 00217 // there are three positions for the scheduler... 00218 wns::scheduler::SchedulerSpotType schedulerSpot; 00219 if (isDL && schedulerState->isTx ) 00220 { 00221 schedulerSpot = wns::scheduler::SchedulerSpot::DLMaster(); 00222 assure(canHandleDL(), "DLMaster"); 00223 } 00224 else if(!isDL && !schedulerState->isTx ) 00225 { 00226 schedulerSpot = wns::scheduler::SchedulerSpot::ULMaster(); 00227 assure(canHandleUL(), "ULMaster"); 00228 } 00229 else if(!isDL && schedulerState->isTx ) 00230 { 00231 schedulerSpot = wns::scheduler::SchedulerSpot::ULSlave(); 00232 assure(canBeSlave(), "ULSlave scheduler needs SlaveAspect of strategy"); 00233 assure(!schedulerState->useCQI,"cannot useCQI in slave scheduler"); 00234 } 00235 else 00236 { 00237 assure(0,"invalid case for schedulerSpot: isDL="<<isDL<<", isTx="<<schedulerState->isTx); 00238 throw wns::Exception("invalid case for schedulerSpot"); 00239 } 00240 schedulerState->schedulerSpot = schedulerSpot; 00241 00242 MESSAGE_SINGLE(NORMAL, logger,"Strategy::setFriends(): isDL=" 00243 << isDL <<", isTx=" << schedulerState->isTx 00244 << ", schedulerSpot=" << wns::scheduler::SchedulerSpot::toString(schedulerSpot) 00245 << ", useCQI=" << schedulerState->useCQI); 00246 } // setFriends 00247 00248 SchedulerStatePtr 00249 Strategy::getNewSchedulerState() 00250 { 00251 MESSAGE_SINGLE(NORMAL, logger,"Strategy::getNewSchedulerState()"); 00252 00253 assure(schedulerState==SchedulerStatePtr(), 00254 "schedulerState must be empty before making a new one"); 00255 00256 schedulerState = SchedulerStatePtr(new SchedulerState(this)); 00257 00258 assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid"); 00259 00260 return schedulerState; 00261 } 00262 00263 SchedulerStatePtr 00264 Strategy::revolveSchedulerState(const StrategyInput& strategyInput) 00265 { 00266 assure(schedulerState != SchedulerStatePtr(),"schedulerState must be valid"); 00267 assure(colleagues.registry != NULL,"registry == NULL"); 00268 assure(&strategyInput != NULL,"strategyInput == NULL"); 00269 00270 schedulerState->currentState = RevolvingStatePtr(new RevolvingState(&strategyInput)); 00271 return schedulerState; 00272 } 00273 00274 SchedulerStatePtr 00275 Strategy::getSchedulerState() 00276 { 00277 assure(schedulerState != SchedulerStatePtr(),"schedulerState must be valid"); 00278 return schedulerState; 00279 } 00280 00281 MapInfoCollectionPtr 00282 Strategy::getMapInfo() const 00283 { 00284 // if startScheduling has never been called but mapHandler calls getMapInfo(): return empty 00285 if (schedulerState->currentState==wns::scheduler::strategy::RevolvingStatePtr()) 00286 return MapInfoCollectionPtr(new MapInfoCollection); 00287 00288 MapInfoCollectionPtr bursts = schedulerState->currentState->bursts; 00289 00290 assure(bursts!=MapInfoCollectionPtr(),"bursts must not be NULL here"); 00291 00292 return bursts; 00293 } 00294 00295 wns::scheduler::PowerCapabilities 00296 Strategy::getPowerCapabilities(const UserID user) const 00297 { 00298 /* This method changes the state "schedulerState->powerCapabilities". 00299 This is good and ok if all users are the same (default of all systems), 00300 but if they are different (future), APC must call this function anytime. 00301 */ 00302 switch (schedulerState->powerControlType) 00303 { 00304 case PowerControlDLMaster: 00305 { 00306 schedulerState->powerCapabilities = 00307 colleagues.registry->getPowerCapabilities(); 00308 break; 00309 } 00310 case PowerControlULMaster: 00311 { 00312 // peer unknown. Assume peer=UT. 00313 if (!user.isValid()) 00314 { 00315 MESSAGE_SINGLE(NORMAL, logger, "getPowerCapabilities(NULL): asking registry..."); 00316 schedulerState->powerCapabilities = colleagues.registry->getPowerCapabilities(user); 00317 00318 MESSAGE_SINGLE(NORMAL, logger, "getPowerCapabilities(NULL): nominal=" 00319 << schedulerState->powerCapabilities.nominalPerSubband); 00320 00321 return schedulerState->powerCapabilities; 00322 } 00323 schedulerState->powerCapabilities = colleagues.registry->getPowerCapabilities(user); 00324 break; 00325 } 00326 case PowerControlULSlave: 00327 { 00328 if (schedulerState->defaultTxPower!=wns::Power()) 00329 { 00330 // don't use powerCapabilities but masterBurst instead 00331 assure(schedulerState->defaultTxPower!=wns::Power(),"undefined defaultTxPower"); 00332 schedulerState->powerCapabilities.nominalPerSubband = schedulerState->defaultTxPower; 00333 schedulerState->powerCapabilities.maxPerSubband = schedulerState->defaultTxPower; 00334 // limit not used for slave 00335 schedulerState->powerCapabilities.maxOverall = schedulerState->defaultTxPower * 1000.0; 00336 } 00337 // not given (by masterBurst) because there is an InputSchedulingMap (new method) 00338 else 00339 { 00340 assure(schedulerState->currentState->strategyInput->inputSchedulingMap != wns::scheduler::SchedulingMapPtr(), 00341 "need inputSchedulingMap with txPower information"); 00342 00343 // the power settings in inputSchedulingMap can be overwritten 00344 // if APC strategy is changed to use nominal power. Therefore we need these values: 00345 schedulerState->powerCapabilities = colleagues.registry->getPowerCapabilities(); 00346 } 00347 break; 00348 } 00349 default: 00350 { 00351 throw wns::Exception("invalid powerControlType"); 00352 } 00353 } // switch(powerControlType) 00354 if (user.isValid()) 00355 { 00356 MESSAGE_SINGLE(NORMAL, logger, "getPowerCapabilities(" 00357 << user.getName() << "): nominal=" 00358 << schedulerState->powerCapabilities.nominalPerSubband); 00359 00360 } 00361 else 00362 { 00363 MESSAGE_SINGLE(NORMAL, logger, "getPowerCapabilities(NULL): nominal=" 00364 << schedulerState->powerCapabilities.nominalPerSubband); 00365 } 00366 assure(schedulerState->powerCapabilities.nominalPerSubband != wns::Power(), 00367 "undefined power nominalPerSubband="<<schedulerState->powerCapabilities.nominalPerSubband); 00368 00369 return schedulerState->powerCapabilities; 00370 } 00371 00372 // perform master scheduling 00373 StrategyResult 00374 Strategy::startScheduling(const StrategyInput& strategyInput) 00375 { 00376 if (strategyInput.fChannels < 1) 00377 throw wns::Exception("Need at least one subBand"); 00378 00379 if (strategyInput.slotLength < 0.0) 00380 throw wns::Exception("Invalid slotLength"); 00381 00382 if (strategyInput.slotLength < schedulerState->symbolDuration) 00383 throw wns::Exception("Can't schedule on slot shorter than OFDM symbol"); 00384 00385 if (strategyInput.numberOfTimeSlots < 1) 00386 throw wns::Exception("Need at least one TimeSlot"); 00387 00388 // strategyInput.maxSpatialLayers > 1 means SDMA or MIMO 00389 if (strategyInput.maxSpatialLayers < 1) 00390 throw wns::Exception("Need at least one spatialLayer"); 00391 00392 assure(isNewStrategy() || strategyInput.beamforming || strategyInput.maxSpatialLayers == 1, 00393 "beamforming=" << strategyInput.beamforming 00394 << " && maxSpatialLayers=" 00395 << strategyInput.maxSpatialLayers 00396 << ": MIMO not supported in old strategies"); 00397 00398 // prepare a new state for this timeFrame: 00399 schedulerState = revolveSchedulerState(strategyInput); 00400 00401 // master scheduling on freshly created empty resources 00402 // the fresh Scheduling Map (empty and free) is prepared in the RevolvingStatePtr() constructor 00403 if (strategyInput.inputSchedulingMap == wns::scheduler::SchedulingMapPtr()) 00404 { 00405 MESSAGE_SINGLE(NORMAL, logger, "inputSchedulingMap is empty"); 00406 00407 } 00408 // slave scheduling or preallocated SchedulingMap 00409 else 00410 { 00411 MESSAGE_SINGLE(NORMAL, logger, "inputSchedulingMap exists: " 00412 << strategyInput.inputSchedulingMap->toString()); 00413 00414 assure(schedulerState->currentState->schedulingMap != wns::scheduler::SchedulingMapPtr(), 00415 "schedulingMap initialization failed"); 00416 assure(schedulerState->currentState->schedulingMap == strategyInput.inputSchedulingMap, 00417 "schedulingMap must be set in revolveSchedulerState()"); 00418 } 00419 wns::scheduler::SchedulingMapPtr schedulingMap = schedulerState->currentState->schedulingMap; // alias 00420 00421 // master scheduling 00422 if (schedulerState->schedulerSpot != wns::scheduler::SchedulerSpot::ULSlave()) 00423 { 00424 assure(strategyInput.mapInfoEntryFromMaster == MapInfoEntryPtr(),"mapInfoEntryFromMaster must be NULL"); 00425 00426 MESSAGE_BEGIN(NORMAL, logger, m, "startScheduling(master): "); 00427 if (strategyInput.frameNrIsValid()) 00428 m << "frameNr=" << strategyInput.frameNr << ", "; 00429 m << "fChannels=" << strategyInput.fChannels 00430 << ", maxSpatialLayers=" << strategyInput.maxSpatialLayers 00431 << ", slotLength=" << strategyInput.slotLength; 00432 MESSAGE_END(); 00433 00434 // not necessary but these defaults may be optionally provided by the caller: 00435 // may be undefined (NULL) in most cases 00436 schedulerState->setDefaultPhyMode(strategyInput.defaultPhyModePtr); 00437 // may be undefined (0.0) in most cases 00438 schedulerState->setDefaultTxPower(strategyInput.defaultTxPower); 00439 00440 // only if master and beamforming 00441 // grouping needed for beamforming & its antenna pattern 00442 if (groupingRequired() && !colleagues.queue->isEmpty()) 00443 { 00444 GroupingPtr sdmaGrouping = GroupingPtr(new Grouping()); 00445 UserSet allUsers; 00446 allUsers = colleagues.queue->getQueuedUsers(); 00447 UserSet activeUsers = colleagues.registry->filterReachable(allUsers, strategyInput.getFrameNr()); 00448 if (schedulerState->isTx) // transmitter grouping 00449 { 00450 MESSAGE_SINGLE(NORMAL, logger, "StartScheduling(): get TxGrouping"); 00451 sdmaGrouping = colleagues.grouper->getTxGroupingPtr(activeUsers, strategyInput.maxSpatialLayers); 00452 } 00453 // receiver grouping 00454 else 00455 { 00456 MESSAGE_SINGLE(NORMAL, logger, "StartScheduling(): get RxGrouping"); 00457 sdmaGrouping = colleagues.grouper->getRxGroupingPtr(activeUsers, strategyInput.maxSpatialLayers); 00458 } 00459 schedulerState->currentState->setGrouping(sdmaGrouping); 00460 00461 assure(schedulerState->currentState->getGrouping() == sdmaGrouping,"invalid grouping"); 00462 00463 MESSAGE_SINGLE(NORMAL, logger, "StartScheduling(): Number of Groups = " << sdmaGrouping->groups.size()); 00464 MESSAGE_SINGLE(NORMAL, logger, "StartScheduling(): grouping.getDebugOutput = " << sdmaGrouping->getDebugOutput()); 00465 } 00466 else 00467 { 00468 MESSAGE_SINGLE(VERBOSE, logger, "StartScheduling(): no grouping required."); 00469 } 00470 00471 } 00472 // slave scheduling 00473 else 00474 { 00475 // two ways of master input: 00476 // 1. old way: mapInfoEntryFromMaster 00477 // 2. new way: inputSchedulingMap 00478 if (strategyInput.mapInfoEntryFromMaster != MapInfoEntryPtr()) 00479 { 00480 assure(strategyInput.mapInfoEntryFromMaster != MapInfoEntryPtr(),"mapInfoEntryFromMaster must be non-NULL"); 00481 00482 MESSAGE_SINGLE(NORMAL, logger,"startScheduling(slave): fChannels=" 00483 << strategyInput.fChannels 00484 << ", subBand=" 00485 << strategyInput.mapInfoEntryFromMaster->subBand); 00486 00487 MESSAGE_SINGLE(NORMAL, logger,"PhyMode=" 00488 << *(strategyInput.mapInfoEntryFromMaster->phyModePtr) 00489 << ", txPower=" << strategyInput.mapInfoEntryFromMaster->txPower); 00490 00491 schedulerState->setDefaultPhyMode(strategyInput.mapInfoEntryFromMaster->phyModePtr); 00492 schedulerState->setDefaultTxPower(strategyInput.mapInfoEntryFromMaster->txPower); 00493 } 00494 else 00495 { 00496 assure(strategyInput.inputSchedulingMap != wns::scheduler::SchedulingMapPtr(), 00497 "slave scheduling requires inputSchedulingMap"); 00498 00499 MESSAGE_SINGLE(NORMAL, logger, "SlaveScheduling with given inputSchedulingMap..."); 00500 00501 // all PhyModes and TxPower are written in the inputSchedulingMap 00502 // I may only use those resources (subchannels,slots) where my userID is written into (UTx) 00503 // Before going to UT's PhyUser, take care to use the right userID! 00504 // it must be reverted (to BSx) in the PhyCommand to send to the right peer. 00505 00506 assure(schedulerState->currentState->schedulingMap == strategyInput.inputSchedulingMap, 00507 "schedulingMap must be set in revolveSchedulerState()"); 00508 00509 // set empty all resources but keep userID, PhyMode, TxPower 00510 MESSAGE_SINGLE(NORMAL, logger, "inputSchedulingMap->processMasterMap()"); 00511 schedulerState->currentState->schedulingMap->processMasterMap(); 00512 00513 MESSAGE_SINGLE(NORMAL, logger, "prepared master schedulingMap=" 00514 << schedulerState->currentState->schedulingMap->toString()); 00515 } 00516 } 00517 // empty bursts result datastructure MapInfoCollection (not schedulingMap) 00518 schedulerState->clearMap(); 00519 00520 // prepare CQI 00521 if (schedulerState->useCQI) 00522 { 00523 schedulerState->currentState->channelQualitiesOfAllUsers = 00524 ChannelQualitiesOfAllUsersPtr(new ChannelQualitiesOfAllUsers()); 00525 } 00526 00527 // Initialize the "working" datastructures 00528 // new burst result structure (part of the state): 00529 assure(schedulerState->currentState->bursts==MapInfoCollectionPtr(),"bursts must be NULL here"); 00530 00531 MapInfoCollectionPtr bursts = MapInfoCollectionPtr(new wns::scheduler::MapInfoCollection); 00532 schedulerState->currentState->bursts = bursts; 00533 00534 // initialize helper strategies for DSA,APC: 00535 if (colleagues.dsastrategy != NULL) 00536 colleagues.dsastrategy->initialize(schedulerState, schedulingMap); 00537 00538 if (colleagues.dsafbstrategy != NULL) 00539 colleagues.dsafbstrategy->initialize(schedulerState, schedulingMap); 00540 00541 if (colleagues.apcstrategy != NULL) 00542 colleagues.apcstrategy->initialize(schedulerState,schedulingMap); 00543 00544 // this calls the derived strategies (various algorithms): 00545 StrategyResult strategyResult = 00546 this->doStartScheduling(schedulerState, schedulingMap); 00547 00548 assure(strategyResult.schedulingMap == schedulingMap,"schedulingMap mismatch"); 00549 00550 if (colleagues.apcstrategy != NULL) 00551 colleagues.apcstrategy->postProcess(schedulerState,schedulingMap); 00552 00553 return strategyResult; 00554 } // startScheduling 00555 00556 00557 MapInfoEntryPtr 00558 Strategy::doAdaptiveResourceScheduling(RequestForResource& request, 00559 SchedulingMapPtr schedulingMap) 00560 { 00561 assure(colleagues.dsastrategy !=NULL, "dsastrategy==NULL"); 00562 assure(colleagues.dsafbstrategy != NULL, "dsafbstrategy==NULL"); 00563 assure(colleagues.apcstrategy != NULL, "apcstrategy==NULL"); 00564 assure(schedulerState->currentState != RevolvingStatePtr(), 00565 "currentState must be valid"); 00566 assure(schedulerState->currentState->strategyInput != NULL, 00567 "strategyInput must be valid"); 00568 00569 int frameNr = schedulerState->currentState->strategyInput->getFrameNr(); 00570 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling("<<request.user.getName()<<",cid="<<request.cid<<",bits="<<request.bits<<"): useCQI="<<schedulerState->useCQI); 00571 00572 // empty means no result. Filled later 00573 MapInfoEntryPtr resultMapInfoEntry; 00574 00575 // The slave RS-TX in the UT does not need to and cannot do AdaptiveResourceScheduling: 00576 if (schedulerState->powerControlType == PowerControlULSlave) 00577 { 00578 assure(schedulerState->schedulerSpot==wns::scheduler::SchedulerSpot::ULSlave(), 00579 "PowerControlULSlave requires SchedulerSpot::ULSlave"); 00580 assure(schedulerState->currentState->strategyInput!=NULL,"need strategyInput"); 00581 00582 // don't do anything. Just return the known=given masterBurst 00583 if (schedulerState->currentState->strategyInput->mapInfoEntryFromMaster != MapInfoEntryPtr()) 00584 { 00585 assure(schedulerState->currentState->strategyInput->mapInfoEntryFromMaster != MapInfoEntryPtr(), 00586 "need masterBurst"); 00587 00588 // copy and new SmartPtr to carry the result 00589 MapInfoEntryPtr mapInfoEntry = MapInfoEntryPtr( 00590 new MapInfoEntry(*(schedulerState->currentState->strategyInput->mapInfoEntryFromMaster))); 00591 00592 assure(mapInfoEntry != MapInfoEntryPtr(),"need masterBurst"); 00593 assure(mapInfoEntry->user.isValid(),"need user in masterBurst"); 00594 00595 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): using masterBurst in slave mode: user=" 00596 << UserID(mapInfoEntry->user).getName() 00597 << " -> request.user=" 00598 << request.user.getName() 00599 << " (destination peer)"); 00600 00601 mapInfoEntry->user = request.user; 00602 00603 assure(mapInfoEntry->phyModePtr!=wns::service::phy::phymode::PhyModeInterfacePtr(), 00604 "phyMode must be defined in masterBurst" << mapInfoEntry->toString()); 00605 00606 // needed later 00607 request.phyModePtr=mapInfoEntry->phyModePtr; 00608 00609 // no space 00610 if (!schedulingMap->pduFitsInto(request,mapInfoEntry)) 00611 return resultMapInfoEntry; 00612 00613 return mapInfoEntry; 00614 } 00615 else 00616 { 00617 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): using inputSchedulingMap. request.user=" 00618 << request.user.getName() 00619 << " (destination peer)"); 00620 00621 assure(schedulerState->currentState->strategyInput->inputSchedulingMap != wns::scheduler::SchedulingMapPtr(), + 00622 "slave scheduling requires inputSchedulingMap"); 00623 assure(!colleagues.dsastrategy->requiresCQI(),"SlaveScheduler DSAStrategy must not require CQI"); 00624 } 00625 } 00626 00627 // SmartPtr (allocated in CQI) 00628 ChannelQualitiesOnAllSubBandsPtr cqiForUser; 00629 wns::CandI estimatedCandI; 00630 00631 assure(schedulerState->defaultPhyModePtr == wns::service::phy::phymode::PhyModeInterfacePtr(), 00632 "defaultPhyModePtr must not be set at this point (either master scheduler or inputSchedulingMap method)"); 00633 00634 if (schedulerState->useCQI) 00635 { 00636 assure (schedulerState->powerControlType!=PowerControlULSlave,"slave must not use CQI"); 00637 00638 // is the CQI state already available in our state? 00639 // NO -> get current CQI state 00640 if (!schedulerState->currentState->channelQualitiesOfAllUsers->knowsUser(request.user)) 00641 { 00642 // RS-TX (master DL) 00643 if (schedulerState->isTx) 00644 { 00645 // TODO: change CQIHandler so that it produces SmartPtr 00646 cqiForUser = colleagues.registry->getChannelQualities4UserOnDownlink(request.user, frameNr); 00647 } 00648 // RS-RX (master UL) 00649 else 00650 { 00651 cqiForUser = colleagues.registry->getChannelQualities4UserOnUplink(request.user, frameNr); 00652 } 00653 (*(schedulerState->currentState->channelQualitiesOfAllUsers)).insert( 00654 std::map<UserID,ChannelQualitiesOnAllSubBandsPtr>::value_type(request.user,cqiForUser)); 00655 00656 } 00657 else 00658 { 00659 cqiForUser = schedulerState->currentState->channelQualitiesOfAllUsers->find(request.user)->second; 00660 } 00661 } 00662 00663 dsastrategy::DSAResult dsaResult; 00664 int subChannel = dsastrategy::DSAsubChannelNotFound; 00665 int timeSlot = 0; 00666 int spatialLayer = 0; 00667 bool CQIrequired = colleagues.dsastrategy->requiresCQI(); 00668 bool CQIavailable = (cqiForUser!=ChannelQualitiesOnAllSubBandsPtr()) 00669 && (schedulerState->currentState->channelQualitiesOfAllUsers != ChannelQualitiesOfAllUsersPtr()) 00670 && ((*(schedulerState->currentState->channelQualitiesOfAllUsers))[request.user]->size() > 0); 00671 00672 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(" 00673 << request.user.getName() 00674 << ",cid=" << request.cid 00675 << ",bits=" << request.bits 00676 << "): useCQI=" << schedulerState->useCQI 00677 << ",CQIrequired=" << CQIrequired 00678 << ",CQIavailable="<<CQIavailable); 00679 00680 // memory of request structure 00681 ChannelQualityOnOneSubChannel& cqiOnSubChannel 00682 = request.cqiOnSubChannel; 00683 00684 // start dynamic subchannel assignment (DSA): 00685 // with or without CQI information? 00686 if (schedulerState->useCQI && CQIrequired && CQIavailable) 00687 { 00688 assure (schedulerState->powerControlType!=PowerControlULSlave,"slave must not use CQI"); 00689 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(" 00690 << request.user.getName() 00691 << ",cid=" 00692 << request.cid 00693 << ",bits=" 00694 << request.bits 00695 << "): calling dsastrategy"); 00696 00697 // start dynamic subchannel assignment 00698 dsaResult = colleagues.dsastrategy->getSubChannelWithDSA(request, schedulerState, schedulingMap); 00699 subChannel = dsaResult.subChannel; 00700 timeSlot = dsaResult.timeSlot; 00701 spatialLayer = dsaResult.spatialLayer; 00702 00703 if (subChannel==dsastrategy::DSAsubChannelNotFound) 00704 return resultMapInfoEntry; 00705 00706 assure(cqiForUser!=ChannelQualitiesOnAllSubBandsPtr(), "cqiForUser[" 00707 << request.user.getName() 00708 << "]==NULL"); 00709 00710 // this writes into request structure: 00711 // copy 00712 cqiOnSubChannel = (*cqiForUser)[subChannel]; 00713 00714 assure(&cqiOnSubChannel == &(request.cqiOnSubChannel),"copy failed: addresses don't match"); 00715 00716 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(" 00717 << request.user.getName() 00718 << ",cid=" << request.cid 00719 << ",bits=" << request.bits 00720 << "): subChannel="<<subChannel); 00721 } 00722 // no CQI required or available 00723 else 00724 { 00725 if (!CQIrequired) 00726 { 00727 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): calling dsastrategy"); 00728 // start dynamic subchannel assignment 00729 dsaResult = colleagues.dsastrategy->getSubChannelWithDSA(request, schedulerState, schedulingMap); 00730 } 00731 else 00732 { // no CQI available (principially or temporary) 00733 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): calling dsafbstrategy (fallback)"); 00734 dsaResult = colleagues.dsafbstrategy->getSubChannelWithDSA(request, schedulerState, schedulingMap); 00735 } 00736 subChannel = dsaResult.subChannel; 00737 timeSlot = dsaResult.timeSlot; 00738 spatialLayer = dsaResult.spatialLayer; 00739 00740 if (subChannel==dsastrategy::DSAsubChannelNotFound) 00741 return resultMapInfoEntry; 00742 00743 // assume flat channel and nominal TxPower for this case 00744 wns::Power nominalPowerPerSubChannel = getPowerCapabilities(request.user).nominalPerSubband; 00745 cqiOnSubChannel = (schedulerState->isTx)? 00746 (colleagues.registry->estimateTxSINRAt(request.user)) // Tx 00747 : 00748 (colleagues.registry->estimateRxSINROf(request.user)); // Rx 00749 } 00750 00751 // Tell result of DSA: subChannel 00752 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(" 00753 << request.user.getName() 00754 << ",cid="<<request.cid 00755 << ",bits="<<request.bits<<"):" 00756 << " subChannel.tSlot.spatialLayer=" 00757 << subChannel<<"."<<timeSlot<<"."<<spatialLayer); 00758 00759 if (subChannel==dsastrategy::DSAsubChannelNotFound) 00760 return resultMapInfoEntry; 00761 00762 // must be replaced by code which copes with that case: 00763 assure(subChannel != dsastrategy::DSAsubChannelNotFound, "DSAsubChannelNotFound"); 00764 00765 // fix the proposed subChannel value: 00766 request.subChannel = subChannel; 00767 request.timeSlot = timeSlot; 00768 request.spatialLayer = spatialLayer; 00769 00770 wns::Power txPower; 00771 apcstrategy::APCResult apcResult; 00773 // Master 00774 if (schedulerState->powerControlType!=PowerControlULSlave) 00775 { 00776 // do adaptive power allocation 00777 apcResult = colleagues.apcstrategy->doStartAPC(request, schedulerState, schedulingMap); 00778 // not (yet) possible: 00779 if (apcResult.txPower == wns::Power()) 00780 return resultMapInfoEntry; 00781 00782 // fix the proposed phyMode value: 00783 request.phyModePtr = apcResult.phyModePtr; 00784 txPower = apcResult.txPower; 00785 00786 // process result: 00787 estimatedCandI.I = cqiOnSubChannel.interference; 00788 estimatedCandI.C = apcResult.txPower / cqiOnSubChannel.pathloss.get_factor(); 00789 00790 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): txP=" 00791 << apcResult.txPower 00792 << ", pl=" << cqiOnSubChannel.pathloss 00793 << ", sinr=" << estimatedCandI.toSINR() 00794 << ", PhyMode=" << *(apcResult.phyModePtr)); 00795 00796 assure(std::fabs(estimatedCandI.C.get_dBm() - apcResult.estimatedCandI.C.get_dBm()) < 1e-6, 00797 "estimatedCandI mismatch: C=" << estimatedCandI.C << " != " << apcResult.estimatedCandI.C); 00798 assure(std::fabs(estimatedCandI.I.get_dBm() - apcResult.estimatedCandI.I.get_dBm()) < 1e-6, 00799 "estimatedCandI mismatch: I=" << estimatedCandI.I << " != " << apcResult.estimatedCandI.I); 00800 assure(std::fabs(estimatedCandI.toSINR().get_dB() - apcResult.sinr.get_dB()) < 1e-6, 00801 "sinr mismatch: sinr=" << estimatedCandI.toSINR() << " != " << apcResult.sinr); 00802 00803 // estimatedCandI (calculated here) and apcResult.estimatedCandI should be the same 00804 double minSINRforPhyMode = colleagues.registry->getPhyModeMapper()->getMinimumSINR(); 00805 00806 // this could mean "APC failed" 00807 if ((apcResult.sinr.get_dB() < minSINRforPhyMode)) 00808 { 00809 MESSAGE_SINGLE(NORMAL, logger,"doAdaptiveResourceScheduling(): too low SINR! sinr=" 00810 << estimatedCandI.toSINR() 00811 << ", PhyMode=" 00812 << *(apcResult.phyModePtr) 00813 << " requires " 00814 << minSINRforPhyMode << "dB"); 00815 00816 // If the value is extremely low, it is likely that something bad has happened 00817 assure(estimatedCandI.C.get_dBm() > -190, 00818 "sinr=" << apcResult.sinr.get_dB() 00819 << " but minSINRforPhyMode=" 00820 << minSINRforPhyMode << " not reached. Estimation was: C=" 00821 << estimatedCandI.C << ", I="<<estimatedCandI.I<<" (blind)"); 00822 00823 if (schedulerState->excludeTooLowSINR) 00824 { 00825 return resultMapInfoEntry; 00826 } 00827 } 00828 } 00829 // slave scheduling (PowerControlULSlave) 00830 else 00831 { 00832 request.phyModePtr = schedulingMap->getPhyModeUsedInResource(subChannel,timeSlot,spatialLayer); 00833 txPower = schedulingMap->getTxPowerUsedInResource(subChannel,timeSlot,spatialLayer); 00834 } 00835 00836 // This really fixes the proposed values of DSA and APC. 00837 resultMapInfoEntry = MapInfoEntryPtr(new MapInfoEntry()); 00838 resultMapInfoEntry->frameNr = frameNr; 00839 resultMapInfoEntry->subBand = subChannel; 00840 resultMapInfoEntry->timeSlot = timeSlot; 00841 resultMapInfoEntry->spatialLayer = spatialLayer; 00842 resultMapInfoEntry->user = request.user; 00843 resultMapInfoEntry->sourceUser = schedulerState->myUserID; 00844 resultMapInfoEntry->txPower = txPower; // apcResult.txPower; 00845 resultMapInfoEntry->phyModePtr = request.phyModePtr; // = apcResult.phyModePtr 00846 resultMapInfoEntry->estimatedCQI = cqiOnSubChannel; 00847 00848 // Set antennaPattern etc. according to grouping result 00849 if (groupingRequired()) 00850 { 00851 assure(schedulerState->currentState->getGrouping() != GroupingPtr(),"invalid grouping"); 00852 00853 wns::service::phy::ofdma::PatternPtr antennaPattern; 00854 antennaPattern = schedulerState->currentState->getGrouping()->patterns[request.user]; 00855 int groupIndex = schedulerState->currentState->getGrouping()->userGroupNumber[request.user] - 1; 00856 00857 assure(groupIndex <= schedulerState->currentState->getGrouping()->groups.size(), "invalid group index"); 00858 00859 Group currentGroup = schedulerState->currentState->getGrouping()->groups[groupIndex]; 00860 estimatedCandI = currentGroup[request.user]; 00861 resultMapInfoEntry->estimatedCQI.carrier = estimatedCandI.C; 00862 resultMapInfoEntry->estimatedCQI.interference = estimatedCandI.I; 00863 resultMapInfoEntry->estimatedCQI.pathloss = estimatedCandI.PL; 00864 resultMapInfoEntry->estimatedCQI.sdma.iIntra = estimatedCandI.sdma.iIntra; 00865 00866 assure(antennaPattern != wns::service::phy::ofdma::PatternPtr(),"invalid pattern"); 00867 00868 resultMapInfoEntry->pattern = antennaPattern; 00869 } 00870 resultMapInfoEntry->start = wns::scheduler::undefinedTime; 00871 resultMapInfoEntry->end = wns::scheduler::undefinedTime; 00872 00873 return resultMapInfoEntry; 00874 } // doAdaptiveResourceScheduling 00875 00876 wns::service::phy::phymode::PhyModeInterfacePtr 00877 Strategy::getBestPhyMode(const wns::Ratio& sinr) const 00878 { 00879 if (schedulerState->currentState->strategyInput->defaultPhyModePtr != 00880 wns::service::phy::phymode::PhyModeInterfacePtr()) 00881 { 00882 assure(schedulerState->currentState->strategyInput->defaultPhyModePtr->isValid(), 00883 "defaultPhyModePtr is invalid!"); 00884 00885 return schedulerState->currentState->strategyInput->defaultPhyModePtr; 00886 } 00887 // do link adaptation 00888 else 00889 { 00890 return colleagues.registry->getBestPhyMode(sinr); 00891 } 00892 } 00893 00894 wns::scheduler::SchedulerSpotType 00895 Strategy::getSchedulerSpotType() const 00896 { 00897 assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid"); 00898 assure(schedulerState->schedulerSpot>0,"uninitialized schedulerSpot=" 00899 << schedulerState->schedulerSpot); 00900 00901 return schedulerState->schedulerSpot; 00902 } 00903 00904 bool 00905 Strategy::isTx() const 00906 { 00907 // comes from Python. isTx=true for RS-TX (DL,UL) in (BS,UT,RN) 00908 assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid"); 00909 00910 return schedulerState->isTx; 00911 } 00912 00913 // method only to support the old strategies. Not intended for new schedulers. 00914 wns::Power 00915 Strategy::getTxPower() const 00916 { 00917 wns::Power power; 00918 MESSAGE_SINGLE(NORMAL, logger, "getTxPower()"); 00919 00920 assure(schedulerState != SchedulerStatePtr(), 00921 "schedulerState must be valid"); 00922 assure(schedulerState->currentState != RevolvingStatePtr(), 00923 "currentState must be valid"); 00924 assure(schedulerState->currentState->strategyInput != NULL, 00925 "need strategyInput"); 00926 assure(!isNewStrategy(), 00927 "getTxPower() only allowed for the old obsolete strategies"); 00928 00929 // not yet prepared. Do it now. 00930 if (schedulerState->powerCapabilities.nominalPerSubband==wns::Power()) 00931 { 00932 MESSAGE_SINGLE(NORMAL, logger, "getTxPower: asking getPowerCapabilities(NULL)..."); 00933 // NULL because peer unknown 00934 getPowerCapabilities(UserID()); 00935 } 00936 power = schedulerState->powerCapabilities.nominalPerSubband; 00937 00938 assure(power != wns::Power(),"undefined power=" << power); 00939 00940 return power; 00941 } 00942 00943 float 00944 Strategy::getResourceUsage() const 00945 { 00946 assure(schedulerState!=SchedulerStatePtr(),"schedulerState must be valid"); 00947 assure(schedulerState->currentState!=RevolvingStatePtr(),"currentState must be valid"); 00948 assure(schedulerState->currentState->schedulingMap!=wns::scheduler::SchedulingMapPtr(),"schedulingMap must be valid"); 00949 00950 // This is the default implementation. Overload in your desired strategy 00951 // if you want information about the resource usage. 00952 // In general it is better to call schedulingMap->getResourceUsage() in the system specific methods after scheduling 00953 if (schedulerState->currentState->schedulingMap!=SchedulingMapPtr()) 00954 { 00955 return schedulerState->currentState->schedulingMap->getResourceUsage(); 00956 } 00957 else 00958 { 00959 return 0.0; 00960 } 00961 } 00962 00963 bool 00964 Strategy::groupingRequired() const 00965 { 00966 assure(schedulerState != SchedulerStatePtr(), 00967 "schedulerState must be valid"); 00968 assure(schedulerState->currentState != RevolvingStatePtr(), 00969 "currentState must be valid"); 00970 assure(schedulerState->currentState->strategyInput != NULL, 00971 "schedulerState->currentState->strategyInput must be valid"); 00972 00973 bool isMaster = (schedulerState->schedulerSpot == wns::scheduler::SchedulerSpot::DLMaster() 00974 || schedulerState->schedulerSpot == wns::scheduler::SchedulerSpot::ULMaster()); 00975 00976 return (schedulerState->currentState->strategyInput->beamforming && isMaster); 00977 }
1.5.5