hc
2025-02-14 bbb9540dc49f70f6b703d1c8d1b85fa5f602d86e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
// SPDX-License-Identifier: GPL-2.0 OR Linux-OpenIB
/*
 * Copyright (c) 2019, Mellanox Technologies inc.  All rights reserved.
 */
 
#include <linux/dim.h>
 
static int rdma_dim_step(struct dim *dim)
{
   if (dim->tune_state == DIM_GOING_RIGHT) {
       if (dim->profile_ix == (RDMA_DIM_PARAMS_NUM_PROFILES - 1))
           return DIM_ON_EDGE;
       dim->profile_ix++;
       dim->steps_right++;
   }
   if (dim->tune_state == DIM_GOING_LEFT) {
       if (dim->profile_ix == 0)
           return DIM_ON_EDGE;
       dim->profile_ix--;
       dim->steps_left++;
   }
 
   return DIM_STEPPED;
}
 
static int rdma_dim_stats_compare(struct dim_stats *curr,
                 struct dim_stats *prev)
{
   /* first stat */
   if (!prev->cpms)
       return DIM_STATS_SAME;
 
   if (IS_SIGNIFICANT_DIFF(curr->cpms, prev->cpms))
       return (curr->cpms > prev->cpms) ? DIM_STATS_BETTER :
                       DIM_STATS_WORSE;
 
   if (IS_SIGNIFICANT_DIFF(curr->cpe_ratio, prev->cpe_ratio))
       return (curr->cpe_ratio > prev->cpe_ratio) ? DIM_STATS_BETTER :
                       DIM_STATS_WORSE;
 
   return DIM_STATS_SAME;
}
 
static bool rdma_dim_decision(struct dim_stats *curr_stats, struct dim *dim)
{
   int prev_ix = dim->profile_ix;
   u8 state = dim->tune_state;
   int stats_res;
   int step_res;
 
   if (state != DIM_PARKING_ON_TOP && state != DIM_PARKING_TIRED) {
       stats_res = rdma_dim_stats_compare(curr_stats,
                          &dim->prev_stats);
 
       switch (stats_res) {
       case DIM_STATS_SAME:
           if (curr_stats->cpe_ratio <= 50 * prev_ix)
               dim->profile_ix = 0;
           break;
       case DIM_STATS_WORSE:
           dim_turn(dim);
           /* fall through */
       case DIM_STATS_BETTER:
           step_res = rdma_dim_step(dim);
           if (step_res == DIM_ON_EDGE)
               dim_turn(dim);
           break;
       }
   }
 
   dim->prev_stats = *curr_stats;
 
   return dim->profile_ix != prev_ix;
}
 
void rdma_dim(struct dim *dim, u64 completions)
{
   struct dim_sample *curr_sample = &dim->measuring_sample;
   struct dim_stats curr_stats;
   u32 nevents;
 
   dim_update_sample_with_comps(curr_sample->event_ctr + 1, 0, 0,
                    curr_sample->comp_ctr + completions,
                    &dim->measuring_sample);
 
   switch (dim->state) {
   case DIM_MEASURE_IN_PROGRESS:
       nevents = curr_sample->event_ctr - dim->start_sample.event_ctr;
       if (nevents < DIM_NEVENTS)
           break;
       dim_calc_stats(&dim->start_sample, curr_sample, &curr_stats);
       if (rdma_dim_decision(&curr_stats, dim)) {
           dim->state = DIM_APPLY_NEW_PROFILE;
           schedule_work(&dim->work);
           break;
       }
       /* fall through */
   case DIM_START_MEASURE:
       dim->state = DIM_MEASURE_IN_PROGRESS;
       dim_update_sample_with_comps(curr_sample->event_ctr, 0, 0,
                        curr_sample->comp_ctr,
                        &dim->start_sample);
       break;
   case DIM_APPLY_NEW_PROFILE:
       break;
   }
}
EXPORT_SYMBOL(rdma_dim);