diff options
| author | Joe Perches <joe@perches.com> | 2014-12-21 18:25:36 +0800 |
|---|---|---|
| committer | Moyster <oysterized@gmail.com> | 2016-08-26 20:06:32 +0200 |
| commit | 9722cd7360077819a5af4937c0f742149fcec82c (patch) | |
| tree | 065c8dcbeef39f4c701d846d2a0bbe56ad57a41d /include/linux | |
| parent | a2253bb117db4df4f14e401fc16ea11f73569815 (diff) | |
jiffies conversions: Use compile time constants when possible
Do the multiplications and divisions at compile time
instead of runtime when the converted value is a constant.
Make the calculation functions static __always_inline to jiffies.h.
Add #defines with __builtin_constant_p to test and use the
static inline or the runtime functions as appropriate.
Prefix the old exported symbols/functions with __
Signed-off-by: Joe Perches <joe@perches.com>
Signed-off-by: Stefan Guendhoer <stefan@guendhoer.com>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/jiffies.h | 136 |
1 files changed, 132 insertions, 4 deletions
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h index c039fe131..69cfc6e09 100644 --- a/include/linux/jiffies.h +++ b/include/linux/jiffies.h @@ -276,10 +276,138 @@ extern unsigned long preset_lpj; /* * Convert various time units to each other: */ -extern unsigned int jiffies_to_msecs(const unsigned long j); -extern unsigned int jiffies_to_usecs(const unsigned long j); -extern unsigned long msecs_to_jiffies(const unsigned int m); -extern unsigned long usecs_to_jiffies(const unsigned int u); + +/* + * Avoid unnecessary multiplications/divisions in the + * two most common HZ cases: + */ +static __always_inline unsigned int +__inline_jiffies_to_msecs(const unsigned long j) +{ +#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) + return (MSEC_PER_SEC / HZ) * j; +#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) + return (j + (HZ / MSEC_PER_SEC) - 1)/(HZ / MSEC_PER_SEC); +#else +# if BITS_PER_LONG == 32 + return (HZ_TO_MSEC_MUL32 * j) >> HZ_TO_MSEC_SHR32; +# else + return (j * HZ_TO_MSEC_NUM) / HZ_TO_MSEC_DEN; +# endif +#endif +} +extern unsigned int __jiffies_to_msecs(const unsigned long j); + +#define jiffies_to_msecs(x) \ + (__builtin_constant_p(x) ? \ + __inline_jiffies_to_msecs(x) : \ + __jiffies_to_msecs(x)) + +static __always_inline unsigned int +__inline_jiffies_to_usecs(const unsigned long j) +{ +#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) + return (USEC_PER_SEC / HZ) * j; +#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC) + return (j + (HZ / USEC_PER_SEC) - 1)/(HZ / USEC_PER_SEC); +#else +# if BITS_PER_LONG == 32 + return (HZ_TO_USEC_MUL32 * j) >> HZ_TO_USEC_SHR32; +# else + return (j * HZ_TO_USEC_NUM) / HZ_TO_USEC_DEN; +# endif +#endif +} +extern unsigned int __jiffies_to_usecs(const unsigned long j); + +#define jiffies_to_usecs(x) \ + (__builtin_constant_p(x) ? \ + __inline_jiffies_to_usecs(x) : \ + __jiffies_to_usecs(x)) + +/* + * When we convert to jiffies then we interpret incoming values + * the following way: + * + * - negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET) + * + * - 'too large' values [that would result in larger than + * MAX_JIFFY_OFFSET values] mean 'infinite timeout' too. + * + * - all other values are converted to jiffies by either multiplying + * the input value by a factor or dividing it with a factor + * + * We must also be careful about 32-bit overflows. + */ +static __always_inline unsigned long +__inline_msecs_to_jiffies(const unsigned int m) +{ + /* + * Negative value, means infinite timeout: + */ + if ((int)m < 0) + return MAX_JIFFY_OFFSET; + +#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) + /* + * HZ is equal to or smaller than 1000, and 1000 is a nice + * round multiple of HZ, divide with the factor between them, + * but round upwards: + */ + return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ); +#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC) + /* + * HZ is larger than 1000, and HZ is a nice round multiple of + * 1000 - simply multiply with the factor between them. + * + * But first make sure the multiplication result cannot + * overflow: + */ + if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET)) + return MAX_JIFFY_OFFSET; + + return m * (HZ / MSEC_PER_SEC); +#else + /* + * Generic case - multiply, round and divide. But first + * check that if we are doing a net multiplication, that + * we wouldn't overflow: + */ + if (HZ > MSEC_PER_SEC && m > jiffies_to_msecs(MAX_JIFFY_OFFSET)) + return MAX_JIFFY_OFFSET; + + return (MSEC_TO_HZ_MUL32 * m + MSEC_TO_HZ_ADJ32) + >> MSEC_TO_HZ_SHR32; +#endif +} +extern unsigned long __msecs_to_jiffies(const unsigned int m); + +#define msecs_to_jiffies(x) \ + (__builtin_constant_p(x) ? \ + __inline_msecs_to_jiffies(x) : \ + __msecs_to_jiffies(x)) + +static __always_inline unsigned long +__inline_usecs_to_jiffies(const unsigned int u) +{ + if (u > jiffies_to_usecs(MAX_JIFFY_OFFSET)) + return MAX_JIFFY_OFFSET; +#if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) + return (u + (USEC_PER_SEC / HZ) - 1) / (USEC_PER_SEC / HZ); +#elif HZ > USEC_PER_SEC && !(HZ % USEC_PER_SEC) + return u * (HZ / USEC_PER_SEC); +#else + return (USEC_TO_HZ_MUL32 * u + USEC_TO_HZ_ADJ32) + >> USEC_TO_HZ_SHR32; +#endif +} +extern unsigned long __usecs_to_jiffies(const unsigned int u); + +#define usecs_to_jiffies(x) \ + (__builtin_constant_p(x) ? \ + __inline_usecs_to_jiffies(x) : \ + __usecs_to_jiffies(x)) + extern unsigned long timespec_to_jiffies(const struct timespec *value); extern void jiffies_to_timespec(const unsigned long jiffies, struct timespec *value); |
