feat(lite): support base lite ipc fork debugdev-support-lite-fork-debug-mode
@@ -14,6 +14,7 @@ | |||||
#include "lite-c/tensor_c.h" | #include "lite-c/tensor_c.h" | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | |||||
#include <string.h> | #include <string.h> | ||||
#define LITE_CAPI_CHECK(_expr) \ | #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_get_tensor_total_size_in_byte(c_input_tensor, &length_in_byte)); | ||||
LITE_CAPI_CHECK(LITE_get_tensor_memory(c_input_tensor, &dst_ptr)); | LITE_CAPI_CHECK(LITE_get_tensor_memory(c_input_tensor, &dst_ptr)); | ||||
//! copy or forward data to network | //! copy or forward data to network | ||||
memset(dst_ptr, 5, length_in_byte); | |||||
LITE_memset(dst_ptr, 5, length_in_byte); | |||||
//! forward | //! forward | ||||
LITE_CAPI_CHECK(LITE_forward(c_network)); | LITE_CAPI_CHECK(LITE_forward(c_network)); | ||||
@@ -66,23 +67,41 @@ int basic_c_interface(const char* mode_path) { | |||||
float max = -1.0f; | float max = -1.0f; | ||||
float sum = 0.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++) { | for (size_t i = 0; i < out_length; i++) { | ||||
float data = ((float*)(output_ptr))[i]; | |||||
float data = final_dst_ptr[i]; | |||||
sum += data; | sum += data; | ||||
if (max < data) | if (max < data) | ||||
max = data; | max = data; | ||||
} | } | ||||
printf("max=%e, sum=%e\n", max, sum); | printf("max=%e, sum=%e\n", max, sum); | ||||
LITE_destroy_network(c_network); | |||||
if (is_enable_ipc_debug) { | |||||
free(copy_ptr); | |||||
} | |||||
return 0; | return 0; | ||||
} | } | ||||
int main(int argc, char** argv) { | 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"); | "build.\n"); | ||||
return -1; | 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}}} | // 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(); | 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 | /*! \brief Get device count | ||||
* \param[in] device_type device type | * \param[in] device_type device type | ||||
* \return the device count | * \return the device count | ||||
@@ -159,6 +159,15 @@ LITE_API int LITE_tensor_share_memory_with( | |||||
LITE_API int LITE_get_tensor_memory(const LiteTensor tensor, void** data); | 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. | * \brief get the memory pointer of a Tensor object. | ||||
* \param[in] tensor The input Tensor | * \param[in] tensor The input Tensor | ||||
* \param[in] index The coordinate in the tensor | * \param[in] index The coordinate in the tensor | ||||
@@ -230,6 +239,11 @@ LITE_API int LITE_tensor_concat( | |||||
LiteTensor* tensors, int nr_tensor, int dim, LiteDeviceType dst_device, | LiteTensor* tensors, int nr_tensor, int dim, LiteDeviceType dst_device, | ||||
int device_id, LiteTensor* result_tensor); | int device_id, LiteTensor* result_tensor); | ||||
/** | |||||
* \brief fuction like memset | |||||
*/ | |||||
LITE_API void* LITE_memset(void* s, int c, size_t n); | |||||
#ifdef __cplusplus | #ifdef __cplusplus | ||||
} | } | ||||
#endif | #endif | ||||
@@ -1,5 +1,6 @@ | |||||
#include "lite/global.h" | #include "lite/global.h" | ||||
#include "common.h" | #include "common.h" | ||||
#include "ipc_helper.h" | |||||
#include "lite-c/global_c.h" | #include "lite-c/global_c.h" | ||||
namespace { | namespace { | ||||
@@ -47,7 +48,24 @@ void LITE_clear_last_error() { | |||||
const char* LITE_get_last_error() { | const char* LITE_get_last_error() { | ||||
LITE_LOCK_GUARD(mtx_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) { | 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 "lite/network.h" | ||||
#include "common.h" | #include "common.h" | ||||
#include "ipc_helper.h" | |||||
#include "lite-c/network_c.h" | #include "lite-c/network_c.h" | ||||
#include "../../src/network_impl_base.h" | #include "../../src/network_impl_base.h" | ||||
@@ -204,11 +205,32 @@ int LITE_make_network( | |||||
LiteNetwork* network, const LiteConfig config, const LiteNetworkIO network_io) { | LiteNetwork* network, const LiteConfig config, const LiteNetworkIO network_io) { | ||||
LITE_CAPI_BEGIN(); | LITE_CAPI_BEGIN(); | ||||
LITE_ASSERT(network, "The network pass to LITE api is null"); | 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(); | LITE_CAPI_END(); | ||||
} | } | ||||
@@ -234,17 +256,53 @@ int LITE_load_model_from_path(LiteNetwork network, const char* model_path) { | |||||
LITE_CAPI_BEGIN(); | LITE_CAPI_BEGIN(); | ||||
LITE_ASSERT(network, "The network pass to LITE api is null"); | LITE_ASSERT(network, "The network pass to LITE api is null"); | ||||
LITE_ASSERT(model_path, "The model path 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(); | LITE_CAPI_END(); | ||||
} | } | ||||
int LITE_destroy_network(LiteNetwork network) { | int LITE_destroy_network(LiteNetwork network) { | ||||
LITE_CAPI_BEGIN(); | LITE_CAPI_BEGIN(); | ||||
LITE_ASSERT(network, "The network pass to LITE api is null"); | 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(); | LITE_CAPI_END(); | ||||
} | } | ||||
@@ -252,14 +310,48 @@ int LITE_destroy_network(LiteNetwork network) { | |||||
int LITE_forward(const LiteNetwork network) { | int LITE_forward(const LiteNetwork network) { | ||||
LITE_CAPI_BEGIN(); | LITE_CAPI_BEGIN(); | ||||
LITE_ASSERT(network, "The network pass to LITE api is null"); | 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(); | LITE_CAPI_END(); | ||||
} | } | ||||
int LITE_wait(const LiteNetwork network) { | int LITE_wait(const LiteNetwork network) { | ||||
LITE_CAPI_BEGIN(); | LITE_CAPI_BEGIN(); | ||||
LITE_ASSERT(network, "The network pass to LITE api is null"); | 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(); | LITE_CAPI_END(); | ||||
} | } | ||||
@@ -268,9 +360,31 @@ int LITE_get_io_tensor( | |||||
LiteTensor* tensor) { | LiteTensor* tensor) { | ||||
LITE_CAPI_BEGIN(); | LITE_CAPI_BEGIN(); | ||||
LITE_ASSERT(network, "The network pass to LITE api is null"); | 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(); | 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_CAPI_BEGIN(); | ||||
LITE_ASSERT(network, "The network pass to LITE api is null"); | LITE_ASSERT(network, "The network pass to LITE api is null"); | ||||
LITE_ASSERT(name, "The name ptr 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(); | LITE_CAPI_END(); | ||||
} | } | ||||
@@ -4,6 +4,7 @@ | |||||
#include <unordered_map> | #include <unordered_map> | ||||
#include "../../src/tensor_impl_base.h" | #include "../../src/tensor_impl_base.h" | ||||
#include "common.h" | #include "common.h" | ||||
#include "ipc_helper.h" | |||||
#include "lite-c/tensor_c.h" | #include "lite-c/tensor_c.h" | ||||
const LiteLayout default_layout = { | const LiteLayout default_layout = { | ||||
@@ -166,7 +167,70 @@ int LITE_get_tensor_memory(const LiteTensor tensor, void** data) { | |||||
LITE_CAPI_BEGIN(); | LITE_CAPI_BEGIN(); | ||||
LITE_ASSERT(tensor, "The tensor pass to LITE c_api is null"); | 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"); | 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(); | 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_CAPI_BEGIN(); | ||||
LITE_ASSERT(tensor, "The tensor pass to LITE c_api is null"); | 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"); | 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(); | LITE_CAPI_END(); | ||||
} | } | ||||
@@ -11,6 +11,7 @@ | |||||
#ifdef __ANDROID__ | #ifdef __ANDROID__ | ||||
#include <android/log.h> | #include <android/log.h> | ||||
#include <sys/system_properties.h> | |||||
#endif | #endif | ||||
using namespace lite; | using namespace lite; | ||||
@@ -18,7 +19,26 @@ using namespace lite; | |||||
namespace lite { | namespace lite { | ||||
namespace log_detail { | 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> | template <class T, size_t N> | ||||
constexpr size_t countof(T (&)[N]) { | constexpr size_t countof(T (&)[N]) { | ||||