Version:  2.0.40 2.2.26 2.4.37 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10

Linux/lib/dynamic_queue_limits.c

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

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us