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