/* * Recalculate statistics and counters of a given rate */ void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs) { if (unlikely(mrs->attempts > 0)) { mrs->sample_skipped = 0; mrs->cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); if (unlikely(!mrs->att_hist)) { mrs->prob_ewma = mrs->cur_prob; } else { /* update exponential weighted moving variance */ mrs->prob_ewmsd = minstrel_ewmsd(mrs->prob_ewmsd, mrs->cur_prob, mrs->prob_ewma, EWMA_LEVEL); /*update exponential weighted moving avarage */ mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma, mrs->cur_prob, EWMA_LEVEL); } mrs->att_hist += mrs->attempts; mrs->succ_hist += mrs->success; } else { mrs->sample_skipped++; } mrs->last_success = mrs->success; mrs->last_attempts = mrs->attempts; mrs->success = 0; mrs->attempts = 0; }
static void minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) { u8 tmp_tp_rate[MAX_THR_RATES]; u8 tmp_prob_rate = 0; u32 usecs; int i; for (i = 0; i < MAX_THR_RATES; i++) tmp_tp_rate[i] = 0; for (i = 0; i < mi->n_rates; i++) { struct minstrel_rate *mr = &mi->r[i]; struct minstrel_rate_stats *mrs = &mi->r[i].stats; usecs = mr->perfect_tx_time; if (!usecs) usecs = 1000000; if (unlikely(mrs->attempts > 0)) { mrs->sample_skipped = 0; mrs->cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); mrs->succ_hist += mrs->success; mrs->att_hist += mrs->attempts; mrs->probability = minstrel_ewma(mrs->probability, mrs->cur_prob, EWMA_LEVEL); } else mrs->sample_skipped++; mrs->last_success = mrs->success; mrs->last_attempts = mrs->attempts; mrs->success = 0; mrs->attempts = 0; /* Update throughput per rate, reset thr. below 10% success */ if (mrs->probability < MINSTREL_FRAC(10, 100)) mrs->cur_tp = 0; else mrs->cur_tp = mrs->probability * (1000000 / usecs); /* Sample less often below the 10% chance of success. * Sample less often above the 95% chance of success. */ if (mrs->probability > MINSTREL_FRAC(95, 100) || mrs->probability < MINSTREL_FRAC(10, 100)) { mr->adjusted_retry_count = mrs->retry_count >> 1; if (mr->adjusted_retry_count > 2) mr->adjusted_retry_count = 2; mr->sample_limit = 4; } else {
/* * Recalculate success probabilities and counters for a rate using EWMA */ static void minstrel_calc_rate_ewma(struct minstrel_rate_stats *mr) { if (unlikely(mr->attempts > 0)) { mr->sample_skipped = 0; mr->cur_prob = MINSTREL_FRAC(mr->success, mr->attempts); if (!mr->att_hist) mr->probability = mr->cur_prob; else mr->probability = minstrel_ewma(mr->probability, mr->cur_prob, EWMA_LEVEL); mr->att_hist += mr->attempts; mr->succ_hist += mr->success; } else { mr->sample_skipped++; } mr->last_success = mr->success; mr->last_attempts = mr->attempts; mr->success = 0; mr->attempts = 0; }
/* * Update rate statistics and select new primary rates * * Rules for rate selection: * - max_prob_rate must use only one stream, as a tradeoff between delivery * probability and throughput during strong fluctuations * - as long as the max prob rate has a probability of more than 75%, pick * higher throughput rates, even if the probablity is a bit lower */ static void minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) { struct minstrel_mcs_group_data *mg; struct minstrel_rate_stats *mrs; int group, i, j, cur_prob; u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; u16 tmp_cck_tp_rate[MAX_THR_RATES], index; if (mi->ampdu_packets > 0) { mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL); mi->ampdu_len = 0; mi->ampdu_packets = 0; } mi->sample_slow = 0; mi->sample_count = 0; /* Initialize global rate indexes */ for(j = 0; j < MAX_THR_RATES; j++){ tmp_mcs_tp_rate[j] = 0; tmp_cck_tp_rate[j] = 0; } /* Find best rate sets within all MCS groups*/ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { mg = &mi->groups[group]; if (!mg->supported) continue; mi->sample_count++; /* (re)Initialize group rate indexes */ for(j = 0; j < MAX_THR_RATES; j++) tmp_group_tp_rate[j] = group; for (i = 0; i < MCS_GROUP_RATES; i++) { if (!(mg->supported & BIT(i))) continue; index = MCS_GROUP_RATES * group + i; mrs = &mg->rates[i]; mrs->retry_updated = false; minstrel_calc_rate_stats(mrs); cur_prob = mrs->prob_ewma; if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0) continue; /* Find max throughput rate set */ if (group != MINSTREL_CCK_GROUP) { minstrel_ht_sort_best_tp_rates(mi, index, tmp_mcs_tp_rate); } else if (group == MINSTREL_CCK_GROUP) { minstrel_ht_sort_best_tp_rates(mi, index, tmp_cck_tp_rate); } /* Find max throughput rate set within a group */ minstrel_ht_sort_best_tp_rates(mi, index, tmp_group_tp_rate); /* Find max probability rate per group and global */ minstrel_ht_set_best_prob_rate(mi, index); } memcpy(mg->max_group_tp_rate, tmp_group_tp_rate, sizeof(mg->max_group_tp_rate)); } /* Assign new rate set per sta */ minstrel_ht_assign_best_tp_rates(mi, tmp_mcs_tp_rate, tmp_cck_tp_rate); memcpy(mi->max_tp_rate, tmp_mcs_tp_rate, sizeof(mi->max_tp_rate)); /* Try to increase robustness of max_prob_rate*/ minstrel_ht_prob_rate_reduce_streams(mi); /* try to sample all available rates during each interval */ mi->sample_count *= 8; #ifdef CONFIG_MAC80211_DEBUGFS /* use fixed index if set */ if (mp->fixed_rate_idx != -1) { for (i = 0; i < 4; i++) mi->max_tp_rate[i] = mp->fixed_rate_idx; mi->max_prob_rate = mp->fixed_rate_idx; } #endif /* Reset update timer */ mi->last_stats_update = jiffies; }
/* * Update rate statistics and select new primary rates * * Rules for rate selection: * - max_prob_rate must use only one stream, as a tradeoff between delivery * probability and throughput during strong fluctuations * - as long as the max prob rate has a probability of more than 3/4, pick * higher throughput rates, even if the probablity is a bit lower */ static void minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) { struct minstrel_mcs_group_data *mg; struct minstrel_rate_stats *mr; int cur_prob, cur_prob_tp, cur_tp, cur_tp2; int group, i, index; bool mi_rates_valid = false; if (mi->ampdu_packets > 0) { mi->avg_ampdu_len = minstrel_ewma(mi->avg_ampdu_len, MINSTREL_FRAC(mi->ampdu_len, mi->ampdu_packets), EWMA_LEVEL); mi->ampdu_len = 0; mi->ampdu_packets = 0; } mi->sample_slow = 0; mi->sample_count = 0; for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { bool mg_rates_valid = false; cur_prob = 0; cur_prob_tp = 0; cur_tp = 0; cur_tp2 = 0; mg = &mi->groups[group]; if (!mg->supported) continue; mi->sample_count++; for (i = 0; i < MCS_GROUP_RATES; i++) { if (!(mg->supported & BIT(i))) continue; index = MCS_GROUP_RATES * group + i; /* initialize rates selections starting indexes */ if (!mg_rates_valid) { mg->max_tp_rate = mg->max_tp_rate2 = mg->max_prob_rate = i; if (!mi_rates_valid) { mi->max_tp_rate = mi->max_tp_rate2 = mi->max_prob_rate = index; mi_rates_valid = true; } mg_rates_valid = true; } mr = &mg->rates[i]; mr->retry_updated = false; minstrel_calc_rate_ewma(mr); minstrel_ht_calc_tp(mi, group, i); if (!mr->cur_tp) continue; if ((mr->cur_tp > cur_prob_tp && mr->probability > MINSTREL_FRAC(3, 4)) || mr->probability > cur_prob) { mg->max_prob_rate = index; cur_prob = mr->probability; cur_prob_tp = mr->cur_tp; } if (mr->cur_tp > cur_tp) { swap(index, mg->max_tp_rate); cur_tp = mr->cur_tp; mr = minstrel_get_ratestats(mi, index); } if (index >= mg->max_tp_rate) continue; if (mr->cur_tp > cur_tp2) { mg->max_tp_rate2 = index; cur_tp2 = mr->cur_tp; } } } /* try to sample all available rates during each interval */ mi->sample_count *= 8; cur_prob = 0; cur_prob_tp = 0; cur_tp = 0; cur_tp2 = 0; for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { mg = &mi->groups[group]; if (!mg->supported) continue; mr = minstrel_get_ratestats(mi, mg->max_tp_rate); if (cur_tp < mr->cur_tp) { mi->max_tp_rate2 = mi->max_tp_rate; cur_tp2 = cur_tp; mi->max_tp_rate = mg->max_tp_rate; cur_tp = mr->cur_tp; mi->max_prob_streams = minstrel_mcs_groups[group].streams - 1; } mr = minstrel_get_ratestats(mi, mg->max_tp_rate2); if (cur_tp2 < mr->cur_tp) { mi->max_tp_rate2 = mg->max_tp_rate2; cur_tp2 = mr->cur_tp; } } if (mi->max_prob_streams < 1) mi->max_prob_streams = 1; for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { mg = &mi->groups[group]; if (!mg->supported) continue; mr = minstrel_get_ratestats(mi, mg->max_prob_rate); if (cur_prob_tp < mr->cur_tp && minstrel_mcs_groups[group].streams <= mi->max_prob_streams) { mi->max_prob_rate = mg->max_prob_rate; cur_prob = mr->cur_prob; cur_prob_tp = mr->cur_tp; } } #ifdef CPTCFG_MAC80211_DEBUGFS /* use fixed index if set */ if (mp->fixed_rate_idx != -1) { mi->max_tp_rate = mp->fixed_rate_idx; mi->max_tp_rate2 = mp->fixed_rate_idx; mi->max_prob_rate = mp->fixed_rate_idx; } #endif mi->stats_update = jiffies; }