LCOV - code coverage report
Current view: top level - lib - memory.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 45 56 80.4 %
Date: 2016-09-14 01:02:56 Functions: 7 8 87.5 %
Branches: 19 30 63.3 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * Copyright (c) 2012, 2013 Nicira, Inc.
       3                 :            :  *
       4                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       5                 :            :  * you may not use this file except in compliance with the License.
       6                 :            :  * You may obtain a copy of the License at:
       7                 :            :  *
       8                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       9                 :            :  *
      10                 :            :  * Unless required by applicable law or agreed to in writing, software
      11                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      12                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      13                 :            :  * See the License for the specific language governing permissions and
      14                 :            :  * limitations under the License.
      15                 :            :  */
      16                 :            : 
      17                 :            : #include <config.h>
      18                 :            : #include "memory.h"
      19                 :            : #include <stdbool.h>
      20                 :            : #include <sys/time.h>
      21                 :            : #include <sys/resource.h>
      22                 :            : #include "openvswitch/dynamic-string.h"
      23                 :            : #include "poll-loop.h"
      24                 :            : #include "simap.h"
      25                 :            : #include "timeval.h"
      26                 :            : #include "unixctl.h"
      27                 :            : #include "openvswitch/vlog.h"
      28                 :            : 
      29                 :       3882 : VLOG_DEFINE_THIS_MODULE(memory);
      30                 :            : 
      31                 :            : /* The number of milliseconds before the first report of daemon memory usage,
      32                 :            :  * and the number of milliseconds between checks for daemon memory growth.  */
      33                 :            : #define MEMORY_CHECK_INTERVAL (10 * 1000)
      34                 :            : 
      35                 :            : /* When we should next check memory usage and possibly trigger a report. */
      36                 :            : static long long int next_check;
      37                 :            : 
      38                 :            : /* The last time at which we reported memory usage, and the usage we reported
      39                 :            :  * at that time. */
      40                 :            : static long long int last_report;
      41                 :            : static unsigned long int last_reported_maxrss;
      42                 :            : 
      43                 :            : /* Are we expecting a call to memory_report()? */
      44                 :            : static bool want_report;
      45                 :            : 
      46                 :            : /* Unixctl connections waiting for responses. */
      47                 :            : static struct unixctl_conn **conns;
      48                 :            : static size_t n_conns;
      49                 :            : 
      50                 :            : static void memory_init(void);
      51                 :            : 
      52                 :            : /* Runs the memory monitor.
      53                 :            :  *
      54                 :            :  * The client should call memory_should_report() afterward.
      55                 :            :  *
      56                 :            :  * This function, and the remainder of this module's interface, should be
      57                 :            :  * called from only a single thread. */
      58                 :            : void
      59                 :     164178 : memory_run(void)
      60                 :            : {
      61                 :            :     struct rusage usage;
      62                 :            :     long long int now;
      63                 :            : 
      64                 :     164178 :     memory_init();
      65                 :            : 
      66                 :            :     /* Time for a check? */
      67                 :     164178 :     now = time_msec();
      68         [ +  + ]:     164178 :     if (now < next_check) {
      69                 :     164033 :         return;
      70                 :            :     }
      71                 :        490 :     next_check = now + MEMORY_CHECK_INTERVAL;
      72                 :            : 
      73                 :            :     /* Time for a report? */
      74                 :        490 :     getrusage(RUSAGE_SELF, &usage);
      75         [ +  + ]:        490 :     if (!last_reported_maxrss) {
      76         [ +  - ]:        145 :         VLOG_INFO("%lu kB peak resident set size after %.1f seconds",
      77                 :            :                   (unsigned long int) usage.ru_maxrss,
      78                 :            :                   (now - time_boot_msec()) / 1000.0);
      79         [ -  + ]:        345 :     } else if (usage.ru_maxrss >= last_reported_maxrss * 1.5) {
      80         [ #  # ]:          0 :         VLOG_INFO("peak resident set size grew %.0f%% in last %.1f seconds, "
      81                 :            :                   "from %lu kB to %lu kB",
      82                 :            :                   ((double) usage.ru_maxrss / last_reported_maxrss - 1) * 100,
      83                 :            :                   (now - last_report) / 1000.0,
      84                 :            :                   last_reported_maxrss, (unsigned long int) usage.ru_maxrss);
      85                 :            :     } else {
      86                 :        345 :         return;
      87                 :            :     }
      88                 :            : 
      89                 :            :     /* Request a report. */
      90                 :        145 :     want_report = true;
      91                 :        145 :     last_report = now;
      92                 :        145 :     last_reported_maxrss = usage.ru_maxrss;
      93                 :            : }
      94                 :            : 
      95                 :            : /* Causes the poll loop to wake up if the memory monitor needs to run. */
      96                 :            : void
      97                 :     164178 : memory_wait(void)
      98                 :            : {
      99         [ -  + ]:     164178 :     if (memory_should_report()) {
     100                 :          0 :         poll_immediate_wake();
     101                 :            :     }
     102                 :     164178 : }
     103                 :            : 
     104                 :            : /* Returns true if the caller should log some information about memory usage
     105                 :            :  * (with memory_report()), false otherwise. */
     106                 :            : bool
     107                 :     328356 : memory_should_report(void)
     108                 :            : {
     109 [ +  + ][ -  + ]:     328356 :     return want_report || n_conns > 0;
     110                 :            : }
     111                 :            : 
     112                 :            : static void
     113                 :        145 : compose_report(const struct simap *usage, struct ds *s)
     114                 :            : {
     115                 :        145 :     const struct simap_node **nodes = simap_sort(usage);
     116                 :        145 :     size_t n = simap_count(usage);
     117                 :            :     size_t i;
     118                 :            : 
     119         [ +  + ]:        755 :     for (i = 0; i < n; i++) {
     120                 :        610 :         const struct simap_node *node = nodes[i];
     121                 :            : 
     122                 :        610 :         ds_put_format(s, "%s:%u ", node->name, node->data);
     123                 :            :     }
     124                 :        145 :     ds_chomp(s, ' ');
     125                 :        145 :     free(nodes);
     126                 :        145 : }
     127                 :            : 
     128                 :            : /* Logs the contents of 'usage', as a collection of name-count pairs.
     129                 :            :  *
     130                 :            :  * 'usage' should capture large-scale statistics that one might reasonably
     131                 :            :  * expect to correlate with memory usage.  For example, each OpenFlow flow
     132                 :            :  * requires some memory, so ovs-vswitchd includes the total number of flows in
     133                 :            :  * 'usage'. */
     134                 :            : void
     135                 :        145 : memory_report(const struct simap *usage)
     136                 :            : {
     137                 :            :     struct ds s;
     138                 :            :     size_t i;
     139                 :            : 
     140                 :        145 :     ds_init(&s);
     141                 :        145 :     compose_report(usage, &s);
     142                 :            : 
     143         [ +  - ]:        145 :     if (want_report) {
     144         [ +  + ]:        145 :         if (s.length) {
     145         [ +  - ]:        144 :             VLOG_INFO("%s", ds_cstr(&s));
     146                 :            :         }
     147                 :        145 :         want_report = false;
     148                 :            :     }
     149         [ -  + ]:        145 :     if (n_conns) {
     150         [ #  # ]:          0 :         for (i = 0; i < n_conns; i++) {
     151                 :          0 :             unixctl_command_reply(conns[i], ds_cstr(&s));
     152                 :            :         }
     153                 :          0 :         free(conns);
     154                 :          0 :         conns = NULL;
     155                 :          0 :         n_conns = 0;
     156                 :            :     }
     157                 :            : 
     158                 :        145 :     ds_destroy(&s);
     159                 :        145 : }
     160                 :            : 
     161                 :            : static void
     162                 :          0 : memory_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
     163                 :            :                     const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
     164                 :            : {
     165                 :          0 :     conns = xrealloc(conns, (n_conns + 1) * sizeof *conns);
     166                 :          0 :     conns[n_conns++] = conn;
     167                 :          0 : }
     168                 :            : 
     169                 :            : static void
     170                 :     164178 : memory_init(void)
     171                 :            : {
     172                 :            :     static bool inited = false;
     173                 :            : 
     174         [ +  + ]:     164178 :     if (!inited) {
     175                 :       1875 :         inited = true;
     176                 :       1875 :         unixctl_command_register("memory/show", "", 0, 0,
     177                 :            :                                  memory_unixctl_show, NULL);
     178                 :            : 
     179                 :       1875 :         next_check = time_boot_msec() + MEMORY_CHECK_INTERVAL;
     180                 :            :     }
     181                 :     164178 : }

Generated by: LCOV version 1.12