From: Pablo Neira Ayuso <pablo@netfilter.org>
To: netfilter-devel@vger.kernel.org
Cc: phil@nwl.cc
Subject: [PATCH nft 2/2,v2] intervals: Do not sort cached set elements over and over again
Date: Thu, 16 Jun 2022 11:04:46 +0200 [thread overview]
Message-ID: <20220616090446.275985-2-pablo@netfilter.org> (raw)
In-Reply-To: <20220616090446.275985-1-pablo@netfilter.org>
From: Phil Sutter <phil@nwl.cc>
When adding element(s) to a non-empty set, code merged the two lists and
sorted the result. With many individual 'add element' commands this
causes substantial overhead. Make use of the fact that
existing_set->init is sorted already, sort only the list of new elements
and use list_splice_sorted() to merge the two sorted lists.
Add set_sort_splice() and use it for set element overlap detection and
automerge.
A test case adding ~25k elements in individual commands completes in
about 1/4th of the time with this patch applied.
Joint work with Pablo.
Fixes: 3da9643fb9ff9 ("intervals: add support to automerge with kernel elements")
Signed-off-by: Phil Sutter <phil@nwl.cc>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v2: add set_sort_splice() and reuse it for the automerge case.
include/expression.h | 1 +
src/intervals.c | 46 +++++++++++++++++++++-----------------------
src/mergesort.c | 2 +-
3 files changed, 24 insertions(+), 25 deletions(-)
diff --git a/include/expression.h b/include/expression.h
index 2c3818e89b79..0f7ffb3a0a62 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -480,6 +480,7 @@ extern struct expr *compound_expr_alloc(const struct location *loc,
extern void compound_expr_add(struct expr *compound, struct expr *expr);
extern void compound_expr_remove(struct expr *compound, struct expr *expr);
extern void list_expr_sort(struct list_head *head);
+extern void list_splice_sorted(struct list_head *list, struct list_head *head);
extern struct expr *concat_expr_alloc(const struct location *loc);
diff --git a/src/intervals.c b/src/intervals.c
index e20341320da2..dcc06d18d594 100644
--- a/src/intervals.c
+++ b/src/intervals.c
@@ -118,6 +118,26 @@ static bool merge_ranges(struct set_automerge_ctx *ctx,
return false;
}
+static void set_sort_splice(struct expr *init, struct set *set)
+{
+ struct set *existing_set = set->existing_set;
+
+ set_to_range(init);
+ list_expr_sort(&init->expressions);
+
+ if (!existing_set)
+ return;
+
+ if (existing_set->init) {
+ set_to_range(existing_set->init);
+ list_splice_sorted(&existing_set->init->expressions,
+ &init->expressions);
+ init_list_head(&existing_set->init->expressions);
+ } else {
+ existing_set->init = set_expr_alloc(&internal_location, set);
+ }
+}
+
static void setelem_automerge(struct set_automerge_ctx *ctx)
{
struct expr *i, *next, *prev = NULL;
@@ -222,18 +242,7 @@ int set_automerge(struct list_head *msgs, struct cmd *cmd, struct set *set,
return 0;
}
- if (existing_set) {
- if (existing_set->init) {
- list_splice_init(&existing_set->init->expressions,
- &init->expressions);
- } else {
- existing_set->init = set_expr_alloc(&internal_location,
- set);
- }
- }
-
- set_to_range(init);
- list_expr_sort(&init->expressions);
+ set_sort_splice(init, set);
ctx.purge = set_expr_alloc(&internal_location, set);
@@ -591,18 +600,7 @@ int set_overlap(struct list_head *msgs, struct set *set, struct expr *init)
struct expr *i, *n, *clone;
int err;
- if (existing_set) {
- if (existing_set->init) {
- list_splice_init(&existing_set->init->expressions,
- &init->expressions);
- } else {
- existing_set->init = set_expr_alloc(&internal_location,
- set);
- }
- }
-
- set_to_range(init);
- list_expr_sort(&init->expressions);
+ set_sort_splice(init, set);
err = setelem_overlap(msgs, set, init);
diff --git a/src/mergesort.c b/src/mergesort.c
index 8e6aac5fb24e..dca71422dd94 100644
--- a/src/mergesort.c
+++ b/src/mergesort.c
@@ -70,7 +70,7 @@ static int expr_msort_cmp(const struct expr *e1, const struct expr *e2)
return ret;
}
-static void list_splice_sorted(struct list_head *list, struct list_head *head)
+void list_splice_sorted(struct list_head *list, struct list_head *head)
{
struct list_head *h = head->next;
struct list_head *l = list->next;
--
2.30.2
next prev parent reply other threads:[~2022-06-16 9:04 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-06-16 9:04 [PATCH nft 1/2] intervals: do not empty cache for maps Pablo Neira Ayuso
2022-06-16 9:04 ` Pablo Neira Ayuso [this message]
2022-06-23 16:05 ` [PATCH nft 2/2,v2] intervals: Do not sort cached set elements over and over again Phil Sutter
2022-06-23 16:17 ` Pablo Neira Ayuso
2022-06-23 16:25 ` Phil Sutter
2022-06-23 17:19 ` Pablo Neira Ayuso
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=20220616090446.275985-2-pablo@netfilter.org \
--to=pablo@netfilter.org \
--cc=netfilter-devel@vger.kernel.org \
--cc=phil@nwl.cc \
/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.