forked from openvswitch/ovs
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tests: Add very simple conntrack benchmark.
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: `./tests/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 <[email protected]> Acked-by: Flavio Leitner <[email protected]>
- Loading branch information
1 parent
6c54734
commit 8cb1462
Showing
2 changed files
with
173 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 struct ovs_barrier 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); | ||
ovs_barrier_block(&barrier); | ||
for (i = 0; i < n_pkts; i += batch_size) { | ||
conntrack_execute(&ct, pkt_batch, true, 0, NULL, NULL, NULL); | ||
} | ||
ovs_barrier_block(&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); | ||
ovs_barrier_init(&barrier, 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 */ | ||
ovs_barrier_block(&barrier); | ||
start = time_msec(); | ||
|
||
/* Wait for the threads to finish the work */ | ||
ovs_barrier_block(&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); | ||
ovs_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); |