[Utils/Trinity-SMI] Add an option to wait the interval between updates
authorDongju Chae <dongju.chae@samsung.com>
Tue, 24 Nov 2020 03:57:12 +0000 (12:57 +0900)
committer송욱/On-Device Lab(SR)/Staff Engineer/삼성전자 <wook16.song@samsung.com>
Thu, 26 Nov 2020 04:35:44 +0000 (13:35 +0900)
This patch adds an option to wait the interval between updates in
the command line tool, trinity-smi. It requires ncurses as the extra
dependency.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
debian/control
packaging/npu-engine.spec
utils/trinity_smi/meson.build
utils/trinity_smi/trinity-smi.cc

index 1f5c629..250df3f 100644 (file)
@@ -5,7 +5,7 @@ Maintainer: MyungJoo Ham <myungjoo.ham@samsung.com>
 Build-Depends: ninja-build, meson (>=0.50), debhelper (>=9),
  gcc-9 | gcc-8 | gcc-7 | gcc-6 | gcc-5, libgtest-dev, python,
  libiniparser-dev, pkg-config, cmake, libdrm-dev,
- linux-fvp-headers, libmrpsim-dev, libtinyxml2-dev
+ linux-fvp-headers, libmrpsim-dev, libtinyxml2-dev, libncurses-dev
 Standards-Version: 3.8.2
 Homepage: https://research.samsung.com
 
@@ -36,6 +36,6 @@ Description: NPU Engine Example Package
 Package: npu-engine-utils
 Architecture: amd64
 Multi-Arch: same
-Depends: npu-engine, ${shlibs:Depends}, ${misc:Depends}
+Depends: npu-engine, libncurses5, ${shlibs:Depends}, ${misc:Depends}
 Description: NPU Engine Utils Package
  This provides utility packages for NPU Engine, including metadata extraction of model files.
index a4a71ce..c86156f 100644 (file)
@@ -19,6 +19,9 @@ BuildRequires:        linux-npu-headers
 # NE-CONF uses iniparser
 BuildRequires: pkgconfig(iniparser)
 
+# utils
+BuildRequires: ncurses-devel
+
 # test
 BuildRequires:  gtest-devel
 BuildRequires:  pkgconfig(libdrm)
@@ -78,6 +81,7 @@ Example application package for NPU Engine, including UnitTests and AppTest with
 
 %package utils
 Requires:      npu-engine = %{version}-%{release}
+Requires: ncurses5
 Summary:  NPU Engine Example Package
 %description utils
 This probides utility packages for NPU Engine, including metadata extraction of model files.
index 46c5fc4..e4baf71 100644 (file)
@@ -1,6 +1,9 @@
+ncurses_dep = dependency('ncurses')
+
 utils_model_inspect = executable('trinity-smi',
   ['trinity-smi.cc'],
   include_directories: [ne_host_inc, ne_common_inc],
+  dependencies : ncurses_dep,
   link_with : ne_library_shared,
   install : true,
   install_rpath : ne_libdir,
index b19f396..dff506a 100644 (file)
 #include <unistd.h>
 #include <errno.h>
 
+#include <ncurses.h>
+#include <signal.h>
+#include <getopt.h>
+
 using namespace std;
 
+static struct option longopts[] = {
+  {"help", no_argument, 0, 'h'},
+  {"device-node", optional_argument, 0, 'd'},
+  {"app-id", optional_argument, 0, 'a'},
+  {"interval", optional_argument, 0, 'i'},
+  {0, 0, 0, 0}
+};
+
 /** @brief Class of Trinity SMI (Trinity System Management Interface) */
 class TrinitySMI {
   public:
-    TrinitySMI (const char *name) {
-      const char * last = strrchr (name, '/');
-      if (last != NULL) {
-        name_ = string (last + 1);
-      } else {
-        name_ = string (name);
-      }
-    }
+    TrinitySMI () : help_only_ (false) {}
     ~TrinitySMI () {}
 
-    bool check_arguments (int argc, char ** argv);
+    void parse_arguments (int argc, char ** argv);
+    void check_arguments (int argc, char ** argv);
 
     void append_version ();
     void append_stats ();
 
-    void dump ();
+    void dump (bool use_curses);
+    int loop ();
 
     void set_device (string node) { node_ = node; }
     void set_appid (string appid) { appid_ = appid; }
+    void set_interval (string interval) { interval_ = interval; }
 
   private:
     uint32_t get_api_level ();
@@ -62,8 +70,12 @@ class TrinitySMI {
     string name_;
     stringstream ss_;
 
+    string help_msg_;
+    bool help_only_;
+
     string appid_;
     string node_;
+    string interval_;
 };
 
 /** @brief get driver api level from any device */
@@ -445,24 +457,109 @@ out:
 void
 TrinitySMI::append_help ()
 {
+  ss_ << help_msg_;
   ss_ << "\nUsage: " << name_ << " [options]\n";
   ss_ << "Options:\n";
-  ss_ << "  -h \t\tShow help messages\n";
-  ss_ << "  -d [dev node] Specify a device node that you're interested in\n";
-  ss_ << "\t\t(e.g., -d triv2-0)\n";
-  ss_ << "  -a [app id] \tSpecify a app id that you're interested in\n";
-  ss_ << "\t\t(e.g., -d triv2-0 -a 125)\n";
+  ss_ << "  -h, --help\t\t\tShow help messages\n";
+  ss_ << "  -d, --device-node=<node>\tDevice node that you're interested in\n";
+  ss_ << "\t\t\t\t(e.g., -d /dev/triv2-0)\n";
+  ss_ << "  -a, --app-id=<id>\t\tApp id that you're interested in\n";
+  ss_ << "\t\t\t\t(e.g., -d /dev/triv2-0 -a 125)\n";
+  ss_ << "  -i, --interval=<secs>\t\tInterval in seconds to wait between updates\n";
+  ss_ << "\t\t\t\t(e.g., -i 1)\n";
+}
+
+/** @brief show the appended string to screen */
+void
+TrinitySMI::dump (bool use_curses)
+{
+  string s = ss_.str ();
+
+  if (use_curses)
+    mvaddstr (0, 0, s.c_str ());
+  else
+    cout << s;
+
+  ss_.str ("");
+}
+
+static uint32_t
+get_interval (const char * interval_str)
+{
+  char *endptr;
+  unsigned long interval = 0;
+
+  if (interval_str) {
+    errno = 0;
+    interval = strtoul (interval_str, &endptr, 10);
+    if (errno != 0 || interval_str == endptr)
+      interval = 0;
+  }
+
+  return interval;
+}
+
+static void do_exit(int status)
+{
+  endwin();
+  exit(status);
+}
+
+static void die(int notused)
+{
+  (void) notused;
+  do_exit(0);
+}
+
+int
+TrinitySMI::loop ()
+{
+  uint32_t interval = get_interval (interval_.c_str ());
+  bool use_curses = (interval != 0 && !help_only_);
+
+  if (use_curses) {
+    signal (SIGINT, die);
+    signal (SIGTERM, die);
+    signal (SIGHUP, die);
+
+    initscr ();
+    nonl ();
+    noecho ();
+    cbreak ();
+  }
+
+  do {
+    clear ();
+
+    append_version ();
+    if (help_only_)
+      append_help ();
+    else
+      append_stats ();
+    dump (use_curses);
+
+    refresh();
+
+    if (interval != 0)
+      sleep (interval);
+
+  } while (use_curses);
+
+  if (use_curses)
+    endwin();
+
+  return 0;
 }
 
 /** @brief check the given arguments */
-bool
+void
 TrinitySMI::check_arguments (int argc, char ** argv)
 {
   int c;
 
   optind = 0;
   opterr = 0;
-  while ((c = getopt (argc, argv, "hd:a:")) != -1) {
+  while ((c = getopt_long (argc, argv, "hd:a:i:", longopts, (int *) 0)) != EOF) {
     switch (c) {
       case 'd':
         set_device (optarg);
@@ -470,45 +567,52 @@ TrinitySMI::check_arguments (int argc, char ** argv)
       case 'a':
         set_appid (optarg);
         break;
+      case 'i':
+        set_interval (optarg);
+        break;
       case '?':
         if (optopt == 'd')
-          ss_ << "\nOption '-d' requires an extra argument\n";
+          help_msg_ = "\nOption '-d' requires an extra argument\n";
         else if (optopt == 'a')
-          ss_ << "\nOption '-a' requires an extra argument\n";
+          help_msg_ = "\nOption '-a' requires an extra argument\n";
+        else if (optopt == 'i')
+          help_msg_ = "\nOption '-i' requires an extra argument\n";
         else
-          ss_ << "\nUnknown flag detected: " << (char) optopt << "\n";
+          help_msg_ = "\nUnknown flag detected: " + to_string ((char) optopt) + "\n";
         // no-break
       case 'h':
-        append_help ();
-        return false;
+        help_only_ = true;
+        break;
     }
   }
 
   if (!appid_.empty () && node_.empty ()) {
-    ss_ << "\nOption '-a' requires Option '-d' as well, to specify a device node\n";
-    append_help ();
-    return false;
+    help_msg_ = "\nOption '-a' requires Option '-d' as well, to specify a device node\n";
+    help_only_ = true;
   }
-
-  return true;
 }
 
-/** @brief show the appended string to screen */
 void
-TrinitySMI::dump ()
+TrinitySMI::parse_arguments (int argc, char ** argv)
 {
-  cout << ss_.str ();
+  char * name = argv[0];
+  const char * last = strrchr (name, '/');
+
+  if (last != NULL) {
+    name_ = string (last + 1);
+  } else {
+    name_ = string (name);
+  }
+
+  check_arguments (argc, argv);
 }
 
 /** @brief main routine of trinity-smi */
 int main (int argc, char **argv)
 {
-  TrinitySMI smi (argv[0]);
+  TrinitySMI smi;
 
-  smi.append_version ();
-  if (smi.check_arguments (argc, argv))
-    smi.append_stats ();
-  smi.dump ();
+  smi.parse_arguments (argc, argv);
 
-  return 0;
+  return smi.loop ();
 }