add an implementation of the minstrel rate control algorithm
This commit is contained in:
720
src/devices/wifi/minstrel-wifi-manager.cc
Normal file
720
src/devices/wifi/minstrel-wifi-manager.cc
Normal file
@@ -0,0 +1,720 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 Duy Nguyen
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Duy Nguyen <duy@soe.ucsc.edu>
|
||||
*
|
||||
* Some Comments:
|
||||
*
|
||||
* 1) Segment Size is declared for completeness but not used because it has
|
||||
* to do more with the requirement of the specific hardware.
|
||||
*
|
||||
* 2) By default, Minstrel applies the multi-rate retry(the core of Minstrel
|
||||
* algorithm). Otherwise, please use ConstantRateWifiManager instead.
|
||||
*
|
||||
* http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/minstrel
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#include "minstrel-wifi-manager.h"
|
||||
#include "wifi-phy.h"
|
||||
#include "ns3/random-variable.h"
|
||||
#include "ns3/simulator.h"
|
||||
#include "ns3/log.h"
|
||||
#include "ns3/uinteger.h"
|
||||
#include "ns3/double.h"
|
||||
#include "ns3/wifi-mac.h"
|
||||
#include "ns3/assert.h"
|
||||
#include <vector>
|
||||
|
||||
NS_LOG_COMPONENT_DEFINE ("MinstrelWifiManager");
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
NS_OBJECT_ENSURE_REGISTERED (MinstrelWifiManager);
|
||||
|
||||
TypeId
|
||||
MinstrelWifiManager::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::MinstrelWifiManager")
|
||||
.SetParent<WifiRemoteStationManager> ()
|
||||
.AddConstructor<MinstrelWifiManager> ()
|
||||
.AddAttribute ("UpdateStatistics",
|
||||
"The interval between updating statistics table ",
|
||||
TimeValue (Seconds (0.1)),
|
||||
MakeTimeAccessor (&MinstrelWifiManager::m_updateStats),
|
||||
MakeTimeChecker ())
|
||||
.AddAttribute ("LookAroundRate",
|
||||
"the percentage to try other rates",
|
||||
DoubleValue (10),
|
||||
MakeDoubleAccessor (&MinstrelWifiManager::m_lookAroundRate),
|
||||
MakeDoubleChecker<double> ())
|
||||
.AddAttribute ("EWMA",
|
||||
"EWMA level",
|
||||
DoubleValue (75),
|
||||
MakeDoubleAccessor (&MinstrelWifiManager::m_ewmaLevel),
|
||||
MakeDoubleChecker<double> ())
|
||||
.AddAttribute ("SegmentSize",
|
||||
"The largest allowable segment size packet",
|
||||
DoubleValue (6000),
|
||||
MakeDoubleAccessor (&MinstrelWifiManager::m_segmentSize),
|
||||
MakeDoubleChecker <double> ())
|
||||
.AddAttribute ("SampleColumn",
|
||||
"The number of columns used for sampling",
|
||||
DoubleValue (10),
|
||||
MakeDoubleAccessor (&MinstrelWifiManager::m_sampleCol),
|
||||
MakeDoubleChecker <double> ())
|
||||
.AddAttribute ("PacketLength",
|
||||
"The packet length used for calculating mode TxTime",
|
||||
DoubleValue (1200),
|
||||
MakeDoubleAccessor (&MinstrelWifiManager::m_pktLen),
|
||||
MakeDoubleChecker <double> ())
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
MinstrelWifiManager::MinstrelWifiManager ()
|
||||
{}
|
||||
|
||||
MinstrelWifiManager::~MinstrelWifiManager ()
|
||||
{}
|
||||
|
||||
void
|
||||
MinstrelWifiManager::SetupPhy (Ptr<WifiPhy> phy)
|
||||
{
|
||||
uint32_t nModes = phy->GetNModes ();
|
||||
for (uint32_t i = 0; i < nModes; i++)
|
||||
{
|
||||
WifiMode mode = phy->GetMode (i);
|
||||
AddCalcTxTime (mode, phy->CalculateTxDuration (m_pktLen, mode, WIFI_PREAMBLE_LONG));
|
||||
}
|
||||
WifiRemoteStationManager::SetupPhy (phy);
|
||||
}
|
||||
|
||||
WifiRemoteStation *
|
||||
MinstrelWifiManager::CreateStation (void)
|
||||
{
|
||||
return new MinstrelWifiRemoteStation (this);
|
||||
}
|
||||
|
||||
Time
|
||||
MinstrelWifiManager::GetCalcTxTime (WifiMode mode) const
|
||||
{
|
||||
|
||||
for (TxTime::const_iterator i = m_calcTxTime.begin (); i != m_calcTxTime.end (); i++)
|
||||
{
|
||||
if (mode == i->second)
|
||||
{
|
||||
return i->first;
|
||||
}
|
||||
}
|
||||
NS_ASSERT (false);
|
||||
return Seconds (0);
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiManager::AddCalcTxTime (WifiMode mode, Time t)
|
||||
{
|
||||
m_calcTxTime.push_back (std::make_pair (t, mode));
|
||||
}
|
||||
|
||||
MinstrelWifiRemoteStation::MinstrelWifiRemoteStation (Ptr<MinstrelWifiManager> stations)
|
||||
:m_stations (stations),
|
||||
m_nextStatsUpdate (Simulator::Now () + stations->m_updateStats),
|
||||
m_col (0),
|
||||
m_index (0),
|
||||
m_maxTpRate (0),
|
||||
m_maxTpRate2 (0),
|
||||
m_maxProbRate (0),
|
||||
m_packetCount (0),
|
||||
m_sampleCount (0),
|
||||
m_isSampling (false),
|
||||
m_sampleRate (0),
|
||||
m_sampleRateSlower (false),
|
||||
m_currentRate (0),
|
||||
m_shortRetry (0),
|
||||
m_longRetry (0),
|
||||
m_retry (0),
|
||||
m_err (0),
|
||||
m_txrate (0),
|
||||
m_initialized (false)
|
||||
{}
|
||||
|
||||
MinstrelWifiRemoteStation::~MinstrelWifiRemoteStation ()
|
||||
{}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::CheckInit(void)
|
||||
{
|
||||
if (!m_initialized)
|
||||
{
|
||||
m_minstrelTable = MinstrelRate(GetNSupportedModes ());
|
||||
m_sampleTable = SampleRate(GetNSupportedModes (), std::vector<uint32_t> (m_stations->m_sampleCol));
|
||||
InitSampleTable ();
|
||||
RateInit ();
|
||||
m_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::DoReportRxOk (double rxSnr, WifiMode txMode)
|
||||
{
|
||||
NS_LOG_DEBUG("DoReportRxOk m_txrate=" << m_txrate);
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::DoReportRtsFailed (void)
|
||||
{
|
||||
NS_LOG_DEBUG("DoReportRtsFailed m_txrate=" << m_txrate);
|
||||
|
||||
m_shortRetry++;
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::DoReportRtsOk (double ctsSnr, WifiMode ctsMode, double rtsSnr)
|
||||
{
|
||||
NS_LOG_DEBUG ("self="<<this<<" rts ok");
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::DoReportFinalRtsFailed (void)
|
||||
{
|
||||
UpdateRetry ();
|
||||
m_err++;
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::DoReportDataFailed (void)
|
||||
{
|
||||
CheckInit();
|
||||
|
||||
m_longRetry++;
|
||||
|
||||
NS_LOG_DEBUG ("DoReportDataFailed " << this << "\t rate " << m_txrate << "\tlongRetry \t" << m_longRetry);
|
||||
|
||||
/// for normal rate, we're not currently sampling random rates
|
||||
if (!m_isSampling)
|
||||
{
|
||||
/// use best throughput rate
|
||||
if( m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
|
||||
{
|
||||
; ///< there's still a few retries left
|
||||
}
|
||||
|
||||
/// use second best throughput rate
|
||||
else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
|
||||
m_minstrelTable[m_maxTpRate].adjustedRetryCount))
|
||||
{
|
||||
m_txrate = m_maxTpRate2;
|
||||
}
|
||||
|
||||
/// use best probability rate
|
||||
else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
|
||||
m_minstrelTable[m_maxTpRate2].adjustedRetryCount +
|
||||
m_minstrelTable[m_maxTpRate].adjustedRetryCount))
|
||||
{
|
||||
m_txrate = m_maxProbRate;
|
||||
}
|
||||
|
||||
/// use lowest base rate
|
||||
else if (m_longRetry > (m_minstrelTable[m_txrate].adjustedRetryCount +
|
||||
m_minstrelTable[m_maxTpRate2].adjustedRetryCount +
|
||||
m_minstrelTable[m_maxTpRate].adjustedRetryCount))
|
||||
{
|
||||
m_txrate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// for look-around rate, we're currently sampling random rates
|
||||
else
|
||||
{
|
||||
/// current sampling rate is slower than the current best rate
|
||||
if (m_sampleRateSlower)
|
||||
{
|
||||
/// use best throughput rate
|
||||
if (m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
|
||||
{
|
||||
; ///< there are a few retries left
|
||||
}
|
||||
|
||||
/// use random rate
|
||||
else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
|
||||
m_minstrelTable[m_maxTpRate].adjustedRetryCount))
|
||||
{
|
||||
m_txrate = m_sampleRate;
|
||||
}
|
||||
|
||||
/// use max probability rate
|
||||
else if (m_longRetry <= (m_minstrelTable[m_txrate].adjustedRetryCount +
|
||||
m_minstrelTable[m_sampleRate].adjustedRetryCount +
|
||||
m_minstrelTable[m_maxTpRate].adjustedRetryCount ))
|
||||
{
|
||||
m_txrate = m_maxProbRate;
|
||||
}
|
||||
|
||||
/// use lowest base rate
|
||||
else if (m_longRetry > (m_minstrelTable[m_txrate].adjustedRetryCount +
|
||||
m_minstrelTable[m_sampleRate].adjustedRetryCount +
|
||||
m_minstrelTable[m_maxTpRate].adjustedRetryCount))
|
||||
{
|
||||
m_txrate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// current sampling rate is better than current best rate
|
||||
else
|
||||
{
|
||||
/// use random rate
|
||||
if (m_longRetry < m_minstrelTable[m_txrate].adjustedRetryCount)
|
||||
{
|
||||
; ///< keep using it
|
||||
}
|
||||
|
||||
/// use the best rate
|
||||
else if (m_longRetry <= m_minstrelTable[m_txrate].adjustedRetryCount +
|
||||
m_minstrelTable[m_sampleRate].adjustedRetryCount)
|
||||
{
|
||||
m_txrate = m_maxTpRate;
|
||||
}
|
||||
|
||||
/// use the best probability rate
|
||||
else if (m_longRetry <= m_minstrelTable[m_txrate].adjustedRetryCount +
|
||||
m_minstrelTable[m_maxTpRate].adjustedRetryCount +
|
||||
m_minstrelTable[m_sampleRate].adjustedRetryCount)
|
||||
{
|
||||
m_txrate = m_maxProbRate;
|
||||
}
|
||||
|
||||
/// use the lowest base rate
|
||||
else if (m_longRetry > m_minstrelTable[m_txrate].adjustedRetryCount +
|
||||
m_minstrelTable[m_maxTpRate].adjustedRetryCount +
|
||||
m_minstrelTable[m_sampleRate].adjustedRetryCount)
|
||||
{
|
||||
m_txrate = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::DoReportDataOk (double ackSnr, WifiMode ackMode, double dataSnr)
|
||||
{
|
||||
m_isSampling = false;
|
||||
m_sampleRateSlower=false;
|
||||
|
||||
CheckInit ();
|
||||
|
||||
m_minstrelTable[m_txrate].numRateSuccess++;
|
||||
m_minstrelTable[m_txrate].numRateAttempt++;
|
||||
|
||||
UpdateRetry ();
|
||||
|
||||
m_minstrelTable[m_txrate].numRateAttempt += m_retry;
|
||||
m_packetCount++;
|
||||
|
||||
if (GetNSupportedModes () >= 1)
|
||||
{
|
||||
m_txrate = FindRate ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::DoReportFinalDataFailed (void)
|
||||
{
|
||||
NS_LOG_DEBUG ("DoReportFinalDataFailed m_txrate=" << m_txrate);
|
||||
|
||||
m_isSampling = false;
|
||||
m_sampleRateSlower=false;
|
||||
|
||||
UpdateRetry ();
|
||||
|
||||
m_minstrelTable[m_txrate].numRateAttempt += m_retry;
|
||||
m_err++;
|
||||
|
||||
if (GetNSupportedModes () >= 1)
|
||||
{
|
||||
m_txrate = FindRate ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::UpdateRetry (void)
|
||||
{
|
||||
m_retry = m_shortRetry + m_longRetry;
|
||||
m_shortRetry = 0;
|
||||
m_longRetry = 0;
|
||||
}
|
||||
|
||||
Ptr<WifiRemoteStationManager>
|
||||
MinstrelWifiRemoteStation::GetManager (void) const
|
||||
{
|
||||
return m_stations;
|
||||
}
|
||||
|
||||
WifiMode
|
||||
MinstrelWifiRemoteStation::DoGetDataMode (uint32_t size)
|
||||
{
|
||||
UpdateStats ();
|
||||
if (!m_initialized)
|
||||
{
|
||||
CheckInit ();
|
||||
|
||||
/// start the rate at half way
|
||||
m_txrate = GetNSupportedModes () / 2;
|
||||
}
|
||||
return GetSupportedMode (m_txrate);
|
||||
}
|
||||
|
||||
WifiMode
|
||||
MinstrelWifiRemoteStation::DoGetRtsMode (void)
|
||||
{
|
||||
NS_LOG_DEBUG ("DoGetRtsMode m_txrate=" << m_txrate);
|
||||
|
||||
UpdateStats ();
|
||||
return GetSupportedMode (0);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MinstrelWifiRemoteStation::GetNextSample ()
|
||||
{
|
||||
uint32_t bitrate;
|
||||
bitrate = m_sampleTable[m_index][m_col];
|
||||
m_index++;
|
||||
|
||||
/// bookeeping for m_index and m_col variables
|
||||
if (m_index > (GetNSupportedModes () -2))
|
||||
{
|
||||
m_index =0;
|
||||
m_col++;
|
||||
if (m_col >= m_stations->m_sampleCol)
|
||||
{
|
||||
m_col = 0;
|
||||
}
|
||||
}
|
||||
return bitrate;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
MinstrelWifiRemoteStation::FindRate ()
|
||||
{
|
||||
NS_LOG_DEBUG ("FindRate " << "packet=" << m_packetCount );
|
||||
|
||||
if ((m_sampleCount + m_packetCount) == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
uint32_t idx;
|
||||
|
||||
/// for determining when to try a sample rate
|
||||
UniformVariable coinFlip (0, 100);
|
||||
|
||||
/**
|
||||
* if we are below the target of look around rate percentage, look around
|
||||
* note: do it randomly by flipping a coin instead sampling
|
||||
* all at once until it reaches the look around rate
|
||||
*/
|
||||
if ( (((100* m_sampleCount) / (m_sampleCount + m_packetCount )) < m_stations->m_lookAroundRate) &&
|
||||
((int)coinFlip.GetValue ()) % 2 == 1 )
|
||||
{
|
||||
|
||||
/// now go through the table and find an index rate
|
||||
idx = GetNextSample ();
|
||||
|
||||
|
||||
/**
|
||||
* This if condition is used to make sure that we don't need to use
|
||||
* the sample rate it is the same as our current rate
|
||||
*/
|
||||
if (idx != m_maxTpRate && idx != m_txrate)
|
||||
{
|
||||
|
||||
/// start sample count
|
||||
m_sampleCount++;
|
||||
|
||||
/// set flag that we are currently sampling
|
||||
m_isSampling = true;
|
||||
|
||||
/// bookeeping for resetting stuff
|
||||
if (m_packetCount >= 10000)
|
||||
{
|
||||
m_sampleCount = 0;
|
||||
m_packetCount = 0;
|
||||
}
|
||||
|
||||
/// error check
|
||||
if (idx >= GetNSupportedModes () || idx < 0 )
|
||||
{
|
||||
NS_LOG_DEBUG ("ALERT!!! ERROR");
|
||||
}
|
||||
|
||||
/// set the rate that we're currently sampling
|
||||
m_sampleRate = idx;
|
||||
|
||||
if (m_sampleRate == m_maxTpRate)
|
||||
{
|
||||
m_sampleRate = m_maxTpRate2;
|
||||
}
|
||||
|
||||
/// is this rate slower than the current best rate
|
||||
m_sampleRateSlower = (m_minstrelTable[idx].perfectTxTime > m_minstrelTable[m_maxTpRate].perfectTxTime);
|
||||
|
||||
/// using the best rate instead
|
||||
if (m_sampleRateSlower)
|
||||
{
|
||||
idx = m_maxTpRate;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// continue using the best rate
|
||||
else
|
||||
{
|
||||
idx = m_maxTpRate;
|
||||
}
|
||||
|
||||
|
||||
NS_LOG_DEBUG ("FindRate " << "sample rate=" << idx);
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::UpdateStats ()
|
||||
{
|
||||
if (Simulator::Now () < m_nextStatsUpdate)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
NS_LOG_DEBUG ("Updating stats="<<this);
|
||||
|
||||
m_nextStatsUpdate = Simulator::Now () + m_stations->m_updateStats;
|
||||
|
||||
Time txTime;
|
||||
uint32_t tempProb;
|
||||
|
||||
for (uint32_t i =0; i < GetNSupportedModes (); i++)
|
||||
{
|
||||
|
||||
/// calculate the perfect tx time for this rate
|
||||
txTime = m_minstrelTable[i].perfectTxTime;
|
||||
|
||||
/// just for initialization
|
||||
if (txTime.GetMicroSeconds () == 0)
|
||||
{
|
||||
txTime = Seconds (1);
|
||||
}
|
||||
|
||||
NS_LOG_DEBUG ("m_txrate=" << m_txrate << "\t attempt=" << m_minstrelTable[i].numRateAttempt << "\t success=" << m_minstrelTable[i].numRateSuccess);
|
||||
|
||||
/// if we've attempted something
|
||||
if (m_minstrelTable[i].numRateAttempt)
|
||||
{
|
||||
/**
|
||||
* calculate the probability of success
|
||||
* assume probability scales from 0 to 18000
|
||||
*/
|
||||
tempProb = (m_minstrelTable[i].numRateSuccess * 18000) / m_minstrelTable[i].numRateAttempt;
|
||||
|
||||
/// bookeeping
|
||||
m_minstrelTable[i].successHist += m_minstrelTable[i].numRateSuccess;
|
||||
m_minstrelTable[i].attemptHist += m_minstrelTable[i].numRateAttempt;
|
||||
m_minstrelTable[i].prob = tempProb;
|
||||
|
||||
/// ewma probability
|
||||
tempProb = ((tempProb * (100 - m_stations->m_ewmaLevel)) + (m_minstrelTable[i].ewmaProb * m_stations->m_ewmaLevel) )/100;
|
||||
|
||||
m_minstrelTable[i].ewmaProb = tempProb;
|
||||
|
||||
/// calculating throughput
|
||||
m_minstrelTable[i].throughput = tempProb * (1000000 / txTime.GetMicroSeconds());
|
||||
|
||||
}
|
||||
|
||||
/// bookeeping
|
||||
m_minstrelTable[i].prevNumRateAttempt= m_minstrelTable[i].numRateAttempt;
|
||||
m_minstrelTable[i].prevNumRateSuccess = m_minstrelTable[i].numRateSuccess;
|
||||
m_minstrelTable[i].numRateSuccess = 0;
|
||||
m_minstrelTable[i].numRateAttempt = 0;
|
||||
|
||||
/// Sample less often below 10% and above 95% of success
|
||||
if ((m_minstrelTable[i].ewmaProb > 17100) || (m_minstrelTable[i].ewmaProb < 1800))
|
||||
{
|
||||
/**
|
||||
* retry count denotes the number of retries permitted for each rate
|
||||
* # retry_count/2
|
||||
*/
|
||||
m_minstrelTable[i].adjustedRetryCount = m_minstrelTable[i].retryCount >> 1;
|
||||
if (m_minstrelTable[i].adjustedRetryCount > 2)
|
||||
{
|
||||
m_minstrelTable[i].adjustedRetryCount = 2 ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_minstrelTable[i].adjustedRetryCount = m_minstrelTable[i].retryCount;
|
||||
}
|
||||
|
||||
/// if it's 0 allow one retry limit
|
||||
if (m_minstrelTable[i].adjustedRetryCount == 0)
|
||||
{
|
||||
m_minstrelTable[i].adjustedRetryCount = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
uint32_t max_prob = 0, index_max_prob =0, max_tp =0, index_max_tp=0, index_max_tp2=0;
|
||||
|
||||
/// go find max throughput, second maximum throughput, high probability succ
|
||||
for (uint32_t i =0; i < GetNSupportedModes (); i++)
|
||||
{
|
||||
NS_LOG_DEBUG ("throughput" << m_minstrelTable[i].throughput << "\n ewma" << m_minstrelTable[i].ewmaProb);
|
||||
|
||||
if (max_tp < m_minstrelTable[i].throughput)
|
||||
{
|
||||
index_max_tp = i;
|
||||
max_tp = m_minstrelTable[i].throughput;
|
||||
}
|
||||
|
||||
if (max_prob < m_minstrelTable[i].ewmaProb)
|
||||
{
|
||||
index_max_prob = i;
|
||||
max_prob = m_minstrelTable[i].ewmaProb;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
max_tp = 0;
|
||||
/// find the second highest max
|
||||
for (uint32_t i =0; i < GetNSupportedModes (); i++)
|
||||
{
|
||||
if ((i != index_max_tp) && (max_tp < m_minstrelTable[i].throughput))
|
||||
{
|
||||
index_max_tp2 = i;
|
||||
max_tp = m_minstrelTable[i].throughput;
|
||||
}
|
||||
}
|
||||
|
||||
m_maxTpRate = index_max_tp;
|
||||
m_maxTpRate2 = index_max_tp2;
|
||||
m_maxProbRate = index_max_prob;
|
||||
m_currentRate = index_max_tp;
|
||||
|
||||
if (index_max_tp > m_txrate)
|
||||
{
|
||||
m_txrate= index_max_tp;
|
||||
}
|
||||
|
||||
NS_LOG_DEBUG ("max tp="<< index_max_tp << "\nmax tp2="<< index_max_tp2<< "\nmax prob="<< index_max_prob);
|
||||
|
||||
/// reset it
|
||||
RateInit ();
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::RateInit ()
|
||||
{
|
||||
NS_LOG_DEBUG ("RateInit="<<this);
|
||||
|
||||
for (uint32_t i = 0; i < GetNSupportedModes (); i++)
|
||||
{
|
||||
m_minstrelTable[i].numRateAttempt = 0;
|
||||
m_minstrelTable[i].numRateSuccess = 0;
|
||||
m_minstrelTable[i].prob = 0;
|
||||
m_minstrelTable[i].ewmaProb = 0;
|
||||
m_minstrelTable[i].prevNumRateAttempt = 0;
|
||||
m_minstrelTable[i].prevNumRateSuccess = 0;
|
||||
m_minstrelTable[i].successHist = 0;
|
||||
m_minstrelTable[i].attemptHist = 0;
|
||||
m_minstrelTable[i].throughput = 0;
|
||||
m_minstrelTable[i].perfectTxTime = m_stations->GetCalcTxTime (GetSupportedMode (i));
|
||||
m_minstrelTable[i].retryCount =1;
|
||||
m_minstrelTable[i].adjustedRetryCount =1;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::InitSampleTable ()
|
||||
{
|
||||
NS_LOG_DEBUG ("InitSampleTable="<<this);
|
||||
|
||||
m_col = m_index = 0;
|
||||
|
||||
/// for off-seting to make rates fall between 0 and numrates
|
||||
uint32_t numSampleRates= GetNSupportedModes () - 1;
|
||||
|
||||
uint32_t newIndex;
|
||||
for (uint32_t col = 0; col < m_stations->m_sampleCol; col++)
|
||||
{
|
||||
for (uint32_t i = 0; i < numSampleRates; i++ )
|
||||
{
|
||||
|
||||
/**
|
||||
* The next two lines basically tries to generate a random number
|
||||
* between 0 and the number of available rates
|
||||
*/
|
||||
UniformVariable uv (0, numSampleRates);
|
||||
newIndex = (i + (uint32_t)uv.GetValue ()) % numSampleRates;
|
||||
|
||||
/// this loop is used for filling in other uninitilized places
|
||||
while (m_sampleTable[newIndex][col] != 0)
|
||||
{
|
||||
newIndex = (newIndex + 1)%GetNSupportedModes ();
|
||||
}
|
||||
m_sampleTable[newIndex][col] = i+1;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::PrintSampleTable ()
|
||||
{
|
||||
NS_LOG_DEBUG ("PrintSampleTable="<<this );
|
||||
|
||||
uint32_t numSampleRates= GetNSupportedModes ();
|
||||
for (uint32_t i=0; i < numSampleRates; i++)
|
||||
{
|
||||
for (uint32_t j=0; j < m_stations->m_sampleCol; j++)
|
||||
{
|
||||
std::cout << m_sampleTable[i][j] << "\t";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MinstrelWifiRemoteStation::PrintTable ()
|
||||
{
|
||||
NS_LOG_DEBUG ("PrintTable="<<this);
|
||||
|
||||
for (uint32_t i=0; i < GetNSupportedModes (); i++)
|
||||
{
|
||||
std::cout << "index(" << i << ") = " << m_minstrelTable[i].perfectTxTime<< "\n";
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
255
src/devices/wifi/minstrel-wifi-manager.h
Normal file
255
src/devices/wifi/minstrel-wifi-manager.h
Normal file
@@ -0,0 +1,255 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2009 Duy Nguyen
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Duy Nguyen <duy@soe.ucsc.edu>
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifndef MINSTREL_WIFI_MANAGER_H
|
||||
#define MINSTREL_WIFI_MANAGER_H
|
||||
|
||||
#include "wifi-remote-station-manager.h"
|
||||
#include "wifi-mode.h"
|
||||
#include "ns3/nstime.h"
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* \author Duy Nguyen
|
||||
* \brief Implementation of Minstrel Rate Control Algorithm
|
||||
*
|
||||
* Porting Minstrel from Madwifi and Linux Kernel
|
||||
* http://linuxwireless.org/en/developers/Documentation/mac80211/RateControl/minstrel
|
||||
*/
|
||||
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
/**
|
||||
* A struct to contain all information related to a data rate
|
||||
*/
|
||||
struct RateInfo{
|
||||
|
||||
/**
|
||||
* Perfect transmission time calculation, or frame calculation
|
||||
* Given a bit rate and a packet length n bytes
|
||||
*/
|
||||
Time perfectTxTime;
|
||||
|
||||
|
||||
uint32_t retryCount; ///< retry limit
|
||||
uint32_t adjustedRetryCount; ///< adjust the retry limit for this rate
|
||||
uint32_t numRateAttempt; ///< how many number of attempts so far
|
||||
uint32_t numRateSuccess; ///< number of successful pkts
|
||||
uint32_t prob; ///< (# pkts success )/(# total pkts)
|
||||
|
||||
/**
|
||||
* EWMA calculation
|
||||
* ewma_prob =[prob *(100 - ewma_level) + (ewma_prob_old * ewma_level)]/100
|
||||
*/
|
||||
uint32_t ewmaProb;
|
||||
|
||||
uint32_t prevNumRateAttempt; ///< from last rate
|
||||
uint32_t prevNumRateSuccess; ///< from last rate
|
||||
uint64_t successHist; ///< aggregate of all successes
|
||||
uint64_t attemptHist; ///< aggregate of all attempts
|
||||
uint32_t throughput; ///< throughput of a rate
|
||||
};
|
||||
|
||||
/**
|
||||
* Data structure for a Minstrel Rate table
|
||||
* A vector of a struct RateInfo
|
||||
*/
|
||||
typedef std::vector<struct RateInfo> MinstrelRate;
|
||||
|
||||
/**
|
||||
* Data structure for a Sample Rate table
|
||||
* A vector of a vector uint32_t
|
||||
*/
|
||||
typedef std::vector<std::vector<uint32_t> > SampleRate;
|
||||
|
||||
|
||||
class MinstrelWifiManager : public WifiRemoteStationManager
|
||||
{
|
||||
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
MinstrelWifiManager ();
|
||||
virtual ~MinstrelWifiManager();
|
||||
|
||||
virtual void SetupPhy (Ptr<WifiPhy> phy);
|
||||
|
||||
/// for estimating the TxTime of a packet with a given mode
|
||||
Time GetCalcTxTime (WifiMode mode) const;
|
||||
void AddCalcTxTime (WifiMode mode, Time t);
|
||||
|
||||
private:
|
||||
friend class MinstrelWifiRemoteStation;
|
||||
virtual class WifiRemoteStation *CreateStation (void);
|
||||
|
||||
typedef std::vector<std::pair<Time,WifiMode> > TxTime;
|
||||
|
||||
TxTime m_calcTxTime; ///< to hold all the calculated TxTime for all modes
|
||||
Time m_updateStats; ///< how frequent do we calculate the stats(1/10 seconds)
|
||||
double m_lookAroundRate; ///< the % to try other rates than our current rate
|
||||
double m_ewmaLevel; ///< exponential weighted moving average
|
||||
uint32_t m_segmentSize; ///< largest allowable segment size
|
||||
uint32_t m_sampleCol; ///< number of sample columns
|
||||
uint32_t m_pktLen; ///< packet length used for calculate mode TxTime
|
||||
|
||||
};
|
||||
|
||||
class MinstrelWifiRemoteStation : public WifiRemoteStation
|
||||
{
|
||||
public:
|
||||
MinstrelWifiRemoteStation (Ptr<MinstrelWifiManager> stations);
|
||||
|
||||
virtual ~MinstrelWifiRemoteStation ();
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* when packet is successfully received
|
||||
* see wifi-remote-station-manager.h for more documentation
|
||||
*/
|
||||
virtual void DoReportRxOk (double rxSnr, WifiMode txMode);
|
||||
|
||||
/// when RTS timeout expires
|
||||
virtual void DoReportRtsFailed (void);
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* Retry Chain table is implemented here
|
||||
*
|
||||
* Try | LOOKAROUND RATE | NORMAL RATE
|
||||
* | random < best | random > best |
|
||||
* --------------------------------------------------------------
|
||||
* 1 | Best throughput | Random rate | Best throughput
|
||||
* 2 | Random rate | Best throughput | Next best throughput
|
||||
* 3 | Best probability | Best probability | Best probability
|
||||
* 4 | Lowest Baserate | Lowest baserate | Lowest baserate
|
||||
*
|
||||
* Note: For clarity, multiple blocks of if's and else's are used
|
||||
* After a failing 7 times, DoReportFinalDataFailed will be called
|
||||
*/
|
||||
virtual void DoReportDataFailed (void);
|
||||
|
||||
/// when receive a CTS, associated with an RTS
|
||||
virtual void DoReportRtsOk (double ctsSnr, WifiMode ctsMode, double rtsSnr);
|
||||
|
||||
/// when an ACK, associated with a data pkt, is received
|
||||
virtual void DoReportDataOk (double ackSnr, WifiMode ackMode, double dataSnr);
|
||||
|
||||
/// after calling ReportRtsFailed if NeedRtsRetransmission returns false
|
||||
virtual void DoReportFinalRtsFailed (void);
|
||||
|
||||
/// after calling ReportDataFailed if NeedDataRetransmission returns false
|
||||
virtual void DoReportFinalDataFailed (void);
|
||||
|
||||
|
||||
private:
|
||||
virtual Ptr<WifiRemoteStationManager> GetManager (void) const;
|
||||
|
||||
/**
|
||||
* returns the transmission mode for sending this packet
|
||||
* this function gets called when node is getting ready to send DATA
|
||||
* see wifi-remote-station-manager.h for more documentation
|
||||
*/
|
||||
virtual WifiMode DoGetDataMode (uint32_t size);
|
||||
|
||||
/// returns the transmission mode for sending RTS packet
|
||||
virtual WifiMode DoGetRtsMode (void);
|
||||
|
||||
/// update the number of retries and reset accordingly
|
||||
void UpdateRetry (void);
|
||||
|
||||
/// getting the next sample from Sample Table
|
||||
uint32_t GetNextSample (void);
|
||||
|
||||
/// find a rate to use from Minstrel Table
|
||||
uint32_t FindRate (void);
|
||||
|
||||
/// updating the Minstrel Table every 1/10 seconds
|
||||
void UpdateStats (void);
|
||||
|
||||
/// initialize Minstrel Table
|
||||
void RateInit (void);
|
||||
|
||||
/// initialize Sample Table
|
||||
void InitSampleTable (void);
|
||||
|
||||
/// printing Sample Table
|
||||
void PrintSampleTable (void);
|
||||
|
||||
/// printing Minstrel Table
|
||||
void PrintTable (void);
|
||||
|
||||
/**
|
||||
* \param packet lenghth
|
||||
* \param current WifiMode
|
||||
* \returns calcuated transmit duration
|
||||
*/
|
||||
Time CalcRatePacket (uint32_t, WifiMode);
|
||||
|
||||
void CheckInit(void); ///< check for initializations
|
||||
|
||||
Ptr<MinstrelWifiManager> m_stations;
|
||||
|
||||
Time m_nextStatsUpdate; ///< 10 times every second
|
||||
|
||||
MinstrelRate m_minstrelTable; ///< minstrel table
|
||||
|
||||
SampleRate m_sampleTable; ///< sample table
|
||||
|
||||
/**
|
||||
* To keep track of the current position in the our random sample table
|
||||
* going row by row from 1st column until the 10th column(Minstrel defines 10)
|
||||
* then we wrap back to the row 1 col 1.
|
||||
* note: there are many other ways to do this.
|
||||
*/
|
||||
uint32_t m_col, m_index;
|
||||
|
||||
uint32_t m_maxTpRate; ///< the current throughput rate
|
||||
uint32_t m_maxTpRate2; ///< second highest throughput rate
|
||||
uint32_t m_maxProbRate; ///< rate with highest prob of success
|
||||
|
||||
int m_packetCount; ///< total number of packets as of now
|
||||
int m_sampleCount; ///< how many packets we have sample so far
|
||||
|
||||
bool m_isSampling; ///< a flag to indicate we are currently sampling
|
||||
uint32_t m_sampleRate; ///< current sample rate
|
||||
bool m_sampleRateSlower; ///< a flag to indicate sample rate is slower
|
||||
uint32_t m_currentRate; ///< current rate we are using
|
||||
|
||||
uint32_t m_shortRetry; ///< short retries such as control packts
|
||||
uint32_t m_longRetry; ///< long retries such as data packets
|
||||
uint32_t m_retry; ///< total retries short + long
|
||||
uint32_t m_err; ///< retry errors
|
||||
uint32_t m_txrate; ///< current transmit rate
|
||||
|
||||
bool m_initialized; ///< for initializing tables
|
||||
|
||||
|
||||
};
|
||||
|
||||
}// namespace ns3
|
||||
|
||||
#endif /* MINSTREL_WIFI_MANAGER_H */
|
||||
@@ -63,6 +63,7 @@ def build(bld):
|
||||
'msdu-aggregator.cc',
|
||||
'amsdu-subframe-header.cc',
|
||||
'msdu-standard-aggregator.cc',
|
||||
'minstrel-wifi-manager.cc',
|
||||
]
|
||||
headers = bld.new_task_gen('ns3header')
|
||||
headers.module = 'wifi'
|
||||
@@ -113,6 +114,7 @@ def build(bld):
|
||||
'dcf-manager.h',
|
||||
'mac-rx-middle.h',
|
||||
'mac-low.h',
|
||||
'minstrel-wifi-manager.h'
|
||||
]
|
||||
|
||||
if bld.env['ENABLE_GSL']:
|
||||
|
||||
Reference in New Issue
Block a user