LCOV - code coverage report
Current view: top level - vswitchd - system-stats.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 13 217 6.0 %
Date: 2016-09-14 01:02:56 Functions: 4 17 23.5 %
Branches: 3 120 2.5 %

           Branch data     Line data    Source code
       1                 :            : /* Copyright (c) 2010, 2012, 2013, 2014 Nicira, Inc.
       2                 :            :  *
       3                 :            :  * Licensed under the Apache License, Version 2.0 (the "License");
       4                 :            :  * you may not use this file except in compliance with the License.
       5                 :            :  * You may obtain a copy of the License at:
       6                 :            :  *
       7                 :            :  *     http://www.apache.org/licenses/LICENSE-2.0
       8                 :            :  *
       9                 :            :  * Unless required by applicable law or agreed to in writing, software
      10                 :            :  * distributed under the License is distributed on an "AS IS" BASIS,
      11                 :            :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      12                 :            :  * See the License for the specific language governing permissions and
      13                 :            :  * limitations under the License.
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <config.h>
      17                 :            : 
      18                 :            : #include "system-stats.h"
      19                 :            : 
      20                 :            : #include <ctype.h>
      21                 :            : #include <dirent.h>
      22                 :            : #include <errno.h>
      23                 :            : #if HAVE_MNTENT_H
      24                 :            : #include <mntent.h>
      25                 :            : #endif
      26                 :            : #include <stdint.h>
      27                 :            : #include <stdio.h>
      28                 :            : #include <stdlib.h>
      29                 :            : #if HAVE_SYS_STATVFS_H
      30                 :            : #include <sys/statvfs.h>
      31                 :            : #endif
      32                 :            : #include <unistd.h>
      33                 :            : 
      34                 :            : #include "daemon.h"
      35                 :            : #include "dirs.h"
      36                 :            : #include "openvswitch/dynamic-string.h"
      37                 :            : #include "openvswitch/json.h"
      38                 :            : #include "latch.h"
      39                 :            : #include "openvswitch/ofpbuf.h"
      40                 :            : #include "ovs-rcu.h"
      41                 :            : #include "ovs-thread.h"
      42                 :            : #include "poll-loop.h"
      43                 :            : #include "openvswitch/shash.h"
      44                 :            : #include "smap.h"
      45                 :            : #include "timeval.h"
      46                 :            : #include "openvswitch/vlog.h"
      47                 :            : 
      48                 :       1288 : VLOG_DEFINE_THIS_MODULE(system_stats);
      49                 :            : 
      50                 :            : /* #ifdefs make it a pain to maintain code: you have to try to build both ways.
      51                 :            :  * Thus, this file tries to compile as much of the code as possible regardless
      52                 :            :  * of the target, by writing "if (LINUX)" instead of "#ifdef __linux__" where
      53                 :            :  * this is possible. */
      54                 :            : #ifdef __linux__
      55                 :            : #define LINUX 1
      56                 :            : #include <asm/param.h>
      57                 :            : #else
      58                 :            : #define LINUX 0
      59                 :            : #endif
      60                 :            : 
      61                 :            : static void
      62                 :          0 : get_cpu_cores(struct smap *stats)
      63                 :            : {
      64                 :          0 :     long int n_cores = count_cpu_cores();
      65         [ #  # ]:          0 :     if (n_cores > 0) {
      66                 :          0 :         smap_add_format(stats, "cpu", "%ld", n_cores);
      67                 :            :     }
      68                 :          0 : }
      69                 :            : 
      70                 :            : static void
      71                 :          0 : get_load_average(struct smap *stats OVS_UNUSED)
      72                 :            : {
      73                 :            : #if HAVE_GETLOADAVG
      74                 :            :     double loadavg[3];
      75                 :            : 
      76         [ #  # ]:          0 :     if (getloadavg(loadavg, 3) == 3) {
      77                 :          0 :         smap_add_format(stats, "load_average", "%.2f,%.2f,%.2f",
      78                 :            :                         loadavg[0], loadavg[1], loadavg[2]);
      79                 :            :     }
      80                 :            : #endif
      81                 :          0 : }
      82                 :            : 
      83                 :            : static unsigned int
      84                 :          0 : get_page_size(void)
      85                 :            : {
      86                 :            :     static unsigned int cached;
      87                 :            : 
      88         [ #  # ]:          0 :     if (!cached) {
      89                 :            : #ifndef _WIN32
      90                 :          0 :         long int value = sysconf(_SC_PAGESIZE);
      91                 :            : #else
      92                 :            :         long int value;
      93                 :            :         SYSTEM_INFO sysinfo;
      94                 :            :         GetSystemInfo(&sysinfo);
      95                 :            :         value = sysinfo.dwPageSize;
      96                 :            : #endif
      97         [ #  # ]:          0 :         if (value >= 0) {
      98                 :          0 :             cached = value;
      99                 :            :         }
     100                 :            :     }
     101                 :            : 
     102                 :          0 :     return cached;
     103                 :            : }
     104                 :            : 
     105                 :            : static void
     106                 :          0 : get_memory_stats(struct smap *stats)
     107                 :            : {
     108                 :            :     if (!LINUX) {
     109                 :            :         unsigned int pagesize = get_page_size();
     110                 :            : #ifdef _SC_PHYS_PAGES
     111                 :            :         long int phys_pages = sysconf(_SC_PHYS_PAGES);
     112                 :            : #else
     113                 :            :         long int phys_pages = 0;
     114                 :            : #endif
     115                 :            : #ifdef _SC_AVPHYS_PAGES
     116                 :            :         long int avphys_pages = sysconf(_SC_AVPHYS_PAGES);
     117                 :            : #else
     118                 :            :         long int avphys_pages = 0;
     119                 :            : #endif
     120                 :            :         int mem_total, mem_used;
     121                 :            : 
     122                 :            : #ifndef _WIN32
     123                 :            :         if (pagesize <= 0 || phys_pages <= 0 || avphys_pages <= 0) {
     124                 :            :             return;
     125                 :            :         }
     126                 :            : 
     127                 :            :         mem_total = phys_pages * (pagesize / 1024);
     128                 :            :         mem_used = (phys_pages - avphys_pages) * (pagesize / 1024);
     129                 :            : #else
     130                 :            :         MEMORYSTATUS memory_status;
     131                 :            :         GlobalMemoryStatus(&memory_status);
     132                 :            : 
     133                 :            :         mem_total = memory_status.dwTotalPhys;
     134                 :            :         mem_used = memory_status.dwTotalPhys - memory_status.dwAvailPhys;
     135                 :            : #endif
     136                 :            :         smap_add_format(stats, "memory", "%d,%d", mem_total, mem_used);
     137                 :            :     } else {
     138                 :            :         static const char file_name[] = "/proc/meminfo";
     139                 :            :         int mem_used, mem_cache, swap_used;
     140                 :          0 :         int mem_free = 0;
     141                 :          0 :         int buffers = 0;
     142                 :          0 :         int cached = 0;
     143                 :          0 :         int swap_free = 0;
     144                 :          0 :         int mem_total = 0;
     145                 :          0 :         int swap_total = 0;
     146                 :            :         struct shash dict;
     147                 :            :         char line[128];
     148                 :            :         FILE *stream;
     149                 :            : 
     150                 :          0 :         stream = fopen(file_name, "r");
     151         [ #  # ]:          0 :         if (!stream) {
     152         [ #  # ]:          0 :             VLOG_WARN_ONCE("%s: open failed (%s)",
     153                 :            :                            file_name, ovs_strerror(errno));
     154                 :          0 :             return;
     155                 :            :         }
     156                 :            : 
     157                 :          0 :         shash_init(&dict);
     158                 :          0 :         shash_add(&dict, "MemTotal", &mem_total);
     159                 :          0 :         shash_add(&dict, "MemFree", &mem_free);
     160                 :          0 :         shash_add(&dict, "Buffers", &buffers);
     161                 :          0 :         shash_add(&dict, "Cached", &cached);
     162                 :          0 :         shash_add(&dict, "SwapTotal", &swap_total);
     163                 :          0 :         shash_add(&dict, "SwapFree", &swap_free);
     164         [ #  # ]:          0 :         while (fgets(line, sizeof line, stream)) {
     165                 :            :             char key[16];
     166                 :            :             int value;
     167                 :            : 
     168         [ #  # ]:          0 :             if (ovs_scan(line, "%15[^:]: %u", key, &value)) {
     169                 :          0 :                 int *valuep = shash_find_data(&dict, key);
     170         [ #  # ]:          0 :                 if (valuep) {
     171                 :          0 :                     *valuep = value;
     172                 :            :                 }
     173                 :            :             }
     174                 :            :         }
     175                 :          0 :         fclose(stream);
     176                 :          0 :         shash_destroy(&dict);
     177                 :            : 
     178                 :          0 :         mem_used = mem_total - mem_free;
     179                 :          0 :         mem_cache = buffers + cached;
     180                 :          0 :         swap_used = swap_total - swap_free;
     181                 :          0 :         smap_add_format(stats, "memory", "%d,%d,%d,%d,%d",
     182                 :            :                         mem_total, mem_used, mem_cache, swap_total, swap_used);
     183                 :            :     }
     184                 :            : }
     185                 :            : 
     186                 :            : /* Returns the time at which the system booted, as the number of milliseconds
     187                 :            :  * since the epoch, or 0 if the time of boot cannot be determined. */
     188                 :            : static long long int
     189                 :          0 : get_boot_time(void)
     190                 :            : {
     191                 :            :     static long long int cache_expiration = LLONG_MIN;
     192                 :            :     static long long int boot_time;
     193                 :            : 
     194                 :            :     ovs_assert(LINUX);
     195                 :            : 
     196         [ #  # ]:          0 :     if (time_msec() >= cache_expiration) {
     197                 :            :         static const char stat_file[] = "/proc/stat";
     198                 :            :         char line[128];
     199                 :            :         FILE *stream;
     200                 :            : 
     201                 :          0 :         cache_expiration = time_msec() + 5 * 1000;
     202                 :            : 
     203                 :          0 :         stream = fopen(stat_file, "r");
     204         [ #  # ]:          0 :         if (!stream) {
     205         [ #  # ]:          0 :             VLOG_ERR_ONCE("%s: open failed (%s)",
     206                 :            :                           stat_file, ovs_strerror(errno));
     207                 :          0 :             return boot_time;
     208                 :            :         }
     209                 :            : 
     210         [ #  # ]:          0 :         while (fgets(line, sizeof line, stream)) {
     211                 :            :             long long int btime;
     212         [ #  # ]:          0 :             if (ovs_scan(line, "btime %lld", &btime)) {
     213                 :          0 :                 boot_time = btime * 1000;
     214                 :          0 :                 goto done;
     215                 :            :             }
     216                 :            :         }
     217         [ #  # ]:          0 :         VLOG_ERR_ONCE("%s: btime not found", stat_file);
     218                 :            :     done:
     219                 :          0 :         fclose(stream);
     220                 :            :     }
     221                 :          0 :     return boot_time;
     222                 :            : }
     223                 :            : 
     224                 :            : static unsigned long long int
     225                 :          0 : ticks_to_ms(unsigned long long int ticks)
     226                 :            : {
     227                 :            :     ovs_assert(LINUX);
     228                 :            : 
     229                 :            : #ifndef USER_HZ
     230                 :            : #define USER_HZ 100
     231                 :            : #endif
     232                 :            : 
     233                 :            : #if USER_HZ == 100              /* Common case. */
     234                 :          0 :     return ticks * (1000 / USER_HZ);
     235                 :            : #else  /* Alpha and some other architectures.  */
     236                 :            :     double factor = 1000.0 / USER_HZ;
     237                 :            :     return ticks * factor + 0.5;
     238                 :            : #endif
     239                 :            : }
     240                 :            : 
     241                 :            : struct raw_process_info {
     242                 :            :     unsigned long int vsz;      /* Virtual size, in kB. */
     243                 :            :     unsigned long int rss;      /* Resident set size, in kB. */
     244                 :            :     long long int uptime;       /* ms since started. */
     245                 :            :     long long int cputime;      /* ms of CPU used during 'uptime'. */
     246                 :            :     pid_t ppid;                 /* Parent. */
     247                 :            :     char name[18];              /* Name (surrounded by parentheses). */
     248                 :            : };
     249                 :            : 
     250                 :            : static bool
     251                 :          0 : get_raw_process_info(pid_t pid, struct raw_process_info *raw)
     252                 :            : {
     253                 :            :     unsigned long long int vsize, rss, start_time, utime, stime;
     254                 :            :     long long int start_msec;
     255                 :            :     unsigned long ppid;
     256                 :            :     char file_name[128];
     257                 :            :     FILE *stream;
     258                 :            :     int n;
     259                 :            : 
     260                 :            :     ovs_assert(LINUX);
     261                 :            : 
     262                 :          0 :     sprintf(file_name, "/proc/%lu/stat", (unsigned long int) pid);
     263                 :          0 :     stream = fopen(file_name, "r");
     264         [ #  # ]:          0 :     if (!stream) {
     265         [ #  # ]:          0 :         VLOG_ERR_ONCE("%s: open failed (%s)",
     266                 :            :                       file_name, ovs_strerror(errno));
     267                 :          0 :         return false;
     268                 :            :     }
     269                 :            : 
     270                 :          0 :     n = fscanf(stream,
     271                 :            :                "%*d "           /* (1. pid) */
     272                 :            :                "%17s "          /* 2. process name */
     273                 :            :                "%*c "           /* (3. state) */
     274                 :            :                "%lu "           /* 4. ppid */
     275                 :            :                "%*d "           /* (5. pgid) */
     276                 :            :                "%*d "           /* (6. sid) */
     277                 :            :                "%*d "           /* (7. tty_nr) */
     278                 :            :                "%*d "           /* (8. tty_pgrp) */
     279                 :            :                "%*u "           /* (9. flags) */
     280                 :            :                "%*u "           /* (10. min_flt) */
     281                 :            :                "%*u "           /* (11. cmin_flt) */
     282                 :            :                "%*u "           /* (12. maj_flt) */
     283                 :            :                "%*u "           /* (13. cmaj_flt) */
     284                 :            :                "%llu "          /* 14. utime */
     285                 :            :                "%llu "          /* 15. stime */
     286                 :            :                "%*d "           /* (16. cutime) */
     287                 :            :                "%*d "           /* (17. cstime) */
     288                 :            :                "%*d "           /* (18. priority) */
     289                 :            :                "%*d "           /* (19. nice) */
     290                 :            :                "%*d "           /* (20. num_threads) */
     291                 :            :                "%*d "           /* (21. always 0) */
     292                 :            :                "%llu "          /* 22. start_time */
     293                 :            :                "%llu "          /* 23. vsize */
     294                 :            :                "%llu "          /* 24. rss */
     295                 :            : #if 0
     296                 :            :                /* These are here for documentation but #if'd out to save
     297                 :            :                 * actually parsing them from the stream for no benefit. */
     298                 :            :                "%*lu "          /* (25. rsslim) */
     299                 :            :                "%*lu "          /* (26. start_code) */
     300                 :            :                "%*lu "          /* (27. end_code) */
     301                 :            :                "%*lu "          /* (28. start_stack) */
     302                 :            :                "%*lu "          /* (29. esp) */
     303                 :            :                "%*lu "          /* (30. eip) */
     304                 :            :                "%*lu "          /* (31. pending signals) */
     305                 :            :                "%*lu "          /* (32. blocked signals) */
     306                 :            :                "%*lu "          /* (33. ignored signals) */
     307                 :            :                "%*lu "          /* (34. caught signals) */
     308                 :            :                "%*lu "          /* (35. whcan) */
     309                 :            :                "%*lu "          /* (36. always 0) */
     310                 :            :                "%*lu "          /* (37. always 0) */
     311                 :            :                "%*d "           /* (38. exit_signal) */
     312                 :            :                "%*d "           /* (39. task_cpu) */
     313                 :            :                "%*u "           /* (40. rt_priority) */
     314                 :            :                "%*u "           /* (41. policy) */
     315                 :            :                "%*llu "         /* (42. blkio_ticks) */
     316                 :            :                "%*lu "          /* (43. gtime) */
     317                 :            :                "%*ld"           /* (44. cgtime) */
     318                 :            : #endif
     319                 :          0 :                , raw->name, &ppid, &utime, &stime, &start_time, &vsize, &rss);
     320                 :          0 :     fclose(stream);
     321         [ #  # ]:          0 :     if (n != 7) {
     322         [ #  # ]:          0 :         VLOG_ERR_ONCE("%s: fscanf failed", file_name);
     323                 :          0 :         return false;
     324                 :            :     }
     325                 :            : 
     326                 :          0 :     start_msec = get_boot_time() + ticks_to_ms(start_time);
     327                 :            : 
     328                 :          0 :     raw->vsz = vsize / 1024;
     329                 :          0 :     raw->rss = rss * (getpagesize() / 1024);
     330                 :          0 :     raw->uptime = time_wall_msec() - start_msec;
     331                 :          0 :     raw->cputime = ticks_to_ms(utime + stime);
     332                 :          0 :     raw->ppid = ppid;
     333                 :            : 
     334                 :          0 :     return true;
     335                 :            : }
     336                 :            : 
     337                 :            : static int
     338                 :          0 : count_crashes(pid_t pid)
     339                 :            : {
     340                 :            :     char file_name[128];
     341                 :            :     const char *paren;
     342                 :            :     char line[128];
     343                 :          0 :     int crashes = 0;
     344                 :            :     FILE *stream;
     345                 :            : 
     346                 :            :     ovs_assert(LINUX);
     347                 :            : 
     348                 :          0 :     sprintf(file_name, "/proc/%lu/cmdline", (unsigned long int) pid);
     349                 :          0 :     stream = fopen(file_name, "r");
     350         [ #  # ]:          0 :     if (!stream) {
     351         [ #  # ]:          0 :         VLOG_WARN_ONCE("%s: open failed (%s)", file_name, ovs_strerror(errno));
     352                 :          0 :         goto exit;
     353                 :            :     }
     354                 :            : 
     355         [ #  # ]:          0 :     if (!fgets(line, sizeof line, stream)) {
     356 [ #  # ][ #  # ]:          0 :         VLOG_WARN_ONCE("%s: read failed (%s)", file_name,
     357                 :            :                        feof(stream) ? "end of file" : ovs_strerror(errno));
     358                 :          0 :         goto exit_close;
     359                 :            :     }
     360                 :            : 
     361                 :          0 :     paren = strchr(line, '(');
     362         [ #  # ]:          0 :     if (paren) {
     363                 :            :         int x;
     364         [ #  # ]:          0 :         if (ovs_scan(paren + 1, "%d", &x)) {
     365                 :          0 :             crashes = x;
     366                 :            :         }
     367                 :            :     }
     368                 :            : 
     369                 :            : exit_close:
     370                 :          0 :     fclose(stream);
     371                 :            : exit:
     372                 :          0 :     return crashes;
     373                 :            : }
     374                 :            : 
     375                 :            : struct process_info {
     376                 :            :     unsigned long int vsz;      /* Virtual size, in kB. */
     377                 :            :     unsigned long int rss;      /* Resident set size, in kB. */
     378                 :            :     long long int booted;       /* ms since monitor started. */
     379                 :            :     int crashes;                /* # of crashes (usually 0). */
     380                 :            :     long long int uptime;       /* ms since last (re)started by monitor. */
     381                 :            :     long long int cputime;      /* ms of CPU used during 'uptime'. */
     382                 :            : };
     383                 :            : 
     384                 :            : static bool
     385                 :          0 : get_process_info(pid_t pid, struct process_info *pinfo)
     386                 :            : {
     387                 :            :     struct raw_process_info child;
     388                 :            : 
     389                 :            :     ovs_assert(LINUX);
     390         [ #  # ]:          0 :     if (!get_raw_process_info(pid, &child)) {
     391                 :          0 :         return false;
     392                 :            :     }
     393                 :            : 
     394                 :          0 :     pinfo->vsz = child.vsz;
     395                 :          0 :     pinfo->rss = child.rss;
     396                 :          0 :     pinfo->booted = child.uptime;
     397                 :          0 :     pinfo->crashes = 0;
     398                 :          0 :     pinfo->uptime = child.uptime;
     399                 :          0 :     pinfo->cputime = child.cputime;
     400                 :            : 
     401         [ #  # ]:          0 :     if (child.ppid) {
     402                 :            :         struct raw_process_info parent;
     403                 :            : 
     404                 :          0 :         get_raw_process_info(child.ppid, &parent);
     405         [ #  # ]:          0 :         if (!strcmp(child.name, parent.name)) {
     406                 :          0 :             pinfo->booted = parent.uptime;
     407                 :          0 :             pinfo->crashes = count_crashes(child.ppid);
     408                 :            :         }
     409                 :            :     }
     410                 :            : 
     411                 :          0 :     return true;
     412                 :            : }
     413                 :            : 
     414                 :            : static void
     415                 :          0 : get_process_stats(struct smap *stats)
     416                 :            : {
     417                 :            : #ifndef _WIN32
     418                 :            :     struct dirent *de;
     419                 :            :     DIR *dir;
     420                 :            : 
     421                 :          0 :     dir = opendir(ovs_rundir());
     422         [ #  # ]:          0 :     if (!dir) {
     423         [ #  # ]:          0 :         VLOG_ERR_ONCE("%s: open failed (%s)",
     424                 :            :                       ovs_rundir(), ovs_strerror(errno));
     425                 :          0 :         return;
     426                 :            :     }
     427                 :            : 
     428         [ #  # ]:          0 :     while ((de = readdir(dir)) != NULL) {
     429                 :            :         struct process_info pinfo;
     430                 :            :         char *file_name;
     431                 :            :         char *extension;
     432                 :            :         char *key;
     433                 :            :         pid_t pid;
     434                 :            : 
     435                 :            : #ifdef _DIRENT_HAVE_D_TYPE
     436 [ #  # ][ #  # ]:          0 :         if (de->d_type != DT_UNKNOWN && de->d_type != DT_REG) {
     437                 :          0 :             continue;
     438                 :            :         }
     439                 :            : #endif
     440                 :            : 
     441                 :          0 :         extension = strrchr(de->d_name, '.');
     442 [ #  # ][ #  # ]:          0 :         if (!extension || strcmp(extension, ".pid")) {
     443                 :          0 :             continue;
     444                 :            :         }
     445                 :            : 
     446                 :          0 :         file_name = xasprintf("%s/%s", ovs_rundir(), de->d_name);
     447                 :          0 :         pid = read_pidfile(file_name);
     448                 :          0 :         free(file_name);
     449         [ #  # ]:          0 :         if (pid < 0) {
     450                 :          0 :             continue;
     451                 :            :         }
     452                 :            : 
     453                 :          0 :         key = xasprintf("process_%.*s",
     454                 :          0 :                         (int) (extension - de->d_name), de->d_name);
     455         [ #  # ]:          0 :         if (!smap_get(stats, key)) {
     456         [ #  # ]:          0 :             if (LINUX && get_process_info(pid, &pinfo)) {
     457                 :          0 :                 smap_add_format(stats, key, "%lu,%lu,%lld,%d,%lld,%lld",
     458                 :            :                                 pinfo.vsz, pinfo.rss, pinfo.cputime,
     459                 :            :                                 pinfo.crashes, pinfo.booted, pinfo.uptime);
     460                 :            :             } else {
     461                 :          0 :                 smap_add(stats, key, "");
     462                 :            :             }
     463                 :            :         }
     464                 :          0 :         free(key);
     465                 :            :     }
     466                 :            : 
     467                 :          0 :     closedir(dir);
     468                 :            : #endif /* _WIN32 */
     469                 :            : }
     470                 :            : 
     471                 :            : static void
     472                 :          0 : get_filesys_stats(struct smap *stats OVS_UNUSED)
     473                 :            : {
     474                 :            : #if HAVE_GETMNTENT_R && HAVE_STATVFS
     475                 :            :     static const char file_name[] = "/etc/mtab";
     476                 :            :     struct mntent mntent;
     477                 :            :     struct mntent *me;
     478                 :            :     char buf[4096];
     479                 :            :     FILE *stream;
     480                 :            :     struct ds s;
     481                 :            : 
     482                 :          0 :     stream = setmntent(file_name, "r");
     483         [ #  # ]:          0 :     if (!stream) {
     484         [ #  # ]:          0 :         VLOG_ERR_ONCE("%s: open failed (%s)", file_name, ovs_strerror(errno));
     485                 :          0 :         return;
     486                 :            :     }
     487                 :            : 
     488                 :          0 :     ds_init(&s);
     489         [ #  # ]:          0 :     while ((me = getmntent_r(stream, &mntent, buf, sizeof buf)) != NULL) {
     490                 :            :         unsigned long long int total, free;
     491                 :            :         struct statvfs vfs;
     492                 :            :         char *p;
     493                 :            : 
     494                 :            :         /* Skip non-local and read-only filesystems. */
     495         [ #  # ]:          0 :         if (strncmp(me->mnt_fsname, "/dev", 4)
     496         [ #  # ]:          0 :             || !strstr(me->mnt_opts, "rw")) {
     497                 :          0 :             continue;
     498                 :            :         }
     499                 :            : 
     500                 :            :         /* Given the mount point we can stat the file system. */
     501 [ #  # ][ #  # ]:          0 :         if (statvfs(me->mnt_dir, &vfs) && vfs.f_flag & ST_RDONLY) {
     502                 :            :             /* That's odd... */
     503                 :          0 :             continue;
     504                 :            :         }
     505                 :            : 
     506                 :            :         /* Now format the data. */
     507         [ #  # ]:          0 :         if (s.length) {
     508                 :          0 :             ds_put_char(&s, ' ');
     509                 :            :         }
     510         [ #  # ]:          0 :         for (p = me->mnt_dir; *p != '\0'; p++) {
     511 [ #  # ][ #  # ]:          0 :             ds_put_char(&s, *p == ' ' || *p == ',' ? '_' : *p);
     512                 :            :         }
     513                 :          0 :         total = (unsigned long long int) vfs.f_frsize * vfs.f_blocks / 1024;
     514                 :          0 :         free = (unsigned long long int) vfs.f_frsize * vfs.f_bfree / 1024;
     515                 :          0 :         ds_put_format(&s, ",%llu,%llu", total, total - free);
     516                 :            :     }
     517                 :          0 :     endmntent(stream);
     518                 :            : 
     519         [ #  # ]:          0 :     if (s.length) {
     520                 :          0 :         smap_add(stats, "file_systems", ds_cstr(&s));
     521                 :            :     }
     522                 :          0 :     ds_destroy(&s);
     523                 :            : #endif  /* HAVE_GETMNTENT_R && HAVE_STATVFS */
     524                 :            : }
     525                 :            : 
     526                 :            : #define SYSTEM_STATS_INTERVAL (5 * 1000) /* In milliseconds. */
     527                 :            : 
     528                 :            : static struct ovs_mutex mutex = OVS_MUTEX_INITIALIZER;
     529                 :            : static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
     530                 :            : static struct latch latch OVS_GUARDED_BY(mutex);
     531                 :            : static bool enabled;
     532                 :            : static bool started OVS_GUARDED_BY(mutex);
     533                 :            : static struct smap *system_stats OVS_GUARDED_BY(mutex);
     534                 :            : 
     535                 :            : OVS_NO_RETURN static void *system_stats_thread_func(void *);
     536                 :            : static void discard_stats(void);
     537                 :            : 
     538                 :            : /* Enables or disables system stats collection, according to 'enable'. */
     539                 :            : void
     540                 :       4243 : system_stats_enable(bool enable)
     541                 :            : {
     542         [ -  + ]:       4243 :     if (enabled != enable) {
     543                 :          0 :         ovs_mutex_lock(&mutex);
     544         [ #  # ]:          0 :         if (enable) {
     545         [ #  # ]:          0 :             if (!started) {
     546                 :          0 :                 ovs_thread_create("system_stats",
     547                 :            :                                   system_stats_thread_func, NULL);
     548                 :          0 :                 latch_init(&latch);
     549                 :          0 :                 started = true;
     550                 :            :             }
     551                 :          0 :             discard_stats();
     552                 :          0 :             xpthread_cond_signal(&cond);
     553                 :            :         }
     554                 :          0 :         enabled = enable;
     555                 :          0 :         ovs_mutex_unlock(&mutex);
     556                 :            :     }
     557                 :       4243 : }
     558                 :            : 
     559                 :            : /* Tries to obtain a new snapshot of system stats every SYSTEM_STATS_INTERVAL
     560                 :            :  * milliseconds.
     561                 :            :  *
     562                 :            :  * When a new snapshot is available (which only occurs if system stats are
     563                 :            :  * enabled), returns it as an smap owned by the caller.  The caller must use
     564                 :            :  * both smap_destroy() and free() to completely free the returned data.
     565                 :            :  *
     566                 :            :  * When no new snapshot is available, returns NULL. */
     567                 :            : struct smap *
     568                 :     103919 : system_stats_run(void)
     569                 :            : {
     570                 :     103919 :     struct smap *stats = NULL;
     571                 :            : 
     572                 :     103919 :     ovs_mutex_lock(&mutex);
     573         [ -  + ]:     103919 :     if (system_stats) {
     574                 :          0 :         latch_poll(&latch);
     575                 :            : 
     576         [ #  # ]:          0 :         if (enabled) {
     577                 :          0 :             stats = system_stats;
     578                 :          0 :             system_stats = NULL;
     579                 :            :         } else {
     580                 :          0 :             discard_stats();
     581                 :            :         }
     582                 :            :     }
     583                 :     103919 :     ovs_mutex_unlock(&mutex);
     584                 :            : 
     585                 :     103919 :     return stats;
     586                 :            : }
     587                 :            : 
     588                 :            : /* Causes poll_block() to wake up when system_stats_run() needs to be
     589                 :            :  * called. */
     590                 :            : void
     591                 :     105174 : system_stats_wait(void)
     592                 :            : {
     593         [ -  + ]:     105174 :     if (enabled) {
     594                 :          0 :         latch_wait(&latch);
     595                 :            :     }
     596                 :     105174 : }
     597                 :            : 
     598                 :            : static void
     599                 :          0 : discard_stats(void) OVS_REQUIRES(mutex)
     600                 :            : {
     601         [ #  # ]:          0 :     if (system_stats) {
     602                 :          0 :         smap_destroy(system_stats);
     603                 :          0 :         free(system_stats);
     604                 :          0 :         system_stats = NULL;
     605                 :            :     }
     606                 :          0 : }
     607                 :            : 
     608                 :            : static void *
     609                 :          0 : system_stats_thread_func(void *arg OVS_UNUSED)
     610                 :            : {
     611                 :          0 :     pthread_detach(pthread_self());
     612                 :            : 
     613                 :            :     for (;;) {
     614                 :            :         long long int next_refresh;
     615                 :            :         struct smap *stats;
     616                 :            : 
     617                 :          0 :         ovs_mutex_lock(&mutex);
     618         [ #  # ]:          0 :         while (!enabled) {
     619                 :            :             /* The thread is sleeping, potentially for a long time, and it's
     620                 :            :              * not holding RCU protected references, so it makes sense to
     621                 :            :              * quiesce */
     622                 :          0 :             ovsrcu_quiesce_start();
     623                 :          0 :             ovs_mutex_cond_wait(&cond, &mutex);
     624                 :          0 :             ovsrcu_quiesce_end();
     625                 :            :         }
     626                 :          0 :         ovs_mutex_unlock(&mutex);
     627                 :            : 
     628                 :          0 :         stats = xmalloc(sizeof *stats);
     629                 :          0 :         smap_init(stats);
     630                 :          0 :         get_cpu_cores(stats);
     631                 :          0 :         get_load_average(stats);
     632                 :          0 :         get_memory_stats(stats);
     633                 :          0 :         get_process_stats(stats);
     634                 :          0 :         get_filesys_stats(stats);
     635                 :            : 
     636                 :          0 :         ovs_mutex_lock(&mutex);
     637                 :          0 :         discard_stats();
     638                 :          0 :         system_stats = stats;
     639                 :          0 :         latch_set(&latch);
     640                 :          0 :         ovs_mutex_unlock(&mutex);
     641                 :            : 
     642                 :          0 :         next_refresh = time_msec() + SYSTEM_STATS_INTERVAL;
     643                 :            :         do {
     644                 :          0 :             poll_timer_wait_until(next_refresh);
     645                 :          0 :             poll_block();
     646         [ #  # ]:          0 :         } while (time_msec() < next_refresh);
     647                 :          0 :     }
     648                 :            : }

Generated by: LCOV version 1.12