--- /dev/null
+/**
+ * Proprietary
+ * Copyright (C) 2020 Samsung Electronics
+ * Copyright (C) 2020 Dongju Chae <dongju.chae@samsung.com>
+ */
+/**
+ * @file trinity-smi.cc
+ * @date 13 Nov 2020
+ * @brief Utility for mangement and monitoring of trinity devices
+ * @author Dongju Chae <dongju.chae@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <libnpuhost.h>
+#include <npubinfmt.h>
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <chrono>
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+using namespace std;
+
+/** @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 () {}
+
+ uint32_t get_api_level ();
+
+ void append_version ();
+ void append_help ();
+ void append_devices ();
+ void append_processes ();
+
+ void dump ();
+
+ private:
+ string name_;
+ stringstream ss_;
+};
+
+/** @brief get driver api level from any device */
+uint32_t
+TrinitySMI::get_api_level ()
+{
+ dev_type types[] = {NPUCOND_TRIV_CONN_SOCIP, NPUCOND_TRIV2_CONN_SOCIP};
+ uint32_t level = 0;
+
+ for (auto type : types) {
+ npudev_h dev;
+ int ret;
+
+ ret = getnumNPUdeviceByType (type);
+ if (ret > 0) {
+ ret = getNPUdeviceByType (&dev, type, 0);
+ if (ret != 0)
+ continue;
+
+ ret = getNPU_driverAPILevel (dev, &level);
+ putNPUdevice (dev);
+
+ if (ret == 0)
+ return level;
+ else
+ level = 0;
+ }
+ }
+
+ return level;
+}
+
+/** @brief show the version of npu-engine and driver */
+void
+TrinitySMI::append_version ()
+{
+ auto now = chrono::system_clock::now ();
+ time_t now_time = chrono::system_clock::to_time_t (now);
+ string smi_ver, lib_ver;
+
+ smi_ver += to_string (VER_NE_MAJOR) + ".";
+ smi_ver += to_string (VER_NE_MINOR) + ".";
+ smi_ver += to_string (VER_NE_EXTRA);
+
+ uint32_t major, minor, extra;
+
+ getVersion (&major, &minor, &extra);
+ lib_ver += to_string (major) + ".";
+ lib_ver += to_string (minor) + ".";
+ lib_ver += to_string (extra);
+
+ uint32_t api_level = get_api_level ();
+
+ ss_ << std::ctime (&now_time);
+ ss_ << "+--------------------------------------------------------+\n";
+ ss_ << "| TRINITY-SMI: " << smi_ver;
+ ss_ << " NPU-ENGINE: " << lib_ver;
+ ss_ << " DRIVER-API: ";
+ ss_ << setw (3);
+#ifdef ENABLE_EMUL
+ ss_ << "SIM";
+#else
+ ss_ << (api_level == 0 ? "INV" : to_string (api_level));
+#endif
+ ss_ << " |\n";
+ ss_ << "+--------------------------------------------------------+\n";
+}
+
+/** @brief show the list of trinity devices */
+void
+TrinitySMI::append_devices ()
+{
+ dev_type types[] = {
+ NPUCOND_TRIV_CONN_SOCIP,
+ NPUCOND_TRIV2_CONN_SOCIP,
+ NPUCOND_TRIA_CONN_SOCIP
+ };
+
+ ss_ << "+--------------------------------------------------------+\n";
+ ss_ << "| CLASS | DEVICE NODE | TOPS | STATUS | # REQUESTS |\n";
+ ss_ << "|========================================================|\n";
+
+ uint32_t count = 0;
+ for (auto type : types) {
+ string cls, node;
+
+ if (type & DEVICETYPE_TRIV) {
+ cls = string ("TRIV");
+ node = string ("/dev/triv");
+ } else if (type & DEVICETYPE_TRIV2) {
+ cls = string ("TRIV2");
+ node = string ("/dev/triv2");
+ } else if (type & DEVICETYPE_TRIA) {
+ cls = string ("TRIA");
+ node = string ("/dev/tria");
+ } else {
+ break;
+ }
+
+ for (int i = 0; i < getnumNPUdeviceByType (type); i++) {
+ string node_str = node + "-" + to_string (i);
+ string tops_str, status_str, num_str;
+
+#ifdef ENABLE_EMUL
+ tops_str = string ("emul");
+ status_str = string ("idle");
+ num_str = to_string (0);
+#else
+ uint32_t tops;
+ npudev_h dev;
+ npu_status status;
+ uint32_t num;
+
+ if (getNPUdeviceByType (&dev, type, i) != 0)
+ break;
+
+ if (getNPU_tops (dev, &tops) != 0) {
+ putNPUdevice (dev);
+ break;
+ }
+
+ if (getNPU_deviceStatus (dev, &status, &num) != 0) {
+ putNPUdevice (dev);
+ break;
+ }
+
+ tops_str = to_string (tops);
+ num_str = to_string (num);
+
+ if (status == NPU_READY)
+ status_str = string ("ready");
+ else if (status == NPU_IDLE)
+ status_str = string ("idle");
+ else
+ status_str = string ("error");
+
+ putNPUdevice (dev);
+#endif
+
+ ss_ << "| " << right << setw (5) << cls << " ";
+ ss_ << "| " << right << setw (13) << node_str << " ";
+ ss_ << "| " << right << setw (4) << tops_str << " ";
+ ss_ << "| " << right << setw (8) << status_str << " ";
+ ss_ << "| " << right << setw (12) << num_str << " |\n";
+ count++;
+ }
+ }
+ if (count == 0)
+ ss_ << "| " << left << setw (55) << "No available device detected" << "|\n";
+ ss_ << "+--------------------------------------------------------+\n";
+}
+
+/** @brief show the list of running processes */
+void
+TrinitySMI::append_processes ()
+{
+ /** TODO */
+ ss_ << "+--------------------------------------------------------+\n";
+ ss_ << "| " << left << setw (55) << "No running processes found" << "|\n";
+ ss_ << "+--------------------------------------------------------+\n";
+}
+
+/** @brief show the usage and help messages */
+void
+TrinitySMI::append_help ()
+{
+ ss_ << "\nUsage: " << name_ << " [options]\n";
+ ss_ << "Options:\n";
+ ss_ << " -d \t\t Show list of trinity devices\n";
+ ss_ << " -p \t\t Show list of running processes\n";
+ ss_ << " -h \t\t Show help messages\n";
+}
+
+/** @brief show the appended string to screen */
+void
+TrinitySMI::dump ()
+{
+ cout << ss_.str ();
+}
+
+/** @brief main routine of trinity-smi */
+int main (int argc, char **argv)
+{
+ TrinitySMI smi (argv[0]);
+
+ smi.append_version ();
+
+ if (argc > 1) {
+ int c;
+
+ optind = 0;
+ opterr = 0;
+ while ((c = getopt (argc, argv, "dph")) != -1) {
+ switch (c) {
+ case 'd':
+ smi.append_devices ();
+ break;
+ case 'p':
+ smi.append_processes ();
+ break;
+ case 'h':
+ smi.append_help ();
+ break;
+ }
+ }
+ } else {
+ smi.append_help ();
+ }
+
+ smi.dump ();
+ return 0;
+}