And (almost) keep the output format of the former python script.

Allows to use this basic command also on systems that do not come with
python installed.

Signed-off-by: Ralf Ramsauer <r...@ramses-pyramidenbau.de>
---
 tools/Makefile             |   1 -
 tools/jailhouse-cell-stats | 119 -------------------------
 tools/jailhouse.c          | 216 ++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 215 insertions(+), 121 deletions(-)
 delete mode 100755 tools/jailhouse-cell-stats

diff --git a/tools/Makefile b/tools/Makefile
index 9b6e176..390cf6d 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -21,7 +21,6 @@ TARGETS := jailhouse
 INST_TARGETS := $(TARGETS)
 HELPERS := \
        jailhouse-cell-linux \
-       jailhouse-cell-stats \
        jailhouse-config-create \
        jailhouse-hardware-check
 TEMPLATES := jailhouse-config-collect.tmpl root-cell-config.c.tmpl
diff --git a/tools/jailhouse-cell-stats b/tools/jailhouse-cell-stats
deleted file mode 100755
index cf0d4a4..0000000
--- a/tools/jailhouse-cell-stats
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/usr/bin/env python
-
-# Jailhouse, a Linux-based partitioning hypervisor
-#
-# Copyright (c) Siemens AG, 2014
-#
-# Authors:
-#  Jan Kiszka <jan.kis...@siemens.com>
-#
-# This work is licensed under the terms of the GNU GPL, version 2.  See
-# the COPYING file in the top-level directory.
-
-from __future__ import print_function
-import curses
-import datetime
-import os
-import sys
-
-cells_dir = "/sys/devices/jailhouse/cells/"
-cell_dir  = cells_dir + "%d/"
-stats_dir = cell_dir + "statistics/"
-
-
-def main(stdscr, cell_id, cell_name, stats_names):
-    try:
-        curses.use_default_colors()
-        curses.curs_set(0)
-    except curses.error:
-        pass
-    curses.noecho()
-    curses.halfdelay(10)
-    value = dict.fromkeys(stats_names)
-    old_value = dict.fromkeys(stats_names, None)
-    while True:
-        now = datetime.datetime.now()
-
-        for name in stats_names:
-            f = open((stats_dir + "/%s") % (cell_id, name), "r")
-            value[name] = int(f.read())
-
-        def sortkey(name):
-            if old_value[name] is None:
-                return (-value[name], name)
-            else:
-                return (old_value[name] - value[name], -value[name], name)
-
-        stdscr.erase()
-        stdscr.addstr(0, 0, "Statistics for %s cell" % cell_name)
-        (height, width) = stdscr.getmaxyx()
-        stdscr.hline(2, 0, " ", width, curses.A_REVERSE)
-        stdscr.addstr(2, 0, "COUNTER", curses.A_REVERSE)
-        stdscr.addstr(2, 30, "%10s" % "SUM", curses.A_REVERSE)
-        stdscr.addstr(2, 40, "%10s" % "PER SEC", curses.A_REVERSE)
-        line = 3
-        for name in sorted(stats_names, key=sortkey):
-            stdscr.addstr(line, 0, name)
-            stdscr.addstr(line, 30, "%10u" % value[name])
-            if not old_value[name] is None:
-                dt = (now - last_refresh).total_seconds()
-                delta_per_sec = (value[name] - old_value[name]) / dt
-                stdscr.addstr(line, 40, "%10u" % round(delta_per_sec))
-            old_value[name] = value[name]
-            line += 1
-        stdscr.hline(height - 1, 0, " ", width, curses.A_REVERSE)
-        stdscr.addstr(height - 1, 1, "Q - Quit", curses.A_REVERSE)
-        stdscr.refresh()
-
-        last_refresh = now
-
-        try:
-            if stdscr.getch() == ord('q'):
-                break
-            curses.halfdelay(40)
-        except KeyboardInterrupt:
-            break
-        except curses.error:
-            continue
-
-
-def usage(exit_code):
-    prog = os.path.basename(sys.argv[0]).replace('-', ' ')
-    print("usage: %s { ID | [--name] NAME }" % prog)
-    exit(exit_code)
-
-
-argc = len(sys.argv)
-use_name = argc >= 2 and sys.argv[1] == "--name"
-
-if argc < 2 or argc > 3 or (not use_name and argc > 2):
-    usage(1)
-if sys.argv[1] in ("--help", "-h"):
-    usage(0)
-
-cell_id = -1
-try:
-    if use_name:
-        cell_name = sys.argv[2]
-    else:
-        cell_name = sys.argv[1]
-        try:
-            cell_id = int(sys.argv[1])
-            with open((cell_dir + "name") % cell_id, "r") as f:
-                cell_name = f.read().rstrip()
-        except ValueError:
-            pass
-
-    if cell_id == -1:
-        for id in os.listdir(cells_dir):
-            f = open((cell_dir + "name") % int(id), "r")
-            if f.read().rstrip() == cell_name:
-                cell_id = int(id)
-                break
-
-    stats_names = os.listdir(stats_dir % cell_id)
-except OSError as e:
-    print("reading stats: %s" % e.strerror, file=sys.stderr)
-    exit(1)
-
-curses.wrapper(main, cell_id, cell_name, stats_names)
diff --git a/tools/jailhouse.c b/tools/jailhouse.c
index 84e5fe3..e3efcaa 100644
--- a/tools/jailhouse.c
+++ b/tools/jailhouse.c
@@ -10,6 +10,7 @@
  * the COPYING file in the top-level directory.
  */
 
+#include <ctype.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -23,9 +24,13 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
+#include <termios.h>
+#include <time.h>
 
 #include <jailhouse.h>
 
+#define ANSI_CLRSCR            "\e[1;1H\e[2J"
+
 #define JAILHOUSE_EXEC_DIR     LIBEXECDIR "/jailhouse"
 #define JAILHOUSE_DEVICE       "/dev/jailhouse"
 #define JAILHOUSE_CELLS                "/sys/devices/jailhouse/cells/"
@@ -43,11 +48,16 @@ struct jailhouse_cell_info {
        char *cpus_failed_list;
 };
 
+struct jailhouse_stat {
+       const char *name;
+       unsigned long value;
+       int per_second;
+};
+
 static const struct extension extensions[] = {
        { "cell", "linux", "CELLCONFIG KERNEL [-i | --initrd FILE]\n"
          "              [-c | --cmdline \"STRING\"] "
                                        "[-w | --write-params FILE]" },
-       { "cell", "stats", "{ ID | [--name] NAME }" },
        { "config", "create", "[-h] [-g] [-r ROOT] "
          "[--mem-inmates MEM_INMATES]\n"
          "                 [--mem-hv MEM_HV] FILE" },
@@ -70,6 +80,7 @@ static void __attribute__((noreturn)) help(char *prog, int 
exit_status)
                                "{ IMAGE | { -s | --string } \"STRING\" }\n"
               "             [-a | --address ADDRESS] ...\n"
               "   cell start { ID | [--name] NAME }\n"
+              "   cell stats { ID | [--name] NAME }\n"
               "   cell shutdown { ID | [--name] NAME }\n"
               "   cell destroy { ID | [--name] NAME }\n",
               basename(prog));
@@ -196,6 +207,19 @@ static char *read_sysfs_cell_string(const unsigned int id, 
const char *entry)
        return ret;
 }
 
+static unsigned long read_sysfs_cell_stat(int id, const char *stat_entry)
+{
+       char *stat_string, buffer[128];
+       unsigned long ret;
+
+       snprintf(buffer, sizeof(buffer), "statistics/%s", stat_entry);
+       stat_string = read_sysfs_cell_string(id, buffer);
+       ret = strtoul(stat_string, NULL, 10);
+       free(stat_string);
+
+       return ret;
+}
+
 static int enable(int argc, char *argv[])
 {
        void *config;
@@ -368,6 +392,194 @@ static int cell_list(int argc, char *argv[])
        return 0;
 }
 
+static int get_cell_id_by_name(const char *name)
+{
+       int ret = -ENOENT;
+       int num_entries;
+       struct dirent **namelist;
+
+       unsigned int id;
+       char *candidate;
+
+       num_entries = scandir(JAILHOUSE_CELLS, &namelist, cell_match, NULL);
+       if (num_entries == -1)
+               return -errno;
+
+       while (num_entries--) {
+               id = strtoul(namelist[num_entries]->d_name, NULL, 10);
+               free(namelist[num_entries]);
+
+               candidate = read_sysfs_cell_string(id, "name");
+               if (strcmp(candidate, name) == 0)
+                       ret = id;
+               free(candidate);
+       }
+
+       free(namelist);
+       return ret;
+}
+
+static int stat_cmp(const void *a, const void *b)
+{
+       const struct jailhouse_stat *js_a = a, *js_b = b;
+
+       if (js_b->per_second != js_a->per_second)
+               return js_b->per_second - js_a->per_second;
+
+       if (js_b->value != js_a->value)
+               return js_b->value > js_a->value;
+
+       return strcmp(js_a->name, js_b->name);
+}
+
+static int cell_stats(int argc, char *argv[])
+{
+       bool use_name = false;
+       char buffer[128], *cell_name, *endptr, keypress;
+       fd_set rdfs;
+       int cell_id = -1, err = -1, i, stats_entries;
+       struct dirent **namelist;
+       struct jailhouse_stat *stats;
+       struct termios orig_term, term;
+       struct timeval keypress_timeout = {1, 0};
+       time_t last_refresh, now;
+       unsigned long value;
+       unsigned long int tmp;
+
+       /* check cmdline and get cell id */
+       if (argc < 4)
+               help(argv[0], 1);
+
+       if (strcmp(argv[3], "--name") == 0)
+               use_name = true;
+
+       if (use_name && argc < 5)
+               help(argv[0], 1);
+
+       /* set temporary cell name */
+       cell_name = argv[3 + (use_name ? 1 : 0)];
+
+       if (!use_name) {
+               tmp = strtoul(cell_name, &endptr, 10);
+               if (!(tmp == ULONG_MAX || tmp > INT_MAX || cell_name == endptr))
+                       cell_id = tmp;
+       }
+
+       if (cell_id == -1) {
+               cell_id = get_cell_id_by_name(cell_name);
+               if (cell_id < 0) {
+                       errno = -cell_id;
+                       goto out;
+               }
+       }
+
+       /* get cell name */
+       cell_name = read_sysfs_cell_string(cell_id, "name");
+
+       /* get names of all observations */
+       snprintf(buffer, sizeof(buffer), JAILHOUSE_CELLS "%d/statistics/",
+                cell_id);
+       stats_entries = scandir(buffer, &namelist, cell_match, NULL);
+       if (stats_entries == -1)
+               goto name_free;
+
+       /* allocate memory for stats */
+       stats = malloc(stats_entries * sizeof(struct jailhouse_stat));
+       if (stats == NULL) {
+               errno = ENOMEM;
+               goto namelist_free;
+       }
+
+       /* get initial stats */
+       last_refresh = time(NULL);
+       for (i = 0; i < stats_entries; i++) {
+               stats[i].name = namelist[i]->d_name;
+               stats[i].per_second = 0;
+               stats[i].value = read_sysfs_cell_stat(cell_id,
+                                                     namelist[i]->d_name);
+       }
+
+       /* store terminal settings and disable local echo and canonical mode */
+       err = tcgetattr(STDIN_FILENO, &orig_term);
+       if (err == -1)
+               goto stats_free;
+       memcpy(&term, &orig_term, sizeof(term));
+       term.c_lflag &= ~(ICANON | ECHO);
+       err = tcsetattr(STDIN_FILENO, TCSANOW, &term);
+       if (err == -1)
+               goto stats_free;
+
+       do {
+               /* print banner */
+               printf(ANSI_CLRSCR
+                      "Statistics for %s cell\n\n"
+                      "%-30s%-6s%s\n",
+                      cell_name, "COUNTER", "SUM", "PER SEC");
+
+               /* update statistics */
+               now = time(NULL);
+               for (i = 0; i < stats_entries; i++) {
+                       value = read_sysfs_cell_stat(cell_id, stats[i].name);
+                       if (now - last_refresh)
+                               stats[i].per_second = (value -
+                                                      stats[i].value) /
+                                                     (now - last_refresh);
+                       stats[i].value = value;
+               }
+
+               /* order current statistics */
+               qsort(stats, stats_entries, sizeof(struct jailhouse_stat),
+                     stat_cmp);
+
+               /* print ordered statistics */
+               for (i = 0; i < stats_entries; i++)
+                       printf("%-27s%*lu%*d\n", stats[i].name, 6,
+                              stats[i].value, 10, stats[i].per_second);
+
+               last_refresh = now;
+
+               printf("\n Q Quit");
+               fflush(stdout);
+
+               FD_ZERO(&rdfs);
+               FD_SET(STDIN_FILENO, &rdfs);
+               err = select(STDIN_FILENO + 1, &rdfs, NULL, NULL,
+                            &keypress_timeout);
+               if (err == -1)
+                       goto stats_free;
+               if (err)
+                       err = read(STDIN_FILENO, &keypress, 1);
+               if (err == -1)
+                       goto stats_free;
+
+               err = 0;
+               keypress_timeout.tv_sec = 4;
+               keypress_timeout.tv_usec = 0;
+       } while (toupper(keypress) != 'Q');
+
+stats_free:
+       printf("\n");
+
+       /* restore terminal settings */
+       tcsetattr(0, TCSANOW, &orig_term);
+
+       free(stats);
+
+namelist_free:
+       for (i = 0; i < stats_entries; i++)
+               free(namelist[i]);
+       free(namelist);
+
+name_free:
+       free(cell_name);
+
+out:
+       if (err == -1)
+               perror("reading stats");
+
+       return err;
+}
+
 static int cell_shutdown_load(int argc, char *argv[],
                              enum shutdown_load_mode mode)
 {
@@ -492,6 +704,8 @@ static int cell_management(int argc, char *argv[])
                err = cell_shutdown_load(argc, argv, LOAD);
        } else if (strcmp(argv[2], "start") == 0) {
                err = cell_simple_cmd(argc, argv, JAILHOUSE_CELL_START);
+       } else if (strcmp(argv[2], "stats") == 0) {
+               err = cell_stats(argc, argv);
        } else if (strcmp(argv[2], "shutdown") == 0) {
                err = cell_shutdown_load(argc, argv, SHUTDOWN);
        } else if (strcmp(argv[2], "destroy") == 0) {
-- 
2.10.0

-- 
You received this message because you are subscribed to the Google Groups 
"Jailhouse" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to jailhouse-dev+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to