0001
0002
0003
0004
0005
0006 #include <linux/dim.h>
0007
0008 static int rdma_dim_step(struct dim *dim)
0009 {
0010 if (dim->tune_state == DIM_GOING_RIGHT) {
0011 if (dim->profile_ix == (RDMA_DIM_PARAMS_NUM_PROFILES - 1))
0012 return DIM_ON_EDGE;
0013 dim->profile_ix++;
0014 dim->steps_right++;
0015 }
0016 if (dim->tune_state == DIM_GOING_LEFT) {
0017 if (dim->profile_ix == 0)
0018 return DIM_ON_EDGE;
0019 dim->profile_ix--;
0020 dim->steps_left++;
0021 }
0022
0023 return DIM_STEPPED;
0024 }
0025
0026 static int rdma_dim_stats_compare(struct dim_stats *curr,
0027 struct dim_stats *prev)
0028 {
0029
0030 if (!prev->cpms)
0031 return DIM_STATS_SAME;
0032
0033 if (IS_SIGNIFICANT_DIFF(curr->cpms, prev->cpms))
0034 return (curr->cpms > prev->cpms) ? DIM_STATS_BETTER :
0035 DIM_STATS_WORSE;
0036
0037 if (IS_SIGNIFICANT_DIFF(curr->cpe_ratio, prev->cpe_ratio))
0038 return (curr->cpe_ratio > prev->cpe_ratio) ? DIM_STATS_BETTER :
0039 DIM_STATS_WORSE;
0040
0041 return DIM_STATS_SAME;
0042 }
0043
0044 static bool rdma_dim_decision(struct dim_stats *curr_stats, struct dim *dim)
0045 {
0046 int prev_ix = dim->profile_ix;
0047 u8 state = dim->tune_state;
0048 int stats_res;
0049 int step_res;
0050
0051 if (state != DIM_PARKING_ON_TOP && state != DIM_PARKING_TIRED) {
0052 stats_res = rdma_dim_stats_compare(curr_stats,
0053 &dim->prev_stats);
0054
0055 switch (stats_res) {
0056 case DIM_STATS_SAME:
0057 if (curr_stats->cpe_ratio <= 50 * prev_ix)
0058 dim->profile_ix = 0;
0059 break;
0060 case DIM_STATS_WORSE:
0061 dim_turn(dim);
0062 fallthrough;
0063 case DIM_STATS_BETTER:
0064 step_res = rdma_dim_step(dim);
0065 if (step_res == DIM_ON_EDGE)
0066 dim_turn(dim);
0067 break;
0068 }
0069 }
0070
0071 dim->prev_stats = *curr_stats;
0072
0073 return dim->profile_ix != prev_ix;
0074 }
0075
0076 void rdma_dim(struct dim *dim, u64 completions)
0077 {
0078 struct dim_sample *curr_sample = &dim->measuring_sample;
0079 struct dim_stats curr_stats;
0080 u32 nevents;
0081
0082 dim_update_sample_with_comps(curr_sample->event_ctr + 1, 0, 0,
0083 curr_sample->comp_ctr + completions,
0084 &dim->measuring_sample);
0085
0086 switch (dim->state) {
0087 case DIM_MEASURE_IN_PROGRESS:
0088 nevents = curr_sample->event_ctr - dim->start_sample.event_ctr;
0089 if (nevents < DIM_NEVENTS)
0090 break;
0091 dim_calc_stats(&dim->start_sample, curr_sample, &curr_stats);
0092 if (rdma_dim_decision(&curr_stats, dim)) {
0093 dim->state = DIM_APPLY_NEW_PROFILE;
0094 schedule_work(&dim->work);
0095 break;
0096 }
0097 fallthrough;
0098 case DIM_START_MEASURE:
0099 dim->state = DIM_MEASURE_IN_PROGRESS;
0100 dim_update_sample_with_comps(curr_sample->event_ctr, 0, 0,
0101 curr_sample->comp_ctr,
0102 &dim->start_sample);
0103 break;
0104 case DIM_APPLY_NEW_PROFILE:
0105 break;
0106 }
0107 }
0108 EXPORT_SYMBOL(rdma_dim);