From patchwork Tue Feb 20 22:13:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Michelson X-Patchwork-Id: 875815 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zmFKD0Vvxz9s0v for ; Wed, 21 Feb 2018 09:14:40 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 4524912B1; Tue, 20 Feb 2018 22:13:38 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 3392A11F6 for ; Tue, 20 Feb 2018 22:13:35 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx1.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id CA7A9419 for ; Tue, 20 Feb 2018 22:13:33 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 146C58163C50 for ; Tue, 20 Feb 2018 22:13:33 +0000 (UTC) Received: from monae.redhat.com (ovpn-124-121.rdu2.redhat.com [10.10.124.121]) by smtp.corp.redhat.com (Postfix) with ESMTP id E4B78AF008 for ; Tue, 20 Feb 2018 22:13:32 +0000 (UTC) From: Mark Michelson To: dev@openvswitch.org Date: Tue, 20 Feb 2018 16:13:31 -0600 Message-Id: <20180220221332.2535-2-mmichels@redhat.com> In-Reply-To: <20180220221332.2535-1-mmichels@redhat.com> References: <20180220221332.2535-1-mmichels@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 20 Feb 2018 22:13:33 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Tue, 20 Feb 2018 22:13:33 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'mmichels@redhat.com' RCPT:'' X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, T_RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v4 1/2] Add performance measuring API X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This is similar to the existing coverage and perf-counter APIs in OVS. However, rather than keeping counters, this is aimed at timing how long operations take to perform. "Operations" in this case can be anything from a loop iteration, to a function, to something more complex. The library will keep track of how long it takes to perform the particular operations and will maintain statistics of those running times. Statistics for a particular operation can be queried from the command line by using ovs-appctl -t performance/show . The API is designed to be pretty small. The expected steps are as follows: 1) Create a performance measurement, providing a unique name, using performance_create() 2) Add calls to start_sample() and end_sample() to mark the start and stop of the operation you wish to measure. Two CLI commands have been added: * Display statistics for a particular measurement. * Reset a particular measurement. Signed-off-by: Mark Michelson --- lib/automake.mk | 2 + lib/performance.c | 480 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/performance.h | 42 +++++ 3 files changed, 524 insertions(+) create mode 100644 lib/performance.c create mode 100644 lib/performance.h diff --git a/lib/automake.mk b/lib/automake.mk index 5c26e0f33..b65dd2c13 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -222,6 +222,8 @@ lib_libopenvswitch_la_SOURCES = \ lib/pcap-file.h \ lib/perf-counter.h \ lib/perf-counter.c \ + lib/performance.h \ + lib/performance.c \ lib/poll-loop.c \ lib/process.c \ lib/process.h \ diff --git a/lib/performance.c b/lib/performance.c new file mode 100644 index 000000000..e37dcd169 --- /dev/null +++ b/lib/performance.c @@ -0,0 +1,480 @@ +/* Copyright (c) 2017 Red Hat, 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 + +#include "performance.h" +#include "openvswitch/shash.h" +#include "openvswitch/vlog.h" +#include "unixctl.h" +#include "openvswitch/dynamic-string.h" +#include "openvswitch/poll-loop.h" +#include "ovs-thread.h" +#include +#include "socket-util.h" + +VLOG_DEFINE_THIS_MODULE(performance); + +struct sample { + unsigned long long start_time; /* Time when we started this sample */ + unsigned long long end_time; /* Time when we ended this sample */ +}; + +struct average { + double average; /* Moving average */ + double alpha; /* Weight given to new samples */ +}; + +#define MARKERS 5 + +/* The naming of these fields is based on the naming used in the + * P-square algorithm paper. + */ +struct percentile { + int n[MARKERS]; + double n_prime[MARKERS]; + double q[MARKERS]; + double dn[MARKERS]; + double percentile; +}; + +struct performance { + struct sample cur_sample; + enum performance_units units; + unsigned long long samples; + unsigned long long max; + unsigned long long min; + struct percentile pctl; + struct average short_term; + struct average long_term; +}; + +enum performance_op { + OP_START_SAMPLE, + OP_END_SAMPLE, + OP_RESET, + OP_SHUTDOWN, +}; + +struct performance_packet { + enum performance_op op; + char name[32]; + unsigned long long time; +}; + +static struct shash performances = SHASH_INITIALIZER(&performances); +static struct ovs_mutex performances_lock = OVS_MUTEX_INITIALIZER; + +static int performance_pipe[2]; +static pthread_t performance_thread_id; + +const char *unit_name[] = { + [PERF_MS] = "msec", + [PERF_US] = "usec", + [PERF_NS] = "nsec", +}; + +/* Percentile value we are calculating */ +#define P 0.95 + +static int +comp_samples(const void *left, const void *right) +{ + const double *left_d = left; + const double *right_d = right; + + return (int) *right_d - *left_d; +} + +/* Calculate the percentile using the P-square algorithm. For more + * information, see https://www1.cse.wustl.edu/~jain/papers/ftp/psqr.pdf + */ +static void +calc_percentile(unsigned long long samples, struct percentile *pctl, + double new_sample) +{ + /* For the first MARKERS samples, we calculate the percentile + * in the traditional way + */ + if (samples <= MARKERS) { + pctl->q[samples - 1] = new_sample; + qsort(pctl->q, samples, sizeof *pctl->q, comp_samples); + if (samples == MARKERS) { + pctl->n[0] = 0; + pctl->n[1] = 1; + pctl->n[2] = 2; + pctl->n[3] = 3; + pctl->n[4] = 4; + + pctl->n_prime[0] = 0; + pctl->n_prime[1] = 2 * P; + pctl->n_prime[2] = 4 * P; + pctl->n_prime[3] = 2 + 2 * P; + pctl->n_prime[4] = 4; + + pctl->dn[0] = 0; + pctl->dn[1] = P / 2; + pctl->dn[2] = P; + pctl->dn[3] = (1 + P) / 2; + pctl->dn[4] = 1; + } + pctl->percentile = pctl->q[(int) P * samples]; + return; + } + + /* From here on, update the markers using quadratic spline calculations */ + int k; + if (new_sample < pctl->q[0]) { + k = 0; + pctl->q[0] = new_sample; + } else if (new_sample < pctl->q[1]) { + k = 0; + } else if (new_sample < pctl->q[2]) { + k = 1; + } else if (new_sample < pctl->q[3]) { + k = 2; + } else if (new_sample <= pctl->q[4]) { + k = 3; + } else { + k = 3; + pctl->q[4] = new_sample; + } + + for (int i = k + 1; i < MARKERS; i++) { + pctl->n[i]++; + } + + for (int i = 0; i < MARKERS; i++) { + pctl->n_prime[i] += pctl->dn[i]; + } + + for (int i = 1; i < MARKERS - 1; i++) { + double d = pctl->n_prime[i] - pctl->n[i]; + + if ((d >= 1 && pctl->n[i + 1] - pctl->n[i] > 1) || + (d <= -1 && pctl->n[i - 1] - pctl->n[i] < -1)) { + d = d >= 0 ? 1 : -1; + + double a = d / (pctl->n[i + 1] - pctl->n[i - 1]); + double b = (pctl->n[i] - pctl->n[i - 1] + d) * + (pctl->q[i + 1] - pctl->q[i]) / (pctl->n[i + 1] - pctl->n[i]); + double c = (pctl->n[i + 1] - pctl->n[i] - d) * + (pctl->q[i] - pctl->q[i - 1]) / (pctl->n[i] - pctl->n[i - 1]); + + double candidate = pctl->q[i] + a * (b + c); + if (pctl->q[i - 1] < candidate && candidate < pctl->q[i + 1]) { + pctl->q[i] = candidate; + } else { + pctl->q[i] = pctl->q[i] + + (d * (pctl->q[i + (int)d] - pctl->q[i]) / + (pctl->n[i +(int)d] - pctl->n[i])); + } + + pctl->n[i] += d; + } + } + + pctl->percentile = pctl->q[2]; +} + +static void +calc_average(struct average *avg, double new_sample) +{ + avg->average = new_sample * avg->alpha + (1 - avg->alpha) * avg->average; +} + +static void +add_sample(struct performance *perf, double new_sample) +{ + if (new_sample > perf->max) { + perf->max = new_sample; + } else if (new_sample < perf->min) { + perf->min = new_sample; + } + + calc_percentile(perf->samples, &perf->pctl, new_sample); + + if (perf->samples++ == 0) { + perf->short_term.average = perf->long_term.average = new_sample; + return; + } + + calc_average(&perf->short_term, new_sample); + calc_average(&perf->long_term, new_sample); +} + +static void +performance_print(struct performance *perf, const char *name, + struct ds *s) +{ + ds_put_format(s, "Statistics for '%s'\n", name); + + const char *units = unit_name[perf->units]; + ds_put_format(s, "\t Total samples: %llu\n", perf->samples); + ds_put_format(s, "\t Maximum: %llu %s\n", perf->max, units); + ds_put_format(s, "\t Minimum: %llu %s\n", perf->min, units); + ds_put_format(s, "\t 95th percentile: %f %s\n", + perf->pctl.percentile, units); + ds_put_format(s, "\t Short term average: %f %s\n", + perf->short_term.average, units); + ds_put_format(s, "\t Long term average: %f %s\n", + perf->long_term.average, units); +} + +static bool +performance_show_protected(int argc, const char *argv[], struct ds *s) +{ + struct performance *perf; + + if (argc > 1) { + perf = shash_find_data(&performances, argv[1]); + if (!perf) { + ds_put_cstr(s, "No such performance"); + return false; + } + performance_print(perf, argv[1], s); + } else { + struct shash_node *node; + SHASH_FOR_EACH (node, &performances) { + perf = node->data; + performance_print(perf, node->name, s); + } + } + + return true; +} + +static void +performance_show(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[], void *ignore OVS_UNUSED) +{ + struct ds s = DS_EMPTY_INITIALIZER; + bool success; + + ovs_mutex_lock(&performances_lock); + success = performance_show_protected(argc, argv, &s); + ovs_mutex_unlock(&performances_lock); + + if (success) { + unixctl_command_reply(conn, ds_cstr(&s)); + } else { + unixctl_command_reply_error(conn, ds_cstr(&s)); + } + ds_destroy(&s); +} + +static void +performance_reset(struct unixctl_conn *conn, int argc OVS_UNUSED, + const char *argv[], void *ignore OVS_UNUSED) +{ + struct performance_packet pkt = { + .op = OP_RESET, + }; + if (argc > 1) { + ovs_strlcpy(pkt.name, argv[1], sizeof(pkt.name)); + } + write(performance_pipe[1], &pkt, sizeof(pkt)); + unixctl_command_reply(conn, ""); +} + +static bool +performance_start_sample_protected(const struct performance_packet *pkt) +{ + struct performance *perf = shash_find_data(&performances, pkt->name); + if (!perf) { + return false; + } + + /* We already started sampling. Need an end before + * we start another sample + */ + if (perf->cur_sample.start_time) { + return false; + } + + perf->cur_sample.start_time = pkt->time; + return true; +} + +static bool +performance_end_sample_protected(const struct performance_packet *pkt) +{ + struct performance *perf = shash_find_data(&performances, pkt->name); + if (!perf) { + return false; + } + + /* We can't end a sample if we haven't started one */ + if (!perf->cur_sample.start_time) { + return false; + } + + perf->cur_sample.end_time = pkt->time; + add_sample(perf, perf->cur_sample.end_time - perf->cur_sample.start_time); + perf->cur_sample.start_time = perf->cur_sample.end_time = 0; + return true; +} + +static void reset_performance(struct performance *perf) +{ + perf->short_term.average = 0; + perf->long_term.average = 0; + perf->pctl.percentile = 0; + perf->samples = 0; + perf->max = 0; + perf->min = 0; +} + +static void +performance_reset_protected(const struct performance_packet *pkt) +{ + if (pkt->name[0]) { + struct performance *perf = shash_find_data(&performances, pkt->name); + if (!perf) { + return; + } + reset_performance(perf); + return; + } + + struct shash_node *node; + SHASH_FOR_EACH (node, &performances) { + struct performance *perf = node->data; + reset_performance(perf); + } +} + +static void * +performance_thread(void *ign OVS_UNUSED) +{ + bool should_exit = false; + + while (!should_exit) { + struct performance_packet pkt; + while (read(performance_pipe[0], &pkt, sizeof(pkt)) > 0) { + ovs_mutex_lock(&performances_lock); + switch (pkt.op) { + case OP_START_SAMPLE: + performance_start_sample_protected(&pkt); + break; + case OP_END_SAMPLE: + performance_end_sample_protected(&pkt); + break; + case OP_RESET: + performance_reset_protected(&pkt); + break; + case OP_SHUTDOWN: + should_exit = true; + break; + } + ovs_mutex_unlock(&performances_lock); + } + + if (!should_exit) { + poll_fd_wait(performance_pipe[0], POLLIN); + poll_block(); + } + } + + return NULL; +} + +static void +performance_exit(void) +{ + struct shash_node *node, *node_next; + struct performance_packet pkt = { + .op = OP_SHUTDOWN, + }; + + write(performance_pipe[1], &pkt, sizeof pkt); + xpthread_join(performance_thread_id, NULL); + + /* Process is exiting and we have joined the only + * other competing thread. We are now the sole owners + * of all data in the file. + */ + SHASH_FOR_EACH_SAFE (node, node_next, &performances) { + struct performance *perf = node->data; + shash_delete(&performances, node); + free(perf); + } + shash_destroy(&performances); + ovs_mutex_destroy(&performances_lock); +} + +static void +do_init_performance(void) +{ + unixctl_command_register("performance/show", "[NAME]", 0, 1, + performance_show, NULL); + unixctl_command_register("performance/reset", "[NAME]", 0, 1, + performance_reset, NULL); + xpipe_nonblocking(performance_pipe); + performance_thread_id = ovs_thread_create( + "performance", performance_thread, NULL); + atexit(performance_exit); +} + +static void +performance_init(void) +{ + static struct ovsthread_once once = OVSTHREAD_ONCE_INITIALIZER; + if (ovsthread_once_start(&once)) { + do_init_performance(); + ovsthread_once_done(&once); + } +} + +void +performance_create(const char *name, enum performance_units units) +{ + performance_init(); + + struct performance *perf = xzalloc(sizeof *perf); + perf->units = units; + perf->short_term.alpha = 0.50; + perf->long_term.alpha = 0.01; + + ovs_mutex_lock(&performances_lock); + shash_add(&performances, name, perf); + ovs_mutex_unlock(&performances_lock); +} + +bool +performance_start_sample(const char *name, unsigned long long ts) +{ + struct performance_packet pkt = { + .op = OP_START_SAMPLE, + .time = ts, + }; + ovs_strlcpy(pkt.name, name, sizeof(pkt.name)); + write(performance_pipe[1], &pkt, sizeof(pkt)); + + return true; +} + +bool +performance_end_sample(const char *name, unsigned long long ts) +{ + struct performance_packet pkt = { + .op = OP_END_SAMPLE, + .time = ts, + }; + ovs_strlcpy(pkt.name, name, sizeof(pkt.name)); + write(performance_pipe[1], &pkt, sizeof(pkt)); + + return true; +} diff --git a/lib/performance.h b/lib/performance.h new file mode 100644 index 000000000..f039689e8 --- /dev/null +++ b/lib/performance.h @@ -0,0 +1,42 @@ +/* Copyright (c) 2017 Red Hat, 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. + */ + +#ifndef PERFORMANCE_H +#define PERFORMANCE_H 1 + +#include + +enum performance_units { + PERF_MS, + PERF_US, + PERF_NS, +}; + +/* Create a new performance measurement. + * The "units" are not used for any calculations but are printed when + * statistics are requested. + */ +void performance_create(const char *name, enum performance_units units); + +/* Indicate that a performance measurement is beginning. */ +bool performance_start_sample(const char *name, unsigned long long ts); + +/* Indicate that a performance measurement has ended. The + * sample will be added to the history of performance + * measurements for this tracker + */ +bool performance_end_sample(const char *name, unsigned long long ts); + +#endif /* performance.h */ From patchwork Tue Feb 20 22:13:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mark Michelson X-Patchwork-Id: 875814 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3zmFJf4wLfz9s0x for ; Wed, 21 Feb 2018 09:14:10 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 488F11213; Tue, 20 Feb 2018 22:13:37 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id 7398711F6 for ; Tue, 20 Feb 2018 22:13:34 +0000 (UTC) X-Greylist: domain auto-whitelisted by SQLgrey-1.7.6 Received: from mx1.redhat.com (mx3-rdu2.redhat.com [66.187.233.73]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id E4757466 for ; Tue, 20 Feb 2018 22:13:33 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 3DD004040857 for ; Tue, 20 Feb 2018 22:13:33 +0000 (UTC) Received: from monae.redhat.com (ovpn-124-121.rdu2.redhat.com [10.10.124.121]) by smtp.corp.redhat.com (Postfix) with ESMTP id 2170BAF009 for ; Tue, 20 Feb 2018 22:13:33 +0000 (UTC) From: Mark Michelson To: dev@openvswitch.org Date: Tue, 20 Feb 2018 16:13:32 -0600 Message-Id: <20180220221332.2535-3-mmichels@redhat.com> In-Reply-To: <20180220221332.2535-1-mmichels@redhat.com> References: <20180220221332.2535-1-mmichels@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 20 Feb 2018 22:13:33 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Tue, 20 Feb 2018 22:13:33 +0000 (UTC) for IP:'10.11.54.5' DOMAIN:'int-mx05.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'mmichels@redhat.com' RCPT:'' X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_LOW, T_RP_MATCHES_RCVD autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH v4 2/2] Measure performance of ovn-controller loop. X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org This modifies ovn-controller to measure the amount of time it takes to detect a change in the southbound database and generate the resulting flow table. This may require multiple iterations of the ovn-controller loop. The statistics can be queried using: ovs-appctl -t ovn-controller performance/show ovn-controller-loop The statistics can be reset using: ovs-appctl -t ovn-controller performance/reset ovn-controller-loop Signed-off-by: Mark Michelson --- ovn/controller/ovn-controller.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ovn/controller/ovn-controller.c b/ovn/controller/ovn-controller.c index 7592bda25..b9f8950d4 100644 --- a/ovn/controller/ovn-controller.c +++ b/ovn/controller/ovn-controller.c @@ -57,6 +57,9 @@ #include "stream.h" #include "unixctl.h" #include "util.h" +#include "timeval.h" +#include "timer.h" +#include "performance.h" VLOG_DEFINE_THIS_MODULE(main); @@ -67,6 +70,8 @@ static unixctl_cb_func inject_pkt; #define DEFAULT_BRIDGE_NAME "br-int" #define DEFAULT_PROBE_INTERVAL_MSEC 5000 +#define CONTROLLER_LOOP_PERFORMANCE_NAME "ovn-controller-loop" + static void update_probe_interval(struct controller_ctx *, const char *ovnsb_remote); static void parse_options(int argc, char *argv[]); @@ -639,8 +644,10 @@ main(int argc, char *argv[]) unixctl_command_register("inject-pkt", "MICROFLOW", 1, 1, inject_pkt, &pending_pkt); + performance_create(CONTROLLER_LOOP_PERFORMANCE_NAME, PERF_MS); /* Main loop. */ exiting = false; + unsigned int our_seqno = 0; while (!exiting) { /* Check OVN SB database. */ char *new_ovnsb_remote = get_ovnsb_remote(ovs_idl_loop.idl); @@ -659,6 +666,12 @@ main(int argc, char *argv[]) .ovnsb_idl_txn = ovsdb_idl_loop_run(&ovnsb_idl_loop), }; + if (our_seqno != ovsdb_idl_get_seqno(ctx.ovnsb_idl)) { + performance_start_sample(CONTROLLER_LOOP_PERFORMANCE_NAME, + time_msec()); + our_seqno = ovsdb_idl_get_seqno(ctx.ovnsb_idl); + } + update_probe_interval(&ctx, ovnsb_remote); update_ssl_config(ctx.ovs_idl); @@ -728,6 +741,9 @@ main(int argc, char *argv[]) ofctrl_put(&flow_table, &pending_ct_zones, get_nb_cfg(ctx.ovnsb_idl)); + performance_end_sample(CONTROLLER_LOOP_PERFORMANCE_NAME, + time_msec()); + hmap_destroy(&flow_table); } if (ctx.ovnsb_idl_txn) { @@ -792,6 +808,7 @@ main(int argc, char *argv[]) ofctrl_wait(); pinctrl_wait(&ctx); } + ovsdb_idl_loop_commit_and_wait(&ovnsb_idl_loop); if (ovsdb_idl_loop_commit_and_wait(&ovs_idl_loop) == 1) {