diff --git a/api/include/mk_util.h b/api/include/mk_util.h index 32f9da7a..fb79dc82 100644 --- a/api/include/mk_util.h +++ b/api/include/mk_util.h @@ -128,6 +128,15 @@ API_EXPORT char *API_CALL mk_ini_dump_string(mk_ini ini); * @param file 配置文件路径 */ API_EXPORT void API_CALL mk_ini_dump_file(mk_ini ini, const char *file); +///////////////////////////////////////////统计///////////////////////////////////////////// + +typedef void(API_CALL *on_mk_get_statistic_cb)(void *user_data, mk_ini ini); + +/** + * 获取内存数据统计 + * @param ini 存放统计结果 + */ +API_EXPORT void API_CALL mk_get_statistic(on_mk_get_statistic_cb cb, void *user_data, on_user_data_free free_cb); ///////////////////////////////////////////日志///////////////////////////////////////////// diff --git a/api/source/mk_util.cpp b/api/source/mk_util.cpp index eda27162..e2817161 100644 --- a/api/source/mk_util.cpp +++ b/api/source/mk_util.cpp @@ -15,6 +15,9 @@ #include "Util/util.h" #include "Util/mini.h" #include "Util/logger.h" +#include "Util/TimeTicker.h" +#include "Poller/EventPoller.h" +#include "Thread/WorkThreadPool.h" #include "Common/config.h" using namespace std; @@ -132,6 +135,129 @@ API_EXPORT void API_CALL mk_ini_dump_file(mk_ini ini, const char *file) { ptr->dumpFile(file); } +extern uint64_t getTotalMemUsage(); +extern uint64_t getTotalMemBlock(); +extern uint64_t getThisThreadMemUsage(); +extern uint64_t getThisThreadMemBlock(); +extern std::vector getBlockTypeSize(); +extern uint64_t getTotalMemBlockByType(int type); +extern uint64_t getThisThreadMemBlockByType(int type); + +namespace mediakit { +class MediaSource; +class MultiMediaSourceMuxer; +class FrameImp; +class Frame; +class RtpPacket; +class RtmpPacket; +} // namespace mediakit + +namespace toolkit { +class TcpServer; +class TcpSession; +class UdpServer; +class UdpSession; +class TcpClient; +class Socket; +class Buffer; +class BufferRaw; +class BufferLikeString; +class BufferList; +} // namespace toolkit + +API_EXPORT void API_CALL mk_get_statistic(on_mk_get_statistic_cb func, void *user_data, on_user_data_free free_cb) { + assert(func); + std::shared_ptr data(user_data, free_cb); + auto cb = [func, data](const toolkit::mINI &ini) { func(data.get(), (mk_ini)&ini); }; + auto obj = std::make_shared(); + auto &val = *obj; + + val["object.MediaSource"] = ObjectStatistic::count(); + val["object.MultiMediaSourceMuxer"] = ObjectStatistic::count(); + + val["object.TcpServer"] = ObjectStatistic::count(); + val["object.TcpSession"] = ObjectStatistic::count(); + val["object.UdpServer"] = ObjectStatistic::count(); + val["object.UdpSession"] = ObjectStatistic::count(); + val["object.TcpClient"] = ObjectStatistic::count(); + val["object.Socket"] = ObjectStatistic::count(); + + val["object.FrameImp"] = ObjectStatistic::count(); + val["object.Frame"] = ObjectStatistic::count(); + + val["object.Buffer"] = ObjectStatistic::count(); + val["object.BufferRaw"] = ObjectStatistic::count(); + val["object.BufferLikeString"] = ObjectStatistic::count(); + val["object.BufferList"] = ObjectStatistic::count(); + + val["object.RtpPacket"] = ObjectStatistic::count(); + val["object.RtmpPacket"] = ObjectStatistic::count(); +#ifdef ENABLE_MEM_DEBUG + auto bytes = getTotalMemUsage(); + val["memory.memUsage"] = bytes; + val["memory.memUsageMB"] = (int)(bytes / 1024 / 1024); + val["memory.memBlock"] = getTotalMemBlock(); + static auto block_type_size = getBlockTypeSize(); + { + int i = 0; + string str; + size_t last = 0; + for (auto sz : block_type_size) { + str.append(to_string(last) + "~" + to_string(sz) + ":" + to_string(getTotalMemBlockByType(i++)) + ";"); + last = sz; + } + str.pop_back(); + val["memory.memBlockTypeCount"] = str; + } +#endif + + auto thread_size = EventPollerPool::Instance().getExecutorSize() + WorkThreadPool::Instance().getExecutorSize(); + std::shared_ptr> thread_mem_info = std::make_shared>(thread_size); + + shared_ptr finished(nullptr, [thread_mem_info, cb, obj](void *) { + for (auto &val : *thread_mem_info) { + auto thread_name = val["name"]; + replace(thread_name, "...", "~~~"); + auto prefix = "thread-" + thread_name + "."; + for (auto &pr : val) { + (*obj).emplace(prefix + pr.first, std::move(pr.second)); + } + } + // 触发回调 + cb(*obj); + }); + + auto pos = 0; + auto lambda = [&](const TaskExecutor::Ptr &executor) { + auto &val = (*thread_mem_info)[pos++]; + val["load"] = executor->load(); + Ticker ticker; + executor->async([finished, &val, ticker]() { + val["name"] = getThreadName(); + val["delay"] = ticker.elapsedTime(); +#ifdef ENABLE_MEM_DEBUG + auto bytes = getThisThreadMemUsage(); + val["memUsage"] = bytes; + val["memUsageMB"] = bytes / 1024 / 1024; + val["memBlock"] = getThisThreadMemBlock(); + { + int i = 0; + string str; + size_t last = 0; + for (auto sz : block_type_size) { + str.append(to_string(last) + "~" + to_string(sz) + ":" + to_string(getThisThreadMemBlockByType(i++)) + ";"); + last = sz; + } + str.pop_back(); + val["memBlockTypeCount"] = str; + } +#endif + }); + }; + EventPollerPool::Instance().for_each(lambda); + WorkThreadPool::Instance().for_each(lambda); +} + API_EXPORT void API_CALL mk_log_printf(int level, const char *file, const char *function, int line, const char *fmt, ...) { va_list ap; va_start(ap, fmt); diff --git a/api/tests/server.c b/api/tests/server.c index 28f44ada..a61862ed 100644 --- a/api/tests/server.c +++ b/api/tests/server.c @@ -189,6 +189,14 @@ static void on_mk_webrtc_get_answer_sdp_func(void *user_data, const char *answer free((void *)answer); } } + +void API_CALL on_get_statistic_cb(void *user_data, mk_ini ini) { + const char *response_header[] = { NULL }; + char *str = mk_ini_dump_string(ini); + mk_http_response_invoker_do_string(user_data, 200, response_header, str); + mk_free(str); +} + /** * 收到http api请求广播(包括GET/POST) * @param parser http请求内容对象 @@ -247,6 +255,9 @@ void API_CALL on_mk_http_request(const mk_parser parser, mk_webrtc_get_answer_sdp(mk_http_response_invoker_clone(invoker), on_mk_webrtc_get_answer_sdp_func, mk_parser_get_url_param(parser, "type"), mk_parser_get_content(parser, NULL), rtc_url); + } else if (strcmp(url, "/index/api/getStatistic") == 0) { + //拦截api: /index/api/webrtc + mk_get_statistic(on_get_statistic_cb, mk_http_response_invoker_clone(invoker), (on_user_data_free) mk_http_response_invoker_clone_release); } else { *consumed = 0; return;