From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Xen-devel <xen-devel@lists.xenproject.org>
Cc: "Andrew Cooper" <andrew.cooper3@citrix.com>,
"Jan Beulich" <JBeulich@suse.com>,
"Roger Pau Monné" <roger.pau@citrix.com>, "Wei Liu" <wl@xen.org>,
"Stefano Stabellini" <sstabellini@kernel.org>,
"Julien Grall" <julien@xen.org>,
"Volodymyr Babchuk" <Volodymyr_Babchuk@epam.com>,
"Bertrand Marquis" <bertrand.marquis@arm.com>
Subject: [PATCH 3/5] xen/sort: Switch to an extern inline implementation
Date: Thu, 11 Nov 2021 17:57:38 +0000 [thread overview]
Message-ID: <20211111175740.23480-4-andrew.cooper3@citrix.com> (raw)
In-Reply-To: <20211111175740.23480-1-andrew.cooper3@citrix.com>
There are exactly 3 callers of sort() in the hypervisor.
Both arm callers pass in NULL for the swap function. While this might seem
like an attractive option at first, it causes generic_swap() to be used which
forced a byte-wise copy. Provide real swap functions which the compiler can
optimise sensibly.
Furthermore, use of function pointers in tight loops like that can be very bad
for performance. Implement sort() as extern inline, so the optimiser can
judge whether to inline things or not.
On x86, the diffstat shows how much of a better job the compiler can do when
it is able to see the cmp/swap implementations.
$ ../scripts/bloat-o-meter xen-syms-before xen-syms-after
add/remove: 0/5 grow/shrink: 1/1 up/down: 505/-735 (-230)
Function old new delta
sort_exception_table 31 536 +505
u32_swap 9 - -9
generic_swap 34 - -34
cmp_ex 36 - -36
swap_ex 41 - -41
sort_exception_tables 90 38 -52
sort 563 - -563
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Wei Liu <wl@xen.org>
CC: Stefano Stabellini <sstabellini@kernel.org>
CC: Julien Grall <julien@xen.org>
CC: Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>
CC: Bertrand Marquis <bertrand.marquis@arm.com>
---
xen/arch/arm/bootfdt.c | 9 +++++-
xen/arch/arm/io.c | 9 +++++-
xen/include/xen/sort.h | 55 +++++++++++++++++++++++++++++++++-
xen/lib/sort.c | 80 ++------------------------------------------------
4 files changed, 72 insertions(+), 81 deletions(-)
diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index afaa0e249b71..e318ef960386 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -448,6 +448,13 @@ static int __init cmp_memory_node(const void *key, const void *elem)
return 0;
}
+static void __init swap_memory_node(void *_a, void *_b, size_t size)
+{
+ struct membank *a = _a, *b = _b;
+
+ SWAP(*a, *b);
+}
+
/**
* boot_fdt_info - initialize bootinfo from a DTB
* @fdt: flattened device tree binary
@@ -472,7 +479,7 @@ size_t __init boot_fdt_info(const void *fdt, paddr_t paddr)
* the banks sorted in ascending order. So sort them through.
*/
sort(bootinfo.mem.bank, bootinfo.mem.nr_banks, sizeof(struct membank),
- cmp_memory_node, NULL);
+ cmp_memory_node, swap_memory_node);
early_print_info();
diff --git a/xen/arch/arm/io.c b/xen/arch/arm/io.c
index 729287e37c59..1a066f9ae502 100644
--- a/xen/arch/arm/io.c
+++ b/xen/arch/arm/io.c
@@ -80,6 +80,13 @@ static int cmp_mmio_handler(const void *key, const void *elem)
return 0;
}
+static void swap_mmio_handler(void *_a, void *_b, size_t size)
+{
+ struct mmio_handler *a = _a, *b = _b;
+
+ SWAP(*a, *b);
+}
+
static const struct mmio_handler *find_mmio_handler(struct domain *d,
paddr_t gpa)
{
@@ -170,7 +177,7 @@ void register_mmio_handler(struct domain *d,
/* Sort mmio handlers in ascending order based on base address */
sort(vmmio->handlers, vmmio->num_entries, sizeof(struct mmio_handler),
- cmp_mmio_handler, NULL);
+ cmp_mmio_handler, swap_mmio_handler);
write_unlock(&vmmio->lock);
}
diff --git a/xen/include/xen/sort.h b/xen/include/xen/sort.h
index a403652948e7..01479ea44606 100644
--- a/xen/include/xen/sort.h
+++ b/xen/include/xen/sort.h
@@ -3,8 +3,61 @@
#include <xen/types.h>
+/*
+ * sort - sort an array of elements
+ * @base: pointer to data to sort
+ * @num: number of elements
+ * @size: size of each element
+ * @cmp: pointer to comparison function
+ * @swap: pointer to swap function or NULL
+ *
+ * This function does a heapsort on the given array. You may provide a
+ * swap function optimized to your element type.
+ *
+ * Sorting time is O(n log n) both on average and worst-case. While
+ * qsort is about 20% faster on average, it suffers from exploitable
+ * O(n*n) worst-case behavior and extra memory requirements that make
+ * it less suitable for kernel use.
+ */
+#ifndef SORT_IMPLEMENTATION
+extern gnu_inline
+#endif
void sort(void *base, size_t num, size_t size,
int (*cmp)(const void *, const void *),
- void (*swap)(void *, void *, size_t));
+ void (*swap)(void *, void *, size_t))
+{
+ /* pre-scale counters for performance */
+ size_t i = (num / 2) * size, n = num * size, c, r;
+
+ /* heapify */
+ while ( i > 0 )
+ {
+ for ( r = i -= size; r * 2 + size < n; r = c )
+ {
+ c = r * 2 + size;
+ if ( (c < n - size) && (cmp(base + c, base + c + size) < 0) )
+ c += size;
+ if ( cmp(base + r, base + c) >= 0 )
+ break;
+ swap(base + r, base + c, size);
+ }
+ }
+
+ /* sort */
+ for ( i = n; i > 0; )
+ {
+ i -= size;
+ swap(base, base + i, size);
+ for ( r = 0; r * 2 + size < i; r = c )
+ {
+ c = r * 2 + size;
+ if ( (c < i - size) && (cmp(base + c, base + c + size) < 0) )
+ c += size;
+ if ( cmp(base + r, base + c) >= 0 )
+ break;
+ swap(base + r, base + c, size);
+ }
+ }
+}
#endif /* __XEN_SORT_H__ */
diff --git a/xen/lib/sort.c b/xen/lib/sort.c
index 35ce0d7abdec..b7e78cc0e8d2 100644
--- a/xen/lib/sort.c
+++ b/xen/lib/sort.c
@@ -4,81 +4,5 @@
* Jan 23 2005 Matt Mackall <mpm@selenic.com>
*/
-#include <xen/types.h>
-
-static void u32_swap(void *a, void *b, size_t size)
-{
- uint32_t t = *(uint32_t *)a;
-
- *(uint32_t *)a = *(uint32_t *)b;
- *(uint32_t *)b = t;
-}
-
-static void generic_swap(void *a, void *b, size_t size)
-{
- char t;
-
- do {
- t = *(char *)a;
- *(char *)a++ = *(char *)b;
- *(char *)b++ = t;
- } while ( --size > 0 );
-}
-
-/*
- * sort - sort an array of elements
- * @base: pointer to data to sort
- * @num: number of elements
- * @size: size of each element
- * @cmp: pointer to comparison function
- * @swap: pointer to swap function or NULL
- *
- * This function does a heapsort on the given array. You may provide a
- * swap function optimized to your element type.
- *
- * Sorting time is O(n log n) both on average and worst-case. While
- * qsort is about 20% faster on average, it suffers from exploitable
- * O(n*n) worst-case behavior and extra memory requirements that make
- * it less suitable for kernel use.
- */
-
-void sort(void *base, size_t num, size_t size,
- int (*cmp)(const void *, const void *),
- void (*swap)(void *, void *, size_t size))
-{
- /* pre-scale counters for performance */
- size_t i = (num / 2) * size, n = num * size, c, r;
-
- if ( !swap )
- swap = (size == 4 ? u32_swap : generic_swap);
-
- /* heapify */
- while ( i > 0 )
- {
- for ( r = i -= size; r * 2 + size < n; r = c )
- {
- c = r * 2 + size;
- if ( (c < n - size) && (cmp(base + c, base + c + size) < 0) )
- c += size;
- if ( cmp(base + r, base + c) >= 0 )
- break;
- swap(base + r, base + c, size);
- }
- }
-
- /* sort */
- for ( i = n; i > 0; )
- {
- i -= size;
- swap(base, base + i, size);
- for ( r = 0; r * 2 + size < i; r = c )
- {
- c = r * 2 + size;
- if ( (c < i - size) && (cmp(base + c, base + c + size) < 0) )
- c += size;
- if ( cmp(base + r, base + c) >= 0 )
- break;
- swap(base + r, base + c, size);
- }
- }
-}
+#define SORT_IMPLEMENTATION
+#include <xen/sort.h>
--
2.11.0
next prev parent reply other threads:[~2021-11-11 17:58 UTC|newest]
Thread overview: 34+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-11-11 17:57 [PATCH 0/5] xen: various function pointer cleanups Andrew Cooper
2021-11-11 17:57 ` [PATCH 1/5] xen/domain: Remove function pointers from domain pause helpers Andrew Cooper
2021-11-12 9:36 ` Julien Grall
2021-11-18 1:47 ` Andrew Cooper
2021-11-18 9:28 ` Julien Grall
2021-11-12 9:57 ` Jan Beulich
2021-11-17 23:31 ` Andrew Cooper
2021-11-15 10:13 ` Bertrand Marquis
2021-11-15 10:20 ` Jan Beulich
2021-11-15 10:23 ` Bertrand Marquis
2021-11-15 10:55 ` Jan Beulich
2021-11-15 11:23 ` Bertrand Marquis
2021-11-15 14:11 ` Julien Grall
2021-11-15 14:45 ` Bertrand Marquis
2021-11-16 0:41 ` Stefano Stabellini
2021-11-16 7:15 ` Jan Beulich
2021-11-11 17:57 ` [PATCH 2/5] xen/domain: Improve pirq handling Andrew Cooper
2021-11-12 10:16 ` Jan Beulich
2021-11-11 17:57 ` Andrew Cooper [this message]
2021-11-11 18:15 ` [PATCH 3/5] xen/sort: Switch to an extern inline implementation Julien Grall
2021-11-16 0:36 ` Stefano Stabellini
2021-11-16 0:41 ` Andrew Cooper
2021-12-17 15:56 ` Andrew Cooper
2021-12-17 16:15 ` Julien Grall
2021-11-12 9:39 ` Julien Grall
2021-11-12 10:25 ` Jan Beulich
2021-11-11 17:57 ` [PATCH 4/5] xen/wait: Remove indirect jump Andrew Cooper
2021-11-12 10:35 ` Jan Beulich
2021-11-11 17:57 ` [PATCH 5/5] x86/ioapic: Drop function pointers from __ioapic_{read,write}_entry() Andrew Cooper
2021-11-12 10:43 ` Jan Beulich
2021-11-18 0:32 ` Andrew Cooper
2021-11-18 9:06 ` Jan Beulich
2021-11-18 9:07 ` Jan Beulich
2021-11-18 17:33 ` Andrew Cooper
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20211111175740.23480-4-andrew.cooper3@citrix.com \
--to=andrew.cooper3@citrix.com \
--cc=JBeulich@suse.com \
--cc=Volodymyr_Babchuk@epam.com \
--cc=bertrand.marquis@arm.com \
--cc=julien@xen.org \
--cc=roger.pau@citrix.com \
--cc=sstabellini@kernel.org \
--cc=wl@xen.org \
--cc=xen-devel@lists.xenproject.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.