Might as well. I sent out a patch: http://openvswitch.org/pipermail/dev/2012-July/018971.html
On Wed, May 23, 2012 at 12:30:55AM -0700, Justin Pettit wrote: > 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