Do you think this is worth documenting in NEWS and adding a *-unixctl.man 
fragment like the other ovs-appctl commands?

--Justin


On May 8, 2012, at 3:47 PM, Ben Pfaff wrote:

> Signed-off-by: Ben Pfaff <b...@nicira.com>
> ---
> lib/automake.mk                                    |    2 +
> lib/memory.c                                       |  175 ++++++++++++++++++++
> lib/memory.h                                       |   60 +++++++
> lib/rconn.c                                        |    7 +
> lib/rconn.h                                        |    3 +-
> ofproto/connmgr.c                                  |   25 +++
> ofproto/connmgr.h                                  |    3 +
> ofproto/ofproto-dpif.c                             |   11 ++
> ofproto/ofproto-provider.h                         |    8 +
> ofproto/ofproto.c                                  |   26 +++
> ofproto/ofproto.h                                  |    3 +
> ofproto/pinsched.c                                 |   10 +-
> ofproto/pinsched.h                                 |    4 +-
> ofproto/pktbuf.c                                   |   22 +++-
> ofproto/pktbuf.h                                   |    4 +-
> ovsdb/jsonrpc-server.c                             |   42 +++++
> ovsdb/jsonrpc-server.h                             |    6 +-
> ovsdb/ovsdb-server.c                               |   16 ++-
> ovsdb/ovsdb.c                                      |   22 +++-
> ovsdb/ovsdb.h                                      |    5 +-
> utilities/bugtool/automake.mk                      |    1 +
> utilities/bugtool/ovs-bugtool-memory-show          |   19 ++
> .../bugtool/plugins/network-status/openvswitch.xml |    1 +
> vswitchd/bridge.c                                  |   12 ++
> vswitchd/bridge.h                                  |    6 +-
> vswitchd/ovs-vswitchd.c                            |   12 ++
> 26 files changed, 495 insertions(+), 10 deletions(-)
> create mode 100644 lib/memory.c
> create mode 100644 lib/memory.h
> create mode 100755 utilities/bugtool/ovs-bugtool-memory-show
> 
> diff --git a/lib/automake.mk b/lib/automake.mk
> index 920babd..29ac53c 100644
> --- a/lib/automake.mk
> +++ b/lib/automake.mk
> @@ -79,6 +79,8 @@ lib_libopenvswitch_a_SOURCES = \
>       lib/lockfile.h \
>       lib/mac-learning.c \
>       lib/mac-learning.h \
> +     lib/memory.c \
> +     lib/memory.h \
>       lib/meta-flow.c \
>       lib/meta-flow.h \
>       lib/multipath.c \
> diff --git a/lib/memory.c b/lib/memory.c
> new file mode 100644
> index 0000000..779860e
> --- /dev/null
> +++ b/lib/memory.c
> @@ -0,0 +1,175 @@
> +/*
> + * Copyright (c) 2012 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 "memory.h"
> +#include <stdbool.h>
> +#include <sys/time.h>
> +#include <sys/resource.h>
> +#include "dynamic-string.h"
> +#include "poll-loop.h"
> +#include "simap.h"
> +#include "timeval.h"
> +#include "unixctl.h"
> +#include "vlog.h"
> +
> +VLOG_DEFINE_THIS_MODULE(memory);
> +
> +/* The number of milliseconds before the first report of daemon memory usage,
> + * and the number of milliseconds between checks for daemon memory growth.  
> */
> +#define MEMORY_CHECK_INTERVAL (10 * 1000)
> +
> +/* When we should next check memory usage and possibly trigger a report. */
> +static long long int next_check;
> +
> +/* The last time at which we reported memory usage, and the usage we reported
> + * at that time. */
> +static long long int last_report;
> +static unsigned long int last_reported_maxrss;
> +
> +/* Are we expecting a call to memory_report()? */
> +static bool want_report;
> +
> +/* Unixctl connections waiting for responses. */
> +static struct unixctl_conn **conns;
> +static size_t n_conns;
> +
> +static void memory_init(void);
> +
> +/* Runs the memory monitor.
> + *
> + * The client should call memory_should_report() afterward. */
> +void
> +memory_run(void)
> +{
> +    struct rusage usage;
> +    long long int now;
> +
> +    memory_init();
> +
> +    /* Time for a check? */
> +    now = time_msec();
> +    if (now < next_check) {
> +        return;
> +    }
> +    next_check = now + MEMORY_CHECK_INTERVAL;
> +
> +    /* Time for a report? */
> +    getrusage(RUSAGE_SELF, &usage);
> +    if (!last_reported_maxrss) {
> +        VLOG_INFO("%lu kB peak resident set size after %.1f seconds",
> +                  (unsigned long int) usage.ru_maxrss,
> +                  (now - time_boot_msec()) / 1000.0);
> +    } else if (usage.ru_maxrss >= last_reported_maxrss * 1.5) {
> +        VLOG_INFO("peak resident set size grew %.0f%% in last %.1f seconds, "
> +                  "from %lu kB to %lu kB",
> +                  ((double) usage.ru_maxrss / last_reported_maxrss - 1) * 
> 100,
> +                  (now - last_report) / 1000.0,
> +                  last_reported_maxrss, (unsigned long int) usage.ru_maxrss);
> +    } else {
> +        return;
> +    }
> +
> +    /* Request a report. */
> +    want_report = true;
> +    last_report = now;
> +    last_reported_maxrss = usage.ru_maxrss;
> +}
> +
> +/* Causes the poll loop to wake up if the memory monitor needs to run. */
> +void
> +memory_wait(void)
> +{
> +    if (memory_should_report()) {
> +        poll_immediate_wake();
> +    }
> +}
> +
> +/* Returns true if the caller should log some information about memory usage
> + * (with memory_report()), false otherwise. */
> +bool
> +memory_should_report(void)
> +{
> +    return want_report || n_conns > 0;
> +}
> +
> +static void
> +compose_report(const struct simap *usage, struct ds *s)
> +{
> +    const struct simap_node **nodes = simap_sort(usage);
> +    size_t n = simap_count(usage);
> +    size_t i;
> +
> +    for (i = 0; i < n; i++) {
> +        const struct simap_node *node = nodes[i];
> +
> +        ds_put_format(s, "%s:%u ", node->name, node->data);
> +    }
> +    ds_chomp(s, ' ');
> +}
> +
> +/* Logs the contents of 'usage', as a collection of name-count pairs.
> + *
> + * 'usage' should capture large-scale statistics that one might reasonably
> + * expect to correlate with memory usage.  For example, each OpenFlow flow
> + * requires some memory, so ovs-vswitchd includes the total number of flows 
> in
> + * 'usage'. */
> +void
> +memory_report(const struct simap *usage)
> +{
> +    struct ds s;
> +    size_t i;
> +
> +    ds_init(&s);
> +    compose_report(usage, &s);
> +
> +    if (want_report) {
> +        VLOG_INFO("%s", ds_cstr(&s));
> +        want_report = false;
> +    }
> +    if (n_conns) {
> +        for (i = 0; i < n_conns; i++) {
> +            unixctl_command_reply(conns[i], ds_cstr(&s));
> +        }
> +        free(conns);
> +        conns = NULL;
> +        n_conns = 0;
> +    }
> +
> +    ds_destroy(&s);
> +}
> +
> +static void
> +memory_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
> +                    const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
> +{
> +    conns = xrealloc(conns, (n_conns + 1) * sizeof *conns);
> +    conns[n_conns++] = conn;
> +}
> +
> +static void
> +memory_init(void)
> +{
> +    static bool inited = false;
> +
> +    if (!inited) {
> +        inited = true;
> +        unixctl_command_register("memory/show", "", 0, 0,
> +                                 memory_unixctl_show, NULL);
> +
> +        next_check = time_boot_msec() + MEMORY_CHECK_INTERVAL;
> +    }
> +}
> diff --git a/lib/memory.h b/lib/memory.h
> new file mode 100644
> index 0000000..4edd956
> --- /dev/null
> +++ b/lib/memory.h
> @@ -0,0 +1,60 @@
> +/*
> + * Copyright (c) 2012 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.
> + */
> +
> +#ifndef MEMORY_H
> +#define MEMORY_H 1
> +
> +/* Memory usage monitor.
> + *
> + * This is intended to be called as part of a daemon's main loop.  After some
> + * time to allow the daemon to allocate an initial memory usage, it logs some
> + * memory usage information (most of which must actually be provided by the
> + * client).  At intervals, if the daemon's memory usage has grown
> + * significantly, it again logs information.
> + *
> + * The monitor also has a unixctl interface.
> + *
> + * Intended usage in the program's main loop is like this:
> + *
> + * for (;;) {
> + *     memory_run();
> + *     if (memory_should_report()) {
> + *          struct simap usage;
> + *
> + *          simap_init(&usage);
> + *          ...fill in 'usage' with meaningful statistics...
> + *          memory_report(&usage);
> + *          simap_destroy(&usage);
> + *     }
> + *
> + *     ...
> + *
> + *     memory_wait();
> + *     poll_block();
> + * }
> + */
> +
> +#include <stdbool.h>
> +
> +struct simap;
> +
> +void memory_run(void);
> +void memory_wait(void);
> +
> +bool memory_should_report(void);
> +void memory_report(const struct simap *usage);
> +
> +#endif /* memory.h */
> diff --git a/lib/rconn.c b/lib/rconn.c
> index aa8b7e3..2ddfc69 100644
> --- a/lib/rconn.c
> +++ b/lib/rconn.c
> @@ -855,6 +855,13 @@ rconn_get_last_error(const struct rconn *rc)
> {
>     return rc->last_error;
> }
> +
> +/* Returns the number of messages queued for transmission on 'rc'. */
> +unsigned int
> +rconn_count_txqlen(const struct rconn *rc)
> +{
> +    return list_size(&rc->txq);
> +}
> 
> struct rconn_packet_counter *
> rconn_packet_counter_create(void)
> diff --git a/lib/rconn.h b/lib/rconn.h
> index 2397640..2b1332c 100644
> --- a/lib/rconn.h
> +++ b/lib/rconn.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -91,6 +91,7 @@ int rconn_get_backoff(const struct rconn *);
> unsigned int rconn_get_state_elapsed(const struct rconn *);
> unsigned int rconn_get_connection_seqno(const struct rconn *);
> int rconn_get_last_error(const struct rconn *);
> +unsigned int rconn_count_txqlen(const struct rconn *);
> 
> /* Counts the number of packets queued into an rconn by a given source. */
> struct rconn_packet_counter {
> diff --git a/ofproto/connmgr.c b/ofproto/connmgr.c
> index e80d20c..a0315b2 100644
> --- a/ofproto/connmgr.c
> +++ b/ofproto/connmgr.c
> @@ -33,6 +33,7 @@
> #include "pktbuf.h"
> #include "rconn.h"
> #include "shash.h"
> +#include "simap.h"
> #include "stream.h"
> #include "timeval.h"
> #include "vconn.h"
> @@ -338,6 +339,30 @@ connmgr_wait(struct connmgr *mgr, bool handling_openflow)
>     }
> }
> 
> +/* Adds some memory usage statistics for 'mgr' into 'usage', for use with
> + * memory_report(). */
> +void
> +connmgr_get_memory_usage(const struct connmgr *mgr, struct simap *usage)
> +{
> +    const struct ofconn *ofconn;
> +    unsigned int packets = 0;
> +    unsigned int ofconns = 0;
> +
> +    LIST_FOR_EACH (ofconn, node, &mgr->all_conns) {
> +        int i;
> +
> +        ofconns++;
> +
> +        packets += rconn_count_txqlen(ofconn->rconn);
> +        for (i = 0; i < N_SCHEDULERS; i++) {
> +            packets += pinsched_count_txqlen(ofconn->schedulers[i]);
> +        }
> +        packets += pktbuf_count_packets(ofconn->pktbuf);
> +    }
> +    simap_increase(usage, "ofconns", ofconns);
> +    simap_increase(usage, "packets", packets);
> +}
> +
> /* Returns the ofproto that owns 'ofconn''s connmgr. */
> struct ofproto *
> ofconn_get_ofproto(const struct ofconn *ofconn)
> diff --git a/ofproto/connmgr.h b/ofproto/connmgr.h
> index 8ac0b8d..dec5b71 100644
> --- a/ofproto/connmgr.h
> +++ b/ofproto/connmgr.h
> @@ -30,6 +30,7 @@ struct ofopgroup;
> struct ofputil_flow_removed;
> struct ofputil_packet_in;
> struct ofputil_phy_port;
> +struct simap;
> struct sset;
> 
> /* ofproto supports two kinds of OpenFlow connections:
> @@ -70,6 +71,8 @@ void connmgr_run(struct connmgr *,
>                                          struct ofpbuf *ofp_msg));
> void connmgr_wait(struct connmgr *, bool handling_openflow);
> 
> +void connmgr_get_memory_usage(const struct connmgr *, struct simap *usage);
> +
> struct ofproto *ofconn_get_ofproto(const struct ofconn *);
> 
> void connmgr_retry(struct connmgr *);
> diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
> index 11bde38..988de61 100644
> --- a/ofproto/ofproto-dpif.c
> +++ b/ofproto/ofproto-dpif.c
> @@ -47,6 +47,7 @@
> #include "ofproto-dpif-governor.h"
> #include "ofproto-dpif-sflow.h"
> #include "poll-loop.h"
> +#include "simap.h"
> #include "timer.h"
> #include "unaligned.h"
> #include "unixctl.h"
> @@ -954,6 +955,15 @@ wait(struct ofproto *ofproto_)
> }
> 
> static void
> +get_memory_usage(const struct ofproto *ofproto_, struct simap *usage)
> +{
> +    const struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
> +
> +    simap_increase(usage, "facets", hmap_count(&ofproto->facets));
> +    simap_increase(usage, "subfacets", hmap_count(&ofproto->subfacets));
> +}
> +
> +static void
> flush(struct ofproto *ofproto_)
> {
>     struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
> @@ -6808,6 +6818,7 @@ const struct ofproto_class ofproto_dpif_class = {
>     run,
>     run_fast,
>     wait,
> +    get_memory_usage,
>     flush,
>     get_features,
>     get_tables,
> diff --git a/ofproto/ofproto-provider.h b/ofproto/ofproto-provider.h
> index a74bf9a..1f3ad37 100644
> --- a/ofproto/ofproto-provider.h
> +++ b/ofproto/ofproto-provider.h
> @@ -30,6 +30,7 @@
> #include "timeval.h"
> 
> struct ofputil_flow_mod;
> +struct simap;
> 
> /* An OpenFlow switch.
>  *
> @@ -396,6 +397,13 @@ struct ofproto_class {
>      * poll-loop.h.  */
>     void (*wait)(struct ofproto *ofproto);
> 
> +    /* Adds some memory usage statistics for the implementation of 'ofproto'
> +     * into 'usage', for use with memory_report().
> +     *
> +     * This function is optional. */
> +    void (*get_memory_usage)(const struct ofproto *ofproto,
> +                             struct simap *usage);
> +
>     /* Every "struct rule" in 'ofproto' is about to be deleted, one by one.
>      * This function may prepare for that, for example by clearing state in
>      * advance.  It should *not* actually delete any "struct rule"s from
> diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c
> index 806e56b..23904a8 100644
> --- a/ofproto/ofproto.c
> +++ b/ofproto/ofproto.c
> @@ -45,6 +45,7 @@
> #include "poll-loop.h"
> #include "random.h"
> #include "shash.h"
> +#include "simap.h"
> #include "sset.h"
> #include "timeval.h"
> #include "unaligned.h"
> @@ -1149,6 +1150,31 @@ ofproto_is_alive(const struct ofproto *p)
>     return connmgr_has_controllers(p->connmgr);
> }
> 
> +/* Adds some memory usage statistics for 'ofproto' into 'usage', for use with
> + * memory_report(). */
> +void
> +ofproto_get_memory_usage(const struct ofproto *ofproto, struct simap *usage)
> +{
> +    const struct oftable *table;
> +    unsigned int n_rules;
> +
> +    simap_increase(usage, "ports", hmap_count(&ofproto->ports));
> +    simap_increase(usage, "ops",
> +                   ofproto->n_pending + hmap_count(&ofproto->deletions));
> +
> +    n_rules = 0;
> +    OFPROTO_FOR_EACH_TABLE (table, ofproto) {
> +        n_rules += classifier_count(&table->cls);
> +    }
> +    simap_increase(usage, "rules", n_rules);
> +
> +    if (ofproto->ofproto_class->get_memory_usage) {
> +        ofproto->ofproto_class->get_memory_usage(ofproto, usage);
> +    }
> +
> +    connmgr_get_memory_usage(ofproto->connmgr, usage);
> +}
> +
> void
> ofproto_get_ofproto_controller_info(const struct ofproto *ofproto,
>                                     struct shash *info)
> diff --git a/ofproto/ofproto.h b/ofproto/ofproto.h
> index c8d9857..ea988e7 100644
> --- a/ofproto/ofproto.h
> +++ b/ofproto/ofproto.h
> @@ -39,6 +39,7 @@ struct netdev;
> struct ofproto;
> struct ofport;
> struct shash;
> +struct simap;
> struct netdev_stats;
> 
> struct ofproto_controller_info {
> @@ -153,6 +154,8 @@ int ofproto_run_fast(struct ofproto *);
> void ofproto_wait(struct ofproto *);
> bool ofproto_is_alive(const struct ofproto *);
> 
> +void ofproto_get_memory_usage(const struct ofproto *, struct simap *);
> +
> /* A port within an OpenFlow switch.
>  *
>  * 'name' and 'type' are suitable for passing to netdev_open(). */
> diff --git a/ofproto/pinsched.c b/ofproto/pinsched.c
> index 9053ea2..41e9c8d 100644
> --- a/ofproto/pinsched.c
> +++ b/ofproto/pinsched.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -320,3 +320,11 @@ pinsched_set_limits(struct pinsched *ps, int rate_limit, 
> int burst_limit)
>         drop_packet(ps);
>     }
> }
> +
> +/* Returns the number of packets scheduled to be sent eventually by 'ps'.
> + * Returns 0 if 'ps' is null. */
> +unsigned int
> +pinsched_count_txqlen(const struct pinsched *ps)
> +{
> +    return ps ? ps->n_txq : 0;
> +}
> diff --git a/ofproto/pinsched.h b/ofproto/pinsched.h
> index 26a4d7a..061cb01 100644
> --- a/ofproto/pinsched.h
> +++ b/ofproto/pinsched.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -32,4 +32,6 @@ void pinsched_send(struct pinsched *, uint16_t port_no, 
> struct ofpbuf *,
> void pinsched_run(struct pinsched *, pinsched_tx_cb *, void *aux);
> void pinsched_wait(struct pinsched *);
> 
> +unsigned int pinsched_count_txqlen(const struct pinsched *);
> +
> #endif /* pinsched.h */
> diff --git a/ofproto/pktbuf.c b/ofproto/pktbuf.c
> index acc0d34..71be34a 100644
> --- a/ofproto/pktbuf.c
> +++ b/ofproto/pktbuf.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -232,3 +232,23 @@ pktbuf_discard(struct pktbuf *pb, uint32_t id)
>         p->buffer = NULL;
>     }
> }
> +
> +/* Returns the number of packets buffered in 'pb'.  Returns 0 if 'pb' is
> + * null. */
> +unsigned int
> +pktbuf_count_packets(const struct pktbuf *pb)
> +{
> +    int n = 0;
> +
> +    if (pb) {
> +        int i;
> +
> +        for (i = 0; i < PKTBUF_CNT; i++) {
> +            if (pb->packets[i].buffer) {
> +                n++;
> +            }
> +        }
> +    }
> +
> +    return n;
> +}
> diff --git a/ofproto/pktbuf.h b/ofproto/pktbuf.h
> index 990f2ea..ec99aea 100644
> --- a/ofproto/pktbuf.h
> +++ b/ofproto/pktbuf.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2008, 2009, 2011 Nicira, Inc.
> + * Copyright (c) 2008, 2009, 2011, 2012 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -36,4 +36,6 @@ enum ofperr pktbuf_retrieve(struct pktbuf *, uint32_t id,
>                             struct ofpbuf **bufferp, uint16_t *in_port);
> void pktbuf_discard(struct pktbuf *, uint32_t id);
> 
> +unsigned int pktbuf_count_packets(const struct pktbuf *);
> +
> #endif /* pktbuf.h */
> diff --git a/ovsdb/jsonrpc-server.c b/ovsdb/jsonrpc-server.c
> index 0cc8bdf..bb887d0 100644
> --- a/ovsdb/jsonrpc-server.c
> +++ b/ovsdb/jsonrpc-server.c
> @@ -31,6 +31,7 @@
> #include "reconnect.h"
> #include "row.h"
> #include "server.h"
> +#include "simap.h"
> #include "stream.h"
> #include "table.h"
> #include "timeval.h"
> @@ -51,6 +52,8 @@ static struct ovsdb_jsonrpc_session 
> *ovsdb_jsonrpc_session_create(
>     struct ovsdb_jsonrpc_remote *, struct jsonrpc_session *);
> static void ovsdb_jsonrpc_session_run_all(struct ovsdb_jsonrpc_remote *);
> static void ovsdb_jsonrpc_session_wait_all(struct ovsdb_jsonrpc_remote *);
> +static void ovsdb_jsonrpc_session_get_memory_usage_all(
> +    const struct ovsdb_jsonrpc_remote *, struct simap *usage);
> static void ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *);
> static void ovsdb_jsonrpc_session_reconnect_all(struct ovsdb_jsonrpc_remote 
> *);
> static void ovsdb_jsonrpc_session_set_all_options(
> @@ -293,6 +296,22 @@ ovsdb_jsonrpc_server_wait(struct ovsdb_jsonrpc_server 
> *svr)
>         ovsdb_jsonrpc_session_wait_all(remote);
>     }
> }
> +
> +/* Adds some memory usage statistics for 'svr' into 'usage', for use with
> + * memory_report(). */
> +void
> +ovsdb_jsonrpc_server_get_memory_usage(const struct ovsdb_jsonrpc_server *svr,
> +                                      struct simap *usage)
> +{
> +    struct shash_node *node;
> +
> +    simap_increase(usage, "sessions", svr->n_sessions);
> +    SHASH_FOR_EACH (node, &svr->remotes) {
> +        struct ovsdb_jsonrpc_remote *remote = node->data;
> +
> +        ovsdb_jsonrpc_session_get_memory_usage_all(remote, usage);
> +    }
> +}
> 
> /* JSON-RPC database server session. */
> 
> @@ -315,6 +334,8 @@ struct ovsdb_jsonrpc_session {
> static void ovsdb_jsonrpc_session_close(struct ovsdb_jsonrpc_session *);
> static int ovsdb_jsonrpc_session_run(struct ovsdb_jsonrpc_session *);
> static void ovsdb_jsonrpc_session_wait(struct ovsdb_jsonrpc_session *);
> +static void ovsdb_jsonrpc_session_get_memory_usage(
> +    const struct ovsdb_jsonrpc_session *, struct simap *usage);
> static void ovsdb_jsonrpc_session_set_options(
>     struct ovsdb_jsonrpc_session *, const struct ovsdb_jsonrpc_options *);
> static void ovsdb_jsonrpc_session_got_request(struct ovsdb_jsonrpc_session *,
> @@ -429,6 +450,27 @@ ovsdb_jsonrpc_session_wait_all(struct 
> ovsdb_jsonrpc_remote *remote)
> }
> 
> static void
> +ovsdb_jsonrpc_session_get_memory_usage(const struct ovsdb_jsonrpc_session *s,
> +                                       struct simap *usage)
> +{
> +    simap_increase(usage, "triggers", hmap_count(&s->triggers));
> +    simap_increase(usage, "monitors", hmap_count(&s->monitors));
> +    simap_increase(usage, "backlog", jsonrpc_session_get_backlog(s->js));
> +}
> +
> +static void
> +ovsdb_jsonrpc_session_get_memory_usage_all(
> +    const struct ovsdb_jsonrpc_remote *remote,
> +    struct simap *usage)
> +{
> +    struct ovsdb_jsonrpc_session *s;
> +
> +    LIST_FOR_EACH (s, node, &remote->sessions) {
> +        ovsdb_jsonrpc_session_get_memory_usage(s, usage);
> +    }
> +}
> +
> +static void
> ovsdb_jsonrpc_session_close_all(struct ovsdb_jsonrpc_remote *remote)
> {
>     struct ovsdb_jsonrpc_session *s, *next;
> diff --git a/ovsdb/jsonrpc-server.h b/ovsdb/jsonrpc-server.h
> index 8312a00..2dc0c78 100644
> --- a/ovsdb/jsonrpc-server.h
> +++ b/ovsdb/jsonrpc-server.h
> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2009, 2010, 2011 Nicira, Inc.
> +/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -20,6 +20,7 @@
> 
> struct ovsdb;
> struct shash;
> +struct simap;
> 
> struct ovsdb_jsonrpc_server *ovsdb_jsonrpc_server_create(struct ovsdb *);
> void ovsdb_jsonrpc_server_destroy(struct ovsdb_jsonrpc_server *);
> @@ -59,4 +60,7 @@ void ovsdb_jsonrpc_server_reconnect(struct 
> ovsdb_jsonrpc_server *);
> void ovsdb_jsonrpc_server_run(struct ovsdb_jsonrpc_server *);
> void ovsdb_jsonrpc_server_wait(struct ovsdb_jsonrpc_server *);
> 
> +void ovsdb_jsonrpc_server_get_memory_usage(const struct ovsdb_jsonrpc_server 
> *,
> +                                           struct simap *usage);
> +
> #endif /* ovsdb/jsonrpc-server.h */
> diff --git a/ovsdb/ovsdb-server.c b/ovsdb/ovsdb-server.c
> index 28bf901..7f53e17 100644
> --- a/ovsdb/ovsdb-server.c
> +++ b/ovsdb/ovsdb-server.c
> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2009, 2010, 2011 Nicira, Inc.
> +/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -32,6 +32,7 @@
> #include "jsonrpc-server.h"
> #include "leak-checker.h"
> #include "list.h"
> +#include "memory.h"
> #include "ovsdb.h"
> #include "ovsdb-data.h"
> #include "ovsdb-types.h"
> @@ -39,6 +40,7 @@
> #include "poll-loop.h"
> #include "process.h"
> #include "row.h"
> +#include "simap.h"
> #include "stream-ssl.h"
> #include "stream.h"
> #include "stress.h"
> @@ -143,6 +145,17 @@ main(int argc, char *argv[])
> 
>     exiting = false;
>     while (!exiting) {
> +        memory_run();
> +        if (memory_should_report()) {
> +            struct simap usage;
> +
> +            simap_init(&usage);
> +            ovsdb_jsonrpc_server_get_memory_usage(jsonrpc, &usage);
> +            ovsdb_get_memory_usage(db, &usage);
> +            memory_report(&usage);
> +            simap_destroy(&usage);
> +        }
> +
>         reconfigure_from_db(jsonrpc, db, &remotes);
>         ovsdb_jsonrpc_server_run(jsonrpc);
>         unixctl_server_run(unixctl);
> @@ -157,6 +170,7 @@ main(int argc, char *argv[])
>             update_remote_status(jsonrpc, &remotes, db);
>         }
> 
> +        memory_wait();
>         ovsdb_jsonrpc_server_wait(jsonrpc);
>         unixctl_server_wait(unixctl);
>         ovsdb_trigger_wait(db, time_msec());
> diff --git a/ovsdb/ovsdb.c b/ovsdb/ovsdb.c
> index 584433c..6b53f4a 100644
> --- a/ovsdb/ovsdb.c
> +++ b/ovsdb/ovsdb.c
> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2009, 2010, 2011 Nicira, Inc.
> +/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -22,6 +22,7 @@
> #include "ovsdb-error.h"
> #include "ovsdb-parser.h"
> #include "ovsdb-types.h"
> +#include "simap.h"
> #include "table.h"
> #include "transaction.h"
> 
> @@ -384,6 +385,25 @@ ovsdb_destroy(struct ovsdb *db)
>     }
> }
> 
> +/* Adds some memory usage statistics for 'db' into 'usage', for use with
> + * memory_report(). */
> +void
> +ovsdb_get_memory_usage(const struct ovsdb *db, struct simap *usage)
> +{
> +    const struct shash_node *node;
> +    unsigned int cells = 0;
> +
> +    SHASH_FOR_EACH (node, &db->tables) {
> +        const struct ovsdb_table *table = node->data;
> +        unsigned int n_columns = shash_count(&table->schema->columns);
> +        unsigned int n_rows = hmap_count(&table->rows);
> +
> +        cells += n_rows * n_columns;
> +    }
> +
> +    simap_increase(usage, "cells", cells);
> +}
> +
> struct ovsdb_table *
> ovsdb_get_table(const struct ovsdb *db, const char *name)
> {
> diff --git a/ovsdb/ovsdb.h b/ovsdb/ovsdb.h
> index ea7a9c2..6e4ff79 100644
> --- a/ovsdb/ovsdb.h
> +++ b/ovsdb/ovsdb.h
> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2009, 2010, 2011 Nicira, Inc.
> +/* Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -25,6 +25,7 @@ struct json;
> struct ovsdb_log;
> struct ovsdb_session;
> struct ovsdb_txn;
> +struct simap;
> struct uuid;
> 
> /* Database schema. */
> @@ -66,6 +67,8 @@ struct ovsdb {
> struct ovsdb *ovsdb_create(struct ovsdb_schema *);
> void ovsdb_destroy(struct ovsdb *);
> 
> +void ovsdb_get_memory_usage(const struct ovsdb *, struct simap *usage);
> +
> struct ovsdb_error *ovsdb_from_json(const struct json *, struct ovsdb **)
>     WARN_UNUSED_RESULT;
> struct json *ovsdb_to_json(const struct ovsdb *);
> diff --git a/utilities/bugtool/automake.mk b/utilities/bugtool/automake.mk
> index 676a5a2..1045cee 100644
> --- a/utilities/bugtool/automake.mk
> +++ b/utilities/bugtool/automake.mk
> @@ -15,6 +15,7 @@ bugtool_scripts = \
>       utilities/bugtool/ovs-bugtool-cfm-show \
>       utilities/bugtool/ovs-bugtool-coverage-show \
>       utilities/bugtool/ovs-bugtool-lacp-show \
> +     utilities/bugtool/ovs-bugtool-memory-show \
>       utilities/bugtool/ovs-bugtool-tc-class-show \
>       utilities/bugtool/ovs-bugtool-vsctl-show \
>       utilities/bugtool/ovs-bugtool-ovsdb-dump \
> diff --git a/utilities/bugtool/ovs-bugtool-memory-show 
> b/utilities/bugtool/ovs-bugtool-memory-show
> new file mode 100755
> index 0000000..3bad754
> --- /dev/null
> +++ b/utilities/bugtool/ovs-bugtool-memory-show
> @@ -0,0 +1,19 @@
> +#! /bin/sh
> +
> +# This library is free software; you can redistribute it and/or
> +# modify it under the terms of version 2.1 of the GNU Lesser General
> +# Public License as published by the Free Software Foundation.
> +#
> +# This library is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +# Lesser General Public License for more details.
> +#
> +# You should have received a copy of the GNU Lesser General Public
> +# License along with this library; if not, write to the Free Software
> +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
> +# USA
> +#
> +# Copyright (C) 2012 Nicira, Inc.
> +
> +ovs-appctl memory/show
> diff --git a/utilities/bugtool/plugins/network-status/openvswitch.xml 
> b/utilities/bugtool/plugins/network-status/openvswitch.xml
> index 8ae498f..a8a906e 100644
> --- a/utilities/bugtool/plugins/network-status/openvswitch.xml
> +++ b/utilities/bugtool/plugins/network-status/openvswitch.xml
> @@ -23,4 +23,5 @@
>   <command 
> label="ovs-lacp-show">/usr/share/openvswitch/scripts/ovs-bugtool-lacp-show</command>
>   <command 
> label="ovs-cfm-show">/usr/share/openvswitch/scripts/ovs-bugtool-cfm-show</command>
>   <command 
> label="ovs-coverage-show">/usr/share/openvswitch/scripts/ovs-bugtool-coverage-show</command>
> +  <command 
> label="ovs-memory-show">/usr/share/openvswitch/scripts/ovs-bugtool-memory-show</command>
> </collect>
> diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
> index 13eb80b..c258fc3 100644
> --- a/vswitchd/bridge.c
> +++ b/vswitchd/bridge.c
> @@ -2228,6 +2228,18 @@ bridge_wait(void)
>         }
>     }
> }
> +
> +/* Adds some memory usage statistics for bridges into 'usage', for use with
> + * memory_report(). */
> +void
> +bridge_get_memory_usage(struct simap *usage)
> +{
> +    struct bridge *br;
> +
> +    HMAP_FOR_EACH (br, node, &all_bridges) {
> +        ofproto_get_memory_usage(br->ofproto, usage);
> +    }
> +}
> 
> /* QoS unixctl user interface functions. */
> 
> diff --git a/vswitchd/bridge.h b/vswitchd/bridge.h
> index ecd6ff5..c1b0a2b 100644
> --- a/vswitchd/bridge.h
> +++ b/vswitchd/bridge.h
> @@ -1,4 +1,4 @@
> -/* Copyright (c) 2008, 2009, 2010, 2011 Nicira, Inc.
> +/* Copyright (c) 2008, 2009, 2010, 2011, 2012 Nicira, Inc.
>  *
>  * Licensed under the Apache License, Version 2.0 (the "License");
>  * you may not use this file except in compliance with the License.
> @@ -16,6 +16,8 @@
> #ifndef VSWITCHD_BRIDGE_H
> #define VSWITCHD_BRIDGE_H 1
> 
> +struct simap;
> +
> void bridge_init(const char *remote);
> void bridge_exit(void);
> 
> @@ -23,4 +25,6 @@ void bridge_run(void);
> void bridge_run_fast(void);
> void bridge_wait(void);
> 
> +void bridge_get_memory_usage(struct simap *usage);
> +
> #endif /* bridge.h */
> diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c
> index f97df8d..8ef3b10 100644
> --- a/vswitchd/ovs-vswitchd.c
> +++ b/vswitchd/ovs-vswitchd.c
> @@ -34,12 +34,14 @@
> #include "dpif.h"
> #include "dummy.h"
> #include "leak-checker.h"
> +#include "memory.h"
> #include "netdev.h"
> #include "openflow/openflow.h"
> #include "ovsdb-idl.h"
> #include "poll-loop.h"
> #include "process.h"
> #include "signals.h"
> +#include "simap.h"
> #include "stream-ssl.h"
> #include "stream.h"
> #include "stress.h"
> @@ -93,6 +95,15 @@ main(int argc, char *argv[])
>         if (signal_poll(sighup)) {
>             vlog_reopen_log_file();
>         }
> +        memory_run();
> +        if (memory_should_report()) {
> +            struct simap usage;
> +
> +            simap_init(&usage);
> +            bridge_get_memory_usage(&usage);
> +            memory_report(&usage);
> +            simap_destroy(&usage);
> +        }
>         bridge_run_fast();
>         bridge_run();
>         bridge_run_fast();
> @@ -100,6 +111,7 @@ main(int argc, char *argv[])
>         netdev_run();
> 
>         signal_wait(sighup);
> +        memory_wait();
>         bridge_wait();
>         unixctl_server_wait(unixctl);
>         netdev_wait();
> -- 
> 1.7.2.5
> 
> _______________________________________________
> dev mailing list
> dev@openvswitch.org
> http://openvswitch.org/mailman/listinfo/dev

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to