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 | |||
@@ -159,6 +159,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 | |||
* \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, | |||
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]) { | |||