From: Yonghong Song <yhs@fb.com>
To: <bpf@vger.kernel.org>, <netdev@vger.kernel.org>
Cc: Alexei Starovoitov <ast@fb.com>,
Brian Vazquez <brianvv@google.com>,
Daniel Borkmann <daniel@iogearbox.net>, <kernel-team@fb.com>,
Yonghong Song <yhs@fb.com>
Subject: [PATCH bpf-next 13/13] tools/bpf: measure map batching perf
Date: Wed, 28 Aug 2019 23:45:17 -0700 [thread overview]
Message-ID: <20190829064517.2751629-1-yhs@fb.com> (raw)
In-Reply-To: <20190829064502.2750303-1-yhs@fb.com>
The test program run result:
$ ./test_maps
...
measure_lookup: max_entries 1000000, batch 10, time 342
measure_lookup: max_entries 1000000, batch 1000, time 295
measure_lookup: max_entries 1000000, batch 1000000, time 270
measure_lookup: max_entries 1000000, no batching, time 1346
measure_lookup_delete: max_entries 1000000, batch 10, time 433
measure_lookup_delete: max_entries 1000000, batch 1000, time 363
measure_lookup_delete: max_entries 1000000, batch 1000000, time 357
measure_lookup_delete: max_entries 1000000, not batch, time 1894
measure_delete: max_entries 1000000, batch, time 220
measure_delete: max_entries 1000000, not batch, time 1289
test_map_batch_perf:PASS
...
The test is running on a qemu VM environment. The time
unit is millisecond. A simple hash table with 1M elements
is created.
For lookup and lookup_and_deletion, since buffer allocation
is needed to hold the lookup results, three different
batch sizes (10, 1000, and 1M) are tried. The performance
without batching is also measured. A batch size of 10
can already improves performance dramatically, more than 70%,
and increasing batch size may continue to improve performance,
but with diminishing returns.
For delete, the batch API provides a mechanism to delete all elements
in the map, which is used here. The deletion of the whole map
improves performance by 80% compared to non-batch mechanism.
Signed-off-by: Yonghong Song <yhs@fb.com>
---
.../selftests/bpf/map_tests/map_batch_perf.c | 242 ++++++++++++++++++
1 file changed, 242 insertions(+)
create mode 100644 tools/testing/selftests/bpf/map_tests/map_batch_perf.c
diff --git a/tools/testing/selftests/bpf/map_tests/map_batch_perf.c b/tools/testing/selftests/bpf/map_tests/map_batch_perf.c
new file mode 100644
index 000000000000..42d95651e1ac
--- /dev/null
+++ b/tools/testing/selftests/bpf/map_tests/map_batch_perf.c
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2019 Facebook */
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
+
+#include <test_maps.h>
+
+/* Test map batch performance.
+ * Test three common scenarios:
+ * - batched lookup
+ * - batched lookup and delete
+ * - batched deletion
+ */
+static void map_batch_update(int map_fd, __u32 max_entries, int *keys,
+ int *values)
+{
+ int i, err;
+
+ for (i = 0; i < max_entries; i++) {
+ keys[i] = i + 1;
+ values[i] = i + 2;
+ }
+
+ err = bpf_map_update_batch(map_fd, keys, values, &max_entries, 0, 0);
+ CHECK(err, "bpf_map_update_batch()", "error:%s\n", strerror(errno));
+}
+
+static unsigned long util_gettime(void)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
+}
+
+static void measure_lookup(int map_fd, __u32 max_entries, int *keys,
+ int *values)
+{
+ __u32 batches[3] = {10, 1000};
+ int err, key, value, option;
+ unsigned long start, end;
+ void *p_key, *p_next_key;
+ __u32 count, total;
+
+ map_batch_update(map_fd, max_entries, keys, values);
+
+ /* batched */
+ batches[2] = max_entries;
+ for (option = 0; option < 3; option++) {
+ p_key = NULL;
+ p_next_key = &key;
+ count = batches[option];
+ start = util_gettime();
+ total = 0;
+
+ while (true) {
+ err = bpf_map_lookup_batch(map_fd, p_key, &p_next_key,
+ keys, values, &count, 0, 0);
+ CHECK(err, "bpf_map_lookup_batch()", "error: %s\n",
+ strerror(errno));
+
+ total += count;
+ if (!p_next_key)
+ break;
+
+ if (!p_key)
+ p_key = p_next_key;
+ }
+
+ end = util_gettime();
+ CHECK(total != max_entries,
+ "checking total", "total %u, max_entries %u\n",
+ total, max_entries);
+ printf("%s: max_entries %u, batch %u, time %ld\n", __func__,
+ max_entries, batches[option], end - start);
+ }
+
+ /* not batched */
+ start = util_gettime();
+ p_key = NULL;
+ p_next_key = &key;
+ while (!bpf_map_get_next_key(map_fd, p_key, p_next_key)) {
+ err = bpf_map_lookup_elem(map_fd, p_next_key, &value);
+ CHECK(err, "bpf_map_lookup_elem()", "error: %s\n",
+ strerror(errno));
+ p_key = p_next_key;
+ }
+ end = util_gettime();
+ printf("%s: max_entries %u, no batching, time %ld\n", __func__,
+ max_entries, end - start);
+}
+
+static void measure_lookup_delete(int map_fd, __u32 max_entries, int *keys,
+ int *values)
+{
+ int err, key, next_key, value, option;
+ __u32 batches[3] = {10, 1000};
+ unsigned long start, end;
+ void *p_key, *p_next_key;
+ __u32 count, total;
+
+ /* batched */
+ batches[2] = max_entries;
+ for (option = 0; option < 3; option++) {
+ map_batch_update(map_fd, max_entries, keys, values);
+ p_key = NULL;
+ p_next_key = &key;
+ count = batches[option];
+ start = util_gettime();
+ total = 0;
+
+ while (true) {
+ err = bpf_map_lookup_and_delete_batch(map_fd, p_key,
+ &p_next_key, keys, values, &count, 0, 0);
+ CHECK(err, "bpf_map_lookup_and_delete_batch()",
+ "error: %s\n", strerror(errno));
+
+ total += count;
+ if (!p_next_key)
+ break;
+
+ if (!p_key)
+ p_key = p_next_key;
+ }
+
+ end = util_gettime();
+ CHECK(total != max_entries,
+ "checking total", "total %u, max_entries %u\n",
+ total, max_entries);
+ printf("%s: max_entries %u, batch %u, time %ld\n", __func__,
+ max_entries, batches[option], end - start);
+ }
+
+ /* not batched */
+ map_batch_update(map_fd, max_entries, keys, values);
+ start = util_gettime();
+ p_key = NULL;
+ p_next_key = &key;
+ err = bpf_map_get_next_key(map_fd, p_key, p_next_key);
+ CHECK(err, "bpf_map_get_next_key()", "error: %s\n", strerror(errno));
+ err = bpf_map_lookup_elem(map_fd, p_next_key, &value);
+ CHECK(err, "bpf_map_lookup_elem()", "error: %s\n", strerror(errno));
+
+ p_key = p_next_key;
+ p_next_key = &next_key;
+ while (!bpf_map_get_next_key(map_fd, p_key, p_next_key)) {
+ err = bpf_map_delete_elem(map_fd, p_key);
+ CHECK(err, "bpf_map_delete_elem()", "error: %s\n",
+ strerror(errno));
+
+ err = bpf_map_lookup_elem(map_fd, p_next_key, &value);
+ CHECK(err, "bpf_map_lookup_elem()", "error: %s\n",
+ strerror(errno));
+
+ p_key = p_next_key;
+ p_next_key = (p_next_key == &key) ? &next_key : &key;
+ }
+ err = bpf_map_delete_elem(map_fd, p_key);
+ CHECK(err, "bpf_map_delete_elem()", "error: %s\n",
+ strerror(errno));
+ end = util_gettime();
+ printf("%s: max_entries %u, not batch, time %ld\n", __func__,
+ max_entries, end - start);
+}
+
+static void measure_delete(int map_fd, __u32 max_entries, int *keys,
+ int *values)
+{
+ unsigned long start, end;
+ void *p_key, *p_next_key;
+ int err, key, next_key;
+ __u32 count;
+
+ /* batched */
+ map_batch_update(map_fd, max_entries, keys, values);
+ count = 0;
+ p_next_key = &key;
+ start = util_gettime();
+ err = bpf_map_delete_batch(map_fd, NULL, NULL, NULL, &count, 0, 0);
+ end = util_gettime();
+ CHECK(err, "bpf_map_delete_batch()", "error: %s\n", strerror(errno));
+ CHECK(count != max_entries, "bpf_map_delete_batch()",
+ "count = %u, max_entries = %u\n", count, max_entries);
+
+ printf("%s: max_entries %u, batch, time %ld\n", __func__,
+ max_entries, end - start);
+
+ map_batch_update(map_fd, max_entries, keys, values);
+ p_key = NULL;
+ p_next_key = &key;
+ start = util_gettime();
+ err = bpf_map_get_next_key(map_fd, p_key, p_next_key);
+ CHECK(err, "bpf_map_get_next_key()", "error: %s\n", strerror(errno));
+
+ p_key = p_next_key;
+ p_next_key = &next_key;
+ while (!bpf_map_get_next_key(map_fd, p_key, p_next_key)) {
+ err = bpf_map_delete_elem(map_fd, p_key);
+ CHECK(err, "bpf_map_delete_elem()", "error: %s\n",
+ strerror(errno));
+ p_key = p_next_key;
+ p_next_key = (p_next_key == &key) ? &next_key : &key;
+ }
+ err = bpf_map_delete_elem(map_fd, p_key);
+ CHECK(err, "bpf_map_delete_elem()", "error: %s\n",
+ strerror(errno));
+ end = util_gettime();
+ printf("%s: max_entries %u, not batch, time %ld\n", __func__,
+ max_entries, end - start);
+}
+
+void test_map_batch_perf(void)
+{
+ struct bpf_create_map_attr xattr = {
+ .name = "hash_map",
+ .map_type = BPF_MAP_TYPE_HASH,
+ .key_size = sizeof(int),
+ .value_size = sizeof(int),
+ };
+ const __u32 max_entries = 1000000; // 1M entries for the hash table
+ int map_fd, *keys, *values;
+
+ xattr.max_entries = max_entries;
+ map_fd = bpf_create_map_xattr(&xattr);
+ CHECK(map_fd == -1,
+ "bpf_create_map_xattr()", "error:%s\n", strerror(errno));
+
+ keys = malloc(max_entries * sizeof(int));
+ values = malloc(max_entries * sizeof(int));
+ CHECK(!keys || !values, "malloc()", "error:%s\n", strerror(errno));
+
+ measure_lookup(map_fd, max_entries, keys, values);
+ measure_lookup_delete(map_fd, max_entries, keys, values);
+ measure_delete(map_fd, max_entries, keys, values);
+
+ printf("%s:PASS\n", __func__);
+}
--
2.17.1
next prev parent reply other threads:[~2019-08-29 6:45 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-08-29 6:45 [PATCH bpf-next 00/13] bpf: adding map batch processing support Yonghong Song
2019-08-29 6:45 ` [PATCH bpf-next 01/13] bpf: add bpf_map_value_size and bp_map_copy_value helper functions Yonghong Song
2019-08-29 22:04 ` Song Liu
2019-08-30 6:40 ` Yonghong Song
2019-08-29 6:45 ` [PATCH bpf-next 02/13] bpf: refactor map_update_elem() Yonghong Song
2019-08-29 23:37 ` Song Liu
2019-08-29 6:45 ` [PATCH bpf-next 03/13] bpf: refactor map_delete_elem() Yonghong Song
2019-08-29 23:39 ` Song Liu
2019-08-29 6:45 ` [PATCH bpf-next 04/13] bpf: refactor map_get_next_key() Yonghong Song
2019-08-29 23:39 ` Song Liu
2019-08-29 6:45 ` [PATCH bpf-next 05/13] bpf: adding map batch processing support Yonghong Song
2019-08-29 23:01 ` Brian Vazquez
2019-08-30 6:39 ` Yonghong Song
2019-08-30 6:58 ` Alexei Starovoitov
2019-08-29 6:45 ` [PATCH bpf-next 06/13] tools/bpf: sync uapi header bpf.h Yonghong Song
2019-08-29 6:45 ` [PATCH bpf-next 07/13] tools/bpf: implement libbpf API functions for map batch operations Yonghong Song
2019-08-29 6:45 ` [PATCH bpf-next 08/13] tools/bpf: add test for bpf_map_update_batch() Yonghong Song
2019-08-29 6:45 ` [PATCH bpf-next 09/13] tools/bpf: add test for bpf_map_lookup_batch() Yonghong Song
2019-08-29 6:45 ` [PATCH bpf-next 10/13] tools/bpf: add test for bpf_map_lookup_and_delete_batch() Yonghong Song
2019-08-29 6:45 ` [PATCH bpf-next 11/13] tools/bpf: add test for bpf_map_delete_batch() Yonghong Song
2019-08-29 6:45 ` [PATCH bpf-next 12/13] tools/bpf: add a multithreaded test for map batch operations Yonghong Song
2019-08-29 6:45 ` Yonghong Song [this message]
2019-08-29 18:39 ` [PATCH bpf-next 00/13] bpf: adding map batch processing support Jakub Kicinski
2019-08-29 23:13 ` Brian Vazquez
2019-08-30 0:15 ` Jakub Kicinski
2019-08-30 20:15 ` Stanislav Fomichev
2019-08-30 20:55 ` Yonghong Song
2019-08-30 21:10 ` Jakub Kicinski
2019-08-30 22:24 ` Yonghong Song
2019-08-30 21:18 ` Stanislav Fomichev
2019-09-03 21:01 ` Alexei Starovoitov
2019-09-03 22:30 ` Stanislav Fomichev
2019-09-03 23:07 ` Brian Vazquez
2019-09-04 1:35 ` Alexei Starovoitov
2019-09-03 23:07 ` Yonghong Song
2019-08-30 7:25 ` Yonghong Song
2019-08-30 21:35 ` Jakub Kicinski
2019-08-30 22:38 ` Yonghong Song
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=20190829064517.2751629-1-yhs@fb.com \
--to=yhs@fb.com \
--cc=ast@fb.com \
--cc=bpf@vger.kernel.org \
--cc=brianvv@google.com \
--cc=daniel@iogearbox.net \
--cc=kernel-team@fb.com \
--cc=netdev@vger.kernel.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.