dynamic_queue_limits.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. /*
  2. * Dynamic byte queue limits. See include/linux/dynamic_queue_limits.h
  3. *
  4. * Copyright (c) 2011, Tom Herbert <therbert@google.com>
  5. */
  6. #include <linux/module.h>
  7. #include <linux/types.h>
  8. #include <linux/ctype.h>
  9. #include <linux/kernel.h>
  10. #include <linux/dynamic_queue_limits.h>
  11. #define POSDIFF(A, B) ((A) > (B) ? (A) - (B) : 0)
  12. /* Records completed count and recalculates the queue limit */
  13. void dql_completed(struct dql *dql, unsigned int count)
  14. {
  15. unsigned int inprogress, prev_inprogress, limit;
  16. unsigned int ovlimit, all_prev_completed, completed;
  17. /* Can't complete more than what's in queue */
  18. BUG_ON(count > dql->num_queued - dql->num_completed);
  19. completed = dql->num_completed + count;
  20. limit = dql->limit;
  21. ovlimit = POSDIFF(dql->num_queued - dql->num_completed, limit);
  22. inprogress = dql->num_queued - completed;
  23. prev_inprogress = dql->prev_num_queued - dql->num_completed;
  24. all_prev_completed = POSDIFF(completed, dql->prev_num_queued);
  25. if ((ovlimit && !inprogress) ||
  26. (dql->prev_ovlimit && all_prev_completed)) {
  27. /*
  28. * Queue considered starved if:
  29. * - The queue was over-limit in the last interval,
  30. * and there is no more data in the queue.
  31. * OR
  32. * - The queue was over-limit in the previous interval and
  33. * when enqueuing it was possible that all queued data
  34. * had been consumed. This covers the case when queue
  35. * may have becomes starved between completion processing
  36. * running and next time enqueue was scheduled.
  37. *
  38. * When queue is starved increase the limit by the amount
  39. * of bytes both sent and completed in the last interval,
  40. * plus any previous over-limit.
  41. */
  42. limit += POSDIFF(completed, dql->prev_num_queued) +
  43. dql->prev_ovlimit;
  44. dql->slack_start_time = jiffies;
  45. dql->lowest_slack = UINT_MAX;
  46. } else if (inprogress && prev_inprogress && !all_prev_completed) {
  47. /*
  48. * Queue was not starved, check if the limit can be decreased.
  49. * A decrease is only considered if the queue has been busy in
  50. * the whole interval (the check above).
  51. *
  52. * If there is slack, the amount of execess data queued above
  53. * the the amount needed to prevent starvation, the queue limit
  54. * can be decreased. To avoid hysteresis we consider the
  55. * minimum amount of slack found over several iterations of the
  56. * completion routine.
  57. */
  58. unsigned int slack, slack_last_objs;
  59. /*
  60. * Slack is the maximum of
  61. * - The queue limit plus previous over-limit minus twice
  62. * the number of objects completed. Note that two times
  63. * number of completed bytes is a basis for an upper bound
  64. * of the limit.
  65. * - Portion of objects in the last queuing operation that
  66. * was not part of non-zero previous over-limit. That is
  67. * "round down" by non-overlimit portion of the last
  68. * queueing operation.
  69. */
  70. slack = POSDIFF(limit + dql->prev_ovlimit,
  71. 2 * (completed - dql->num_completed));
  72. slack_last_objs = dql->prev_ovlimit ?
  73. POSDIFF(dql->prev_last_obj_cnt, dql->prev_ovlimit) : 0;
  74. slack = max(slack, slack_last_objs);
  75. if (slack < dql->lowest_slack)
  76. dql->lowest_slack = slack;
  77. if (time_after(jiffies,
  78. dql->slack_start_time + dql->slack_hold_time)) {
  79. limit = POSDIFF(limit, dql->lowest_slack);
  80. dql->slack_start_time = jiffies;
  81. dql->lowest_slack = UINT_MAX;
  82. }
  83. }
  84. /* Enforce bounds on limit */
  85. limit = clamp(limit, dql->min_limit, dql->max_limit);
  86. if (limit != dql->limit) {
  87. dql->limit = limit;
  88. ovlimit = 0;
  89. }
  90. dql->adj_limit = limit + completed;
  91. dql->prev_ovlimit = ovlimit;
  92. dql->prev_last_obj_cnt = dql->last_obj_cnt;
  93. dql->num_completed = completed;
  94. dql->prev_num_queued = dql->num_queued;
  95. }
  96. EXPORT_SYMBOL(dql_completed);
  97. void dql_reset(struct dql *dql)
  98. {
  99. /* Reset all dynamic values */
  100. dql->limit = 0;
  101. dql->num_queued = 0;
  102. dql->num_completed = 0;
  103. dql->last_obj_cnt = 0;
  104. dql->prev_num_queued = 0;
  105. dql->prev_last_obj_cnt = 0;
  106. dql->prev_ovlimit = 0;
  107. dql->lowest_slack = UINT_MAX;
  108. dql->slack_start_time = jiffies;
  109. }
  110. EXPORT_SYMBOL(dql_reset);
  111. int dql_init(struct dql *dql, unsigned hold_time)
  112. {
  113. dql->max_limit = DQL_MAX_LIMIT;
  114. dql->min_limit = 0;
  115. dql->slack_hold_time = hold_time;
  116. dql_reset(dql);
  117. return 0;
  118. }
  119. EXPORT_SYMBOL(dql_init);