From: Ben Pfaff Date: Tue, 8 May 2012 22:44:21 +0000 (-0700) Subject: Add support for tracking and logging daemon memory usage. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0d085684619be0baef309957a3d7410a23cb5f27;p=openvswitch Add support for tracking and logging daemon memory usage. Signed-off-by: Ben Pfaff --- diff --git a/lib/automake.mk b/lib/automake.mk index 338d39cd..1d404c2c 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 00000000..779860eb --- /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 +#include "memory.h" +#include +#include +#include +#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 00000000..4edd9561 --- /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 + +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 aa8b7e30..2ddfc69a 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 23976409..2b1332c5 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 e80d20cc..a0315b23 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 8ac0b8dc..dec5b71c 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 be1a45cb..f2c2ca96 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" @@ -1056,6 +1057,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_) { @@ -7098,6 +7108,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 a74bf9ad..1f3ad37f 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 60dd36a4..0bda06ac 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 c8d98578..ea988e7b 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 9053ea26..41e9c8dd 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 26a4d7a3..061cb01a 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 acc0d34d..71be34a6 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 990f2ea0..ec99aead 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 0cc8bdf9..bb887d0b 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 *, @@ -428,6 +449,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) { diff --git a/ovsdb/jsonrpc-server.h b/ovsdb/jsonrpc-server.h index 8312a002..2dc0c780 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 28bf901e..7f53e177 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 584433c7..6b53f4a3 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 ea7a9c2d..6e4ff791 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 c09380d9..cd422aa4 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 00000000..3bad754d --- /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 b8f086fe..13160710 100644 --- a/utilities/bugtool/plugins/network-status/openvswitch.xml +++ b/utilities/bugtool/plugins/network-status/openvswitch.xml @@ -24,4 +24,5 @@ /usr/share/openvswitch/scripts/ovs-bugtool-cfm-show /usr/share/openvswitch/scripts/ovs-bugtool-coverage-show /usr/share/openvswitch/scripts/ovs-bugtool-bond-show + /usr/share/openvswitch/scripts/ovs-bugtool-memory-show diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 0c78f946..d7209520 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 ecd6ff5f..c1b0a2b5 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 f97df8d6..8ef3b10e 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();