ParetoChurn.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00033 #include "ParetoChurn.h"
00034 
00035 #include "GlobalStatisticsAccess.h"
00036 #include "Churn_m.h"
00037 #include "GlobalStatistics.h"
00038 #include <UnderlayConfigurator.h>
00039 #include <algorithm>
00040 #include <deque>
00041 
00042 Define_Module(ParetoChurn);
00043 
00044 void ParetoChurn::initializeChurn()
00045 {
00046     Enter_Method_Silent();
00047 
00048     initialMean = par("initPhaseCreationInterval");
00049     initialDeviation = initialMean / 3;
00050     lifetimeMean = par("lifetimeMean");
00051     deadtimeMean = par("deadtimeMean");
00052 
00053     WATCH(lifetimeMean);
00054     WATCH(deadtimeMean);
00055 
00056     lastCreatetime = 0;
00057     lastDeletetime = 0;
00058 
00059     globalStatistics = GlobalStatisticsAccess().get();
00060 
00061     double initFinishedTime = initialMean * targetOverlayTerminalNum;
00062 
00063     // try to create a stable equilibrium of nodes in init phase
00064     //
00065     // check for each node if he is present in initial state
00066     // and roll individual mean life+dead times
00067     int liveNodes = 0;
00068     double sum_l_i = 0;
00069     std::deque<node_stat> node_stats;
00070 
00071     for (int i = 0; liveNodes < (int)par("targetOverlayTerminalNum"); i++) {
00072 
00073         double nodeLifetimeMean = individualMeanTime(lifetimeMean);
00074         globalStatistics->recordOutVector("ParetoChurn: Node individual "
00075                                           "mean lifetime", nodeLifetimeMean);
00076         double nodeDeadtimeMean = individualMeanTime(deadtimeMean);
00077         globalStatistics->recordOutVector("ParetoChurn: Node individual "
00078                                           "mean deadtime", nodeDeadtimeMean);
00079         sum_l_i += 1.0/(nodeLifetimeMean + nodeDeadtimeMean);
00080         node_stat nodeStat;
00081         nodeStat.l = nodeLifetimeMean;
00082         nodeStat.d = nodeDeadtimeMean;
00083         double nodeAvailability = nodeLifetimeMean/(nodeLifetimeMean
00084                                                     + nodeDeadtimeMean);
00085 
00086         globalStatistics->recordOutVector("Node availability", nodeAvailability);
00087 
00088         nodeStat.alive = uniform(0, 1) < nodeAvailability;
00089         if (nodeStat.alive) {
00090             liveNodes++;
00091         }
00092         node_stats.push_back( nodeStat );
00093     }
00094 
00095     // compute "stretch" factor to reach the configured average lifetime
00096     // this is neccessary as "individual" lifetime mean has to be bigger than
00097     // "global" lifetime mean, as short-lived nodes will factor in more often
00098     double mean_life = 0;
00099     int numNodes = node_stats.size();
00100     for( int i = 0; i < numNodes; ++i ){
00101         node_stat& stat = node_stats[i];
00102         mean_life += stat.l/( (stat.l + stat.d) * sum_l_i );
00103     }
00104     double stretch = lifetimeMean/mean_life;
00105     liveNodes = 0;
00106 
00107     // schedule creation for all (alive or dead) nodes
00108     for( int i = 0; i < numNodes; ++i ){
00109         node_stat& stat = node_stats.front();
00110         stat.l *= stretch;
00111         stat.d *= stretch;
00112 
00113         if( stat.alive ){
00114             double scheduleTime = truncnormal(initialMean*liveNodes, initialDeviation);
00115             scheduleCreateNodeAt(scheduleTime, initFinishedTime - scheduleTime
00116                                  + residualLifetime(stat.l),
00117                                  stat.l, stat.d);
00118             liveNodes++;
00119         } else {
00120             scheduleCreateNodeAt(initFinishedTime
00121                                  + residualLifetime(stat.d),
00122                                  individualLifetime(stat.l),
00123                                  stat.l, stat.d);
00124         }
00125         node_stats.pop_front();
00126     }
00127 
00128     initFinishedTimer = new cMessage("initFinishTimer");
00129     scheduleAt(initFinishedTime, initFinishedTimer);
00130 }
00131 
00132 void ParetoChurn::handleMessage(cMessage* msg)
00133 {
00134     if (!msg->isSelfMessage()) {
00135         delete msg;
00136         return;
00137     }
00138 
00139     // init phase finished
00140     if (msg ==  initFinishedTimer) {
00141         underlayConfigurator->initFinished();
00142         cancelEvent(initFinishedTimer);
00143         delete initFinishedTimer;
00144         initFinishedTimer = NULL;
00145 
00146         return;
00147     }
00148 
00149     ParetoChurnMessage* churnMsg = check_and_cast<ParetoChurnMessage*>(msg);
00150 
00151     if (churnMsg->getCreateNode() == true) {
00152         createNode(churnMsg->getLifetime(), churnMsg->getMeanLifetime(),
00153                    churnMsg->getMeanDeadtime(), false);
00154     } else {
00155         deleteNode(churnMsg->getAddr(), churnMsg->getMeanLifetime(),
00156                    churnMsg->getMeanDeadtime());
00157     }
00158 
00159     delete msg;
00160 }
00161 
00162 void ParetoChurn::createNode(double lifetime, double meanLifetime,
00163                              double meanDeadtime, bool initialize)
00164 {
00165     ParetoChurnMessage* churnMsg = new ParetoChurnMessage("DeleteNode");
00166     TransportAddress* ta = underlayConfigurator->createNode(type, initialize);
00167     churnMsg->setAddr(*ta);
00168     delete ta;
00169     churnMsg->setCreateNode(false);
00170     churnMsg->setMeanLifetime(meanLifetime);
00171     churnMsg->setMeanDeadtime(meanDeadtime);
00172     scheduleAt(std::max(simTime(), simTime() + lifetime
00173                    - underlayConfigurator->getGracefulLeaveDelay()), churnMsg);
00174 
00175     RECORD_STATS(globalStatistics->recordOutVector("ParetoChurn: Session Time",
00176                                                    lifetime));
00177 
00178     RECORD_STATS(globalStatistics->recordOutVector("ParetoChurn: "
00179                  "Time between creates", SIMTIME_DBL(simTime() - lastCreatetime)));
00180 
00181     lastCreatetime = simTime();
00182 }
00183 
00184 void ParetoChurn::deleteNode(TransportAddress& addr, double meanLifetime,
00185                              double meanDeadtime)
00186 {
00187     // Kill node
00188     underlayConfigurator->preKillNode(NodeType(), &addr);
00189 
00190     RECORD_STATS(globalStatistics->recordOutVector("ParetoChurn: "
00191                "Time between deletes", SIMTIME_DBL(simTime() - lastDeletetime)));
00192     lastDeletetime = simTime();
00193     scheduleCreateNodeAt(SIMTIME_DBL(simTime()+individualLifetime(meanDeadtime)),
00194                          individualLifetime(meanLifetime), meanLifetime,
00195                          meanDeadtime);
00196 }
00197 
00198 void ParetoChurn::scheduleCreateNodeAt(double creationTime, double lifetime,
00199                                        double meanLifetime, double meanDeadtime)
00200 {
00201     ParetoChurnMessage* churnMsg = new ParetoChurnMessage("CreateNode");
00202     churnMsg->setCreateNode(true);
00203     churnMsg->setLifetime(lifetime);
00204     churnMsg->setMeanLifetime(meanLifetime);
00205     churnMsg->setMeanDeadtime(meanDeadtime);
00206     scheduleAt(creationTime, churnMsg);
00207 }
00208 
00209 double ParetoChurn::betaByMean(double mean, double alpha)
00210 {
00211     return 1/(mean*(alpha -1));
00212 }
00213 
00214 double ParetoChurn::shiftedPareto(double a, double b, int rng)
00215 {
00216     // What OMNET calles "pareto_shifted" in reality is a gerneralized pareto,
00217     // not a shifted pareto...
00218     return (pareto_shifted(a, b, 0, rng)/b - 1) / b;
00219 }
00220 
00221 double ParetoChurn::individualMeanTime(double mean)
00222 {
00223 //    return shiftedPareto(3, betaByMean(mean*exp(1)));
00224     return shiftedPareto(3, betaByMean(mean));
00225 }
00226 
00227 double ParetoChurn::individualLifetime(double mean)
00228 {
00229     return shiftedPareto(3, betaByMean(mean));
00230 }
00231 
00232 // Residual lifetime is shifted pareto with the same beta, but
00233 // decreased alpha i.e. beta calculation is based on "old alpha" (in
00234 // this case 3), while "actual alpha" is 2
00235 double ParetoChurn::residualLifetime(double mean)
00236 {
00237     return shiftedPareto(2, betaByMean(mean));
00238 }
00239 
00240 void ParetoChurn::updateDisplayString()
00241 {
00242     char buf[80];
00243     sprintf(buf, "pareto churn");
00244     getDisplayString().setTagArg("t", 0, buf);
00245 }
00246 
00247 ParetoChurn::~ParetoChurn() {
00248     // destroy self timer messages
00249     cancelAndDelete(initFinishedTimer);
00250 }
Generated on Wed May 26 16:21:14 2010 for OverSim by  doxygen 1.6.3