dynamic_queue_limits.c 4.2 KB

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