Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
0002 /*
0003  * Copyright (c) 2019, Mellanox Technologies inc.  All rights reserved.
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     /* first stat */
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);