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