This patch implements run_input ioctl, connecting libmrpsim APIs.
Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
input_config.hw_rdev = devnode_stat.st_rdev;
#else
- input_config.req_id = req_id;
input_config.hw_rdev = 0; /* don't care */
#endif
+ input_config.req_id = req_id;
/** run the inference with the input */
ret = api->runInput (&input_config);
hwmem.type = contiguous ? HWMEM_DMA_CONT : HWMEM_DMA_IOMMU;
+ /* translate dmabuf FDs to cuse-compatible ones */
if (is_cuse_) {
CuseElement *elem = cuse_map.find (dmabuf);
if (elem == nullptr)
return -EINVAL;
} /** else: don't care */
+ /* translate dmabuf FDs to cuse-compatible ones */
+ int dbuf_fd = model_config->dbuf_fd;
+ int metadata_dbuf_fd = model_config->metadata_dbuf_fd;
+
+ if (is_cuse_) {
+ CuseElement *prog = cuse_map.find (dbuf_fd);
+ if (prog == nullptr)
+ return -ENOENT;
+
+ CuseElement *meta = cuse_map.find (metadata_dbuf_fd);
+ if (meta == nullptr)
+ return -ENOENT;
+
+ model_config->dbuf_fd = prog->getDbufFD ();
+ model_config->metadata_dbuf_fd = meta->getDbufFD ();
+ }
+
ret =
ioctl (this->getDeviceFD (), TRINITY_IOCTL_REGISTER_MODEL, model_config);
+ /* rollback FDs to prevent any side-effects */
+ if (is_cuse_) {
+ model_config->dbuf_fd = dbuf_fd;
+ model_config->metadata_dbuf_fd = metadata_dbuf_fd;
+ }
+
if (ret != 0)
return -errno;
input_config->task_handle = val.task_handle;
}
+ /* translate dmabuf FDs to cuse-compatible ones */
+ if (is_cuse_) {
+ CuseElement *elem;
+ void *segt;
+
+ elem = cuse_map.find (input_config->dbuf_fd);
+ if (elem == nullptr)
+ return -ENOENT;
+
+ segt = this->mmap (input_config->dbuf_fd, PAGE_SIZE);
+ if (segt == nullptr)
+ return -EINVAL;
+
+ input_config->dbuf_fd = elem->getDbufFD ();
+ for (uint32_t i = 0; i < input_config->num_segments; i++) {
+ int dbuf_fd = ((int *) segt)[i];
+ if (dbuf_fd < 0) {
+ this->munmap (segt, PAGE_SIZE);
+ return -EINVAL;
+ }
+
+ elem = cuse_map.find (dbuf_fd);
+ if (elem == nullptr) {
+ this->munmap (segt, PAGE_SIZE);
+ return -ENOENT;
+ }
+
+ ((int *) segt)[i] = elem->getDbufFD ();
+ }
+
+ this->munmap (segt, PAGE_SIZE);
+ }
+
ret = ioctl (this->getDeviceFD (), TRINITY_IOCTL_RUN_INPUT, input_config);
if (ret != 0)
return -errno;
model.dbuf_fd = model_dmabuf;
model.program_offset_addr = 0;
model.program_size = 4096;
+ model.metadata_dbuf_fd = model_dmabuf; /* dummy */
EXPECT_EQ (api->registerModel (&model, TEST_NPU_VERSION), 0);
#include <sys/types.h>
#include "trinity-cuse.h"
+#include <triv2profile.h>
+
+#define ENV_PREFIX_SHARE "NE_PREFIX_SHARE"
+#define ENV_PREFIX_PROFILE "NE_PREFIX_PROFILE"
+#define DEFAULT_PREFIX_SHARE NE_PREFIX "/share"
+#define DEFAULT_PREFIX_PROFILE "/tmp"
+
+#define TRIV2_MAX_SEGMENTS 256
+
+static const char *prefix_share;
+static const char *prefix_profile;
/**
* @brief Emulated Dmabuf Impl.
*/
class EmulDmabuf {
public:
- EmulDmabuf (int app_id) : fd_ (-1), shm_fd_ (-1), size_ (0) {
+ EmulDmabuf (int app_id) : fd_ (-1), shm_fd_ (-1), size_ (0), addr_ (nullptr) {
std::string name;
fd_ = global_fd_.fetch_add (1);
if (shm_fd_ < 0)
return;
+ if (addr_ != nullptr)
+ munmap (addr_, size_);
+
shm_unlink (shm_name_.c_str ());
close (shm_fd_);
}
return err;
size_ = size;
+ addr_ = mmap (NULL, size_, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd_, 0);
+ if (addr_ == MAP_FAILED)
+ return -errno;
+
return 0;
}
+ void *getData () const { return addr_; }
size_t getSize () const { return size_; }
int getFD () const { return fd_; }
int shm_fd_;
std::string shm_name_;
size_t size_;
+ void *addr_;
};
/**
}
uint64_t getID () const { return id_; }
+ uint32_t getVersion () const { return version_; }
+ int getDbufFD () const { return dbuf_fd_; }
+ int getMetaDbufFD () const { return metadata_dbuf_fd_; }
+ uint64_t getProgramSize () const { return program_size_; }
+ uint64_t getProgramOffset () const { return program_offset_addr_; }
friend bool operator== (EmulModel &l, EmulModel &r) {
std::unique_lock<std::mutex> lock_l (l.mutex_);
uint64_t metadata_ext_size_;
};
-/** @brief Global file descriptor */
-std::atomic<int> EmulDmabuf::global_fd_ (0);
+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_ (0);
+std::atomic<uint64_t> EmulModel::global_id_ (1);
/** @brief Global mapping of models */
ThreadSafeMap<uint64_t, EmulModel> global_model_map;
return 0;
}
+/**
+ * @brief TRIV2 impl. of run_input ioctl()
+ */
+static int
+triv2_run_input (trinity_cuse_context *ctx,
+ const struct trinity_ioctl_input *in,
+ struct trinity_ioctl_input *out) {
+ EmulDmabuf *dbuf_input = global_dmabuf_map.find (in->dbuf_fd);
+ if (dbuf_input == nullptr)
+ return -ENOENT;
+
+ EmulModel *model = global_model_map.find (in->model_id);
+ if (model == nullptr)
+ return -ENOENT;
+
+ if (model->getVersion () != 3)
+ return -EINVAL;
+
+ EmulDmabuf *dbuf_model = global_dmabuf_map.find (model->getDbufFD ());
+ if (dbuf_model == nullptr)
+ return -ENOENT;
+
+ EmulDmabuf *dbuf_meta = global_dmabuf_map.find (model->getMetaDbufFD ());
+ if (dbuf_meta == nullptr)
+ return -ENOENT;
+
+ memcpy (out, in, sizeof (*in));
+
+ size_t prog_size = model->getProgramSize ();
+ uint32_t num_segs = in->num_segments;
+
+ /* skip */
+ if (prog_size == 0)
+ return 0;
+
+ if (num_segs == 0)
+ return -EINVAL;
+
+ if (num_segs > TRIV2_MAX_SEGMENTS)
+ return -ERANGE;
+
+ void *input = dbuf_input->getData ();
+ char *prog = ((char *) dbuf_model->getData ()) + model->getProgramOffset ();
+ char *meta = (char *) dbuf_meta->getData ();
+ char **segt = new char *[num_segs];
+ uint32_t tops;
+
+ for (uint32_t i = 0; i < num_segs; i++) {
+ int dbuf_fd = reinterpret_cast<int *> (input)[i];
+ uint32_t offset =
+ reinterpret_cast<uint32_t *> ((char *) input + PAGE_SIZE / 2)[i];
+
+ EmulDmabuf *dbuf_seg = global_dmabuf_map.find (dbuf_fd);
+ if (dbuf_seg == nullptr) {
+ delete[] segt;
+ return -EINVAL;
+ }
+
+ segt[i] = static_cast<char *> (dbuf_seg->getData ()) + offset;
+ }
+
+ triv2_get_tops (ctx, &tops);
+
+ std::string cmd_path = NE_PREFIX "/share";
+ if (tops == 2)
+ cmd_path += "/mRPsim/triv2_2tops.cmd";
+ else
+ cmd_path += "/mRPsim/triv2.cmd";
+
+ std::string prof_path = "/tmp";
+ prof_path += "/ne_profile." + std::to_string (in->req_id);
+
+ run_triv2_emul (prog, segt, meta, cmd_path.c_str (), prof_path.c_str ());
+
+ delete[] segt;
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of stop_requests ioctl()
+ */
+static int
+triv2_stop_requests (trinity_cuse_context *ctx) {
+ /* this does not support scheduling. So, do nothing */
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of stop_request ioctl()
+ */
+static int
+triv2_stop_request (trinity_cuse_context *ctx, const int id) {
+ /* NYI, let's check again when reserved apps are running here */
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of stat_current_app ioctl()
+ */
+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;
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of stat_apps ioctl()
+ */
+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;
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of stat_reqs ioctl()
+ */
+static int
+triv2_stat_reqs (trinity_cuse_context *ctx,
+ struct trinity_ioctl_stat_reqs *stat) {
+ /* NYI */
+ memset (stat, '\x00', sizeof (*stat));
+ stat->app_id = ctx->app_id;
+ stat->num_reqs = 0;
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of get_profile_meta ioctl()
+ */
+static int
+triv2_get_profile_meta (trinity_cuse_context *ctx,
+ const struct trinity_ioctl_profile *in,
+ struct trinity_ioctl_profile *out) {
+ /* NYI */
+ *out = *in;
+ out->total_ops = 0;
+ return 0;
+}
+
+/**
+ * @brief TRIV2 impl. of get_profile_buff ioctl()
+ */
+static int
+triv2_get_profile_buff (trinity_cuse_context *ctx,
+ const struct trinity_ioctl_profile *in,
+ struct trinity_ioctl_profile *out) {
+ /* NYI */
+ *out = *in;
+ return 0;
+}
+
/** @brief The ioctl vtable for TRIV2 devices */
static trinity_cuse_ioctl_vtable triv2_vtable{
/* Device Info. */
.hwmem_dealloc = triv2_hwmem_dealloc,
.register_model = triv2_register_model,
.deregister_model = triv2_deregister_model,
+ .run_input = triv2_run_input,
+ .stop_requests = triv2_stop_requests,
+ .stop_request = triv2_stop_request,
+ /* Device Statistics/Profile */
+ .stat_current_app = triv2_stat_current_app,
+ .stat_apps = triv2_stat_apps,
+ .stat_reqs = triv2_stat_reqs,
+ .get_profile_meta = triv2_get_profile_meta,
+ .get_profile_buff = triv2_get_profile_buff,
};
/** @brief Setting the ioctl vtable */
bool
set_ioctl_vtable_triv2 (trinity_cuse_ioctl_vtable **vtable) {
+ static char default_prefix_share[] = DEFAULT_PREFIX_SHARE;
+ static char default_prefix_profile[] = DEFAULT_PREFIX_PROFILE;
+
if (vtable == nullptr)
return false;
*vtable = &triv2_vtable;
+
+ prefix_share = getenv (ENV_PREFIX_SHARE);
+ if (prefix_share == nullptr) {
+ prefix_share = default_prefix_share;
+ setenv (ENV_PREFIX_SHARE, default_prefix_share, 1);
+ }
+ prefix_profile = getenv (ENV_PREFIX_PROFILE);
+ if (prefix_profile == nullptr) {
+ prefix_profile = default_prefix_profile;
+ setenv (ENV_PREFIX_PROFILE, default_prefix_profile, 1);
+ }
+
return true;
}
trinity_cuse_open (fuse_req_t req, struct fuse_file_info *fi) {
trinity_cuse_context *ctx;
- ctx = (trinity_cuse_context *) malloc (sizeof (*ctx));
- if (ctx == NULL) {
- fuse_reply_err (req, ENOMEM);
- return;
- }
-
+ ctx = new trinity_cuse_context;
ctx->app_id = fuse_req_ctx (req)->pid;
fi->fh = (uint64_t) ctx;
trinity_cuse_context *ctx = (trinity_cuse_context *) fi->fh;
if (ctx)
- free (ctx);
+ delete ctx;
fi->fh = 0;
fuse_reply_err (req, 0);
return;
}
+ std::unique_lock<std::mutex> lock (ctx->mutex);
+
switch (cmd) {
case TRINITY_IOCTL_GET_VERSION:
if (!out_size) {
fuse_reply_ioctl (req, vtable->deregister_model (ctx, *val), NULL, 0);
}
break;
+ case TRINITY_IOCTL_RUN_INPUT:
+ if (!in_size || !out_size) {
+ struct iovec iov = {arg, sizeof (struct trinity_ioctl_input)};
+ fuse_reply_ioctl_retry (req, &iov, 1, &iov, 1);
+ } else {
+ const struct trinity_ioctl_input *in_val =
+ static_cast<const struct trinity_ioctl_input *> (in_buf);
+ struct trinity_ioctl_input out_val;
+ fuse_reply_ioctl (req, vtable->run_input (ctx, in_val, &out_val),
+ &out_val, sizeof (out_val));
+ }
+ break;
+ case TRINITY_IOCTL_STOP_REQUESTS:
+ fuse_reply_ioctl (req, vtable->stop_requests (ctx), NULL, 0);
+ break;
+ case TRINITY_IOCTL_STOP_REQUEST:
+ if (!in_size) {
+ struct iovec iov = {arg, sizeof (int)};
+ fuse_reply_ioctl_retry (req, &iov, 1, NULL, 0);
+ } else {
+ const int *val = static_cast<const int *> (in_buf);
+ fuse_reply_ioctl (req, vtable->stop_request (ctx, *val), NULL, 0);
+ }
+ break;
+ case TRINITY_IOCTL_STAT_CURRENT_APP:
+ if (!out_size) {
+ struct iovec iov = {arg, sizeof (struct trinity_ioctl_stat_app)};
+ fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+ } else {
+ struct trinity_ioctl_stat_app val;
+ fuse_reply_ioctl (req, vtable->stat_current_app (ctx, &val), &val,
+ sizeof (val));
+ }
+ break;
+ case TRINITY_IOCTL_STAT_APPS:
+ if (!out_size) {
+ struct iovec iov = {arg, sizeof (struct trinity_ioctl_stat_apps)};
+ fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+ } else {
+ struct trinity_ioctl_stat_apps val;
+ fuse_reply_ioctl (req, vtable->stat_apps (ctx, &val), &val,
+ sizeof (val));
+ }
+ break;
+ case TRINITY_IOCTL_STAT_REQS:
+ if (!out_size) {
+ struct iovec iov = {arg, sizeof (struct trinity_ioctl_stat_reqs)};
+ fuse_reply_ioctl_retry (req, NULL, 0, &iov, 1);
+ } else {
+ struct trinity_ioctl_stat_reqs val;
+ fuse_reply_ioctl (req, vtable->stat_reqs (ctx, &val), &val,
+ sizeof (val));
+ }
+ break;
+ case TRINITY_IOCTL_GET_PROFILE_META:
+ if (!in_size || !out_size) {
+ struct iovec iov = {arg, sizeof (struct trinity_ioctl_profile)};
+ fuse_reply_ioctl_retry (req, &iov, 1, &iov, 1);
+ } else {
+ const struct trinity_ioctl_profile *in_val =
+ static_cast<const struct trinity_ioctl_profile *> (in_buf);
+ struct trinity_ioctl_profile out_val;
+ fuse_reply_ioctl (req, vtable->get_profile_meta (ctx, in_val, &out_val),
+ &out_val, sizeof (out_val));
+ }
+ break;
+ case TRINITY_IOCTL_GET_PROFILE_BUFF:
+ if (!in_size || !out_size) {
+ struct iovec iov = {arg, sizeof (struct trinity_ioctl_profile)};
+ fuse_reply_ioctl_retry (req, &iov, 1, &iov, 1);
+ } else {
+ const struct trinity_ioctl_profile *in_val =
+ static_cast<const struct trinity_ioctl_profile *> (in_buf);
+ struct trinity_ioctl_profile out_val;
+ fuse_reply_ioctl (req, vtable->get_profile_buff (ctx, in_val, &out_val),
+ &out_val, sizeof (out_val));
+ }
+ break;
/* NYI */
default:
fuse_reply_err (req, ENOTTY);
return 0;
if (param.dev_name.empty ()) {
- std::cerr << "[Error] Missing device name (e.g., --name=triv2)\n";
+ std::cerr << "[Error] Missing device name (e.g., triv2)\n";
print_help_message ();
return -EINVAL;
}
#define __TRINITY_FUSE_H__
#include <misc/trinity.h>
+#include <mutex>
/**
* @brief The trinity context
*/
typedef struct {
int app_id;
+ std::mutex mutex;
/* NYI */
} trinity_cuse_context;
const struct trinity_ioctl_model *,
struct trinity_ioctl_model *);
int (*deregister_model) (trinity_cuse_context *, const uint64_t);
+ int (*run_input) (trinity_cuse_context *, const struct trinity_ioctl_input *,
+ struct trinity_ioctl_input *);
+ int (*stop_requests) (trinity_cuse_context *);
+ int (*stop_request) (trinity_cuse_context *, const int);
+ /* Device Statistics/Profile */
+ int (*stat_current_app) (trinity_cuse_context *,
+ struct trinity_ioctl_stat_app *);
+ int (*stat_apps) (trinity_cuse_context *, struct trinity_ioctl_stat_apps *);
+ int (*stat_reqs) (trinity_cuse_context *, struct trinity_ioctl_stat_reqs *);
+ int (*get_profile_meta) (trinity_cuse_context *,
+ const struct trinity_ioctl_profile *,
+ struct trinity_ioctl_profile *);
+ int (*get_profile_buff) (trinity_cuse_context *,
+ const struct trinity_ioctl_profile *,
+ struct trinity_ioctl_profile *);
} trinity_cuse_ioctl_vtable;
#endif