LCOV - code coverage report
Current view: top level - nntrainer - engine.cpp (source / functions) Coverage Total Hit
Test: coverage_filtered.info Lines: 56.1 % 57 32
Test Date: 2025-12-14 20:38:17 Functions: 85.7 % 7 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/nnstreamer/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              : std::string
      66         7065 : Engine::parseComputeEngine(const std::vector<std::string> &props) const {
      67        39953 :   for (auto &prop : props) {
      68              :     std::string key, value;
      69        32888 :     int status = nntrainer::getKeyValue(prop, key, value);
      70        65776 :     if (nntrainer::istrequal(key, "engine")) {
      71              :       constexpr const auto data =
      72              :         std::data(props::ComputeEngineTypeInfo::EnumList);
      73            0 :       for (unsigned int i = 0;
      74            0 :            i < props::ComputeEngineTypeInfo::EnumList.size(); ++i) {
      75            0 :         if (nntrainer::istrequal(value.c_str(),
      76            0 :                                  props::ComputeEngineTypeInfo::EnumStr[i])) {
      77            0 :           return props::ComputeEngineTypeInfo::EnumStr[i];
      78              :         }
      79              :       }
      80              :     }
      81              :   }
      82              : 
      83         7065 :   return "cpu";
      84              : }
      85              : 
      86              : /**
      87              :  * @brief Get the Full Path from given string
      88              :  * @details path is resolved in the following order
      89              :  * 1) if @a path is absolute, return path
      90              :  * ----------------------------------------
      91              :  * 2) if @a base == "" && @a path == "", return "."
      92              :  * 3) if @a base == "" && @a path != "", return @a path
      93              :  * 4) if @a base != "" && @a path == "", return @a base
      94              :  * 5) if @a base != "" && @a path != "", return @a base + "/" + path
      95              :  *
      96              :  * @param path path to calculate from base
      97              :  * @param base base path
      98              :  * @return const std::string
      99              :  */
     100         6234 : const std::string getFullPath(const std::string &path,
     101              :                               const std::string &base) {
     102              :   /// if path is absolute, return path
     103         6234 :   if (path[0] == '/') {
     104              :     return path;
     105              :   }
     106              : 
     107         5556 :   if (base == std::string()) {
     108         4880 :     return path == std::string() ? "." : path;
     109              :   }
     110              : 
     111         6232 :   return path == std::string() ? base : base + "/" + path;
     112              : }
     113              : 
     114         6234 : const std::string Engine::getWorkingPath(const std::string &path) const {
     115         6234 :   return getFullPath(path, working_path_base);
     116              : }
     117              : 
     118          673 : void Engine::setWorkingDirectory(const std::string &base) {
     119          673 :   std::filesystem::path base_path(base);
     120              : 
     121          673 :   if (!std::filesystem::is_directory(base_path)) {
     122            1 :     std::stringstream ss;
     123              :     ss << func_tag << "path is not directory or has no permission: " << base;
     124            3 :     throw std::invalid_argument(ss.str().c_str());
     125            1 :   }
     126              : 
     127          672 :   char *ret = getRealpath(base.c_str(), nullptr);
     128              : 
     129          672 :   if (ret == nullptr) {
     130            0 :     std::stringstream ss;
     131            0 :     ss << func_tag << "failed to get canonical path for the path: ";
     132            0 :     throw std::invalid_argument(ss.str().c_str());
     133            0 :   }
     134              : 
     135         1344 :   working_path_base = std::string(ret);
     136          672 :   ml_logd("working path base has set: %s", working_path_base.c_str());
     137          672 :   free(ret);
     138          673 : }
     139              : 
     140            0 : int Engine::registerContext(const std::string &library_path,
     141              :                             const std::string &base_path) {
     142            0 :   const std::string full_path = getFullPath(library_path, base_path);
     143              : 
     144              :   void *handle = DynamicLibraryLoader::loadLibrary(full_path.c_str(),
     145              :                                                    RTLD_LAZY | RTLD_LOCAL);
     146              :   const char *error_msg = DynamicLibraryLoader::getLastError();
     147              : 
     148            0 :   NNTR_THROW_IF(handle == nullptr, std::invalid_argument)
     149              :     << func_tag << "open plugin failed, reason: " << error_msg;
     150              : 
     151              :   nntrainer::ContextPluggable *pluggable =
     152              :     reinterpret_cast<nntrainer::ContextPluggable *>(
     153              :       DynamicLibraryLoader::loadSymbol(handle, "ml_train_context_pluggable"));
     154              : 
     155              :   error_msg = DynamicLibraryLoader::getLastError();
     156            0 :   auto close_dl = [handle] { DynamicLibraryLoader::freeLibrary(handle); };
     157            0 :   NNTR_THROW_IF_CLEANUP(error_msg != nullptr || pluggable == nullptr,
     158              :                         std::invalid_argument, close_dl)
     159              :     << func_tag << "loading symbol failed, reason: " << error_msg;
     160              : 
     161            0 :   auto context = pluggable->createfunc();
     162            0 :   NNTR_THROW_IF_CLEANUP(context == nullptr, std::invalid_argument, close_dl)
     163              :     << func_tag << "created pluggable context is null";
     164            0 :   auto type = context->getName();
     165            0 :   NNTR_THROW_IF_CLEANUP(type == "", std::invalid_argument, close_dl)
     166              :     << func_tag << "custom layer must specify type name, but it is empty";
     167              : 
     168            0 :   registerContext(type, context);
     169              : 
     170            0 :   return 0;
     171              : }
     172              : 
     173              : } // namespace nntrainer
        

Generated by: LCOV version 2.0-1