feat(lite): support base lite ipc fork debugdev-support-lite-fork-debug-mode
| @@ -14,6 +14,7 @@ | |||
| #include "lite-c/tensor_c.h" | |||
| #include <stdio.h> | |||
| #include <stdlib.h> | |||
| #include <string.h> | |||
| #define LITE_CAPI_CHECK(_expr) \ | |||
| @@ -42,7 +43,7 @@ int basic_c_interface(const char* mode_path) { | |||
| LITE_get_tensor_total_size_in_byte(c_input_tensor, &length_in_byte)); | |||
| LITE_CAPI_CHECK(LITE_get_tensor_memory(c_input_tensor, &dst_ptr)); | |||
| //! copy or forward data to network | |||
| memset(dst_ptr, 5, length_in_byte); | |||
| LITE_memset(dst_ptr, 5, length_in_byte); | |||
| //! forward | |||
| LITE_CAPI_CHECK(LITE_forward(c_network)); | |||
| @@ -66,23 +67,41 @@ int basic_c_interface(const char* mode_path) { | |||
| float max = -1.0f; | |||
| float sum = 0.0f; | |||
| int is_enable_ipc_debug = LITE_is_enable_ipc_debug_mode(); | |||
| float* copy_ptr = NULL; | |||
| float* final_dst_ptr = (float*)output_ptr; | |||
| if (is_enable_ipc_debug) { | |||
| copy_ptr = (float*)(malloc(length_output_in_byte)); | |||
| LITE_CAPI_CHECK(LITE_copy_server_tensor_memory( | |||
| output_ptr, copy_ptr, length_output_in_byte)); | |||
| final_dst_ptr = (float*)copy_ptr; | |||
| } | |||
| for (size_t i = 0; i < out_length; i++) { | |||
| float data = ((float*)(output_ptr))[i]; | |||
| float data = final_dst_ptr[i]; | |||
| sum += data; | |||
| if (max < data) | |||
| max = data; | |||
| } | |||
| printf("max=%e, sum=%e\n", max, sum); | |||
| LITE_destroy_network(c_network); | |||
| if (is_enable_ipc_debug) { | |||
| free(copy_ptr); | |||
| } | |||
| return 0; | |||
| } | |||
| int main(int argc, char** argv) { | |||
| if (argc < 2) { | |||
| printf("usage: lite_c_examples <model file> , just test C interface " | |||
| if (argc < 3) { | |||
| printf("usage: lite_c_examples is_enable_fork_debug_model <model file> , just " | |||
| "test C interface " | |||
| "build.\n"); | |||
| return -1; | |||
| } | |||
| return basic_c_interface(argv[1]); | |||
| if (atoi(argv[1])) { | |||
| LITE_enable_lite_ipc_debug(); | |||
| } | |||
| return basic_c_interface(argv[2]); | |||
| } | |||
| // vim: syntax=cpp.doxygen foldmethod=marker foldmarker=f{{{,f}}} | |||
| @@ -26,6 +26,15 @@ LITE_API void LITE_clear_last_error(); | |||
| */ | |||
| LITE_API const char* LITE_get_last_error(); | |||
| /*! \brief LITE is enable ipc debug mode or not. | |||
| * \return if enable ipc debug mode, will return 1, if not will return 0 | |||
| */ | |||
| LITE_API int LITE_is_enable_ipc_debug_mode(); | |||
| /*! \brief LITE enable ipc debug mode. | |||
| */ | |||
| LITE_API void LITE_enable_lite_ipc_debug(); | |||
| /*! \brief Get device count | |||
| * \param[in] device_type device type | |||
| * \return the device count | |||
| @@ -158,6 +158,15 @@ LITE_API int LITE_tensor_share_memory_with( | |||
| */ | |||
| LITE_API int LITE_get_tensor_memory(const LiteTensor tensor, void** data); | |||
| /** | |||
| * \brief copy tensor memory if fork debug mode. | |||
| * \param[server_ptr] the ptr valid in lite server | |||
| * \param[client_ptr] the ptr only valid in lite client | |||
| * \param[size_in_byte] copy size | |||
| */ | |||
| LITE_API int LITE_copy_server_tensor_memory( | |||
| void* server_ptr, void* client_ptr, size_t size_in_byte); | |||
| /** | |||
| * \brief get the memory pointer of a Tensor object. | |||
| * \param[in] tensor The input Tensor | |||
| @@ -230,6 +239,11 @@ LITE_API int LITE_tensor_concat( | |||
| LiteTensor* tensors, int nr_tensor, int dim, LiteDeviceType dst_device, | |||
| int device_id, LiteTensor* result_tensor); | |||
| /** | |||
| * \brief fuction like memset | |||
| */ | |||
| LITE_API void* LITE_memset(void* s, int c, size_t n); | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| @@ -1,5 +1,6 @@ | |||
| #include "lite/global.h" | |||
| #include "common.h" | |||
| #include "ipc_helper.h" | |||
| #include "lite-c/global_c.h" | |||
| namespace { | |||
| @@ -47,7 +48,24 @@ void LITE_clear_last_error() { | |||
| const char* LITE_get_last_error() { | |||
| LITE_LOCK_GUARD(mtx_error); | |||
| return get_global_error().get_error_msg().c_str(); | |||
| if (ipc_imp::is_server()) { | |||
| return get_global_error().get_error_msg().c_str(); | |||
| } else { | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(nullptr); | |||
| IPC_HELP_REMOTE_CALL(raw_shm_ptr, ipc::RemoteFuncId::LITE_GET_LAST_ERROR); | |||
| char* ret_ptr = static_cast<char*>(raw_shm_ptr); | |||
| return ret_ptr; | |||
| } | |||
| } | |||
| int LITE_is_enable_ipc_debug_mode() { | |||
| return ipc::IpcHelper::is_enable_fork_debug_mode(); | |||
| } | |||
| void LITE_enable_lite_ipc_debug() { | |||
| ipc_imp::enable_lite_ipc_debug(); | |||
| } | |||
| int LITE_get_version(int* major, int* minor, int* patch) { | |||
| @@ -0,0 +1,260 @@ | |||
| #include "ipc_helper.h" | |||
| #include "lite-c/global_c.h" | |||
| #include "lite-c/network_c.h" | |||
| #include "misc.h" | |||
| using namespace ipc_imp; | |||
| namespace ipc { | |||
| static void api_remote_call_cb(struct MsgBody* msg) { | |||
| LITE_DEBUG( | |||
| "into %s: %d remote_func_id: %zu", __func__, __LINE__, msg->remote_func_id); | |||
| switch (static_cast<RemoteFuncId>(msg->remote_func_id)) { | |||
| case RemoteFuncId::LITE_MAKE_NETWORK: { | |||
| LiteNetwork network; | |||
| //! second args is const LiteConfig config | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| LiteConfig config; | |||
| memcpy(&config, shm_ptr_c, sizeof(LiteConfig)); | |||
| //! third args is network_io | |||
| LiteNetworkIO network_io; | |||
| memcpy(&network_io, shm_ptr_c + sizeof(LiteConfig), sizeof(LiteNetworkIO)); | |||
| int ret = LITE_make_network(&network, config, network_io); | |||
| //! API is block, put ret to shm_ptr | |||
| int* ret_ptr = static_cast<int*>(msg->shm_ptr); | |||
| *ret_ptr = ret; | |||
| ret_ptr++; | |||
| void* network_p = static_cast<void*>(ret_ptr); | |||
| memcpy(network_p, &network, sizeof(LiteNetwork)); | |||
| }; break; | |||
| case RemoteFuncId::LITE_LOAD_MODEL_FROM_PATH: { | |||
| LiteNetwork network; | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| memcpy(&network, shm_ptr_c, sizeof(LiteNetwork)); | |||
| int ret = | |||
| LITE_load_model_from_path(network, shm_ptr_c + sizeof(LiteNetwork)); | |||
| //! API is block, put ret to shm_ptr | |||
| int* ret_ptr = static_cast<int*>(msg->shm_ptr); | |||
| *ret_ptr = ret; | |||
| }; break; | |||
| case RemoteFuncId::LITE_GET_LAST_ERROR: { | |||
| auto shm_size = base_get_shm_size(); | |||
| const char* ret = LITE_get_last_error(); | |||
| char* ret_ptr = static_cast<char*>(msg->shm_ptr); | |||
| auto last_error_str_len = strlen(ret) + 1; | |||
| ASSERT_SHM_SIZE(shm_size, last_error_str_len); | |||
| strcpy(ret_ptr, ret); | |||
| }; break; | |||
| case RemoteFuncId::LITE_GET_IO_TENSOR: { | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| LiteNetwork network; | |||
| LiteTensorPhase phase; | |||
| LiteTensor tensor; | |||
| memcpy(&network, shm_ptr_c, sizeof(LiteNetwork)); | |||
| memcpy(&phase, shm_ptr_c + sizeof(LiteNetwork), sizeof(LiteTensorPhase)); | |||
| int ret = LITE_get_io_tensor( | |||
| network, shm_ptr_c + sizeof(LiteNetwork) + sizeof(LiteTensorPhase), | |||
| phase, &tensor); | |||
| //! API is block, put ret to shm_ptr | |||
| int* ret_ptr = static_cast<int*>(msg->shm_ptr); | |||
| *ret_ptr = ret; | |||
| ret_ptr++; | |||
| void* lite_tensor_p = static_cast<void*>(ret_ptr); | |||
| memcpy(lite_tensor_p, &tensor, sizeof(LiteTensor)); | |||
| }; break; | |||
| case RemoteFuncId::LITE_GET_TENSOR_TOTAL_SIZE_IN_BYTE: { | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| LiteTensor tensor; | |||
| size_t size; | |||
| memcpy(&tensor, shm_ptr_c, sizeof(LiteTensor)); | |||
| int ret = LITE_get_tensor_total_size_in_byte(tensor, &size); | |||
| int* ret_ptr = static_cast<int*>(msg->shm_ptr); | |||
| *ret_ptr = ret; | |||
| ret_ptr++; | |||
| memcpy(ret_ptr, &size, sizeof(size_t)); | |||
| }; break; | |||
| case RemoteFuncId::LITE_GET_TENSOR_MEMORY: { | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| LiteTensor tensor; | |||
| void* data; | |||
| memcpy(&tensor, shm_ptr_c, sizeof(LiteTensor)); | |||
| int ret = LITE_get_tensor_memory(tensor, &data); | |||
| int* ret_ptr = static_cast<int*>(msg->shm_ptr); | |||
| *ret_ptr = ret; | |||
| ret_ptr++; | |||
| memcpy(ret_ptr, &data, sizeof(void*)); | |||
| }; break; | |||
| case RemoteFuncId::LITE_MEMSET: { | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| void* s; | |||
| int c; | |||
| size_t n; | |||
| memcpy(&s, shm_ptr_c, sizeof(void*)); | |||
| memcpy(&c, shm_ptr_c + sizeof(void*), sizeof(int)); | |||
| memcpy(&n, shm_ptr_c + sizeof(void*) + sizeof(int), sizeof(size_t)); | |||
| LITE_memset(s, c, n); | |||
| }; break; | |||
| case RemoteFuncId::LITE_FORWARD: { | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| LiteNetwork network; | |||
| memcpy(&network, shm_ptr_c, sizeof(LiteNetwork)); | |||
| int ret = LITE_forward(network); | |||
| int* ret_ptr = static_cast<int*>(msg->shm_ptr); | |||
| *ret_ptr = ret; | |||
| }; break; | |||
| case RemoteFuncId::LITE_WAIT: { | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| LiteNetwork network; | |||
| memcpy(&network, shm_ptr_c, sizeof(LiteNetwork)); | |||
| int ret = LITE_wait(network); | |||
| int* ret_ptr = static_cast<int*>(msg->shm_ptr); | |||
| *ret_ptr = ret; | |||
| }; break; | |||
| case RemoteFuncId::LITE_GET_OUTPUT_NAME: { | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| LiteNetwork network; | |||
| size_t index; | |||
| const char* name; | |||
| memcpy(&network, shm_ptr_c, sizeof(LiteNetwork)); | |||
| memcpy(&index, shm_ptr_c + sizeof(LiteNetwork), sizeof(size_t)); | |||
| int ret = LITE_get_output_name(network, index, &name); | |||
| auto output_name_len = strlen(name) + 1; | |||
| auto shm_size = base_get_shm_size(); | |||
| ASSERT_SHM_SIZE(shm_size, output_name_len); | |||
| int* ret_ptr = static_cast<int*>(msg->shm_ptr); | |||
| *ret_ptr = ret; | |||
| ret_ptr++; | |||
| void* p = static_cast<void*>(ret_ptr); | |||
| char* p_c = static_cast<char*>(p); | |||
| strcpy(p_c, name); | |||
| }; break; | |||
| case RemoteFuncId::LITE_COPY_SERVER_TENSOR_MEMORY: { | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| void* server_ptr; | |||
| size_t size_in_byte; | |||
| memcpy(&server_ptr, shm_ptr_c, sizeof(void*)); | |||
| memcpy(&size_in_byte, shm_ptr_c + sizeof(void*), sizeof(size_t)); | |||
| memcpy(shm_ptr_c, server_ptr, size_in_byte); | |||
| }; break; | |||
| case RemoteFuncId::LITE_DESTROY_NETWORK: { | |||
| char* shm_ptr_c = static_cast<char*>(msg->shm_ptr); | |||
| LiteNetwork network; | |||
| memcpy(&network, shm_ptr_c, sizeof(LiteNetwork)); | |||
| int ret = LITE_destroy_network(network); | |||
| int* ret_ptr = static_cast<int*>(msg->shm_ptr); | |||
| *ret_ptr = ret; | |||
| }; break; | |||
| default: | |||
| LITE_THROW("code issue happened: do not handle RemoteFuncId"); | |||
| } | |||
| }; | |||
| bool IpcHelper::sm_is_enable_fork_ipc = false; | |||
| IpcHelper::IpcHelper() { | |||
| if (!is_server()) { | |||
| sm_is_enable_fork_ipc = is_enable_ipc(); | |||
| auto shm_mem_conut = base_get_shm_count(); | |||
| shm_mem_for_null_consumer_ptr = base_get_shm_ptr(0); | |||
| LITE_ASSERT( | |||
| shm_mem_for_null_consumer_ptr, "invalid shm_ptr: %p", | |||
| shm_mem_for_null_consumer_ptr); | |||
| for (size_t i = 1; i < shm_mem_conut; i++) { | |||
| void* shm_ptr = base_get_shm_ptr(i); | |||
| LITE_ASSERT(shm_ptr, "invalid shm_ptr: %p", shm_ptr); | |||
| //! init consumer ptr as nullptr | |||
| m_shm_ptr2consumer_ptr[shm_ptr] = nullptr; | |||
| } | |||
| shm_size = base_get_shm_size(); | |||
| register_remote_call_cb(&api_remote_call_cb); | |||
| } else { | |||
| LITE_THROW("code issue happened: can not use for client"); | |||
| } | |||
| }; | |||
| IpcHelper::~IpcHelper() { | |||
| struct MsgBody msg; | |||
| msg.type = IPC_SERVER_EXIT; | |||
| send_ipc_msg(&msg); | |||
| join_server(); | |||
| }; | |||
| void* IpcHelper::get_shm_ptr(void* consumer_ptr) { | |||
| LITE_LOCK_GUARD(m_mtx); | |||
| if (!consumer_ptr) { | |||
| return shm_mem_for_null_consumer_ptr; | |||
| } | |||
| void* ret = nullptr; | |||
| //! try find old one | |||
| for (auto&& i : m_shm_ptr2consumer_ptr) { | |||
| if (consumer_ptr == i.second) { | |||
| ret = i.first; | |||
| break; | |||
| } | |||
| } | |||
| //! if not find, try alloc a new one | |||
| if (!ret) { | |||
| for (auto&& i : m_shm_ptr2consumer_ptr) { | |||
| if (nullptr == i.second) { | |||
| i.second = consumer_ptr; | |||
| ret = i.first; | |||
| break; | |||
| } | |||
| } | |||
| } | |||
| if (!ret) { | |||
| LITE_ERROR( | |||
| "can not find any usable shm_mem, may config LITE_DEBUG_IPC_SHM_COUNT " | |||
| "big " | |||
| "than :%zu", | |||
| m_shm_ptr2consumer_ptr.size() + 1); | |||
| LITE_ASSERT(ret); | |||
| } | |||
| return ret; | |||
| }; | |||
| void IpcHelper::release_shm_ptr(void* consumer_ptr) { | |||
| LITE_LOCK_GUARD(m_mtx); | |||
| LITE_ASSERT(consumer_ptr, "invalid consumer_ptr ptr"); | |||
| for (auto&& i : m_shm_ptr2consumer_ptr) { | |||
| if (consumer_ptr == i.second) { | |||
| //! release use of shm_mem, then other consumer can use it | |||
| i.second = nullptr; | |||
| return; | |||
| } | |||
| } | |||
| LITE_THROW( | |||
| "error happened!!, can not find any consumer_ptr in " | |||
| "m_shm_ptr2consumer_ptr"); | |||
| }; | |||
| } // namespace ipc | |||
| @@ -0,0 +1,101 @@ | |||
| #pragma once | |||
| #include <cstdio> | |||
| #include <cstring> | |||
| #include <map> | |||
| #include <string> | |||
| #include <unordered_map> | |||
| #include "ipc_imp.h" | |||
| #define IPC_INSTACE() ipc::IpcHelper::Instance() | |||
| #define IPC_HELP_REMOTE_CALL(SHM_PTR, REMOTEFUNCID) \ | |||
| struct ipc_imp::MsgBody msg; \ | |||
| msg.type = ipc_imp::IPC_CALL_REMOTE_API; \ | |||
| msg.shm_ptr = static_cast<void*>(SHM_PTR); \ | |||
| msg.remote_func_id = static_cast<size_t>(REMOTEFUNCID); \ | |||
| IPC_INSTACE().send_ipc_msg(&msg); | |||
| #define ASSERT_SHM_SIZE(SHM_SIZE, NEED_SIZE) \ | |||
| do { \ | |||
| if (SHM_SIZE < NEED_SIZE) { \ | |||
| LITE_ERROR( \ | |||
| "shm_size not enough to run this api need vs config: (%fMB " \ | |||
| "%fMB), please config it by env: LITE_DEBUG_IPC_SHM_SIZE, for " \ | |||
| "example config to 20MB by: export LITE_DEBUG_IPC_SHM_SIZE=20", \ | |||
| NEED_SIZE / 1024.0 / 1024.0, SHM_SIZE / 1024.0 / 1024.0); \ | |||
| __builtin_trap(); \ | |||
| } \ | |||
| } while (0) | |||
| namespace ipc { | |||
| template <class T> | |||
| class Singleton { | |||
| public: | |||
| Singleton() {} | |||
| static T& Instance() { | |||
| static T _; | |||
| return _; | |||
| } | |||
| }; | |||
| class IpcHelper : public Singleton<IpcHelper> { | |||
| public: | |||
| IpcHelper(const IpcHelper&) = delete; | |||
| IpcHelper& operator=(const IpcHelper&) = delete; | |||
| IpcHelper(); | |||
| ~IpcHelper(); | |||
| //! send msg with default timeout | |||
| struct ipc_imp::MsgBody send_ipc_msg(struct ipc_imp::MsgBody* msg) { | |||
| return send_msg(msg, &tv); | |||
| } | |||
| //! get shm ptr | |||
| void* get_shm_ptr(void* consumer_ptr); | |||
| //! release shm_ptr, NOT free shm_ptr | |||
| void release_shm_ptr(void* consumer_ptr); | |||
| //! check shm size | |||
| void check_shm_size(size_t need_size) { ASSERT_SHM_SIZE(shm_size, need_size); } | |||
| //! is enable ipc fork debug mode | |||
| static bool is_enable_fork_debug_mode() { return sm_is_enable_fork_ipc; } | |||
| static bool sm_is_enable_fork_ipc; | |||
| private: | |||
| //! 5 minutes | |||
| struct timeval tv = {300, 0}; | |||
| //! map of <shm_ptr, consumer_ptr>, | |||
| std::map<void*, void*> m_shm_ptr2consumer_ptr; | |||
| size_t shm_size = 0; | |||
| //! shm_mem for consumer_ptr == nullptr | |||
| void* shm_mem_for_null_consumer_ptr; | |||
| LITE_MUTEX m_mtx; | |||
| }; | |||
| enum class RemoteFuncId : size_t { | |||
| LITE_MAKE_NETWORK = 1, | |||
| LITE_LOAD_MODEL_FROM_PATH = 2, | |||
| LITE_GET_LAST_ERROR = 3, | |||
| LITE_GET_IO_TENSOR = 4, | |||
| LITE_GET_TENSOR_TOTAL_SIZE_IN_BYTE = 5, | |||
| LITE_GET_TENSOR_MEMORY = 6, | |||
| LITE_MEMSET = 7, | |||
| LITE_FORWARD = 8, | |||
| LITE_WAIT = 9, | |||
| LITE_GET_OUTPUT_NAME = 10, | |||
| LITE_COPY_SERVER_TENSOR_MEMORY = 11, | |||
| LITE_DESTROY_NETWORK = 12, | |||
| }; | |||
| } // namespace ipc | |||
| @@ -0,0 +1,370 @@ | |||
| #include "ipc_imp.h" | |||
| #if __linux__ | |||
| #include <sys/prctl.h> | |||
| #include <sys/wait.h> | |||
| #endif | |||
| #ifdef __ANDROID__ | |||
| #include <android/log.h> | |||
| #include <sys/system_properties.h> | |||
| #endif | |||
| namespace ipc_imp { | |||
| namespace { | |||
| //! max count if shm | |||
| #define MAX_SHM_COUNT 15 | |||
| struct ServerConfig { | |||
| #ifdef _LITE_SUPPORT_IPC | |||
| pid_t server_id; | |||
| #else | |||
| size_t server_id; | |||
| #endif | |||
| void* cb; | |||
| int fd_s[2]; | |||
| int fd_c[2]; | |||
| fd_set select_s; | |||
| fd_set select_c; | |||
| void* shm_ptr[MAX_SHM_COUNT]; | |||
| size_t shm_mem_conut; | |||
| //! all shm use the same shm_size | |||
| size_t shm_size; | |||
| }; | |||
| static LITE_MUTEX m_mtx; | |||
| static ServerConfig server_config; | |||
| #ifdef _LITE_SUPPORT_IPC | |||
| static size_t config_shm_memory() { | |||
| //! default config to 10MB | |||
| size_t shm_size = 10 * 1024 * 1024; | |||
| //! env to config LITE_DEBUG_IPC_SHM_SIZE | |||
| //! for example , export LITE_DEBUG_IPC_SHM_SIZE=20, means config SHM size 20MB | |||
| if (auto env = ::std::getenv("LITE_DEBUG_IPC_SHM_SIZE")) | |||
| shm_size = std::stoi(env) * 1024 * 1024; | |||
| #ifdef __ANDROID__ | |||
| //! special for Android prop, attention: getprop may need permission | |||
| char buf[PROP_VALUE_MAX]; | |||
| if (__system_property_get("LITE_DEBUG_IPC_SHM_SIZE", buf) > 0) { | |||
| shm_size = std::stoi(buf) * 1024 * 1024; | |||
| } | |||
| #endif | |||
| return shm_size; | |||
| } | |||
| //! FIXME: detail at create_server(), at this stage, we only support enable lite fork | |||
| //! debug by: LITE_enable_lite_ipc_debug, after issue fix, may support env: | |||
| //! LITE_ENABLE_C_API_WITH_FORK_MODE | |||
| // bool config_enable_debug_fork() { | |||
| // //! debug off, we only support enable fork debug mode with env | |||
| // //! LITE_ENABLE_C_API_WITH_FORK_MODE, not support api to config | |||
| // //! as we will fork as soon as possible by __attribute__((constructor)), | |||
| // //! user may not have to chance to call any normal api before it | |||
| // bool ret = false; | |||
| // //! env to config LITE_ENABLE_C_API_WITH_FORK_MODE | |||
| // //! for example , export LITE_ENABLE_C_API_WITH_FORK_MODE=1, means enable LITE c | |||
| // api | |||
| // //! with fork mode | |||
| // if (auto env = ::std::getenv("LITE_ENABLE_C_API_WITH_FORK_MODE")) { | |||
| // if (std::stoi(env) > 0) { | |||
| // ret = true; | |||
| // } | |||
| // } | |||
| // | |||
| //#ifdef __ANDROID__ | |||
| // //! special for Android prop, attention: getprop may need permission | |||
| // char buf[PROP_VALUE_MAX]; | |||
| // if (__system_property_get("LITE_ENABLE_C_API_WITH_FORK_MODE", buf) > 0) { | |||
| // ret = std::stoi(buf); | |||
| // if (std::stoi(buf) > 0) { | |||
| // ret = true; | |||
| // } | |||
| // } | |||
| //#endif | |||
| // | |||
| // return ret; | |||
| //} | |||
| #endif | |||
| static bool is_enable_debug_fork = false; | |||
| //! internal recycle server when IPC_ASSERT happen | |||
| static void recycle_server() { | |||
| static struct timeval tv = {1, 0}; | |||
| struct MsgBody msg; | |||
| msg.type = IPC_SERVER_EXIT; | |||
| if (server_config.server_id > 0) { | |||
| send_msg(&msg, &tv); | |||
| } | |||
| } | |||
| #define ipc_unlikely(v) __builtin_expect((v), 0) | |||
| #define IPC_ASSERT(expr, msg) \ | |||
| do { \ | |||
| if (ipc_unlikely(!(expr))) { \ | |||
| LITE_ERROR("ipc fatal error: assert failed: %s with msg: %s", #expr, msg); \ | |||
| recycle_server(); \ | |||
| __builtin_trap(); \ | |||
| } \ | |||
| } while (0) | |||
| #ifdef _LITE_SUPPORT_IPC | |||
| static size_t config_shm_memory_count() { | |||
| //! default config to 2 | |||
| size_t shm_cnt = 2; | |||
| //! env to config LITE_DEBUG_IPC_SHM_COUNT | |||
| //! for example , export LITE_DEBUG_IPC_SHM_COUNT=8, means config SHM count 8 | |||
| if (auto env = ::std::getenv("LITE_DEBUG_IPC_SHM_COUNT")) | |||
| shm_cnt = std::stoi(env); | |||
| #ifdef __ANDROID__ | |||
| //! special for Android prop, attention: getprop may need permission | |||
| char buf[PROP_VALUE_MAX]; | |||
| if (__system_property_get("LITE_DEBUG_IPC_SHM_COUNT", buf) > 0) { | |||
| shm_cnt = std::stoi(buf); | |||
| } | |||
| #endif | |||
| IPC_ASSERT( | |||
| shm_cnt >= 2 && shm_cnt <= MAX_SHM_COUNT, | |||
| "error config LITE_DEBUG_IPC_SHM_COUNT, should be range of [2, " | |||
| "MAX_SHM_COUNT]"); | |||
| return shm_cnt; | |||
| } | |||
| #endif | |||
| #ifdef _LITE_SUPPORT_IPC | |||
| static void handle_remote_call(struct MsgBody* msg) { | |||
| LITE_DEBUG("into %s: %d", __func__, __LINE__); | |||
| IPC_ASSERT( | |||
| server_config.cb, | |||
| "handle_remote_call failed: can not find valid " | |||
| "remote_call_cb, please call " | |||
| "register_remote_call_cb firstly!!"); | |||
| remote_call_cb cb = (remote_call_cb)server_config.cb; | |||
| cb(msg); | |||
| } | |||
| static void* ipc_mmap( | |||
| void* addr, size_t length, int prot, int flags, int fd, off_t offset) { | |||
| void* ret = mmap(addr, length, prot, flags, fd, offset); | |||
| IPC_ASSERT(ret != MAP_FAILED, "call mmap failed"); | |||
| return ret; | |||
| } | |||
| static int ipc_munmap(void* addr, size_t length) { | |||
| int ret = munmap(addr, length); | |||
| IPC_ASSERT(0 == ret, "call munmap failed"); | |||
| return ret; | |||
| } | |||
| #endif | |||
| //! start server as soon as possible | |||
| //! FIXME: when use __attribute__((constructor)) on clang, will init before all | |||
| //! static class object, which will lead to flatbuffer runtime issue, env config | |||
| //! with init_priority, do not take effect on diff cpp src file on clang | |||
| // static __attribute__((constructor)) void create_server() { | |||
| void create_server() { | |||
| #ifdef _LITE_SUPPORT_IPC | |||
| LITE_LOCK_GUARD(m_mtx); | |||
| LITE_LOG("try to config lite fork debug model"); | |||
| if (is_enable_debug_fork) | |||
| return; | |||
| is_enable_debug_fork = true; | |||
| //! is_enable_debug_fork = config_enable_debug_fork(); | |||
| //! init default server_config | |||
| server_config.server_id = 0; | |||
| if (!is_enable_debug_fork) | |||
| return; | |||
| server_config.cb = nullptr; | |||
| server_config.shm_size = config_shm_memory(); | |||
| server_config.shm_mem_conut = config_shm_memory_count(); | |||
| for (size_t i = 0; i < server_config.shm_mem_conut; i++) { | |||
| server_config.shm_ptr[i] = ipc_mmap( | |||
| NULL, server_config.shm_size, PROT_READ | PROT_WRITE, | |||
| MAP_SHARED | MAP_ANON, -1, 0); | |||
| } | |||
| IPC_ASSERT(-1 != pipe(server_config.fd_s), "create server pipe failed"); | |||
| IPC_ASSERT(-1 != pipe(server_config.fd_c), "create client pipe failed"); | |||
| FD_ZERO(&server_config.select_s); | |||
| FD_ZERO(&server_config.select_c); | |||
| //! config server and client | |||
| FD_SET(server_config.fd_s[0], &server_config.select_s); | |||
| FD_SET(server_config.fd_c[0], &server_config.select_c); | |||
| server_config.server_id = fork(); | |||
| IPC_ASSERT(server_config.server_id >= 0, "call fork failed"); | |||
| if (server_config.server_id > 0) { | |||
| LITE_LOG("create lite_ipc_server success pid is: %d", server_config.server_id); | |||
| } else { | |||
| std::string server_name = "lite_ipc_server"; | |||
| // TODO: __APPLE__ do not support PR_SET_NAME and PR_SET_PDEATHSIG | |||
| // if caller crash, no have chance to send IPC_SERVER_EXIT | |||
| #if __linux__ | |||
| LITE_LOG("start server with name: %s....", server_name.c_str()); | |||
| prctl(PR_SET_NAME, (unsigned long)server_name.c_str(), 0, 0, 0); | |||
| //! auto die if father crash | |||
| prctl(PR_SET_PDEATHSIG, SIGKILL); | |||
| #else | |||
| LITE_LOG("start server...."); | |||
| #endif | |||
| while (1) { | |||
| LITE_DEBUG("lite_ipc_server wait msg now....."); | |||
| int res = | |||
| select(server_config.fd_s[0] + 1, &server_config.select_s, NULL, | |||
| NULL, NULL); | |||
| IPC_ASSERT( | |||
| res > 0, | |||
| "select issue happened or timeout(but we do not support timeout)"); | |||
| struct MsgBody msg; | |||
| size_t r_size = read(server_config.fd_s[0], &msg, sizeof(msg)); | |||
| IPC_ASSERT(r_size == sizeof(msg), "broken pipe msg"); | |||
| struct MsgBody response; | |||
| response.type = IPC_SERVER_RESPONSE; | |||
| switch (msg.type) { | |||
| case IPC_CALL_REMOTE_API: | |||
| LITE_DEBUG("handle remote call"); | |||
| handle_remote_call(&msg); | |||
| break; | |||
| case IPC_CONFIG_REMOTE_HANDLE_API: | |||
| LITE_DEBUG("handle register remote cb"); | |||
| server_config.cb = msg.cb; | |||
| break; | |||
| default: | |||
| IPC_ASSERT(IPC_SERVER_EXIT == msg.type, "code issue happened!!"); | |||
| } | |||
| size_t w_size = write(server_config.fd_c[1], &response, sizeof(response)); | |||
| IPC_ASSERT(w_size == sizeof(response), "write pip failed"); | |||
| if (IPC_SERVER_EXIT == msg.type) { | |||
| LITE_DEBUG("handle exit now"); | |||
| for (size_t i = 0; i < server_config.shm_mem_conut; i++) { | |||
| ipc_munmap(server_config.shm_ptr[i], server_config.shm_size); | |||
| } | |||
| exit(0); | |||
| } | |||
| } | |||
| } | |||
| #else | |||
| //! TODO: imp for Windows with CreateProcess | |||
| server_config.server_id = 0; | |||
| LITE_ERROR("lite do not support fork debug ipc on this PLATFORM"); | |||
| __builtin_trap(); | |||
| return; | |||
| #endif | |||
| } | |||
| } // namespace | |||
| //////////////////////////////////////////////// api imp ///////////////////////// | |||
| void register_remote_call_cb(remote_call_cb cb) { | |||
| IPC_ASSERT(!server_config.cb, "already register remote_call_cb"); | |||
| IPC_ASSERT(cb, "invalid remote_call_cb"); | |||
| IPC_ASSERT(server_config.server_id, "register cb need server already up"); | |||
| server_config.cb = (void*)cb; | |||
| static struct timeval tv = {5, 0}; | |||
| struct MsgBody msg; | |||
| msg.type = IPC_CONFIG_REMOTE_HANDLE_API; | |||
| msg.cb = (void*)cb; | |||
| send_msg(&msg, &tv); | |||
| } | |||
| struct MsgBody send_msg(struct MsgBody* msg, struct timeval* timeout) { | |||
| #ifdef _LITE_SUPPORT_IPC | |||
| IPC_ASSERT(server_config.server_id > 0, "server not ready"); | |||
| if (IPC_CALL_REMOTE_API == msg->type) { | |||
| IPC_ASSERT( | |||
| server_config.cb, | |||
| "can not find valid remote_call_cb, please " | |||
| "call register_remote_call_cb firstly!!"); | |||
| } | |||
| //! send msg to server | |||
| size_t w_size = write(server_config.fd_s[1], msg, sizeof(struct MsgBody)); | |||
| IPC_ASSERT(w_size == sizeof(struct MsgBody), "write pipe failed"); | |||
| //! now wait server response | |||
| struct MsgBody response; | |||
| LITE_DEBUG("wait server response"); | |||
| int res = select( | |||
| server_config.fd_c[0] + 1, &server_config.select_c, NULL, NULL, timeout); | |||
| if (0 == res) { | |||
| LITE_ERROR("wait server timeout"); | |||
| } | |||
| IPC_ASSERT(res > 0, "select issue happened or timeout"); | |||
| size_t r_size = read(server_config.fd_c[0], &response, sizeof(response)); | |||
| IPC_ASSERT(sizeof(response) == r_size, "broken pipe msg"); | |||
| IPC_ASSERT(IPC_SERVER_RESPONSE == response.type, "error server response type"); | |||
| return response; | |||
| #else | |||
| struct MsgBody response; | |||
| LITE_ERROR("This code should not be called"); | |||
| __builtin_trap(); | |||
| return response; | |||
| #endif | |||
| } | |||
| bool is_server() { | |||
| return !server_config.server_id; | |||
| } | |||
| bool is_enable_ipc() { | |||
| return is_enable_debug_fork; | |||
| } | |||
| void join_server() { | |||
| #ifdef _LITE_SUPPORT_IPC | |||
| if (!is_enable_debug_fork) | |||
| return; | |||
| int ret; | |||
| waitpid(server_config.server_id, &ret, 0); | |||
| if (ret) { | |||
| //! when server crash, we mark server_config.server_id to 0 | |||
| //! to prevent handle more msg, for example recycle_server | |||
| server_config.server_id = 0; | |||
| } | |||
| IPC_ASSERT( | |||
| ret == 0, "child process exit !zero, please check server log for detail"); | |||
| #endif | |||
| } | |||
| void* base_get_shm_ptr(size_t index) { | |||
| return server_config.shm_ptr[index]; | |||
| } | |||
| size_t base_get_shm_count() { | |||
| return server_config.shm_mem_conut; | |||
| } | |||
| size_t base_get_shm_size() { | |||
| return server_config.shm_size; | |||
| } | |||
| void enable_lite_ipc_debug() { | |||
| create_server(); | |||
| } | |||
| } // namespace ipc_imp | |||
| @@ -0,0 +1,63 @@ | |||
| #pragma once | |||
| #undef _LITE_SUPPORT_IPC | |||
| #if __linux__ || __unix__ || __APPLE__ | |||
| #define _LITE_SUPPORT_IPC | |||
| #endif | |||
| #ifdef _LITE_SUPPORT_IPC | |||
| #include <sys/mman.h> | |||
| #include <sys/time.h> | |||
| #include <sys/types.h> | |||
| #endif | |||
| #include "misc.h" | |||
| namespace ipc_imp { | |||
| //! server call api ret | |||
| enum MsgType { | |||
| IPC_SERVER_RESPONSE = 1, | |||
| IPC_CALL_REMOTE_API = 2, | |||
| IPC_SERVER_EXIT = 3, | |||
| IPC_CONFIG_REMOTE_HANDLE_API = 4, | |||
| }; | |||
| struct MsgBody { | |||
| enum MsgType type; | |||
| //! remote call handle callback | |||
| void* cb; | |||
| //! remote call function emum, define by user | |||
| size_t remote_func_id; | |||
| //! mmap region ptr | |||
| void* shm_ptr; | |||
| }; | |||
| //! block wait server return response msg | |||
| struct MsgBody send_msg(struct MsgBody* msg, struct timeval* timeout); | |||
| //! wait server exit | |||
| void join_server(); | |||
| typedef void (*remote_call_cb)(struct MsgBody* msg); | |||
| //! register remote call | |||
| void register_remote_call_cb(remote_call_cb cb); | |||
| //! is server or not, server or do not enable ipc mode will return true | |||
| bool is_server(); | |||
| //! is enable ipc or not | |||
| bool is_enable_ipc(); | |||
| //! get shm ptr | |||
| void* base_get_shm_ptr(size_t index); | |||
| //! get shm count | |||
| size_t base_get_shm_count(); | |||
| // get shm size | |||
| size_t base_get_shm_size(); | |||
| // enable fork ipc debug | |||
| void enable_lite_ipc_debug(); | |||
| } // namespace ipc_imp | |||
| @@ -1,5 +1,6 @@ | |||
| #include "lite/network.h" | |||
| #include "common.h" | |||
| #include "ipc_helper.h" | |||
| #include "lite-c/network_c.h" | |||
| #include "../../src/network_impl_base.h" | |||
| @@ -204,11 +205,32 @@ int LITE_make_network( | |||
| LiteNetwork* network, const LiteConfig config, const LiteNetworkIO network_io) { | |||
| LITE_CAPI_BEGIN(); | |||
| LITE_ASSERT(network, "The network pass to LITE api is null"); | |||
| auto lite_network = std::make_shared<lite::Network>( | |||
| convert_to_lite_config(config), convert_to_lite_io(network_io)); | |||
| LITE_LOCK_GUARD(mtx_network); | |||
| get_gloabl_network_holder()[lite_network.get()] = lite_network; | |||
| *network = lite_network.get(); | |||
| if (ipc_imp::is_server()) { | |||
| auto lite_network = std::make_shared<lite::Network>( | |||
| convert_to_lite_config(config), convert_to_lite_io(network_io)); | |||
| LITE_LOCK_GUARD(mtx_network); | |||
| get_gloabl_network_holder()[lite_network.get()] = lite_network; | |||
| *network = lite_network.get(); | |||
| } else { | |||
| size_t need_size = sizeof(LiteConfig) + sizeof(LiteNetworkIO); | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(nullptr); | |||
| //! second args is const LiteConfig config | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &config, sizeof(LiteConfig)); | |||
| //! third args is network_io | |||
| memcpy(shm_ptr_c + sizeof(LiteNetworkIO), &network_io, sizeof(LiteNetworkIO)); | |||
| IPC_HELP_REMOTE_CALL(raw_shm_ptr, ipc::RemoteFuncId::LITE_MAKE_NETWORK); | |||
| int* ret_ptr = static_cast<int*>(raw_shm_ptr); | |||
| auto ret = *ret_ptr; | |||
| ret_ptr++; | |||
| memcpy(network, ret_ptr, sizeof(LiteNetwork)); | |||
| return ret; | |||
| } | |||
| LITE_CAPI_END(); | |||
| } | |||
| @@ -234,17 +256,53 @@ int LITE_load_model_from_path(LiteNetwork network, const char* model_path) { | |||
| LITE_CAPI_BEGIN(); | |||
| LITE_ASSERT(network, "The network pass to LITE api is null"); | |||
| LITE_ASSERT(model_path, "The model path pass to LITE api is null"); | |||
| static_cast<lite::Network*>(network)->load_model(model_path); | |||
| if (ipc_imp::is_server()) { | |||
| static_cast<lite::Network*>(network)->load_model(model_path); | |||
| } else { | |||
| size_t need_size = sizeof(LiteNetwork) + strlen(model_path) + 1; | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(network); | |||
| //! first args is LiteNetwork network | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &network, sizeof(LiteNetwork)); | |||
| //! second args is const char* model_path | |||
| strcpy(shm_ptr_c + sizeof(LiteNetwork), model_path); | |||
| IPC_HELP_REMOTE_CALL(raw_shm_ptr, ipc::RemoteFuncId::LITE_LOAD_MODEL_FROM_PATH); | |||
| int* ret_ptr = static_cast<int*>(raw_shm_ptr); | |||
| auto ret = *ret_ptr; | |||
| return ret; | |||
| } | |||
| LITE_CAPI_END(); | |||
| } | |||
| int LITE_destroy_network(LiteNetwork network) { | |||
| LITE_CAPI_BEGIN(); | |||
| LITE_ASSERT(network, "The network pass to LITE api is null"); | |||
| LITE_LOCK_GUARD(mtx_network); | |||
| auto& global_holder = get_gloabl_network_holder(); | |||
| if (global_holder.find(network) != global_holder.end()) { | |||
| global_holder.erase(network); | |||
| if (ipc_imp::is_server()) { | |||
| LITE_LOCK_GUARD(mtx_network); | |||
| auto& global_holder = get_gloabl_network_holder(); | |||
| if (global_holder.find(network) != global_holder.end()) { | |||
| global_holder.erase(network); | |||
| } | |||
| } else { | |||
| size_t need_size = sizeof(LiteNetwork); | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(network); | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &network, sizeof(LiteNetwork)); | |||
| IPC_HELP_REMOTE_CALL(raw_shm_ptr, ipc::RemoteFuncId::LITE_DESTROY_NETWORK); | |||
| int* ret_ptr = static_cast<int*>(raw_shm_ptr); | |||
| auto ret = *ret_ptr; | |||
| ret_ptr++; | |||
| return ret; | |||
| } | |||
| LITE_CAPI_END(); | |||
| } | |||
| @@ -252,14 +310,48 @@ int LITE_destroy_network(LiteNetwork network) { | |||
| int LITE_forward(const LiteNetwork network) { | |||
| LITE_CAPI_BEGIN(); | |||
| LITE_ASSERT(network, "The network pass to LITE api is null"); | |||
| static_cast<lite::Network*>(network)->forward(); | |||
| if (ipc_imp::is_server()) { | |||
| static_cast<lite::Network*>(network)->forward(); | |||
| } else { | |||
| size_t need_size = sizeof(LiteNetwork); | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(network); | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &network, sizeof(LiteNetwork)); | |||
| IPC_HELP_REMOTE_CALL(raw_shm_ptr, ipc::RemoteFuncId::LITE_FORWARD); | |||
| int* ret_ptr = static_cast<int*>(raw_shm_ptr); | |||
| auto ret = *ret_ptr; | |||
| ret_ptr++; | |||
| return ret; | |||
| } | |||
| LITE_CAPI_END(); | |||
| } | |||
| int LITE_wait(const LiteNetwork network) { | |||
| LITE_CAPI_BEGIN(); | |||
| LITE_ASSERT(network, "The network pass to LITE api is null"); | |||
| static_cast<lite::Network*>(network)->wait(); | |||
| if (ipc_imp::is_server()) { | |||
| static_cast<lite::Network*>(network)->wait(); | |||
| } else { | |||
| size_t need_size = sizeof(LiteNetwork); | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(network); | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &network, sizeof(LiteNetwork)); | |||
| IPC_HELP_REMOTE_CALL(raw_shm_ptr, ipc::RemoteFuncId::LITE_WAIT); | |||
| int* ret_ptr = static_cast<int*>(raw_shm_ptr); | |||
| auto ret = *ret_ptr; | |||
| ret_ptr++; | |||
| return ret; | |||
| } | |||
| LITE_CAPI_END(); | |||
| } | |||
| @@ -268,9 +360,31 @@ int LITE_get_io_tensor( | |||
| LiteTensor* tensor) { | |||
| LITE_CAPI_BEGIN(); | |||
| LITE_ASSERT(network, "The network pass to LITE api is null"); | |||
| auto io_tensor = | |||
| static_cast<lite::Network*>(network)->get_io_tensor(io_name, phase); | |||
| *tensor = io_tensor.get(); | |||
| if (ipc_imp::is_server()) { | |||
| auto io_tensor = | |||
| static_cast<lite::Network*>(network)->get_io_tensor(io_name, phase); | |||
| *tensor = io_tensor.get(); | |||
| } else { | |||
| size_t need_size = | |||
| sizeof(LiteNetwork) + strlen(io_name) + 1 + sizeof(LiteTensorPhase); | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(network); | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &network, sizeof(LiteNetwork)); | |||
| memcpy(shm_ptr_c + sizeof(LiteNetwork), &phase, sizeof(LiteTensorPhase)); | |||
| strcpy(shm_ptr_c + sizeof(LiteNetwork) + sizeof(LiteTensorPhase), io_name); | |||
| IPC_HELP_REMOTE_CALL(raw_shm_ptr, ipc::RemoteFuncId::LITE_GET_IO_TENSOR); | |||
| int* ret_ptr = static_cast<int*>(raw_shm_ptr); | |||
| auto ret = *ret_ptr; | |||
| ret_ptr++; | |||
| memcpy(tensor, ret_ptr, sizeof(LiteTensor)); | |||
| IPC_INSTACE().release_shm_ptr(network); | |||
| return ret; | |||
| } | |||
| LITE_CAPI_END(); | |||
| } | |||
| @@ -286,8 +400,31 @@ int LITE_get_output_name(const LiteNetwork network, size_t index, const char** n | |||
| LITE_CAPI_BEGIN(); | |||
| LITE_ASSERT(network, "The network pass to LITE api is null"); | |||
| LITE_ASSERT(name, "The name ptr pass to LITE api is null"); | |||
| *name = lite::NetworkHelper::implement(static_cast<lite::Network*>(network)) | |||
| ->get_output_name(index); | |||
| if (ipc_imp::is_server()) { | |||
| *name = lite::NetworkHelper::implement(static_cast<lite::Network*>(network)) | |||
| ->get_output_name(index); | |||
| } else { | |||
| size_t need_size = sizeof(LiteNetwork) + sizeof(index); | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| //! warn: we use get_shm_ptr with nullptr, not with network | |||
| //! so caller need consume this ptr as soon as possible | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(nullptr); | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &network, sizeof(LiteNetwork)); | |||
| memcpy(shm_ptr_c + sizeof(LiteNetwork), &index, sizeof(size_t)); | |||
| IPC_HELP_REMOTE_CALL(raw_shm_ptr, ipc::RemoteFuncId::LITE_GET_OUTPUT_NAME); | |||
| int* ret_ptr = static_cast<int*>(raw_shm_ptr); | |||
| auto ret = *ret_ptr; | |||
| ret_ptr++; | |||
| void* p = static_cast<void*>(ret_ptr); | |||
| char* p_c = static_cast<char*>(p); | |||
| *name = p_c; | |||
| return ret; | |||
| } | |||
| LITE_CAPI_END(); | |||
| } | |||
| @@ -4,6 +4,7 @@ | |||
| #include <unordered_map> | |||
| #include "../../src/tensor_impl_base.h" | |||
| #include "common.h" | |||
| #include "ipc_helper.h" | |||
| #include "lite-c/tensor_c.h" | |||
| const LiteLayout default_layout = { | |||
| @@ -166,7 +167,70 @@ int LITE_get_tensor_memory(const LiteTensor tensor, void** data) { | |||
| LITE_CAPI_BEGIN(); | |||
| LITE_ASSERT(tensor, "The tensor pass to LITE c_api is null"); | |||
| LITE_ASSERT(data, "The data ptr pass to LITE c_api is null"); | |||
| *data = static_cast<lite::Tensor*>(tensor)->get_memory_ptr(); | |||
| if (ipc_imp::is_server()) { | |||
| *data = static_cast<lite::Tensor*>(tensor)->get_memory_ptr(); | |||
| } else { | |||
| size_t need_size = sizeof(LiteTensor); | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(nullptr); | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &tensor, sizeof(LiteTensor)); | |||
| IPC_HELP_REMOTE_CALL(raw_shm_ptr, ipc::RemoteFuncId::LITE_GET_TENSOR_MEMORY); | |||
| int* ret_ptr = static_cast<int*>(raw_shm_ptr); | |||
| auto ret = *ret_ptr; | |||
| ret_ptr++; | |||
| memcpy(data, ret_ptr, sizeof(void*)); | |||
| return ret; | |||
| } | |||
| LITE_CAPI_END(); | |||
| } | |||
| void* LITE_memset(void* s, int c, size_t n) { | |||
| if (ipc_imp::is_server()) { | |||
| return memset(s, c, n); | |||
| } else { | |||
| size_t need_size = sizeof(void*) + sizeof(int) + sizeof(size_t); | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(nullptr); | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &s, sizeof(void*)); | |||
| memcpy(shm_ptr_c + sizeof(void*), &c, sizeof(int)); | |||
| memcpy(shm_ptr_c + sizeof(void*) + sizeof(int), &n, sizeof(size_t)); | |||
| IPC_HELP_REMOTE_CALL(raw_shm_ptr, ipc::RemoteFuncId::LITE_MEMSET); | |||
| return s; | |||
| } | |||
| } | |||
| int LITE_copy_server_tensor_memory( | |||
| void* server_ptr, void* client_ptr, size_t size_in_byte) { | |||
| LITE_CAPI_BEGIN(); | |||
| if (ipc_imp::is_server()) { | |||
| LITE_ASSERT( | |||
| false, "lite not in fork debug mode, please do not call this function"); | |||
| } else { | |||
| size_t need_size = sizeof(void*) + sizeof(size_t); | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| IPC_INSTACE().check_shm_size(size_in_byte); | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(nullptr); | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &server_ptr, sizeof(void*)); | |||
| memcpy(shm_ptr_c + sizeof(void*), &size_in_byte, sizeof(size_t)); | |||
| IPC_HELP_REMOTE_CALL( | |||
| raw_shm_ptr, ipc::RemoteFuncId::LITE_COPY_SERVER_TENSOR_MEMORY); | |||
| memcpy(client_ptr, raw_shm_ptr, size_in_byte); | |||
| return 0; | |||
| } | |||
| LITE_CAPI_END(); | |||
| } | |||
| @@ -186,7 +250,26 @@ int LITE_get_tensor_total_size_in_byte(const LiteTensor tensor, size_t* size) { | |||
| LITE_CAPI_BEGIN(); | |||
| LITE_ASSERT(tensor, "The tensor pass to LITE c_api is null"); | |||
| LITE_ASSERT(size, "The size ptr pass to LITE c_api is null"); | |||
| *size = static_cast<lite::Tensor*>(tensor)->get_tensor_total_size_in_byte(); | |||
| if (ipc_imp::is_server()) { | |||
| *size = static_cast<lite::Tensor*>(tensor)->get_tensor_total_size_in_byte(); | |||
| } else { | |||
| size_t need_size = sizeof(LiteTensor); | |||
| IPC_INSTACE().check_shm_size(need_size); | |||
| void* raw_shm_ptr = IPC_INSTACE().get_shm_ptr(nullptr); | |||
| char* shm_ptr_c = static_cast<char*>(raw_shm_ptr); | |||
| memcpy(shm_ptr_c, &tensor, sizeof(LiteTensor)); | |||
| IPC_HELP_REMOTE_CALL( | |||
| raw_shm_ptr, ipc::RemoteFuncId::LITE_GET_TENSOR_TOTAL_SIZE_IN_BYTE); | |||
| int* ret_ptr = static_cast<int*>(raw_shm_ptr); | |||
| auto ret = *ret_ptr; | |||
| ret_ptr++; | |||
| memcpy(size, ret_ptr, sizeof(size_t)); | |||
| return ret; | |||
| } | |||
| LITE_CAPI_END(); | |||
| } | |||
| @@ -11,6 +11,7 @@ | |||
| #ifdef __ANDROID__ | |||
| #include <android/log.h> | |||
| #include <sys/system_properties.h> | |||
| #endif | |||
| using namespace lite; | |||
| @@ -18,7 +19,26 @@ using namespace lite; | |||
| namespace lite { | |||
| namespace log_detail { | |||
| LiteLogLevel current_log_level = LiteLogLevel::ERROR; | |||
| LiteLogLevel config_default_log_level() { | |||
| auto default_level = LiteLogLevel::ERROR; | |||
| //! env to config LogLevel | |||
| //! DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3, NO_LOG = 4 | |||
| //! for example , export RUNTIME_OVERRIDE_LOG_LEVEL=0, means set LogLevel to | |||
| //! DEBUG | |||
| if (auto env = ::std::getenv("RUNTIME_OVERRIDE_LOG_LEVEL")) | |||
| default_level = static_cast<LiteLogLevel>(std::stoi(env)); | |||
| #ifdef __ANDROID__ | |||
| //! special for Android prop, attention: getprop may need permission | |||
| char buf[PROP_VALUE_MAX]; | |||
| if (__system_property_get("RUNTIME_OVERRIDE_LOG_LEVEL", buf) > 0) { | |||
| default_level = static_cast<LiteLogLevel>(atoi(buf)); | |||
| } | |||
| #endif | |||
| return default_level; | |||
| } | |||
| LiteLogLevel current_log_level = config_default_log_level(); | |||
| template <class T, size_t N> | |||
| constexpr size_t countof(T (&)[N]) { | |||