175957ba3STom Herbert /* 275957ba3STom Herbert * Dynamic queue limits (dql) - Definitions 375957ba3STom Herbert * 475957ba3STom Herbert * Copyright (c) 2011, Tom Herbert <[email protected]> 575957ba3STom Herbert * 675957ba3STom Herbert * This header file contains the definitions for dynamic queue limits (dql). 775957ba3STom Herbert * dql would be used in conjunction with a producer/consumer type queue 875957ba3STom Herbert * (possibly a HW queue). Such a queue would have these general properties: 975957ba3STom Herbert * 1075957ba3STom Herbert * 1) Objects are queued up to some limit specified as number of objects. 1175957ba3STom Herbert * 2) Periodically a completion process executes which retires consumed 1275957ba3STom Herbert * objects. 1375957ba3STom Herbert * 3) Starvation occurs when limit has been reached, all queued data has 1475957ba3STom Herbert * actually been consumed, but completion processing has not yet run 1575957ba3STom Herbert * so queuing new data is blocked. 1675957ba3STom Herbert * 4) Minimizing the amount of queued data is desirable. 1775957ba3STom Herbert * 1875957ba3STom Herbert * The goal of dql is to calculate the limit as the minimum number of objects 1975957ba3STom Herbert * needed to prevent starvation. 2075957ba3STom Herbert * 2175957ba3STom Herbert * The primary functions of dql are: 2275957ba3STom Herbert * dql_queued - called when objects are enqueued to record number of objects 2375957ba3STom Herbert * dql_avail - returns how many objects are available to be queued based 2475957ba3STom Herbert * on the object limit and how many objects are already enqueued 2575957ba3STom Herbert * dql_completed - called at completion time to indicate how many objects 2675957ba3STom Herbert * were retired from the queue 2775957ba3STom Herbert * 2875957ba3STom Herbert * The dql implementation does not implement any locking for the dql data 2975957ba3STom Herbert * structures, the higher layer should provide this. dql_queued should 3075957ba3STom Herbert * be serialized to prevent concurrent execution of the function; this 3175957ba3STom Herbert * is also true for dql_completed. However, dql_queued and dlq_completed can 3275957ba3STom Herbert * be executed concurrently (i.e. they can be protected by different locks). 3375957ba3STom Herbert */ 3475957ba3STom Herbert 3575957ba3STom Herbert #ifndef _LINUX_DQL_H 3675957ba3STom Herbert #define _LINUX_DQL_H 3775957ba3STom Herbert 3875957ba3STom Herbert #ifdef __KERNEL__ 3975957ba3STom Herbert 4075957ba3STom Herbert struct dql { 4175957ba3STom Herbert /* Fields accessed in enqueue path (dql_queued) */ 4275957ba3STom Herbert unsigned int num_queued; /* Total ever queued */ 4375957ba3STom Herbert unsigned int adj_limit; /* limit + num_completed */ 4475957ba3STom Herbert unsigned int last_obj_cnt; /* Count at last queuing */ 4575957ba3STom Herbert 4675957ba3STom Herbert /* Fields accessed only by completion path (dql_completed) */ 4775957ba3STom Herbert 4875957ba3STom Herbert unsigned int limit ____cacheline_aligned_in_smp; /* Current limit */ 4975957ba3STom Herbert unsigned int num_completed; /* Total ever completed */ 5075957ba3STom Herbert 5175957ba3STom Herbert unsigned int prev_ovlimit; /* Previous over limit */ 5275957ba3STom Herbert unsigned int prev_num_queued; /* Previous queue total */ 5375957ba3STom Herbert unsigned int prev_last_obj_cnt; /* Previous queuing cnt */ 5475957ba3STom Herbert 5575957ba3STom Herbert unsigned int lowest_slack; /* Lowest slack found */ 5675957ba3STom Herbert unsigned long slack_start_time; /* Time slacks seen */ 5775957ba3STom Herbert 5875957ba3STom Herbert /* Configuration */ 5975957ba3STom Herbert unsigned int max_limit; /* Max limit */ 6075957ba3STom Herbert unsigned int min_limit; /* Minimum limit */ 6175957ba3STom Herbert unsigned int slack_hold_time; /* Time to measure slack */ 6275957ba3STom Herbert }; 6375957ba3STom Herbert 6475957ba3STom Herbert /* Set some static maximums */ 6575957ba3STom Herbert #define DQL_MAX_OBJECT (UINT_MAX / 16) 6675957ba3STom Herbert #define DQL_MAX_LIMIT ((UINT_MAX / 2) - DQL_MAX_OBJECT) 6775957ba3STom Herbert 6875957ba3STom Herbert /* 6975957ba3STom Herbert * Record number of objects queued. Assumes that caller has already checked 7075957ba3STom Herbert * availability in the queue with dql_avail. 7175957ba3STom Herbert */ 7275957ba3STom Herbert static inline void dql_queued(struct dql *dql, unsigned int count) 7375957ba3STom Herbert { 7475957ba3STom Herbert BUG_ON(count > DQL_MAX_OBJECT); 7575957ba3STom Herbert 7675957ba3STom Herbert dql->last_obj_cnt = count; 77*3d9a0d2fSEric Dumazet 78*3d9a0d2fSEric Dumazet /* We want to force a write first, so that cpu do not attempt 79*3d9a0d2fSEric Dumazet * to get cache line containing last_obj_cnt, num_queued, adj_limit 80*3d9a0d2fSEric Dumazet * in Shared state, but directly does a Request For Ownership 81*3d9a0d2fSEric Dumazet * It is only a hint, we use barrier() only. 82*3d9a0d2fSEric Dumazet */ 83*3d9a0d2fSEric Dumazet barrier(); 84*3d9a0d2fSEric Dumazet 85*3d9a0d2fSEric Dumazet dql->num_queued += count; 8675957ba3STom Herbert } 8775957ba3STom Herbert 8875957ba3STom Herbert /* Returns how many objects can be queued, < 0 indicates over limit. */ 8975957ba3STom Herbert static inline int dql_avail(const struct dql *dql) 9075957ba3STom Herbert { 91*3d9a0d2fSEric Dumazet return ACCESS_ONCE(dql->adj_limit) - ACCESS_ONCE(dql->num_queued); 9275957ba3STom Herbert } 9375957ba3STom Herbert 9475957ba3STom Herbert /* Record number of completed objects and recalculate the limit. */ 9575957ba3STom Herbert void dql_completed(struct dql *dql, unsigned int count); 9675957ba3STom Herbert 9775957ba3STom Herbert /* Reset dql state */ 9875957ba3STom Herbert void dql_reset(struct dql *dql); 9975957ba3STom Herbert 10075957ba3STom Herbert /* Initialize dql state */ 10175957ba3STom Herbert int dql_init(struct dql *dql, unsigned hold_time); 10275957ba3STom Herbert 10375957ba3STom Herbert #endif /* _KERNEL_ */ 10475957ba3STom Herbert 10575957ba3STom Herbert #endif /* _LINUX_DQL_H */ 106