[CUSE] Support app statistics in CUSE
authorDongju Chae <dongju.chae@samsung.com>
Tue, 20 Jul 2021 02:34:18 +0000 (11:34 +0900)
committer채동주/On-Device Lab(SR)/Staff Engineer/삼성전자 <dongju.chae@samsung.com>
Wed, 21 Jul 2021 01:14:37 +0000 (10:14 +0900)
This ptach support app statistics in CUSE device driver.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
src/core/utils/ne-utils.h
utils/trinity_cuse/trinity-cuse-triv2.cc
utils/trinity_cuse/trinity-cuse.cc
utils/trinity_cuse/trinity-cuse.h

index 0d1e2d3..3debf04 100644 (file)
@@ -127,6 +127,12 @@ class ThreadSafeMap {
   ThreadSafeMap () : num_entries_ (0) {}
   ~ThreadSafeMap () { clear (); }
 
+  /** @brief get number of entries */
+  uint32_t size () {
+    std::unique_lock<std::mutex> lock (m_);
+    return num_entries_;
+  }
+
   /** @brief find the target element */
   V *find (K key) {
     typename std::map<K, std::unique_ptr<V>>::iterator it;
index fc3a955..0c9b910 100644 (file)
@@ -21,6 +21,7 @@
 #include <iostream>
 #include <fstream>
 #include <atomic>
+#include <list>
 
 #include <triv2profile.h>
 #include "trinity-cuse.h"
 
 #define TRIV2_MAX_SEGMENTS 256
 
+class EmulDmabuf;
+class EmulModel;
+class EmulProfile;
+class EmulStat;
+
+/** @brief Global mapping of dmabuf */
+ThreadSafeMap<int, EmulDmabuf> global_dmabuf_map;
+/** @brief Global mapping of models */
+ThreadSafeMap<uint64_t, EmulModel> global_model_map;
+/** @brief Global mapping of profile data */
+ThreadSafeMap<int, EmulProfile> global_profile_map;
+/** @brief Global stat map */
+ThreadSafeMap<int, EmulStat> global_stat_map;
+
+/**
+ * @brief Emulated Stat Impl.
+ */
+class EmulStat {
+ public:
+  EmulStat (int app_id) : app_id_ (app_id), refcount_ (0) {
+    memset (&app_stat_, '\x00', sizeof (struct trinity_ioctl_stat_app));
+    app_stat_.app_id = app_id;
+    app_stat_.status = TRINITY_APP_STATUS_PENDING;
+  }
+  ~EmulStat () {}
+
+  static EmulStat *find (int app_id, bool create = true) {
+    EmulStat *stat = global_stat_map.find (app_id);
+    if (stat == nullptr && create) {
+      stat = new EmulStat (app_id);
+      if (global_stat_map.size () > TRINITY_APP_STAT_MAX)
+        removeStale ();
+      if (global_stat_map.insert (app_id, stat) != 0) {
+        delete stat;
+        stat = nullptr;
+      }
+    }
+    return stat;
+  }
+
+  static void removeStale () {
+    std::function<bool(EmulStat *)> functor = [](EmulStat *stat) -> bool {
+      /* remove stale stats with zero refcount */
+      return (stat->getRefCount () == 0);
+    };
+    global_stat_map.for_each (functor);
+  }
+
+  struct trinity_ioctl_stat_app *getAppStat () {
+    return &app_stat_;
+  }
+
+  void setStatus (enum trinity_app_status status) {
+    std::unique_lock<std::mutex> lock (mutex_);
+    app_stat_.status = status;
+  }
+
+  void incRefCount () {
+    std::unique_lock<std::mutex> lock (mutex_);
+    refcount_++;
+    app_stat_.status = TRINITY_APP_STATUS_STARTED;
+  }
+
+  void decRefCount () {
+    std::unique_lock<std::mutex> lock (mutex_);
+    if (refcount_ > 0) {
+      refcount_--;
+      if (refcount_ == 0)
+        app_stat_.status = TRINITY_APP_STATUS_TERMINATED;
+    } else {
+      std::cerr << "Invalid refcount: " << refcount_ << "\n";
+      app_stat_.status = TRINITY_APP_STATUS_ERROR;
+    }
+  }
+
+  int getRefCount () {
+    std::unique_lock<std::mutex> lock (mutex_);
+    return refcount_;
+  }
+
+  void incTotalAllocMem (uint64_t size) {
+    std::unique_lock<std::mutex> lock (mutex_);
+    app_stat_.total_alloc_mem += size;
+  }
+
+  void incTotalFreedMem (uint64_t size) {
+    std::unique_lock<std::mutex> lock (mutex_);
+    app_stat_.total_freed_mem += size;
+  }
+
+ private:
+  std::mutex mutex_;
+
+  int app_id_;
+  int refcount_;
+
+  struct trinity_ioctl_stat_app app_stat_;
+  std::list<struct trinity_ioctl_stat_req *> req_stat_;
+};
+
 /**
  * @brief Emulated Dmabuf Impl.
  */
@@ -330,16 +431,30 @@ class EmulProfile {
 
 /** @brief Global file descriptor */
 std::atomic<int> EmulDmabuf::global_fd_ (1);
-/** @brief Global mapping of dmabuf */
-ThreadSafeMap<int, EmulDmabuf> global_dmabuf_map;
 /** @brief Global model id */
 std::atomic<uint64_t> EmulModel::global_id_ (1);
 /** @brief Global request id */
 std::atomic<int32_t> global_request_id (1);
-/** @brief Global mapping of models */
-ThreadSafeMap<uint64_t, EmulModel> global_model_map;
-/** @brief Global mapping of profile data */
-ThreadSafeMap<int, EmulProfile> global_profile_map;
+
+static int
+triv2_open (trinity_cuse_context *ctx) {
+  EmulStat *stat = EmulStat::find (ctx->app_id);
+  if (stat == nullptr)
+    return -ENOENT;
+
+  stat->incRefCount ();
+  return 0;
+}
+
+static int
+triv2_release (trinity_cuse_context *ctx) {
+  EmulStat *stat = EmulStat::find (ctx->app_id);
+  if (stat == nullptr)
+    return -ENOENT;
+
+  stat->decRefCount ();
+  return 0;
+}
 
 /**
  * @brief TRIV2 impl. of get_version ioctl()
@@ -402,6 +517,7 @@ static int
 triv2_hwmem_alloc (trinity_cuse_context *ctx,
                    const struct trinity_ioctl_hwmem *hwmem) {
   EmulDmabuf *dmabuf;
+  EmulStat *stat;
   size_t size;
 
   size = ALIGNED_SIZE (hwmem->size);
@@ -422,6 +538,11 @@ triv2_hwmem_alloc (trinity_cuse_context *ctx,
         return -EINVAL;
       }
 
+      stat = EmulStat::find (ctx->app_id);
+      if (stat == nullptr)
+        return -ENOENT;
+      stat->incTotalAllocMem (size);
+
       return dmabuf->getFD ();
     default:
       return -ENOTTY;
@@ -434,6 +555,15 @@ triv2_hwmem_alloc (trinity_cuse_context *ctx,
 static int
 triv2_hwmem_dealloc (trinity_cuse_context *ctx,
                      const struct trinity_ioctl_hwmem *hwmem) {
+  EmulDmabuf *dmabuf = global_dmabuf_map.find (hwmem->dbuf_fd);
+  if (dmabuf == nullptr)
+    return -ENOENT;
+
+  EmulStat *stat = EmulStat::find (ctx->app_id);
+  if (stat == nullptr)
+    return -ENOENT;
+  stat->incTotalFreedMem (dmabuf->getSize ());
+
   return global_dmabuf_map.remove (hwmem->dbuf_fd);
 }
 
@@ -588,9 +718,11 @@ triv2_stop_request (trinity_cuse_context *ctx, const int id) {
 static int
 triv2_stat_current_app (trinity_cuse_context *ctx,
                         struct trinity_ioctl_stat_app *stat) {
-  /* NYI */
-  memset (stat, '\x00', sizeof (*stat));
-  stat->app_id = ctx->app_id;
+  EmulStat *s = global_stat_map.find (ctx->app_id);
+  if (s == nullptr)
+    return -ENOENT;
+
+  memcpy (stat, s->getAppStat (), sizeof (*stat));
   return 0;
 }
 
@@ -600,9 +732,19 @@ triv2_stat_current_app (trinity_cuse_context *ctx,
 static int
 triv2_stat_apps (trinity_cuse_context *ctx,
                  struct trinity_ioctl_stat_apps *stat) {
-  /* NYI */
   memset (stat, '\x00', sizeof (*stat));
   stat->num_apps = 0;
+
+  std::function<bool(EmulStat *)> functor = [&](EmulStat *s) -> bool {
+    if (stat->num_apps < TRINITY_APP_STAT_MAX) {
+      memcpy (&stat->stat[stat->num_apps++], s->getAppStat (),
+              sizeof (struct trinity_ioctl_stat_app));
+    }
+    /* don't remove */
+    return false;
+  };
+  global_stat_map.for_each (functor);
+
   return 0;
 }
 
@@ -669,6 +811,8 @@ triv2_get_profile_buff (trinity_cuse_context *ctx,
 
 /** @brief The ioctl vtable for TRIV2 devices */
 static trinity_cuse_ioctl_vtable triv2_vtable{
+    .open = triv2_open,
+    .release = triv2_release,
     /* Device Info. */
     .get_version = triv2_get_version,
     .get_api_level = triv2_get_api_level,
index 0824020..4377037 100644 (file)
@@ -58,6 +58,8 @@ trinity_cuse_open (fuse_req_t req, struct fuse_file_info *fi) {
   ctx->prefix_share = Conf::getInstance ().getPrefixShare ();
   ctx->prefix_profile = Conf::getInstance ().getPrefixProfile ();
 
+  vtable->open (ctx);
+
   fi->fh = (uint64_t) ctx;
   fuse_reply_open (req, fi);
 }
@@ -69,8 +71,10 @@ static void
 trinity_cuse_release (fuse_req_t req, struct fuse_file_info *fi) {
   trinity_cuse_context *ctx = (trinity_cuse_context *) fi->fh;
 
-  if (ctx)
+  if (ctx) {
+    vtable->release (ctx);
     delete ctx;
+  }
 
   fi->fh = 0;
   fuse_reply_err (req, 0);
index 084d09b..bc7ab65 100644 (file)
@@ -32,6 +32,8 @@ typedef struct {
  * @brief The ioctl vtable of each device ioctl
  */
 typedef struct {
+  int (*open) (trinity_cuse_context *);
+  int (*release) (trinity_cuse_context *);
   /* Device Info. */
   int (*get_version) (trinity_cuse_context *, uint32_t *);
   int (*get_api_level) (trinity_cuse_context *, uint32_t *);