Add support for tracking and logging daemon memory usage.
authorBen Pfaff <blp@nicira.com>
Tue, 8 May 2012 22:44:21 +0000 (15:44 -0700)
committerBen Pfaff <blp@nicira.com>
Tue, 22 May 2012 17:32:05 +0000 (10:32 -0700)
Signed-off-by: Ben Pfaff <blp@nicira.com>
26 files changed:
lib/automake.mk
lib/memory.c [new file with mode: 0644]
lib/memory.h [new file with mode: 0644]
lib/rconn.c
lib/rconn.h
ofproto/connmgr.c
ofproto/connmgr.h
ofproto/ofproto-dpif.c
ofproto/ofproto-provider.h
ofproto/ofproto.c
ofproto/ofproto.h
ofproto/pinsched.c
ofproto/pinsched.h
ofproto/pktbuf.c
ofproto/pktbuf.h
ovsdb/jsonrpc-server.c
ovsdb/jsonrpc-server.h
ovsdb/ovsdb-server.c
ovsdb/ovsdb.c
ovsdb/ovsdb.h
utilities/bugtool/automake.mk
utilities/bugtool/ovs-bugtool-memory-show [new file with mode: 0755]
utilities/bugtool/plugins/network-status/openvswitch.xml
vswitchd/bridge.c
vswitchd/bridge.h
vswitchd/ovs-vswitchd.c

index 338d39c..1d404c2 100644 (file)
@@ -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 (file)
index 0000000..779860e
--- /dev/null
@@ -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 (file)
index 0000000..4edd956
--- /dev/null
@@ -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 */
index aa8b7e3..2ddfc69 100644 (file)
@@ -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);
+}
 \f
 struct rconn_packet_counter *
 rconn_packet_counter_create(void)
index 2397640..2b1332c 100644 (file)
@@ -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 {
index e80d20c..a0315b2 100644 (file)
@@ -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)
index 8ac0b8d..dec5b71 100644 (file)
@@ -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 *);
index be1a45c..f2c2ca9 100644 (file)
@@ -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,
index a74bf9a..1f3ad37 100644 (file)
@@ -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
index 60dd36a..0bda06a 100644 (file)
@@ -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)
index c8d9857..ea988e7 100644 (file)
@@ -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(). */
index 9053ea2..41e9c8d 100644 (file)
@@ -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;
+}
index 26a4d7a..061cb01 100644 (file)
@@ -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 */
index acc0d34..71be34a 100644 (file)
@@ -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;
+}
index 990f2ea..ec99aea 100644 (file)
@@ -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 */
index 0cc8bdf..bb887d0 100644 (file)
@@ -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);
+    }
+}
 \f
 /* 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)
 {
index 8312a00..2dc0c78 100644 (file)
@@ -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 */
index 28bf901..7f53e17 100644 (file)
@@ -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());
index 584433c..6b53f4a 100644 (file)
@@ -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)
 {
index ea7a9c2..6e4ff79 100644 (file)
@@ -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 *);
index c09380d..cd422aa 100644 (file)
@@ -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 (executable)
index 0000000..3bad754
--- /dev/null
@@ -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
index b8f086f..1316071 100644 (file)
@@ -24,4 +24,5 @@
   <command label="ovs-appctl-cfm-show">/usr/share/openvswitch/scripts/ovs-bugtool-cfm-show</command>
   <command label="ovs-appctl-coverage-show">/usr/share/openvswitch/scripts/ovs-bugtool-coverage-show</command>
   <command label="ovs-appctl-bond-show">/usr/share/openvswitch/scripts/ovs-bugtool-bond-show</command>
+  <command label="ovs-appctl-memory-show">/usr/share/openvswitch/scripts/ovs-bugtool-memory-show</command>
 </collect>
index 0c78f94..d720952 100644 (file)
@@ -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);
+    }
+}
 \f
 /* QoS unixctl user interface functions. */
 
index ecd6ff5..c1b0a2b 100644 (file)
@@ -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 */
index f97df8d..8ef3b10 100644 (file)
 #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();