From 8a4dbb9142c2412cc4712b7cc90b88b34256af51 Mon Sep 17 00:00:00 2001 From: Dongju Chae Date: Tue, 20 Apr 2021 15:26:05 +0900 Subject: [PATCH] [Utils/Cuse] Implement run_input ioctl and connect libmrpsim This patch implements run_input ioctl, connecting libmrpsim APIs. Signed-off-by: Dongju Chae --- src/core/ne-hw-input-service.cc | 2 +- src/core/npu/NPUdrvAPI_triv2.cc | 57 ++++++++ tests/unittests/ne_core_npu_test.cc | 1 + utils/trinity_cuse/trinity-cuse-triv2.cc | 214 ++++++++++++++++++++++++++++++- utils/trinity_cuse/trinity-cuse.cc | 91 +++++++++++-- utils/trinity_cuse/trinity-cuse.h | 17 +++ 6 files changed, 369 insertions(+), 13 deletions(-) diff --git a/src/core/ne-hw-input-service.cc b/src/core/ne-hw-input-service.cc index 788b4e4..f0c50cd 100644 --- a/src/core/ne-hw-input-service.cc +++ b/src/core/ne-hw-input-service.cc @@ -129,9 +129,9 @@ HwInputService::invoke (const DriverAPI *api, const Model *model, 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); diff --git a/src/core/npu/NPUdrvAPI_triv2.cc b/src/core/npu/NPUdrvAPI_triv2.cc index 36394eb..143500c 100644 --- a/src/core/npu/NPUdrvAPI_triv2.cc +++ b/src/core/npu/NPUdrvAPI_triv2.cc @@ -280,6 +280,7 @@ TrinityVision2API::dealloc (int dmabuf, bool contiguous) const { 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) @@ -402,9 +403,32 @@ TrinityVision2API::registerModel (model_config_t *model_config, 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; @@ -465,6 +489,39 @@ TrinityVision2API::runInput (input_config_t *input_config) const { 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; diff --git a/tests/unittests/ne_core_npu_test.cc b/tests/unittests/ne_core_npu_test.cc index f65c9f6..bb34422 100644 --- a/tests/unittests/ne_core_npu_test.cc +++ b/tests/unittests/ne_core_npu_test.cc @@ -510,6 +510,7 @@ TEST (ne_core_npu_test, run_inference_triv2_n) { 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); diff --git a/utils/trinity_cuse/trinity-cuse-triv2.cc b/utils/trinity_cuse/trinity-cuse-triv2.cc index 674001c..1fe0466 100644 --- a/utils/trinity_cuse/trinity-cuse-triv2.cc +++ b/utils/trinity_cuse/trinity-cuse-triv2.cc @@ -24,13 +24,24 @@ #include #include "trinity-cuse.h" +#include + +#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); @@ -47,6 +58,9 @@ class EmulDmabuf { if (shm_fd_ < 0) return; + if (addr_ != nullptr) + munmap (addr_, size_); + shm_unlink (shm_name_.c_str ()); close (shm_fd_); } @@ -63,9 +77,14 @@ class EmulDmabuf { 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_; } @@ -76,6 +95,7 @@ class EmulDmabuf { int shm_fd_; std::string shm_name_; size_t size_; + void *addr_; }; /** @@ -114,6 +134,11 @@ class EmulModel { } 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 lock_l (l.mutex_); @@ -157,12 +182,11 @@ class EmulModel { uint64_t metadata_ext_size_; }; -/** @brief Global file descriptor */ -std::atomic EmulDmabuf::global_fd_ (0); +std::atomic EmulDmabuf::global_fd_ (1); /** @brief Global mapping of dmabuf */ ThreadSafeMap global_dmabuf_map; /** @brief Global model id */ -std::atomic EmulModel::global_id_ (0); +std::atomic EmulModel::global_id_ (1); /** @brief Global mapping of models */ ThreadSafeMap global_model_map; @@ -296,6 +320,164 @@ triv2_deregister_model (trinity_cuse_context *ctx, const uint64_t model_id) { 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 (input)[i]; + uint32_t offset = + reinterpret_cast ((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 (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. */ @@ -309,14 +491,38 @@ static trinity_cuse_ioctl_vtable triv2_vtable{ .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; } diff --git a/utils/trinity_cuse/trinity-cuse.cc b/utils/trinity_cuse/trinity-cuse.cc index ef50153..9c92b69 100644 --- a/utils/trinity_cuse/trinity-cuse.cc +++ b/utils/trinity_cuse/trinity-cuse.cc @@ -49,12 +49,7 @@ static void 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; @@ -69,7 +64,7 @@ trinity_cuse_release (fuse_req_t req, struct fuse_file_info *fi) { trinity_cuse_context *ctx = (trinity_cuse_context *) fi->fh; if (ctx) - free (ctx); + delete ctx; fi->fh = 0; fuse_reply_err (req, 0); @@ -94,6 +89,8 @@ trinity_cuse_ioctl (fuse_req_t req, int cmd, void *arg, return; } + std::unique_lock lock (ctx->mutex); + switch (cmd) { case TRINITY_IOCTL_GET_VERSION: if (!out_size) { @@ -186,6 +183,84 @@ trinity_cuse_ioctl (fuse_req_t req, int cmd, void *arg, 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 (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 (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 (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 (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); @@ -284,7 +359,7 @@ main (int argc, char **argv) { 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; } diff --git a/utils/trinity_cuse/trinity-cuse.h b/utils/trinity_cuse/trinity-cuse.h index c211c64..b68618d 100644 --- a/utils/trinity_cuse/trinity-cuse.h +++ b/utils/trinity_cuse/trinity-cuse.h @@ -15,12 +15,14 @@ #define __TRINITY_FUSE_H__ #include +#include /** * @brief The trinity context */ typedef struct { int app_id; + std::mutex mutex; /* NYI */ } trinity_cuse_context; @@ -43,6 +45,21 @@ typedef struct { 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 -- 2.7.4