2020-04-22 12:57:39

by Andy Shevchenko

[permalink] [raw]
Subject: [PATCH v4 4/7] kernel.h: Split out min()/max() et al helpers

kernel.h is being used as a dump for all kinds of stuff for a long time.
Here is the attempt to start cleaning it up by splitting out min()/max()
et al helpers.

At the same time convert users in header and lib folder to use new header.
Though for time being include new header back to kernel.h to avoid twisted
indirected includes for existing users.

Signed-off-by: Andy Shevchenko <[email protected]>
---
v4: rebase on latest kernel
include/linux/blkdev.h | 1 +
include/linux/bvec.h | 6 +-
include/linux/jiffies.h | 3 +-
include/linux/kernel.h | 142 +------------------------------------
include/linux/minmax.h | 145 ++++++++++++++++++++++++++++++++++++++
include/linux/nodemask.h | 2 +-
include/linux/uaccess.h | 1 +
kernel/range.c | 3 +-
lib/find_bit.c | 1 +
lib/hexdump.c | 1 +
lib/math/rational.c | 2 +-
lib/math/reciprocal_div.c | 1 +
12 files changed, 162 insertions(+), 146 deletions(-)
create mode 100644 include/linux/minmax.h

diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index 32868fbedc9e9..e39853ebf9c21 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -11,6 +11,7 @@
#include <linux/genhd.h>
#include <linux/list.h>
#include <linux/llist.h>
+#include <linux/minmax.h>
#include <linux/timer.h>
#include <linux/workqueue.h>
#include <linux/pagemap.h>
diff --git a/include/linux/bvec.h b/include/linux/bvec.h
index a81c13ac19728..56d4dec749263 100644
--- a/include/linux/bvec.h
+++ b/include/linux/bvec.h
@@ -7,10 +7,14 @@
#ifndef __LINUX_BVEC_ITER_H
#define __LINUX_BVEC_ITER_H

-#include <linux/kernel.h>
#include <linux/bug.h>
#include <linux/errno.h>
+#include <linux/limits.h>
+#include <linux/minmax.h>
#include <linux/mm.h>
+#include <linux/types.h>
+
+struct page;

/*
* was unsigned short, but we might as well be ready for > 64kB I/O pages
diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index fed6ba96c5278..5e13f801c9021 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -3,8 +3,9 @@
#define _LINUX_JIFFIES_H

#include <linux/cache.h>
+#include <linux/limits.h>
#include <linux/math64.h>
-#include <linux/kernel.h>
+#include <linux/minmax.h>
#include <linux/types.h>
#include <linux/time.h>
#include <linux/timex.h>
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 899302e2b7554..cbdbfe81a535c 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -11,6 +11,7 @@
#include <linux/compiler.h>
#include <linux/bitops.h>
#include <linux/log2.h>
+#include <linux/minmax.h>
#include <linux/typecheck.h>
#include <linux/printk.h>
#include <linux/build_bug.h>
@@ -831,147 +832,6 @@ ftrace_vprintk(const char *fmt, va_list ap)
static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }
#endif /* CONFIG_TRACING */

-/*
- * min()/max()/clamp() macros must accomplish three things:
- *
- * - avoid multiple evaluations of the arguments (so side-effects like
- * "x++" happen only once) when non-constant.
- * - perform strict type-checking (to generate warnings instead of
- * nasty runtime surprises). See the "unnecessary" pointer comparison
- * in __typecheck().
- * - retain result as a constant expressions when called with only
- * constant expressions (to avoid tripping VLA warnings in stack
- * allocation usage).
- */
-#define __typecheck(x, y) \
- (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
-
-/*
- * This returns a constant expression while determining if an argument is
- * a constant expression, most importantly without evaluating the argument.
- * Glory to Martin Uecker <[email protected]>
- */
-#define __is_constexpr(x) \
- (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
-
-#define __no_side_effects(x, y) \
- (__is_constexpr(x) && __is_constexpr(y))
-
-#define __safe_cmp(x, y) \
- (__typecheck(x, y) && __no_side_effects(x, y))
-
-#define __cmp(x, y, op) ((x) op (y) ? (x) : (y))
-
-#define __cmp_once(x, y, unique_x, unique_y, op) ({ \
- typeof(x) unique_x = (x); \
- typeof(y) unique_y = (y); \
- __cmp(unique_x, unique_y, op); })
-
-#define __careful_cmp(x, y, op) \
- __builtin_choose_expr(__safe_cmp(x, y), \
- __cmp(x, y, op), \
- __cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op))
-
-/**
- * min - return minimum of two values of the same or compatible types
- * @x: first value
- * @y: second value
- */
-#define min(x, y) __careful_cmp(x, y, <)
-
-/**
- * max - return maximum of two values of the same or compatible types
- * @x: first value
- * @y: second value
- */
-#define max(x, y) __careful_cmp(x, y, >)
-
-/**
- * min3 - return minimum of three values
- * @x: first value
- * @y: second value
- * @z: third value
- */
-#define min3(x, y, z) min((typeof(x))min(x, y), z)
-
-/**
- * max3 - return maximum of three values
- * @x: first value
- * @y: second value
- * @z: third value
- */
-#define max3(x, y, z) max((typeof(x))max(x, y), z)
-
-/**
- * min_not_zero - return the minimum that is _not_ zero, unless both are zero
- * @x: value1
- * @y: value2
- */
-#define min_not_zero(x, y) ({ \
- typeof(x) __x = (x); \
- typeof(y) __y = (y); \
- __x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); })
-
-/**
- * clamp - return a value clamped to a given range with strict typechecking
- * @val: current value
- * @lo: lowest allowable value
- * @hi: highest allowable value
- *
- * This macro does strict typechecking of @lo/@hi to make sure they are of the
- * same type as @val. See the unnecessary pointer comparisons.
- */
-#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi)
-
-/*
- * ..and if you can't take the strict
- * types, you can specify one yourself.
- *
- * Or not use min/max/clamp at all, of course.
- */
-
-/**
- * min_t - return minimum of two values, using the specified type
- * @type: data type to use
- * @x: first value
- * @y: second value
- */
-#define min_t(type, x, y) __careful_cmp((type)(x), (type)(y), <)
-
-/**
- * max_t - return maximum of two values, using the specified type
- * @type: data type to use
- * @x: first value
- * @y: second value
- */
-#define max_t(type, x, y) __careful_cmp((type)(x), (type)(y), >)
-
-/**
- * clamp_t - return a value clamped to a given range using a given type
- * @type: the type of variable to use
- * @val: current value
- * @lo: minimum allowable value
- * @hi: maximum allowable value
- *
- * This macro does no typechecking and uses temporary variables of type
- * @type to make all the comparisons.
- */
-#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi)
-
-/**
- * clamp_val - return a value clamped to a given range using val's type
- * @val: current value
- * @lo: minimum allowable value
- * @hi: maximum allowable value
- *
- * This macro does no typechecking and uses temporary variables of whatever
- * type the input argument @val is. This is useful when @val is an unsigned
- * type and @lo and @hi are literals that will otherwise be assigned a signed
- * integer type.
- */
-#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
-
-
/**
* swap - swap values of @a and @b
* @a: first value
diff --git a/include/linux/minmax.h b/include/linux/minmax.h
new file mode 100644
index 0000000000000..bfd6ad8229147
--- /dev/null
+++ b/include/linux/minmax.h
@@ -0,0 +1,145 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_MINMAX_H
+#define _LINUX_MINMAX_H
+
+/*
+ * min()/max()/clamp() macros must accomplish three things:
+ *
+ * - avoid multiple evaluations of the arguments (so side-effects like
+ * "x++" happen only once) when non-constant.
+ * - perform strict type-checking (to generate warnings instead of
+ * nasty runtime surprises). See the "unnecessary" pointer comparison
+ * in __typecheck().
+ * - retain result as a constant expressions when called with only
+ * constant expressions (to avoid tripping VLA warnings in stack
+ * allocation usage).
+ */
+#define __typecheck(x, y) \
+ (!!(sizeof((typeof(x) *)1 == (typeof(y) *)1)))
+
+/*
+ * This returns a constant expression while determining if an argument is
+ * a constant expression, most importantly without evaluating the argument.
+ * Glory to Martin Uecker <[email protected]>
+ */
+#define __is_constexpr(x) \
+ (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))
+
+#define __no_side_effects(x, y) \
+ (__is_constexpr(x) && __is_constexpr(y))
+
+#define __safe_cmp(x, y) \
+ (__typecheck(x, y) && __no_side_effects(x, y))
+
+#define __cmp(x, y, op) ((x) op (y) ? (x) : (y))
+
+#define __cmp_once(x, y, unique_x, unique_y, op) ({ \
+ typeof(x) unique_x = (x); \
+ typeof(y) unique_y = (y); \
+ __cmp(unique_x, unique_y, op); })
+
+#define __careful_cmp(x, y, op) \
+ __builtin_choose_expr(__safe_cmp(x, y), \
+ __cmp(x, y, op), \
+ __cmp_once(x, y, __UNIQUE_ID(__x), __UNIQUE_ID(__y), op))
+
+/**
+ * min - return minimum of two values of the same or compatible types
+ * @x: first value
+ * @y: second value
+ */
+#define min(x, y) __careful_cmp(x, y, <)
+
+/**
+ * max - return maximum of two values of the same or compatible types
+ * @x: first value
+ * @y: second value
+ */
+#define max(x, y) __careful_cmp(x, y, >)
+
+/**
+ * min3 - return minimum of three values
+ * @x: first value
+ * @y: second value
+ * @z: third value
+ */
+#define min3(x, y, z) min((typeof(x))min(x, y), z)
+
+/**
+ * max3 - return maximum of three values
+ * @x: first value
+ * @y: second value
+ * @z: third value
+ */
+#define max3(x, y, z) max((typeof(x))max(x, y), z)
+
+/**
+ * min_not_zero - return the minimum that is _not_ zero, unless both are zero
+ * @x: value1
+ * @y: value2
+ */
+#define min_not_zero(x, y) ({ \
+ typeof(x) __x = (x); \
+ typeof(y) __y = (y); \
+ __x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); })
+
+/**
+ * clamp - return a value clamped to a given range with strict typechecking
+ * @val: current value
+ * @lo: lowest allowable value
+ * @hi: highest allowable value
+ *
+ * This macro does strict typechecking of @lo/@hi to make sure they are of the
+ * same type as @val. See the unnecessary pointer comparisons.
+ */
+#define clamp(val, lo, hi) min((typeof(val))max(val, lo), hi)
+
+/*
+ * ..and if you can't take the strict
+ * types, you can specify one yourself.
+ *
+ * Or not use min/max/clamp at all, of course.
+ */
+
+/**
+ * min_t - return minimum of two values, using the specified type
+ * @type: data type to use
+ * @x: first value
+ * @y: second value
+ */
+#define min_t(type, x, y) __careful_cmp((type)(x), (type)(y), <)
+
+/**
+ * max_t - return maximum of two values, using the specified type
+ * @type: data type to use
+ * @x: first value
+ * @y: second value
+ */
+#define max_t(type, x, y) __careful_cmp((type)(x), (type)(y), >)
+
+/**
+ * clamp_t - return a value clamped to a given range using a given type
+ * @type: the type of variable to use
+ * @val: current value
+ * @lo: minimum allowable value
+ * @hi: maximum allowable value
+ *
+ * This macro does no typechecking and uses temporary variables of type
+ * @type to make all the comparisons.
+ */
+#define clamp_t(type, val, lo, hi) min_t(type, max_t(type, val, lo), hi)
+
+/**
+ * clamp_val - return a value clamped to a given range using val's type
+ * @val: current value
+ * @lo: minimum allowable value
+ * @hi: maximum allowable value
+ *
+ * This macro does no typechecking and uses temporary variables of whatever
+ * type the input argument @val is. This is useful when @val is an unsigned
+ * type and @lo and @hi are literals that will otherwise be assigned a signed
+ * integer type.
+ */
+#define clamp_val(val, lo, hi) clamp_t(typeof(val), val, lo, hi)
+
+#endif /* _LINUX_MINMAX_H */
diff --git a/include/linux/nodemask.h b/include/linux/nodemask.h
index 27e7fa36f707f..7f38399cc9fe7 100644
--- a/include/linux/nodemask.h
+++ b/include/linux/nodemask.h
@@ -90,9 +90,9 @@
* for such situations. See below and CPUMASK_ALLOC also.
*/

-#include <linux/kernel.h>
#include <linux/threads.h>
#include <linux/bitmap.h>
+#include <linux/minmax.h>
#include <linux/numa.h>

typedef struct { DECLARE_BITMAP(bits, MAX_NUMNODES); } nodemask_t;
diff --git a/include/linux/uaccess.h b/include/linux/uaccess.h
index 8a215c5c1aed8..cb11957a017f6 100644
--- a/include/linux/uaccess.h
+++ b/include/linux/uaccess.h
@@ -3,6 +3,7 @@
#define __LINUX_UACCESS_H__

#include <linux/instrumented.h>
+#include <linux/minmax.h>
#include <linux/sched.h>
#include <linux/thread_info.h>

diff --git a/kernel/range.c b/kernel/range.c
index d84de6766472d..56435f96da73b 100644
--- a/kernel/range.c
+++ b/kernel/range.c
@@ -2,8 +2,9 @@
/*
* Range add and subtract
*/
-#include <linux/kernel.h>
#include <linux/init.h>
+#include <linux/minmax.h>
+#include <linux/printk.h>
#include <linux/sort.h>
#include <linux/string.h>
#include <linux/range.h>
diff --git a/lib/find_bit.c b/lib/find_bit.c
index 49f875f1baf7e..4a8751010d59f 100644
--- a/lib/find_bit.c
+++ b/lib/find_bit.c
@@ -16,6 +16,7 @@
#include <linux/bitmap.h>
#include <linux/export.h>
#include <linux/kernel.h>
+#include <linux/minmax.h>

#if !defined(find_next_bit) || !defined(find_next_zero_bit) || \
!defined(find_next_bit_le) || !defined(find_next_zero_bit_le) || \
diff --git a/lib/hexdump.c b/lib/hexdump.c
index 147133f8eb2fc..9301578f98e8c 100644
--- a/lib/hexdump.c
+++ b/lib/hexdump.c
@@ -7,6 +7,7 @@
#include <linux/ctype.h>
#include <linux/errno.h>
#include <linux/kernel.h>
+#include <linux/minmax.h>
#include <linux/export.h>
#include <asm/unaligned.h>

diff --git a/lib/math/rational.c b/lib/math/rational.c
index 31fb27db2deb5..d8e985850d10c 100644
--- a/lib/math/rational.c
+++ b/lib/math/rational.c
@@ -11,7 +11,7 @@
#include <linux/rational.h>
#include <linux/compiler.h>
#include <linux/export.h>
-#include <linux/kernel.h>
+#include <linux/minmax.h>

/*
* calculate best rational approximation for a given fraction
diff --git a/lib/math/reciprocal_div.c b/lib/math/reciprocal_div.c
index bf043258fa008..32436dd4171e9 100644
--- a/lib/math/reciprocal_div.c
+++ b/lib/math/reciprocal_div.c
@@ -4,6 +4,7 @@
#include <asm/div64.h>
#include <linux/reciprocal_div.h>
#include <linux/export.h>
+#include <linux/minmax.h>

/*
* For a description of the algorithm please have a look at
--
2.26.1


2020-04-22 15:07:48

by Joe Perches

[permalink] [raw]
Subject: Re: [PATCH v4 4/7] kernel.h: Split out min()/max() et al helpers

On Wed, 2020-04-22 at 15:51 +0300, Andy Shevchenko wrote:
> kernel.h is being used as a dump for all kinds of stuff for a long time.
> Here is the attempt to start cleaning it up by splitting out min()/max()
> et al helpers.

While adding organization into kernel.h by splitting
out various bits into separate files is a fine idea,
I believe removing the generic #include <linux/kernel.h>
from various files and substituting the sub-includes
is not a good idea.

> At the same time convert users in header and lib folder to use new header.
> Though for time being include new header back to kernel.h to avoid twisted
> indirected includes for existing users.

Yeah, that's the difficult bit and it could make
using precompiled headers very cumbersome.

I'd rather make #include <linux/kernel.h>" _more_
common or even used as the mandatory first #include
for all kernel .c files.

That would also ensure that common kernel facilities
are not duplicated or have naming conflicts with other
files.


2020-04-22 15:45:28

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v4 4/7] kernel.h: Split out min()/max() et al helpers

On Wed, Apr 22, 2020 at 07:52:32AM -0700, Joe Perches wrote:
> On Wed, 2020-04-22 at 15:51 +0300, Andy Shevchenko wrote:
> > kernel.h is being used as a dump for all kinds of stuff for a long time.
> > Here is the attempt to start cleaning it up by splitting out min()/max()
> > et al helpers.
>
> While adding organization into kernel.h by splitting
> out various bits into separate files is a fine idea,
> I believe removing the generic #include <linux/kernel.h>
> from various files and substituting the sub-includes
> is not a good idea.

Are you sure?

> > At the same time convert users in header and lib folder to use new header.
> > Though for time being include new header back to kernel.h to avoid twisted
> > indirected includes for existing users.
>
> Yeah, that's the difficult bit and it could make
> using precompiled headers very cumbersome.
>
> I'd rather make #include <linux/kernel.h>" _more_
> common or even used as the mandatory first #include
> for all kernel .c files.

Huh?

Perhaps we may just cat include/linux/* > include/linux/kernel.h?

> That would also ensure that common kernel facilities
> are not duplicated or have naming conflicts with other
> files.

--
With Best Regards,
Andy Shevchenko


2020-04-22 15:55:37

by Joe Perches

[permalink] [raw]
Subject: Re: [PATCH v4 4/7] kernel.h: Split out min()/max() et al helpers

On Wed, 2020-04-22 at 18:44 +0300, Andy Shevchenko wrote:
> On Wed, Apr 22, 2020 at 07:52:32AM -0700, Joe Perches wrote:
> > On Wed, 2020-04-22 at 15:51 +0300, Andy Shevchenko wrote:
> > > kernel.h is being used as a dump for all kinds of stuff for a long time.
> > > Here is the attempt to start cleaning it up by splitting out min()/max()
> > > et al helpers.
> >
> > While adding organization into kernel.h by splitting
> > out various bits into separate files is a fine idea,
> > I believe removing the generic #include <linux/kernel.h>
> > from various files and substituting the sub-includes
> > is not a good idea.
>
> Are you sure?

Yes.

> Perhaps we may just cat include/linux/* > include/linux/kernel.h?

Silly argument, There's a real argument to be made to
tmove many of the files in include/linux to separate
directories or out of include/ altogether to subsystem
specific locations.


2020-04-23 09:36:08

by Rasmus Villemoes

[permalink] [raw]
Subject: Re: [PATCH v4 4/7] kernel.h: Split out min()/max() et al helpers

On 22/04/2020 16.52, Joe Perches wrote:
> On Wed, 2020-04-22 at 15:51 +0300, Andy Shevchenko wrote:

>> At the same time convert users in header and lib folder to use new header.
>> Though for time being include new header back to kernel.h to avoid twisted
>> indirected includes for existing users.
>
> Yeah, that's the difficult bit and it could make
> using precompiled headers very cumbersome.

You mentioned precompiled headers last time as well, but you haven't
demonstrated that using those is either feasible or advantageous - and
if at some distant future time it turns out that they are a good idea,
it's not really any more difficult at that time to do a
linux/kitchen_sink.h that includes whatever common set of headers seems
to provide a reasonable speedup.

Meanwhile, the sheer size of the headers that gets pulled into each and
every TU currently slows down the build:

https://wildmoose.dk/header-bloat/

so anything that reduces the size of common headers like kernel.h will
improve build times (the slowdown is "death by a thousand cuts", hence
so will any individual improvement be hard or impossible to measure by
itself - that doesn't mean it's not worth doing them). Of course, the
include of minmax.h (et al) from kernel.h must be removed, but that's
the kind of thing that can easily take a couple of cycles to get done,
unlike the damage that adding #include <linux/foo.h> to bar.h
immediately causes.

> I'd rather make #include <linux/kernel.h>" _more_
> common or even used as the mandatory first #include
> for all kernel .c files.

No. Please no.

> That would also ensure that common kernel facilities
> are not duplicated or have naming conflicts with other
> files.

What? People duplicate functionality because they're not aware it
already exists, forcing an #include of a declaration of some function
doesn't make any developer know about it.

Rasmus