rdma_dim.c 2.6 KB

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