1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
3 * Copyright (c) 2009 Duy Nguyen
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation;
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * Author: Duy Nguyen <duy@soe.ucsc.edu>
22 * 1) Segment Size is declared for completeness but not used because it has
23 * to do more with the requirement of the specific hardware.
25 * 2) By default, Minstrel applies the multi-rate retry(the core of Minstrel
26 * algorithm). Otherwise, please use ConstantRateWifiManager instead.
28 * http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/minstrel
33 #include "minstrel-wifi-manager.h"
35 #include "ns3/random-variable.h"
36 #include "ns3/simulator.h"
38 #include "ns3/uinteger.h"
39 #include "ns3/double.h"
40 #include "ns3/wifi-mac.h"
41 #include "ns3/assert.h"
44 NS_LOG_COMPONENT_DEFINE ("MinstrelWifiManager");
49 NS_OBJECT_ENSURE_REGISTERED (MinstrelWifiManager);
52 MinstrelWifiManager::GetTypeId (void)
54 static TypeId tid = TypeId ("ns3::MinstrelWifiManager")
55 .SetParent<WifiRemoteStationManager> ()
56 .AddConstructor<MinstrelWifiManager> ()
57 .AddAttribute ("UpdateStatistics",
58 "The interval between updating statistics table ",
59 TimeValue (Seconds (0.1)),
60 MakeTimeAccessor (&MinstrelWifiManager::m_updateStats),
62 .AddAttribute ("LookAroundRate",
63 "the percentage to try other rates",
65 MakeDoubleAccessor (&MinstrelWifiManager::m_lookAroundRate),
66 MakeDoubleChecker<double> ())
67 .AddAttribute ("EWMA",
70 MakeDoubleAccessor (&MinstrelWifiManager::m_ewmaLevel),
71 MakeDoubleChecker<double> ())
72 .AddAttribute ("SegmentSize",
73 "The largest allowable segment size packet",
75 MakeDoubleAccessor (&MinstrelWifiManager::m_segmentSize),
76 MakeDoubleChecker <double> ())
77 .AddAttribute ("SampleColumn",
78 "The number of columns used for sampling",
80 MakeDoubleAccessor (&MinstrelWifiManager::m_sampleCol),
81 MakeDoubleChecker <double> ())
82 .AddAttribute ("PacketLength",
83 "The packet length used for calculating mode TxTime",
85 MakeDoubleAccessor (&MinstrelWifiManager::m_pktLen),
86 MakeDoubleChecker <double> ())
91 MinstrelWifiManager::MinstrelWifiManager ()
94 MinstrelWifiManager::~MinstrelWifiManager ()
98 MinstrelWifiManager::SetupPhy (Ptr<WifiPhy> phy)
100 uint32_t nModes = phy->GetNModes ();
101 for (uint32_t i = 0; i < nModes; i++)
103 WifiMode mode = phy->GetMode (i);
104 AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, mode, WIFI_PREAMBLE_LONG));
106 WifiRemoteStationManager::SetupPhy (phy);
110 MinstrelWifiManager::CreateStation (void)
112 return new MinstrelWifiRemoteStation (this);
116 MinstrelWifiManager::GetCalcTxTime (WifiMode mode) const
119 for (TxTime::const_iterator i = m_calcTxTime.begin (); i != m_calcTxTime.end (); i++)
121 if (mode == i->second)
131 MinstrelWifiManager::AddCalcTxTime (WifiMode mode, Time t)
133 m_calcTxTime.push_back (std::make_pair (t, mode));
136 MinstrelWifiRemoteStation::MinstrelWifiRemoteStation (Ptr<MinstrelWifiManager> stations)
137 :m_stations (stations),
138 m_nextStatsUpdate (Simulator::Now () + stations->m_updateStats),
146 m_isSampling (false),
148 m_sampleRateSlower (false),
155 m_initialized (false)
158 MinstrelWifiRemoteStation::~MinstrelWifiRemoteStation ()
162 MinstrelWifiRemoteStation::CheckInit(void)
166 m_minstrelTable = MinstrelRate(GetNSupportedModes ());
167 m_sampleTable = SampleRate(GetNSupportedModes (), std::vector<uint32_t> (m_stations->m_sampleCol));
170 m_initialized = true;
175 MinstrelWifiRemoteStation::DoReportRxOk (double rxSnr, WifiMode txMode)
177 NS_LOG_DEBUG("DoReportRxOk m_txrate=" << m_txrate);
181 MinstrelWifiRemoteStation::DoReportRtsFailed (void)
183 NS_LOG_DEBUG("DoReportRtsFailed m_txrate=" << m_txrate);
189 MinstrelWifiRemoteStation::DoReportRtsOk (double ctsSnr, WifiMode ctsMode, double rtsSnr)
191 NS_LOG_DEBUG ("self="<<this<<" rts ok");
195 MinstrelWifiRemoteStation::DoReportFinalRtsFailed (void)
202 MinstrelWifiRemoteStation::DoReportDataFailed (void)
208 NS_LOG_DEBUG ("DoReportDataFailed " << this << "\t rate " << m_txrate << "\tlongRetry \t" << m_longRetry);
210 /// for normal rate, we're not currently sampling random rates
213 /// use best throughput rate
214 if( m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
216 ; ///< there's still a few retries left
219 /// use second best throughput rate
220 else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
221 m_minstrelTable[m_maxTpRate].adjustedRetryCount))
223 m_txrate = m_maxTpRate2;
226 /// use best probability rate
227 else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
228 m_minstrelTable[m_maxTpRate2].adjustedRetryCount +
229 m_minstrelTable[m_maxTpRate].adjustedRetryCount))
231 m_txrate = m_maxProbRate;
234 /// use lowest base rate
235 else if (m_longRetry > (m_minstrelTable[m_txrate].adjustedRetryCount +
236 m_minstrelTable[m_maxTpRate2].adjustedRetryCount +
237 m_minstrelTable[m_maxTpRate].adjustedRetryCount))
243 /// for look-around rate, we're currently sampling random rates
246 /// current sampling rate is slower than the current best rate
247 if (m_sampleRateSlower)
249 /// use best throughput rate
250 if (m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
252 ; ///< there are a few retries left
256 else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
257 m_minstrelTable[m_maxTpRate].adjustedRetryCount))
259 m_txrate = m_sampleRate;
262 /// use max probability rate
263 else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
264 m_minstrelTable[m_sampleRate].adjustedRetryCount +
265 m_minstrelTable[m_maxTpRate].adjustedRetryCount ))
267 m_txrate = m_maxProbRate;
270 /// use lowest base rate
271 else if (m_longRetry > (m_minstrelTable[m_txrate].adjustedRetryCount +
272 m_minstrelTable[m_sampleRate].adjustedRetryCount +
273 m_minstrelTable[m_maxTpRate].adjustedRetryCount))
279 /// current sampling rate is better than current best rate
283 if (m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
288 /// use the best rate
289 else if (m_longRetry <= m_minstrelTable[m_txrate].adjustedRetryCount +
290 m_minstrelTable[m_sampleRate].adjustedRetryCount)
292 m_txrate = m_maxTpRate;
295 /// use the best probability rate
296 else if (m_longRetry <= m_minstrelTable[m_txrate].adjustedRetryCount +
297 m_minstrelTable[m_maxTpRate].adjustedRetryCount +
298 m_minstrelTable[m_sampleRate].adjustedRetryCount)
300 m_txrate = m_maxProbRate;
303 /// use the lowest base rate
304 else if (m_longRetry > m_minstrelTable[m_txrate].adjustedRetryCount +
305 m_minstrelTable[m_maxTpRate].adjustedRetryCount +
306 m_minstrelTable[m_sampleRate].adjustedRetryCount)
315 MinstrelWifiRemoteStation::DoReportDataOk (double ackSnr, WifiMode ackMode, double dataSnr)
317 m_isSampling = false;
318 m_sampleRateSlower=false;
322 m_minstrelTable[m_txrate].numRateSuccess++;
323 m_minstrelTable[m_txrate].numRateAttempt++;
327 m_minstrelTable[m_txrate].numRateAttempt += m_retry;
330 if (GetNSupportedModes () >= 1)
332 m_txrate = FindRate ();
337 MinstrelWifiRemoteStation::DoReportFinalDataFailed (void)
339 NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate=" << m_txrate);
341 m_isSampling = false;
342 m_sampleRateSlower=false;
346 m_minstrelTable[m_txrate].numRateAttempt += m_retry;
349 if (GetNSupportedModes () >= 1)
351 m_txrate = FindRate ();
356 MinstrelWifiRemoteStation::UpdateRetry (void)
358 m_retry = m_shortRetry + m_longRetry;
363 Ptr<WifiRemoteStationManager>
364 MinstrelWifiRemoteStation::GetManager (void) const
370 MinstrelWifiRemoteStation::DoGetDataMode (uint32_t size)
377 /// start the rate at half way
378 m_txrate = GetNSupportedModes () / 2;
380 return GetSupportedMode (m_txrate);
384 MinstrelWifiRemoteStation::DoGetRtsMode (void)
386 NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << m_txrate);
389 return GetSupportedMode (0);
393 MinstrelWifiRemoteStation::GetNextSample ()
396 bitrate = m_sampleTable[m_index][m_col];
399 /// bookeeping for m_index and m_col variables
400 if (m_index > (GetNSupportedModes () -2))
404 if (m_col >= m_stations->m_sampleCol)
413 MinstrelWifiRemoteStation::FindRate ()
415 NS_LOG_DEBUG ("FindRate " << "packet=" << m_packetCount );
417 if ((m_sampleCount + m_packetCount) == 0)
425 /// for determining when to try a sample rate
426 UniformVariable coinFlip (0, 100);
429 * if we are below the target of look around rate percentage, look around
430 * note: do it randomly by flipping a coin instead sampling
431 * all at once until it reaches the look around rate
433 if ( (((100* m_sampleCount) / (m_sampleCount + m_packetCount )) < m_stations->m_lookAroundRate) &&
434 ((int)coinFlip.GetValue ()) % 2 == 1 )
437 /// now go through the table and find an index rate
438 idx = GetNextSample ();
442 * This if condition is used to make sure that we don't need to use
443 * the sample rate it is the same as our current rate
445 if (idx != m_maxTpRate && idx != m_txrate)
448 /// start sample count
451 /// set flag that we are currently sampling
454 /// bookeeping for resetting stuff
455 if (m_packetCount >= 10000)
462 if (idx >= GetNSupportedModes () || idx < 0 )
464 NS_LOG_DEBUG ("ALERT!!! ERROR");
467 /// set the rate that we're currently sampling
470 if (m_sampleRate == m_maxTpRate)
472 m_sampleRate = m_maxTpRate2;
475 /// is this rate slower than the current best rate
476 m_sampleRateSlower = (m_minstrelTable[idx].perfectTxTime > m_minstrelTable[m_maxTpRate].perfectTxTime);
478 /// using the best rate instead
479 if (m_sampleRateSlower)
487 /// continue using the best rate
494 NS_LOG_DEBUG ("FindRate " << "sample rate=" << idx);
500 MinstrelWifiRemoteStation::UpdateStats ()
502 if (Simulator::Now () < m_nextStatsUpdate)
507 NS_LOG_DEBUG ("Updating stats="<<this);
509 m_nextStatsUpdate = Simulator::Now () + m_stations->m_updateStats;
514 for (uint32_t i =0; i < GetNSupportedModes (); i++)
517 /// calculate the perfect tx time for this rate
518 txTime = m_minstrelTable[i].perfectTxTime;
520 /// just for initialization
521 if (txTime.GetMicroSeconds () == 0)
523 txTime = Seconds (1);
526 NS_LOG_DEBUG ("m_txrate=" << m_txrate << "\t attempt=" << m_minstrelTable[i].numRateAttempt << "\t success=" << m_minstrelTable[i].numRateSuccess);
528 /// if we've attempted something
529 if (m_minstrelTable[i].numRateAttempt)
532 * calculate the probability of success
533 * assume probability scales from 0 to 18000
535 tempProb = (m_minstrelTable[i].numRateSuccess * 18000) / m_minstrelTable[i].numRateAttempt;
538 m_minstrelTable[i].successHist += m_minstrelTable[i].numRateSuccess;
539 m_minstrelTable[i].attemptHist += m_minstrelTable[i].numRateAttempt;
540 m_minstrelTable[i].prob = tempProb;
543 tempProb = ((tempProb * (100 - m_stations->m_ewmaLevel)) + (m_minstrelTable[i].ewmaProb * m_stations->m_ewmaLevel) )/100;
545 m_minstrelTable[i].ewmaProb = tempProb;
547 /// calculating throughput
548 m_minstrelTable[i].throughput = tempProb * (1000000 / txTime.GetMicroSeconds());
553 m_minstrelTable[i].prevNumRateAttempt= m_minstrelTable[i].numRateAttempt;
554 m_minstrelTable[i].prevNumRateSuccess = m_minstrelTable[i].numRateSuccess;
555 m_minstrelTable[i].numRateSuccess = 0;
556 m_minstrelTable[i].numRateAttempt = 0;
558 /// Sample less often below 10% and above 95% of success
559 if ((m_minstrelTable[i].ewmaProb > 17100) || (m_minstrelTable[i].ewmaProb < 1800))
562 * retry count denotes the number of retries permitted for each rate
565 m_minstrelTable[i].adjustedRetryCount = m_minstrelTable[i].retryCount >> 1;
566 if (m_minstrelTable[i].adjustedRetryCount > 2)
568 m_minstrelTable[i].adjustedRetryCount = 2 ;
573 m_minstrelTable[i].adjustedRetryCount = m_minstrelTable[i].retryCount;
576 /// if it's 0 allow one retry limit
577 if (m_minstrelTable[i].adjustedRetryCount == 0)
579 m_minstrelTable[i].adjustedRetryCount = 1;
584 uint32_t max_prob = 0, index_max_prob =0, max_tp =0, index_max_tp=0, index_max_tp2=0;
586 /// go find max throughput, second maximum throughput, high probability succ
587 for (uint32_t i =0; i < GetNSupportedModes (); i++)
589 NS_LOG_DEBUG ("throughput" << m_minstrelTable[i].throughput << "\n ewma" << m_minstrelTable[i].ewmaProb);
591 if (max_tp < m_minstrelTable[i].throughput)
594 max_tp = m_minstrelTable[i].throughput;
597 if (max_prob < m_minstrelTable[i].ewmaProb)
600 max_prob = m_minstrelTable[i].ewmaProb;
606 /// find the second highest max
607 for (uint32_t i =0; i < GetNSupportedModes (); i++)
609 if ((i != index_max_tp) && (max_tp < m_minstrelTable[i].throughput))
612 max_tp = m_minstrelTable[i].throughput;
616 m_maxTpRate = index_max_tp;
617 m_maxTpRate2 = index_max_tp2;
618 m_maxProbRate = index_max_prob;
619 m_currentRate = index_max_tp;
621 if (index_max_tp > m_txrate)
623 m_txrate= index_max_tp;
626 NS_LOG_DEBUG ("max tp="<< index_max_tp << "\nmax tp2="<< index_max_tp2<< "\nmax prob="<< index_max_prob);
633 MinstrelWifiRemoteStation::RateInit ()
635 NS_LOG_DEBUG ("RateInit="<<this);
637 for (uint32_t i = 0; i < GetNSupportedModes (); i++)
639 m_minstrelTable[i].numRateAttempt = 0;
640 m_minstrelTable[i].numRateSuccess = 0;
641 m_minstrelTable[i].prob = 0;
642 m_minstrelTable[i].ewmaProb = 0;
643 m_minstrelTable[i].prevNumRateAttempt = 0;
644 m_minstrelTable[i].prevNumRateSuccess = 0;
645 m_minstrelTable[i].successHist = 0;
646 m_minstrelTable[i].attemptHist = 0;
647 m_minstrelTable[i].throughput = 0;
648 m_minstrelTable[i].perfectTxTime = m_stations->GetCalcTxTime (GetSupportedMode (i));
649 m_minstrelTable[i].retryCount =1;
650 m_minstrelTable[i].adjustedRetryCount =1;
655 MinstrelWifiRemoteStation::InitSampleTable ()
657 NS_LOG_DEBUG ("InitSampleTable="<<this);
661 /// for off-seting to make rates fall between 0 and numrates
662 uint32_t numSampleRates= GetNSupportedModes () - 1;
665 for (uint32_t col = 0; col < m_stations->m_sampleCol; col++)
667 for (uint32_t i = 0; i < numSampleRates; i++ )
671 * The next two lines basically tries to generate a random number
672 * between 0 and the number of available rates
674 UniformVariable uv (0, numSampleRates);
675 newIndex = (i + (uint32_t)uv.GetValue ()) % numSampleRates;
677 /// this loop is used for filling in other uninitilized places
678 while (m_sampleTable[newIndex][col] != 0)
680 newIndex = (newIndex + 1)%GetNSupportedModes ();
682 m_sampleTable[newIndex][col] = i+1;
689 MinstrelWifiRemoteStation::PrintSampleTable ()
691 NS_LOG_DEBUG ("PrintSampleTable="<<this );
693 uint32_t numSampleRates= GetNSupportedModes ();
694 for (uint32_t i=0; i < numSampleRates; i++)
696 for (uint32_t j=0; j < m_stations->m_sampleCol; j++)
698 std::cout << m_sampleTable[i][j] << "\t";
700 std::cout << std::endl;
705 MinstrelWifiRemoteStation::PrintTable ()
707 NS_LOG_DEBUG ("PrintTable="<<this);
709 for (uint32_t i=0; i < GetNSupportedModes (); i++)
711 std::cout << "index(" << i << ") = " << m_minstrelTable[i].perfectTxTime<< "\n";