def apply_rate(cur_time): global currRate, npkts, nsuccess, NBYTES, NRETRIES remove_stale_results(cur_time) #"Increment the number of packets sent over the link" npkts += 1 #"If no packets have been successfully acknowledged, return the # highest bit-rate that has not had 4 successive failures." if nsuccess == 0: for i, r in sorted(rates.items(), reverse=True): if r.succFails < MAXFAILS: currRate = r.rate return [(ieee80211_to_idx(currRate), NRETRIES)] # Every 10 packets, select a random non-failing bit rate w/ better avg tx #"If the number of packets sent over the link is a multiple of ten," if (nsuccess != 0) and (npkts%10 == 0): #"select a random bit-rate from the bit-rates" cavgTX = rates[currRate].avgTX #" that have not failed four successive times and that #have a minimum packet transmission time lower than the #current bit-rate’s average transmission time." eligible = [r for i, r in rates.items() if r.losslessTX < cavgTX and r.succFails < MAXFAILS] if len(eligible) > 0: sampleRate = choice(eligible).rate #select random rate from eligible return [(ieee80211_to_idx(sampleRate), NRETRIES)] #"Otherwise, send packet at the bit-rate that has the lowest avg transmission time" # Trusts that currRate is properly maintained to be lowest avgTX return [(ieee80211_to_idx(currRate), NRETRIES)]
def apply_rate(cur_time): global currRate, npkts, nsuccess, NBYTES, NRETRIES remove_stale_results(cur_time) #"Increment the number of packets sent over the link" npkts += 1 #"If no packets have been successfully acknowledged, return the # highest bit-rate that has not had 4 successive failures." if nsuccess == 0: rrates = [r[1] for r in sorted(rates.items())] rrates.reverse() retry = [] for r in rrates: if r.succFails < 4: currRate = r.rate retry.append((ieee80211_to_idx(currRate), NRETRIES)) return retry # Every 10 packets, select a random non-failing bit rate w/ better avg tx #"If the number of packets sent over the link is a multiple of ten," if (nsuccess != 0) and (npkts % 10 == 0): #"select a random bit-rate from the bit-rates" cavgTX = rates[currRate].avgTX #" that have not failed four successive times and that #have a minimum packet transmission time lower than the #current bit-rate's average transmission time." eligible = [ r for i, r in rates.items() if r.losslessTX < cavgTX and r.succFails < 4 ] if len(eligible) > 0: sampleRate = choice( eligible).rate #select random rate from eligible return [(ieee80211_to_idx(sampleRate), NRETRIES)] #"Otherwise, send packet at the bit-rate that has the lowest avg transmission time" # Trusts that currRate is properly maintained to be lowest avgTX return [(ieee80211_to_idx(currRate), NRETRIES)]
import os import common RATE=float(os.environ["RATE"]) if "RATE" in os.environ else 1 # Read the rate as a Mbps value and convert it to an index try: IDX = common.ieee80211_to_idx(RATE) except ValueError: opts = [str(rate.dot11_rate / 2) for rate in common.RATES] print("Invalid rate. Options are: {}".format(", ".join(opts))) exit() else: print("Running at rate %r Mbps..." % RATE) def apply_rate(time): return [(IDX, 4)] * 4 def process_feedback(status, timestamp, delay, tries): pass
def bitrate_type(bitrate): return common.RATES[ieee80211_to_idx(bitrate)].phy
def tx_time(rate, length): #rate is Mbps, length in bytes return common.tx_time(ieee80211_to_idx(rate), length)
def apply_rate(cur_time): #cur_time is in nanoseconds global npkts, nsuccess, nlookaround, NBYTES, currRate, NRETRIES, np, nd global bestThruput, nextThruput, bestProb, lowestRate, time_last_called if cur_time - time_last_called >= 1e8: update_stats(cur_time) time_last_called = cur_time #Minstrel spends a particular percentage of frames, doing "look around" i.e. #randomly trying other rates, to gather statistics. The percentage of #"look around" frames defaults to 10%. The distribution of lookaround frames is #also randomized somewhat to avoid any potential "strobing" of lookaround #between similar nodes. #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 delta = (npkts*.1 - (np + nd/2.0)) if delta > 0: #random! #Analysis of information showed that the system was sampling too hard #at some rates. For those rates that never work (54mb, 500m range) #there is no point in sending 10 sample packets (< 6 ms time). Consequently, #for the very very low probability rates, we sample at most twice. if npkts >= 10000: np = 0 npkts = 0 nd = 0 elif delta > len(rates) * 2: '''FROM KERNEL COMMENTS: /* With multi-rate retry, not every planned sample * attempt actually gets used, due to the way the retry * chain is set up - [max_tp,sample,prob,lowest] for * sample_rate < max_tp. * * If there's too much sampling backlog and the link * starts getting worse, minstrel would start bursting * out lots of sampling frames, which would result * in a large throughput loss. */''' np += delta - (len(rates)*2) random = choice(list(rates)) while(random == 1): #never sample at lowest rate random = choice(list(rates)) if random < bestThruput: chain = [bestThruput, random, bestProb, lowestRate] ''' FROM KERNEL: /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark * packets that have the sampling rate deferred to the * second MRR stage. Increase the sample counter only * if the deferred sample rate was actually used. * Use the sample_deferred counter to make sure that * the sampling is not done in large bursts */''' probe_flag = True nd += 1 else: #manages probe counting if rates[random].sample_limit != 0: np += 1 if rates[random].sample_limit > 0: rates[random].sample_limit -= 1 chain = [random, bestThruput, bestProb, lowestRate] else: #normal chain = [bestThruput, nextThruput, bestProb, lowestRate] mrr = [(ieee80211_to_idx(rate), rates[rate].adjusted_retry_count) for rate in chain] return mrr
def apply_rate(cur_time): #cur_time is in nanoseconds global npkts, nsuccess, nlookaround, NBYTES, currRate, NRETRIES global bestThruput, nextThruput, bestProb, lowestRate, time_last_called if cur_time - time_last_called >= 1e8: update_stats(cur_time) time_last_called = cur_time #Minstrel spends a particular percentage of frames, doing "look around" i.e. #randomly trying other rates, to gather statistics. The percentage of #"look around" frames defaults to 10%. The distribution of lookaround frames is #also randomized somewhat to avoid any potential "strobing" of lookaround #between similar nodes. #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 if rates[bestThruput].tban > 4: #print("Temp ban on {}, switching to {}!".format(bestThruput, nextThruput)) rates[bestThruput].tban = 0 bestThruput = nextThruput nextThruput = bestProb if randint(1, 100) <= 10 or rates[bestThruput].tban > 4: #Analysis of information showed that the system was sampling too hard #at some rates. For those rates that never work (54mb, 500m range) #there is no point in sending 10 sample packets (< 6 ms time). Consequently, #for the very very low probability rates, we sample at most twice. random = choice(list(rates)) while (random == 1): #never sample at lowest rate random = choice(list(rates)) if random < bestThruput: r = [(ieee80211_to_idx(bestThruput), rates[bestThruput].adjusted_retry_count), (ieee80211_to_idx(random), rates[random].adjusted_retry_count), (ieee80211_to_idx(bestProb), rates[bestProb].adjusted_retry_count), (ieee80211_to_idx(lowestRate), rates[lowestRate].adjusted_retry_count)] else: #TODO: understand the corresponding kernel code more #and implement if (if necessary) if rates[random].sample_limit != 0: if rates[random].sample_limit > 0: rates[random].sample_limit -= 1 r = [(ieee80211_to_idx(random), rates[random].adjusted_retry_count), (ieee80211_to_idx(bestThruput), rates[bestThruput].adjusted_retry_count), (ieee80211_to_idx(bestProb), rates[bestProb].adjusted_retry_count), (ieee80211_to_idx(lowestRate), rates[lowestRate].adjusted_retry_count)] else: #normal r = [(ieee80211_to_idx(bestThruput), rates[bestThruput].adjusted_retry_count), (ieee80211_to_idx(nextThruput), rates[nextThruput].adjusted_retry_count), (ieee80211_to_idx(bestProb), rates[bestProb].adjusted_retry_count), (ieee80211_to_idx(lowestRate), rates[lowestRate].adjusted_retry_count)] return r
def apply_rate(cur_time): #cur_time is in nanoseconds global npkts, nsuccess, nlookaround, NBYTES, currRate, NRETRIES, np, nd global bestThruput, nextThruput, bestProb, lowestRate, time_last_called if cur_time - time_last_called >= 1e8: update_stats(cur_time) time_last_called = cur_time #Minstrel spends a particular percentage of frames, doing "look around" i.e. #randomly trying other rates, to gather statistics. The percentage of #"look around" frames defaults to 10%. The distribution of lookaround frames is #also randomized somewhat to avoid any potential "strobing" of lookaround #between similar nodes. #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 delta = (npkts * .1 - (np + nd / 2.0)) if delta > 0: #random! #Analysis of information showed that the system was sampling too hard #at some rates. For those rates that never work (54mb, 500m range) #there is no point in sending 10 sample packets (< 6 ms time). Consequently, #for the very very low probability rates, we sample at most twice. if npkts >= 10000: np = 0 npkts = 0 nd = 0 elif delta > len(rates) * 2: '''FROM KERNEL COMMENTS: /* With multi-rate retry, not every planned sample * attempt actually gets used, due to the way the retry * chain is set up - [max_tp,sample,prob,lowest] for * sample_rate < max_tp. * * If there's too much sampling backlog and the link * starts getting worse, minstrel would start bursting * out lots of sampling frames, which would result * in a large throughput loss. */''' np += delta - (len(rates) * 2) random = choice(list(rates)) while (random == 1): #never sample at lowest rate random = choice(list(rates)) if random < bestThruput: chain = [bestThruput, random, bestProb, lowestRate] ''' FROM KERNEL: /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark * packets that have the sampling rate deferred to the * second MRR stage. Increase the sample counter only * if the deferred sample rate was actually used. * Use the sample_deferred counter to make sure that * the sampling is not done in large bursts */''' probe_flag = True nd += 1 else: #manages probe counting if rates[random].sample_limit != 0: np += 1 if rates[random].sample_limit > 0: rates[random].sample_limit -= 1 chain = [random, bestThruput, bestProb, lowestRate] else: #normal chain = [bestThruput, nextThruput, bestProb, lowestRate] mrr = [(ieee80211_to_idx(rate), rates[rate].adjusted_retry_count) for rate in chain] return mrr