[ovs-dev] [PATCH v2] process: Consolidate process related APIs.

Bhanuprakash Bodireddy bhanuprakash.bodireddy at intel.com
Tue Jun 20 09:29:47 UTC 2017


As part of retrieving system statistics, process status APIs along with
helper functions were implemented. Some of them are very generic and can
be reused by other subsystems.

Move the APIs in system-stats.c to process.c and util.c and make them
available. This patch doesn't change any functionality.

CC: Ben Pfaff <blp at ovn.org>
Signed-off-by: Bhanuprakash Bodireddy <bhanuprakash.bodireddy at intel.com>
---
v1->v2
  * Move ticks_to_ms() from util.c to process.c
  * Verify the changes and test it by enabling statistics using,
     $ovs-vsctl set Open_vSwitch . other_config:enable-statistics=true

 lib/process.c           | 189 ++++++++++++++++++++++++++++++++++++
 lib/process.h           |  12 +++
 lib/util.c              |  68 +++++++++++++
 lib/util.h              |   3 +
 vswitchd/system-stats.c | 251 +-----------------------------------------------
 5 files changed, 273 insertions(+), 250 deletions(-)

diff --git a/lib/process.c b/lib/process.c
index e9d0ba9..3e119b5 100644
--- a/lib/process.c
+++ b/lib/process.c
@@ -33,6 +33,7 @@
 #include "poll-loop.h"
 #include "signals.h"
 #include "socket-util.h"
+#include "timeval.h"
 #include "util.h"
 #include "openvswitch/vlog.h"
 
@@ -40,6 +41,13 @@ VLOG_DEFINE_THIS_MODULE(process);
 
 COVERAGE_DEFINE(process_start);
 
+#ifdef __linux__
+#define LINUX 1
+#include <asm/param.h>
+#else
+#define LINUX 0
+#endif
+
 struct process {
     struct ovs_list node;
     char *name;
@@ -50,6 +58,15 @@ struct process {
     int status;
 };
 
+struct raw_process_info {
+    unsigned long int vsz;      /* Virtual size, in kB. */
+    unsigned long int rss;      /* Resident set size, in kB. */
+    long long int uptime;       /* ms since started. */
+    long long int cputime;      /* ms of CPU used during 'uptime'. */
+    pid_t ppid;                 /* Parent. */
+    char name[18];              /* Name (surrounded by parentheses). */
+};
+
 /* Pipe used to signal child termination. */
 static int fds[2];
 
@@ -327,6 +344,178 @@ process_status(const struct process *p)
     return p->status;
 }
 
+int
+count_crashes(pid_t pid)
+{
+    char file_name[128];
+    const char *paren;
+    char line[128];
+    int crashes = 0;
+    FILE *stream;
+
+    ovs_assert(LINUX);
+
+    sprintf(file_name, "/proc/%lu/cmdline", (unsigned long int) pid);
+    stream = fopen(file_name, "r");
+    if (!stream) {
+        VLOG_WARN_ONCE("%s: open failed (%s)", file_name, ovs_strerror(errno));
+        goto exit;
+    }
+
+    if (!fgets(line, sizeof line, stream)) {
+        VLOG_WARN_ONCE("%s: read failed (%s)", file_name,
+                       feof(stream) ? "end of file" : ovs_strerror(errno));
+        goto exit_close;
+    }
+
+    paren = strchr(line, '(');
+    if (paren) {
+        int x;
+        if (ovs_scan(paren + 1, "%d", &x)) {
+            crashes = x;
+        }
+    }
+
+exit_close:
+    fclose(stream);
+exit:
+    return crashes;
+}
+
+static unsigned long long int
+ticks_to_ms(unsigned long long int ticks)
+{
+    ovs_assert(LINUX);
+
+#ifndef USER_HZ
+#define USER_HZ 100
+#endif
+
+#if USER_HZ == 100              /* Common case. */
+    return ticks * (1000 / USER_HZ);
+#else  /* Alpha and some other architectures.  */
+    double factor = 1000.0 / USER_HZ;
+    return ticks * factor + 0.5;
+#endif
+}
+
+static bool
+get_raw_process_info(pid_t pid, struct raw_process_info *raw)
+{
+    unsigned long long int vsize, rss, start_time, utime, stime;
+    long long int start_msec;
+    unsigned long ppid;
+    char file_name[128];
+    FILE *stream;
+    int n;
+
+    ovs_assert(LINUX);
+
+    sprintf(file_name, "/proc/%lu/stat", (unsigned long int) pid);
+    stream = fopen(file_name, "r");
+    if (!stream) {
+        VLOG_ERR_ONCE("%s: open failed (%s)",
+                      file_name, ovs_strerror(errno));
+        return false;
+    }
+
+    n = fscanf(stream,
+               "%*d "           /* (1. pid) */
+               "%17s "          /* 2. process name */
+               "%*c "           /* (3. state) */
+               "%lu "           /* 4. ppid */
+               "%*d "           /* (5. pgid) */
+               "%*d "           /* (6. sid) */
+               "%*d "           /* (7. tty_nr) */
+               "%*d "           /* (8. tty_pgrp) */
+               "%*u "           /* (9. flags) */
+               "%*u "           /* (10. min_flt) */
+               "%*u "           /* (11. cmin_flt) */
+               "%*u "           /* (12. maj_flt) */
+               "%*u "           /* (13. cmaj_flt) */
+               "%llu "          /* 14. utime */
+               "%llu "          /* 15. stime */
+               "%*d "           /* (16. cutime) */
+               "%*d "           /* (17. cstime) */
+               "%*d "           /* (18. priority) */
+               "%*d "           /* (19. nice) */
+               "%*d "           /* (20. num_threads) */
+               "%*d "           /* (21. always 0) */
+               "%llu "          /* 22. start_time */
+               "%llu "          /* 23. vsize */
+               "%llu "          /* 24. rss */
+#if 0
+               /* These are here for documentation but #if'd out to save
+                * actually parsing them from the stream for no benefit. */
+               "%*lu "          /* (25. rsslim) */
+               "%*lu "          /* (26. start_code) */
+               "%*lu "          /* (27. end_code) */
+               "%*lu "          /* (28. start_stack) */
+               "%*lu "          /* (29. esp) */
+               "%*lu "          /* (30. eip) */
+               "%*lu "          /* (31. pending signals) */
+               "%*lu "          /* (32. blocked signals) */
+               "%*lu "          /* (33. ignored signals) */
+               "%*lu "          /* (34. caught signals) */
+               "%*lu "          /* (35. whcan) */
+               "%*lu "          /* (36. always 0) */
+               "%*lu "          /* (37. always 0) */
+               "%*d "           /* (38. exit_signal) */
+               "%*d "           /* (39. task_cpu) */
+               "%*u "           /* (40. rt_priority) */
+               "%*u "           /* (41. policy) */
+               "%*llu "         /* (42. blkio_ticks) */
+               "%*lu "          /* (43. gtime) */
+               "%*ld"           /* (44. cgtime) */
+#endif
+               , raw->name, &ppid, &utime, &stime, &start_time, &vsize, &rss);
+    fclose(stream);
+    if (n != 7) {
+        VLOG_ERR_ONCE("%s: fscanf failed", file_name);
+        return false;
+    }
+
+    start_msec = get_boot_time() + ticks_to_ms(start_time);
+
+    raw->vsz = vsize / 1024;
+    raw->rss = rss * (get_page_size() / 1024);
+    raw->uptime = time_wall_msec() - start_msec;
+    raw->cputime = ticks_to_ms(utime + stime);
+    raw->ppid = ppid;
+
+    return true;
+}
+
+bool
+get_process_info(pid_t pid, struct process_info *pinfo)
+{
+    struct raw_process_info child;
+
+    ovs_assert(LINUX);
+    if (!get_raw_process_info(pid, &child)) {
+        return false;
+    }
+
+    pinfo->vsz = child.vsz;
+    pinfo->rss = child.rss;
+    pinfo->booted = child.uptime;
+    pinfo->crashes = 0;
+    pinfo->uptime = child.uptime;
+    pinfo->cputime = child.cputime;
+
+    if (child.ppid) {
+        struct raw_process_info parent;
+
+        get_raw_process_info(child.ppid, &parent);
+        if (!strcmp(child.name, parent.name)) {
+            pinfo->booted = parent.uptime;
+            pinfo->crashes = count_crashes(child.ppid);
+        }
+    }
+
+    return true;
+}
+
 /* Given 'status', which is a process status in the form reported by waitpid(2)
  * and returned by process_status(), returns a string describing how the
  * process terminated.  The caller is responsible for freeing the string when
diff --git a/lib/process.h b/lib/process.h
index 3feac7e..999ac68 100644
--- a/lib/process.h
+++ b/lib/process.h
@@ -22,6 +22,15 @@
 
 struct process;
 
+struct process_info {
+    unsigned long int vsz;      /* Virtual size, in kB. */
+    unsigned long int rss;      /* Resident set size, in kB. */
+    long long int booted;       /* ms since monitor started. */
+    int crashes;                /* # of crashes (usually 0). */
+    long long int uptime;       /* ms since last (re)started by monitor. */
+    long long int cputime;      /* ms of CPU used during 'uptime'. */
+};
+
 /* Starting and monitoring subprocesses.
  *
  * process_init() and process_start() may safely be called only from a
@@ -39,6 +48,9 @@ int process_status(const struct process *);
 void process_run(void);
 void process_wait(struct process *);
 
+int count_crashes(pid_t);
+bool get_process_info(pid_t, struct process_info *);
+
 /* These functions are thread-safe. */
 char *process_status_msg(int);
 char *process_escape_args(char **argv);
diff --git a/lib/util.c b/lib/util.c
index 85b9350..b832ac1 100644
--- a/lib/util.c
+++ b/lib/util.c
@@ -33,6 +33,7 @@
 #include "ovs-rcu.h"
 #include "ovs-thread.h"
 #include "socket-util.h"
+#include "timeval.h"
 #include "openvswitch/vlog.h"
 #ifdef HAVE_PTHREAD_SET_NAME_NP
 #include <pthread_np.h>
@@ -40,6 +41,13 @@
 
 VLOG_DEFINE_THIS_MODULE(util);
 
+#ifdef __linux__
+#define LINUX 1
+#include <asm/param.h>
+#else
+#define LINUX 0
+#endif
+
 COVERAGE_DEFINE(util_xalloc);
 
 /* argv[0] without directory names. */
@@ -538,6 +546,66 @@ set_subprogram_name(const char *subprogram_name)
 #endif
 }
 
+unsigned int
+get_page_size(void)
+{
+    static unsigned int cached;
+
+    if (!cached) {
+#ifndef _WIN32
+        long int value = sysconf(_SC_PAGESIZE);
+#else
+        long int value;
+        SYSTEM_INFO sysinfo;
+        GetSystemInfo(&sysinfo);
+        value = sysinfo.dwPageSize;
+#endif
+        if (value >= 0) {
+            cached = value;
+        }
+    }
+
+    return cached;
+}
+
+/* Returns the time at which the system booted, as the number of milliseconds
+ * since the epoch, or 0 if the time of boot cannot be determined. */
+long long int
+get_boot_time(void)
+{
+    static long long int cache_expiration = LLONG_MIN;
+    static long long int boot_time;
+
+    ovs_assert(LINUX);
+
+    if (time_msec() >= cache_expiration) {
+        static const char stat_file[] = "/proc/stat";
+        char line[128];
+        FILE *stream;
+
+        cache_expiration = time_msec() + 5 * 1000;
+
+        stream = fopen(stat_file, "r");
+        if (!stream) {
+            VLOG_ERR_ONCE("%s: open failed (%s)",
+                          stat_file, ovs_strerror(errno));
+            return boot_time;
+        }
+
+        while (fgets(line, sizeof line, stream)) {
+            long long int btime;
+            if (ovs_scan(line, "btime %lld", &btime)) {
+                boot_time = btime * 1000;
+                goto done;
+            }
+        }
+        VLOG_ERR_ONCE("%s: btime not found", stat_file);
+    done:
+        fclose(stream);
+    }
+    return boot_time;
+}
+
 /* Returns a pointer to a string describing the program version.  The
  * caller must not modify or free the returned string.
  */
diff --git a/lib/util.h b/lib/util.h
index c2d1c3f..4706c99 100644
--- a/lib/util.h
+++ b/lib/util.h
@@ -112,6 +112,9 @@ extern "C" {
 const char *get_subprogram_name(void);
     void set_subprogram_name(const char *);
 
+unsigned int get_page_size(void);
+long long int get_boot_time(void);
+
 void ovs_print_version(uint8_t min_ofp, uint8_t max_ofp);
 
 OVS_NO_RETURN void out_of_memory(void);
diff --git a/vswitchd/system-stats.c b/vswitchd/system-stats.c
index 553b8fc..c53a9a8 100644
--- a/vswitchd/system-stats.c
+++ b/vswitchd/system-stats.c
@@ -41,6 +41,7 @@
 #include "ovs-thread.h"
 #include "poll-loop.h"
 #include "openvswitch/shash.h"
+#include "process.h"
 #include "smap.h"
 #include "timeval.h"
 #include "openvswitch/vlog.h"
@@ -80,28 +81,6 @@ get_load_average(struct smap *stats OVS_UNUSED)
 #endif
 }
 
-static unsigned int
-get_page_size(void)
-{
-    static unsigned int cached;
-
-    if (!cached) {
-#ifndef _WIN32
-        long int value = sysconf(_SC_PAGESIZE);
-#else
-        long int value;
-        SYSTEM_INFO sysinfo;
-        GetSystemInfo(&sysinfo);
-        value = sysinfo.dwPageSize;
-#endif
-        if (value >= 0) {
-            cached = value;
-        }
-    }
-
-    return cached;
-}
-
 static void
 get_memory_stats(struct smap *stats)
 {
@@ -183,234 +162,6 @@ get_memory_stats(struct smap *stats)
     }
 }
 
-/* Returns the time at which the system booted, as the number of milliseconds
- * since the epoch, or 0 if the time of boot cannot be determined. */
-static long long int
-get_boot_time(void)
-{
-    static long long int cache_expiration = LLONG_MIN;
-    static long long int boot_time;
-
-    ovs_assert(LINUX);
-
-    if (time_msec() >= cache_expiration) {
-        static const char stat_file[] = "/proc/stat";
-        char line[128];
-        FILE *stream;
-
-        cache_expiration = time_msec() + 5 * 1000;
-
-        stream = fopen(stat_file, "r");
-        if (!stream) {
-            VLOG_ERR_ONCE("%s: open failed (%s)",
-                          stat_file, ovs_strerror(errno));
-            return boot_time;
-        }
-
-        while (fgets(line, sizeof line, stream)) {
-            long long int btime;
-            if (ovs_scan(line, "btime %lld", &btime)) {
-                boot_time = btime * 1000;
-                goto done;
-            }
-        }
-        VLOG_ERR_ONCE("%s: btime not found", stat_file);
-    done:
-        fclose(stream);
-    }
-    return boot_time;
-}
-
-static unsigned long long int
-ticks_to_ms(unsigned long long int ticks)
-{
-    ovs_assert(LINUX);
-
-#ifndef USER_HZ
-#define USER_HZ 100
-#endif
-
-#if USER_HZ == 100              /* Common case. */
-    return ticks * (1000 / USER_HZ);
-#else  /* Alpha and some other architectures.  */
-    double factor = 1000.0 / USER_HZ;
-    return ticks * factor + 0.5;
-#endif
-}
-
-struct raw_process_info {
-    unsigned long int vsz;      /* Virtual size, in kB. */
-    unsigned long int rss;      /* Resident set size, in kB. */
-    long long int uptime;       /* ms since started. */
-    long long int cputime;      /* ms of CPU used during 'uptime'. */
-    pid_t ppid;                 /* Parent. */
-    char name[18];              /* Name (surrounded by parentheses). */
-};
-
-static bool
-get_raw_process_info(pid_t pid, struct raw_process_info *raw)
-{
-    unsigned long long int vsize, rss, start_time, utime, stime;
-    long long int start_msec;
-    unsigned long ppid;
-    char file_name[128];
-    FILE *stream;
-    int n;
-
-    ovs_assert(LINUX);
-
-    sprintf(file_name, "/proc/%lu/stat", (unsigned long int) pid);
-    stream = fopen(file_name, "r");
-    if (!stream) {
-        VLOG_ERR_ONCE("%s: open failed (%s)",
-                      file_name, ovs_strerror(errno));
-        return false;
-    }
-
-    n = fscanf(stream,
-               "%*d "           /* (1. pid) */
-               "%17s "          /* 2. process name */
-               "%*c "           /* (3. state) */
-               "%lu "           /* 4. ppid */
-               "%*d "           /* (5. pgid) */
-               "%*d "           /* (6. sid) */
-               "%*d "           /* (7. tty_nr) */
-               "%*d "           /* (8. tty_pgrp) */
-               "%*u "           /* (9. flags) */
-               "%*u "           /* (10. min_flt) */
-               "%*u "           /* (11. cmin_flt) */
-               "%*u "           /* (12. maj_flt) */
-               "%*u "           /* (13. cmaj_flt) */
-               "%llu "          /* 14. utime */
-               "%llu "          /* 15. stime */
-               "%*d "           /* (16. cutime) */
-               "%*d "           /* (17. cstime) */
-               "%*d "           /* (18. priority) */
-               "%*d "           /* (19. nice) */
-               "%*d "           /* (20. num_threads) */
-               "%*d "           /* (21. always 0) */
-               "%llu "          /* 22. start_time */
-               "%llu "          /* 23. vsize */
-               "%llu "          /* 24. rss */
-#if 0
-               /* These are here for documentation but #if'd out to save
-                * actually parsing them from the stream for no benefit. */
-               "%*lu "          /* (25. rsslim) */
-               "%*lu "          /* (26. start_code) */
-               "%*lu "          /* (27. end_code) */
-               "%*lu "          /* (28. start_stack) */
-               "%*lu "          /* (29. esp) */
-               "%*lu "          /* (30. eip) */
-               "%*lu "          /* (31. pending signals) */
-               "%*lu "          /* (32. blocked signals) */
-               "%*lu "          /* (33. ignored signals) */
-               "%*lu "          /* (34. caught signals) */
-               "%*lu "          /* (35. whcan) */
-               "%*lu "          /* (36. always 0) */
-               "%*lu "          /* (37. always 0) */
-               "%*d "           /* (38. exit_signal) */
-               "%*d "           /* (39. task_cpu) */
-               "%*u "           /* (40. rt_priority) */
-               "%*u "           /* (41. policy) */
-               "%*llu "         /* (42. blkio_ticks) */
-               "%*lu "          /* (43. gtime) */
-               "%*ld"           /* (44. cgtime) */
-#endif
-               , raw->name, &ppid, &utime, &stime, &start_time, &vsize, &rss);
-    fclose(stream);
-    if (n != 7) {
-        VLOG_ERR_ONCE("%s: fscanf failed", file_name);
-        return false;
-    }
-
-    start_msec = get_boot_time() + ticks_to_ms(start_time);
-
-    raw->vsz = vsize / 1024;
-    raw->rss = rss * (get_page_size() / 1024);
-    raw->uptime = time_wall_msec() - start_msec;
-    raw->cputime = ticks_to_ms(utime + stime);
-    raw->ppid = ppid;
-
-    return true;
-}
-
-static int
-count_crashes(pid_t pid)
-{
-    char file_name[128];
-    const char *paren;
-    char line[128];
-    int crashes = 0;
-    FILE *stream;
-
-    ovs_assert(LINUX);
-
-    sprintf(file_name, "/proc/%lu/cmdline", (unsigned long int) pid);
-    stream = fopen(file_name, "r");
-    if (!stream) {
-        VLOG_WARN_ONCE("%s: open failed (%s)", file_name, ovs_strerror(errno));
-        goto exit;
-    }
-
-    if (!fgets(line, sizeof line, stream)) {
-        VLOG_WARN_ONCE("%s: read failed (%s)", file_name,
-                       feof(stream) ? "end of file" : ovs_strerror(errno));
-        goto exit_close;
-    }
-
-    paren = strchr(line, '(');
-    if (paren) {
-        int x;
-        if (ovs_scan(paren + 1, "%d", &x)) {
-            crashes = x;
-        }
-    }
-
-exit_close:
-    fclose(stream);
-exit:
-    return crashes;
-}
-
-struct process_info {
-    unsigned long int vsz;      /* Virtual size, in kB. */
-    unsigned long int rss;      /* Resident set size, in kB. */
-    long long int booted;       /* ms since monitor started. */
-    int crashes;                /* # of crashes (usually 0). */
-    long long int uptime;       /* ms since last (re)started by monitor. */
-    long long int cputime;      /* ms of CPU used during 'uptime'. */
-};
-
-static bool
-get_process_info(pid_t pid, struct process_info *pinfo)
-{
-    struct raw_process_info child;
-
-    ovs_assert(LINUX);
-    if (!get_raw_process_info(pid, &child)) {
-        return false;
-    }
-
-    pinfo->vsz = child.vsz;
-    pinfo->rss = child.rss;
-    pinfo->booted = child.uptime;
-    pinfo->crashes = 0;
-    pinfo->uptime = child.uptime;
-    pinfo->cputime = child.cputime;
-
-    if (child.ppid) {
-        struct raw_process_info parent;
-
-        get_raw_process_info(child.ppid, &parent);
-        if (!strcmp(child.name, parent.name)) {
-            pinfo->booted = parent.uptime;
-            pinfo->crashes = count_crashes(child.ppid);
-        }
-    }
-
-    return true;
-}
-
 static void
 get_process_stats(struct smap *stats)
 {
-- 
2.4.11



More information about the dev mailing list