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