#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.
*/
/** @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()
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);
return -EINVAL;
}
+ stat = EmulStat::find (ctx->app_id);
+ if (stat == nullptr)
+ return -ENOENT;
+ stat->incTotalAllocMem (size);
+
return dmabuf->getFD ();
default:
return -ENOTTY;
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);
}
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;
}
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;
}
/** @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,