LCOV - code coverage report
Current view: top level - nntrainer - engine.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 50.8 % 63 32
Test Date: 2026-01-12 20:43:37 Functions: 66.7 % 9 6

            Line data    Source code
       1              : // SPDX-License-Identifier: Apache-2.0
       2              : /**
       3              :  * Copyright (C) 2024 Jijoong Moon <jijoong.moon@samsung.com>
       4              :  *
       5              :  * @file   engine.cpp
       6              :  * @date   27 December 2024
       7              :  * @brief  This file contains engine context related functions and classes that
       8              :  * manages the engines (NPU, GPU, CPU) of the current environment
       9              :  * @see    https://github.com/nntrainer/nntrainer
      10              :  * @author Jijoong Moon <jijoong.moon@samsung.com>
      11              :  * @bug    No known bugs except for NYI items
      12              :  *
      13              :  */
      14              : #include <filesystem>
      15              : #include <iostream>
      16              : #include <sstream>
      17              : #include <string>
      18              : #include <vector>
      19              : 
      20              : #include <app_context.h>
      21              : #include <base_properties.h>
      22              : #include <context.h>
      23              : #include <dynamic_library_loader.h>
      24              : #include <engine.h>
      25              : 
      26              : static std::string solib_suffix = ".so";
      27              : static std::string contextlib_suffix = "context.so";
      28              : static const std::string func_tag = "[Engine] ";
      29              : 
      30              : namespace nntrainer {
      31              : 
      32              : std::mutex engine_mutex;
      33              : 
      34              : std::once_flag global_engine_init_flag;
      35              : 
      36              : nntrainer::Context
      37              :   *Engine::nntrainerRegisteredContext[Engine::RegisterContextMax];
      38              : 
      39           27 : void Engine::add_default_object() {
      40              :   /// @note all layers should be added to the app_context to guarantee that
      41              :   /// createLayer/createOptimizer class is created
      42              : 
      43           27 :   auto &app_context = nntrainer::AppContext::Global();
      44              : 
      45           27 :   init_backend(); // initialize cpu backend
      46           27 :   registerContext("cpu", &app_context);
      47              : 
      48              : #ifdef ENABLE_OPENCL
      49              :   auto &cl_context = nntrainer::ClContext::Global();
      50              : 
      51              :   registerContext("gpu", &cl_context);
      52              : #endif
      53           27 : }
      54              : 
      55           27 : void Engine::initialize() noexcept {
      56              :   try {
      57           27 :     add_default_object();
      58            0 :   } catch (std::exception &e) {
      59            0 :     ml_loge("registering layers failed!!, reason: %s", e.what());
      60            0 :   } catch (...) {
      61            0 :     ml_loge("registering layer failed due to unknown reason");
      62            0 :   }
      63           27 : };
      64              : 
      65            0 : void Engine::release() { thread_pool_manager_.reset(); }
      66              : 
      67              : std::string
      68         7066 : Engine::parseComputeEngine(const std::vector<std::string> &props) const {
      69        39954 :   for (auto &prop : props) {
      70              :     std::string key, value;
      71        32888 :     int status = nntrainer::getKeyValue(prop, key, value);
      72        65776 :     if (nntrainer::istrequal(key, "engine")) {
      73              :       constexpr const auto data =
      74              :         std::data(props::ComputeEngineTypeInfo::EnumList);
      75            0 :       for (unsigned int i = 0;
      76            0 :            i < props::ComputeEngineTypeInfo::EnumList.size(); ++i) {
      77            0 :         if (nntrainer::istrequal(value.c_str(),
      78            0 :                                  props::ComputeEngineTypeInfo::EnumStr[i])) {
      79            0 :           return props::ComputeEngineTypeInfo::EnumStr[i];
      80              :         }
      81              :       }
      82              :     }
      83              :   }
      84              : 
      85         7066 :   return "cpu";
      86              : }
      87              : 
      88              : /**
      89              :  * @brief Get the Full Path from given string
      90              :  * @details path is resolved in the following order
      91              :  * 1) if @a path is absolute, return path
      92              :  * ----------------------------------------
      93              :  * 2) if @a base == "" && @a path == "", return "."
      94              :  * 3) if @a base == "" && @a path != "", return @a path
      95              :  * 4) if @a base != "" && @a path == "", return @a base
      96              :  * 5) if @a base != "" && @a path != "", return @a base + "/" + path
      97              :  *
      98              :  * @param path path to calculate from base
      99              :  * @param base base path
     100              :  * @return const std::string
     101              :  */
     102         6234 : const std::string getFullPath(const std::string &path,
     103              :                               const std::string &base) {
     104              :   /// if path is absolute, return path
     105         6234 :   if (path[0] == '/') {
     106              :     return path;
     107              :   }
     108              : 
     109         5556 :   if (base == std::string()) {
     110         4880 :     return path == std::string() ? "." : path;
     111              :   }
     112              : 
     113         6232 :   return path == std::string() ? base : base + "/" + path;
     114              : }
     115              : 
     116         6234 : const std::string Engine::getWorkingPath(const std::string &path) const {
     117         6234 :   return getFullPath(path, working_path_base);
     118              : }
     119              : 
     120          673 : void Engine::setWorkingDirectory(const std::string &base) {
     121          673 :   std::filesystem::path base_path(base);
     122              : 
     123          673 :   if (!std::filesystem::is_directory(base_path)) {
     124            1 :     std::stringstream ss;
     125              :     ss << func_tag << "path is not directory or has no permission: " << base;
     126            3 :     throw std::invalid_argument(ss.str().c_str());
     127            1 :   }
     128              : 
     129          672 :   char *ret = getRealpath(base.c_str(), nullptr);
     130              : 
     131          672 :   if (ret == nullptr) {
     132            0 :     std::stringstream ss;
     133            0 :     ss << func_tag << "failed to get canonical path for the path: ";
     134            0 :     throw std::invalid_argument(ss.str().c_str());
     135            0 :   }
     136              : 
     137         1344 :   working_path_base = std::string(ret);
     138          672 :   ml_logd("working path base has set: %s", working_path_base.c_str());
     139          672 :   free(ret);
     140          673 : }
     141              : 
     142            0 : int Engine::registerContext(const std::string &library_path,
     143              :                             const std::string &base_path) {
     144            0 :   const std::string full_path = getFullPath(library_path, base_path);
     145              : 
     146              :   void *handle = DynamicLibraryLoader::loadLibrary(full_path.c_str(),
     147              :                                                    RTLD_LAZY | RTLD_LOCAL);
     148              :   const char *error_msg = DynamicLibraryLoader::getLastError();
     149              : 
     150            0 :   NNTR_THROW_IF(handle == nullptr, std::invalid_argument)
     151              :     << func_tag << "open plugin failed, reason: " << error_msg;
     152              : 
     153              :   nntrainer::ContextPluggable *pluggable =
     154              :     reinterpret_cast<nntrainer::ContextPluggable *>(
     155              :       DynamicLibraryLoader::loadSymbol(handle, "ml_train_context_pluggable"));
     156              : 
     157              :   error_msg = DynamicLibraryLoader::getLastError();
     158            0 :   auto close_dl = [handle] { DynamicLibraryLoader::freeLibrary(handle); };
     159            0 :   NNTR_THROW_IF_CLEANUP(error_msg != nullptr || pluggable == nullptr,
     160              :                         std::invalid_argument, close_dl)
     161              :     << func_tag << "loading symbol failed, reason: " << error_msg;
     162              : 
     163            0 :   auto context = pluggable->createfunc();
     164            0 :   NNTR_THROW_IF_CLEANUP(context == nullptr, std::invalid_argument, close_dl)
     165              :     << func_tag << "created pluggable context is null";
     166            0 :   auto type = context->getName();
     167            0 :   NNTR_THROW_IF_CLEANUP(type == "", std::invalid_argument, close_dl)
     168              :     << func_tag << "custom layer must specify type name, but it is empty";
     169              : 
     170            0 :   registerContext(type, context);
     171              : 
     172            0 :   return 0;
     173              : }
     174              : 
     175            0 : ThreadPoolManager *Engine::getThreadPoolManager() {
     176            0 :   std::lock_guard<std::mutex> lock(thread_pool_manager_mutex_);
     177              : 
     178            0 :   if (!thread_pool_manager_) {
     179            0 :     thread_pool_manager_ = std::make_unique<ThreadPoolManager>();
     180              :   }
     181              : 
     182            0 :   return thread_pool_manager_.get();
     183              : }
     184              : 
     185              : } // namespace nntrainer
        

Generated by: LCOV version 2.0-1