User Manual, Developers Guide and API Documentation

ProportionalFair.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  * WNS (Wireless Network Simulator)                                           *
00003  * __________________________________________________________________________ *
00004  *                                                                            *
00005  * Copyright (C) 2004-2006                                                    *
00006  * Chair of Communication Networks (ComNets)                                  *
00007  * Kopernikusstr. 16, D-52074 Aachen, Germany                                 *
00008  * phone: ++49-241-80-27910 (phone), fax: ++49-241-80-22242                   *
00009  * email: wns@comnets.rwth-aachen.de                                          *
00010  * www: http://wns.comnets.rwth-aachen.de                                     *
00011  ******************************************************************************/
00012 
00013 #include <WNS/scheduler/strategy/staticpriority/ProportionalFair.hpp>
00014 #include <WNS/scheduler/SchedulerTypes.hpp>
00015 
00016 #include <vector>
00017 #include <map>
00018 #include <queue>
00019 #include <algorithm>
00020 #include <iostream>
00021 #include <iomanip>
00022 #include <math.h>
00023 
00024 using namespace std;
00025 using namespace wns::scheduler;
00026 using namespace wns::scheduler::strategy;
00027 using namespace wns::scheduler::strategy::staticpriority;
00028 
00029 // begin example "wimac.tutorial.experiment2.staticFactory.substrategy.ProportionalFair.cpp"
00030 STATIC_FACTORY_REGISTER_WITH_CREATOR(ProportionalFair,
00031                                      SubStrategyInterface,
00032                                      "ProportionalFair",
00033                                      wns::PyConfigViewCreator);
00034 // end example
00035                                      
00036 ProportionalFair::ProportionalFair(const wns::pyconfig::View& config)
00037     : SubStrategy(config),
00038       blockSize(config.get<int>("blockSize")),
00039       historyWeight(config.get<float>("historyWeight")),
00040       scalingBetweenMaxTPandPFair(config.get<float>("scalingBetweenMaxTPandPFair")),
00041       rateFairness(config.get<bool>("rateFairness")),
00042       maxRateOfSubchannel(0.0),
00043       allUsers(),
00044       preferenceVariationDistribution(NULL)
00045 {
00046     assure(blockSize>0,"invalid blockSize="<<blockSize);
00047     MESSAGE_SINGLE(NORMAL, logger, "ProportionalFair(): constructed with blockSize="<<blockSize);
00048     pastDataRates.clear();
00049     allUsers.clear();
00050     preferenceVariationDistribution = new wns::distribution::Uniform(-1.0, 1.0);
00051     // historyWeight:
00052     // if 0 no history is taken into account -> maxThroughput Scheduler
00053     assure(scalingBetweenMaxTPandPFair>=0.0, "scalingBetweenMaxTPandPFair="<<scalingBetweenMaxTPandPFair<<" is out of bounds");
00054     assure(scalingBetweenMaxTPandPFair<=1.0, "scalingBetweenMaxTPandPFair="<<scalingBetweenMaxTPandPFair<<" is out of bounds");
00055     assure((historyWeight>=0.0)&&(historyWeight<1.0), "historyWeight="<<historyWeight<<" is out of bounds");
00056 }
00057 
00058 ProportionalFair::~ProportionalFair()
00059 {
00060     delete preferenceVariationDistribution;
00061 }
00062 
00063 void
00064 ProportionalFair::initialize()
00065 {
00066     MESSAGE_SINGLE(NORMAL, logger, "ProportionalFair::initialize()");
00067     wns::service::phy::phymode::PhyModeInterfacePtr phyMode = colleagues.registry->getPhyModeMapper()->getHighestPhyMode();
00068     maxRateOfSubchannel = phyMode->getDataRate();
00069     MESSAGE_SINGLE(NORMAL, logger, "ProportionalFair: maxRateOfSubchannel="<<maxRateOfSubchannel<<" bit/s");
00070     assure(maxRateOfSubchannel>0.0, "unknown maxRateOfSubchannel");
00071 }
00072 
00073 std::priority_queue<ProportionalFair::UserPreference>
00074 ProportionalFair::calculateUserPreferences(UserSet activeUsers, bool txStrategy) const
00075 {
00076     std::map<UserID, ChannelQualityOnOneSubChannel> sinrs;
00077 
00078     // preference for every user in a priority queue which automatically sorts
00079     std::priority_queue<UserPreference> preferences;
00080     assure(preferences.size()==0, "preferences.size() must be 0");
00081 
00082     for ( UserSet::const_iterator iter = activeUsers.begin();
00083           iter != activeUsers.end(); ++iter)
00084     {
00085         UserID user = *iter;
00086         assure(user.isValid(), "No valid user");
00087 
00088         //determines the users SINRs depending on the tx/Rx mode of the strategy
00089         if (txStrategy)
00090         {
00091             sinrs[user] = colleagues.registry->estimateTxSINRAt(user);
00092         }
00093         else
00094         {
00095             sinrs[user] = colleagues.registry->estimateRxSINROf(user);
00096         }
00097 
00098         // calculate PhyModeRate for available users
00099         wns::Ratio sinr(sinrs[user].carrier / sinrs[user].interference);
00100         wns::service::phy::phymode::PhyModeInterfacePtr phyMode = colleagues.registry->getPhyModeMapper()->getBestPhyMode(sinr);
00101         assure(phyMode->isValid(),"invalid PhyMode");
00102 
00103         // calculate userRate, which is the maximum possible data rate
00104         // for one subChannel for the best PhyMode available here
00105         float phyModeRate = phyMode->getDataRate(); // rate [b/s] of one subChannel
00106         float referenceRate;
00107         float pastDataRate = 1.0;
00108 
00109         // get the past data rate for this user:
00110         // iterate over the global past data rates map of all users and
00111         // find the past data rate for this user
00112         // there is exactly one pastDataRate value per userID
00113         int weight = colleagues.registry->getTotalNumberOfUsers(user);
00114         for (std::map<UserID, float>::const_iterator iter = pastDataRates.begin();
00115              iter != pastDataRates.end(); ++iter)
00116         {
00117             if (iter->first/*userID*/ == user)
00118             {
00119                 float dataRate = iter->second;
00120                 // a RN must get a better share of the bandwidth
00121                 // here: proportional to its number of users:
00122                 assure(weight>0, "numberOfUsers(" <<user.getName()<<")=" << weight);
00123                 dataRate /= static_cast<float>(weight);
00124                 // dataRate now has the meaning of a weight.
00125                 pastDataRate = dataRate;
00126             }
00127         } // for all userIDs in pastDataRates
00128 
00129         if (pastDataRate < 0.01)
00130             pastDataRate = 0.01;
00131 
00132         // preference is achievable current user rate divided by a history
00133         // factor that takes the past throughput of this user into account
00134 
00135         assure(maxRateOfSubchannel>0.0, "unknown maxRateOfSubchannel");
00136 
00137         // goal is either rate (true) or resource (false) fairness
00138         if (rateFairness == true)
00139         {
00140             referenceRate = maxRateOfSubchannel;
00141         }
00142         else
00143         {
00144             referenceRate = phyModeRate;
00145         }
00146 
00147         // maxRateOfSubchannel is constant, with range [0..1][bit/s]
00148         float resultMaxThroughput = referenceRate / maxRateOfSubchannel;
00149         float resultPropFair      = referenceRate / pastDataRate; // can be any range
00150         if (scalingBetweenMaxTPandPFair <= 0.5) {
00151             // variate the preference for each user, so that they differ a little bit (1%)
00152             // and the automatic sorting does not always give the same order
00153             // (would be a problem for identical preference weights).
00154             resultMaxThroughput *=  (1 + 0.01*(*preferenceVariationDistribution)());
00155         }
00156         float UserPref =
00157             (1.0-scalingBetweenMaxTPandPFair) * resultMaxThroughput
00158             +scalingBetweenMaxTPandPFair  * resultPropFair;
00159 
00160         MESSAGE_SINGLE(NORMAL, logger, "getPreference("<<user.getName()<<"): weight=" << weight << ", pastDataRate= "<<pastDataRate<<" bit/s, UserPreference= "<<UserPref<<" (resultMaxThroughput="<<resultMaxThroughput<<",resultProportionalFair="<<resultPropFair<<")");
00161 
00162         // calculate preferences for users and order them
00163         preferences.push(UserPreference(UserPref, user));
00164     }
00165     return preferences;
00166 }
00167 
00168 //std::map<UserID, Bit(int)>
00169 std::map<UserID, float>
00170 ProportionalFair::calculateBitsForConnections(const ConnectionSet& currentConnections)
00171 {
00172     std::map<UserID, float> bitsForUsers;
00173 
00174     for ( wns::scheduler::ConnectionSet::const_iterator iter = currentConnections.begin();
00175           iter != currentConnections.end();
00176           ++iter )
00177     {
00178         ConnectionID currentConnection = *iter;
00179         wns::scheduler::UserID user = colleagues.registry->getUserForCID(currentConnection);
00180 
00181         Bit queueLength = 0;
00182         if (colleagues.queue->queueHasPDUs(currentConnection))
00183         {
00184             queueLength = colleagues.queue->numBitsForCid(currentConnection);
00185         }
00186 
00187         if (bitsForUsers.find(user) == bitsForUsers.end())
00188         {
00189             bitsForUsers[user] = queueLength;
00190         }
00191         else
00192         {
00193             bitsForUsers[user] += queueLength;
00194         }
00195     }
00196     return bitsForUsers;
00197 }
00198 
00199 // preferences should be a member
00200 wns::scheduler::ConnectionID
00201 ProportionalFair::getNextConnection(SchedulerStatePtr schedulerState,
00202                                     std::priority_queue<UserPreference> preferences)
00203 {
00204     wns::scheduler::ConnectionID next = -1;
00205 
00206     while (!preferences.empty())
00207     {
00208         int priority = schedulerState->currentState->getCurrentPriority();
00209         const float preference = preferences.top().first;
00210         const UserID user = preferences.top().second;
00211         MESSAGE_SINGLE(NORMAL, logger, "Selected user="<<user.getName());
00212 
00213         ConnectionVector currentPrioConns = getConnectionsForPrio(priority, user);
00214 
00215         if(!currentPrioConns.empty())
00216         {
00217             next = getRandomConnection(currentPrioConns);
00218             MESSAGE_SINGLE(NORMAL, logger, "Selected connection with CID="<<next);
00219             return next;
00220         }
00221         preferences.pop();
00222     }
00223     return next;
00224 }
00225 
00226 // return connections for user belonging to current priority
00227 ConnectionVector
00228 ProportionalFair::getConnectionsForPrio(int currentPrio, const UserID user)
00229 {
00230     ConnectionVector currentPrioConns;
00231     ConnectionVector allRegisteredConns = colleagues.registry->getConnectionsForUser(user);
00232     for (ConnectionVector::const_iterator iter = allRegisteredConns.begin();
00233          iter != allRegisteredConns.end();
00234          ++iter)
00235     {
00236         wns::scheduler::ConnectionID currentConnection = *iter;
00237         // check if the connection has the current priority
00238         if (colleagues.registry->getPriorityForConnection(currentConnection) == currentPrio)
00239         {
00240             if (colleagues.queue->queueHasPDUs(currentConnection))
00241             {
00242                 currentPrioConns.push_back(currentConnection);
00243             }
00244             // else: this conection is empty, go to the next connection of this user
00245         }
00246         // else: this connection belongs to another, i.e. lower priority, go to the next connection of this user
00247     }
00248     return currentPrioConns;
00249 }
00250 
00251 wns::scheduler::ConnectionID
00252 ProportionalFair::getRandomConnection(ConnectionVector currentPrioConns)
00253 {
00254     int numberOfConns = currentPrioConns.size();
00255     wns::distribution::Uniform randomPositionDistribution(0.0, numberOfConns);
00256     float randomNumber = (randomPositionDistribution)();
00257     int randomPosition = static_cast<int>(randomNumber);
00258     MESSAGE_SINGLE(NORMAL, logger, "Drew random number="<<randomNumber<< ", position="<< randomPosition << " out of "<< numberOfConns << " total connections.");
00259     assure(randomPosition<numberOfConns, "Random position of connections="<< randomPosition << " out of range of current connections size="<<numberOfConns);
00260     return currentPrioConns[randomPosition];
00261 }
00262 
00263 // maybe we could get rid of the phase length
00264 void
00265 ProportionalFair::updatePastDataRates(std::map<UserID, float> bitsBeforeThisFrame,
00266                                       std::map<UserID, float> bitsAfterThisFrame,
00267                                       simTimeType phaseLength)
00268 {
00269     UserID user;
00270     float bitsThisFrame = 0.0;
00271     float pastDataRate = 0.0;
00272     float currentRate = 0.0;
00273 
00274     for (std::map<UserID, float>::const_iterator iter = bitsBeforeThisFrame.begin();
00275          iter != bitsBeforeThisFrame.end(); ++iter)
00276     {
00277         user = iter->first;
00278         bitsThisFrame = bitsBeforeThisFrame[user] - bitsAfterThisFrame[user];
00279         currentRate = bitsThisFrame / phaseLength;
00280         pastDataRate = pastDataRates[user];
00281 
00282         if (pastDataRates.find(user) != pastDataRates.end()) {
00283             pastDataRates[user] = (1.0-historyWeight) * currentRate + historyWeight * pastDataRates[user];
00284         } else {
00285             // new user
00286             pastDataRates[user] = currentRate;
00287         }
00288         MESSAGE_SINGLE(NORMAL, logger, "updatePastDataRates("<<user.getName()<<","<<phaseLength<<"s): pastDataRate: new= "<< pastDataRates[user]<<" bit/s, old= "<<pastDataRate<<" bit/s, currentRate= "<<currentRate<<" bit/s");
00289     }
00290 }
00291 
00292 wns::scheduler::MapInfoCollectionPtr
00293 ProportionalFair::doStartSubScheduling(SchedulerStatePtr schedulerState,
00294                                        wns::scheduler::SchedulingMapPtr schedulingMap)
00295 
00296 {
00297     MapInfoCollectionPtr mapInfoCollection = MapInfoCollectionPtr(new wns::scheduler::MapInfoCollection); // result datastructure
00298     UserSet allUsersInQueue = colleagues.queue->getQueuedUsers();
00299     UserSet activeUsers     = colleagues.registry->filterReachable(allUsersInQueue);
00300     ConnectionSet &currentConnections = schedulerState->currentState->activeConnections;
00301 
00302     MESSAGE_SINGLE(NORMAL, logger, "activeUsers= "<< activeUsers.size()<<" , currentConnections= "<<printConnectionSet(currentConnections)<<" ");
00303 
00304     if (activeUsers.empty() || currentConnections.empty()) return mapInfoCollection; // nothing to do
00305 
00306     simTimeType slotLength = schedulingMap->getSlotLength();
00307     bool txStrategy = schedulerState->isTx;
00308     std::map<UserID, float> bitsBeforeThisFrame = calculateBitsForConnections(currentConnections);
00309 
00310     MESSAGE_BEGIN(NORMAL, logger, m, "ProportionalFair");
00311     for (std::map<UserID, float>::const_iterator iter = bitsBeforeThisFrame.begin();
00312          iter != bitsBeforeThisFrame.end(); ++iter)
00313     {
00314         m << "\n User " << iter->first.getName() << " has " << iter->second;
00315         m << " queued bits.";
00316     }
00317     MESSAGE_END();
00318 
00319     std::map<UserID, float> pastDataRates;
00320     // make preferences a member, then no return value needed
00321     std::priority_queue<UserPreference> preferences = calculateUserPreferences(activeUsers, txStrategy);
00322 
00323     // returns the connection of the user with the highest preference, i.e. lowest past data rate
00324     wns::scheduler::ConnectionID currentConnection = getNextConnection(schedulerState, preferences);
00325     //wns::scheduler::UserID user = colleagues.registry->getUserForCid(currentConnection);
00326 
00327     bool spaceLeft= true;
00328     int pduCounter = 0;
00329     // static const noCID and then check for (currentConnection != noCID)
00330     while(spaceLeft && (currentConnection >= 0))
00331     {
00332         // schedule blockSize PDUs for this CID
00333         while( colleagues.queue->queueHasPDUs(currentConnection) && spaceLeft)
00334         {
00335             spaceLeft = scheduleCid(schedulerState,schedulingMap,currentConnection,pduCounter,blockSize,mapInfoCollection);
00336         } // while PDUs in queue
00337         /*if (!colleagues.queue->queueHasPDUs(currentConnection))
00338           { // exit because of queue empty (most probable case for low traffic)
00339           currentConnections.erase(currentConnection);
00340           if (currentConnections.empty()) break; // all queues empty
00341           }*/
00342         currentConnection = getNextConnection(schedulerState, preferences);
00343         // user = colleagues.registry->getUserForCid(currentConnection);
00344         MESSAGE_SINGLE(NORMAL, logger, "doStartSubScheduling(): next connection="<<currentConnection);
00345     } // while(spaceLeft)
00346     MESSAGE_SINGLE(NORMAL, logger, "doStartSubScheduling(): ready: mapInfoCollection="<<mapInfoCollection.getPtr()<<" of size="<<mapInfoCollection->size());
00347 
00348     std::map<UserID, float> bitsAfterThisFrame = calculateBitsForConnections(currentConnections);
00349     
00350     MESSAGE_BEGIN(NORMAL, logger, m, "ProportionalFair");
00351     for (std::map<UserID, float>::const_iterator iter = bitsAfterThisFrame.begin();
00352          iter != bitsAfterThisFrame.end(); ++iter)
00353     {
00354         m << "\n User " << iter->first.getName() << " has " << iter->second;
00355         m << " queued bits left after this frame.";
00356     }
00357     MESSAGE_END();
00358 
00359     assure(bitsBeforeThisFrame.size() == bitsAfterThisFrame.size(), "bitsBeforeThisFrame and bitsAfterThisFrame do not have the same number of users!");
00360     updatePastDataRates(bitsBeforeThisFrame, bitsAfterThisFrame, slotLength);
00361     return mapInfoCollection;
00362 }

Generated on Fri May 25 03:31:55 2012 for openWNS by  doxygen 1.5.5