[ovs-dev] [PATCH v4 06/17] tests: Add very simple conntrack benchmark.
Daniele Di Proietto
diproiettod at vmware.com
Fri Jun 10 22:47:32 UTC 2016
This introduces a very limited but simple benchmark for
conntrack_execute(). It just sends repeatedly the same batch of packets
through the connection tracker and returns the time spent to process
them.
While this is not a realistic benchmark, it has proven useful during
development to evaluate different batching and locking strategies.
E.g. the line:
`./test/ovstest test-conntrack benchmark 1 14880000 32`
starts 1 thread that will send 14880000 packets to the connection
tracker, 32 at a time. It will print the time taken to process them.
Signed-off-by: Daniele Di Proietto <diproiettod at vmware.com>
Acked-by: Flavio Leitner <fbl at sysclose.org>
---
tests/automake.mk | 1 +
tests/test-conntrack.c | 172 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 173 insertions(+)
create mode 100644 tests/test-conntrack.c
diff --git a/tests/automake.mk b/tests/automake.mk
index 777f6db..c3dcb6b 100644
--- a/tests/automake.mk
+++ b/tests/automake.mk
@@ -323,6 +323,7 @@ tests_ovstest_SOURCES = \
tests/test-classifier.c \
tests/test-ccmap.c \
tests/test-cmap.c \
+ tests/test-conntrack.c \
tests/test-csum.c \
tests/test-flows.c \
tests/test-hash.c \
diff --git a/tests/test-conntrack.c b/tests/test-conntrack.c
new file mode 100644
index 0000000..e2224e8
--- /dev/null
+++ b/tests/test-conntrack.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2015 Nicira, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <config.h>
+#include "conntrack.h"
+
+#include "dp-packet.h"
+#include "fatal-signal.h"
+#include "flow.h"
+#include "netdev.h"
+#include "ovs-thread.h"
+#include "ovstest.h"
+#include "timeval.h"
+
+static const char payload[] = "50540000000a50540000000908004500001c0000000000"
+ "11a4cd0a0101010a0101020001000200080000";
+
+static struct dp_packet_batch *
+prepare_packets(size_t n, bool change, unsigned tid)
+{
+ struct dp_packet_batch *pkt_batch = xzalloc(sizeof *pkt_batch);
+ struct flow flow;
+ size_t i;
+
+ ovs_assert(n <= ARRAY_SIZE(pkt_batch->packets));
+
+ dp_packet_batch_init(pkt_batch);
+ pkt_batch->count = n;
+
+ for (i = 0; i < n; i++) {
+ struct udp_header *udp;
+ struct dp_packet *pkt = dp_packet_new(sizeof payload/2);
+
+ dp_packet_put_hex(pkt, payload, NULL);
+ flow_extract(pkt, &flow);
+
+ udp = dp_packet_l4(pkt);
+ udp->udp_src = htons(ntohs(udp->udp_src) + tid);
+
+ if (change) {
+ udp->udp_dst = htons(ntohs(udp->udp_dst) + i);
+ }
+
+ pkt_batch->packets[i] = pkt;
+ }
+
+ return pkt_batch;
+}
+
+static void
+destroy_packets(struct dp_packet_batch *pkt_batch)
+{
+ dp_packet_delete_batch(pkt_batch, true);
+ free(pkt_batch);
+}
+
+struct thread_aux {
+ pthread_t thread;
+ unsigned tid;
+};
+
+static struct conntrack ct;
+static unsigned long n_threads, n_pkts, batch_size;
+static bool change_conn = false;
+static pthread_barrier_t barrier;
+
+static void *
+ct_thread_main(void *aux_)
+{
+ struct thread_aux *aux = aux_;
+ struct dp_packet_batch *pkt_batch;
+ size_t i;
+
+ pkt_batch = prepare_packets(batch_size, change_conn, aux->tid);
+ pthread_barrier_wait(&barrier);
+ for (i = 0; i < n_pkts; i += batch_size) {
+ conntrack_execute(&ct, pkt_batch, true, 0, NULL, NULL, NULL);
+ }
+ pthread_barrier_wait(&barrier);
+ destroy_packets(pkt_batch);
+
+ return NULL;
+}
+
+static void
+test_benchmark(struct ovs_cmdl_context *ctx)
+{
+ struct thread_aux *threads;
+ long long start;
+ unsigned i;
+
+ fatal_signal_init();
+
+ /* Parse arguments */
+ n_threads = strtoul(ctx->argv[1], NULL, 0);
+ if (!n_threads) {
+ ovs_fatal(0, "n_threads must be at least one");
+ }
+ n_pkts = strtoul(ctx->argv[2], NULL, 0);
+ batch_size = strtoul(ctx->argv[3], NULL, 0);
+ if (batch_size == 0 || batch_size > NETDEV_MAX_BURST) {
+ ovs_fatal(0, "batch_size must be between 1 and NETDEV_MAX_BURST(%u)",
+ NETDEV_MAX_BURST);
+ }
+ if (ctx->argc > 4) {
+ change_conn = strtoul(ctx->argv[4], NULL, 0);
+ }
+
+ threads = xcalloc(n_threads, sizeof *threads);
+ pthread_barrier_init(&barrier, NULL, n_threads + 1);
+ conntrack_init(&ct);
+
+ /* Create threads */
+ for (i = 0; i < n_threads; i++) {
+ threads[i].tid = i;
+ threads[i].thread = ovs_thread_create("ct_thread", ct_thread_main,
+ &threads[i]);
+ }
+ /* Starts the work inside the threads */
+ pthread_barrier_wait(&barrier);
+ start = time_msec();
+
+ /* Wait for the threads to finish the work */
+ pthread_barrier_wait(&barrier);
+ printf("conntrack: %5lld ms\n", time_msec() - start);
+
+ for (i = 0; i < n_threads; i++) {
+ xpthread_join(threads[i].thread, NULL);
+ }
+
+ conntrack_destroy(&ct);
+ pthread_barrier_destroy(&barrier);
+ free(threads);
+}
+
+static const struct ovs_cmdl_command commands[] = {
+ /* Connection tracker tests. */
+ /* Starts 'n_threads' threads. Each thread will send 'n_pkts' packets to
+ * the connection tracker, 'batch_size' per call. If 'change_connection'
+ * is '1', each packet in a batch will have a different source and
+ * destination port */
+ {"benchmark", "n_threads n_pkts batch_size [change_connection]", 3, 4,
+ test_benchmark},
+
+ {NULL, NULL, 0, 0, NULL},
+};
+
+static void
+test_conntrack_main(int argc, char *argv[])
+{
+ struct ovs_cmdl_context ctx = {
+ .argc = argc - 1,
+ .argv = argv + 1,
+ };
+ set_program_name(argv[0]);
+ ovs_cmdl_run_command(&ctx, commands);
+}
+
+OVSTEST_REGISTER("test-conntrack", test_conntrack_main);
--
2.8.1
More information about the dev
mailing list