支持线程内存malloc统计 (#1317)

This commit is contained in:
夏楚 2021-12-27 17:40:15 +08:00 committed by GitHub
parent 7f649b94e5
commit 878ce87329
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 132 additions and 55 deletions

@ -1 +1 @@
Subproject commit 8afa63c31522e031c3d4857f0c723ee4e97447fc Subproject commit f2f79123f23943381009e89b407aa6f8ef683a82

View File

@ -212,6 +212,7 @@ static ApiArgsType getAllArgs(const Parser &parser) {
} }
extern uint64_t getTotalMemUsage(); extern uint64_t getTotalMemUsage();
extern uint64_t getThisThreadMemUsage();
static inline void addHttpListener(){ static inline void addHttpListener(){
GET_CONFIG(bool, api_debug, API::kApiDebug); GET_CONFIG(bool, api_debug, API::kApiDebug);
@ -356,8 +357,9 @@ Value makeMediaSourceJson(MediaSource &media){
return item; return item;
} }
Value getStatisticJson() { void getStatisticJson(const function<void(Value &val)> &cb) {
Value val(objectValue); auto obj = std::make_shared<Value>(objectValue);
auto &val = *obj;
val["MediaSource"] = (Json::UInt64)(ObjectStatistic<MediaSource>::count()); val["MediaSource"] = (Json::UInt64)(ObjectStatistic<MediaSource>::count());
val["MultiMediaSourceMuxer"] = (Json::UInt64)(ObjectStatistic<MultiMediaSourceMuxer>::count()); val["MultiMediaSourceMuxer"] = (Json::UInt64)(ObjectStatistic<MultiMediaSourceMuxer>::count());
@ -382,8 +384,46 @@ Value getStatisticJson() {
auto bytes = getTotalMemUsage(); auto bytes = getTotalMemUsage();
val["totalMemUsage"] = (Json::UInt64)bytes; val["totalMemUsage"] = (Json::UInt64)bytes;
val["totalMemUsageMB"] = (int)(bytes / 1024 / 1024); val["totalMemUsageMB"] = (int)(bytes / 1024 / 1024);
auto thread_size = EventPollerPool::Instance().getExecutorSize() + WorkThreadPool::Instance().getExecutorSize();
std::shared_ptr<vector<Value> > thread_mem_info = std::make_shared<vector<Value> >(thread_size);
std::shared_ptr<atomic<uint64_t> > thread_mem_total = std::make_shared<atomic<uint64_t> >(0);
shared_ptr<void> finished(nullptr, [thread_mem_info, cb, obj, thread_mem_total](void *) {
//poller和work线程开辟的内存
for (auto &val : *thread_mem_info) {
(*obj)["threadMem"].append(val);
}
//其他线程申请的内存为总内存减去poller和work线程开辟的内存
auto bytes = getTotalMemUsage() - *thread_mem_total;
Value val;
val["threadName"] = "other threads";
val["threadMemUsage"] = (Json::UInt64) bytes;
val["threadMemUsageMB"] = (int) (bytes / 1024 / 1024);
(*obj)["threadMem"].append(val);
//触发回调
cb(*obj);
});
auto pos = 0;
auto lam = [&](const TaskExecutor::Ptr &executor) {
auto &val = (*thread_mem_info)[pos++];
executor->async([finished, thread_mem_total, &val]() {
auto bytes = getThisThreadMemUsage();
*thread_mem_total += bytes;
val["threadName"] = getThreadName();
val["threadMemUsage"] = (Json::UInt64) bytes;
val["threadMemUsageMB"] = (int) (bytes / 1024 / 1024);
});
};
EventPollerPool::Instance().for_each(lam);
WorkThreadPool::Instance().for_each(lam);
#else
cb(*obj);
#endif #endif
return val;
} }
/** /**
@ -1278,9 +1318,12 @@ void installWebApi() {
}); });
}); });
api_regist("/index/api/getStatistic",[](API_ARGS_MAP){ api_regist("/index/api/getStatistic",[](API_ARGS_MAP_ASYNC){
CHECK_SECRET(); CHECK_SECRET();
val["data"] = getStatisticJson(); getStatisticJson([headerOut, val, invoker](const Value &data) mutable{
val["data"] = data;
invoker(200, headerOut, val.toStyledString());
});
}); });
#ifdef ENABLE_WEBRTC #ifdef ENABLE_WEBRTC

View File

@ -235,5 +235,5 @@ bool checkArgs(Args &args, const First &first, const KeyTypes &...keys) {
void installWebApi(); void installWebApi();
void unInstallWebApi(); void unInstallWebApi();
Value makeMediaSourceJson(MediaSource &media); Value makeMediaSourceJson(MediaSource &media);
Value getStatisticJson(); void getStatisticJson(const function<void(Value &val)> &cb);
#endif //ZLMEDIAKIT_WEBAPI_H #endif //ZLMEDIAKIT_WEBAPI_H

View File

@ -202,12 +202,12 @@ static void reportServerKeepalive() {
GET_CONFIG(float, alive_interval, Hook::kAliveInterval); GET_CONFIG(float, alive_interval, Hook::kAliveInterval);
g_keepalive_timer = std::make_shared<Timer>(alive_interval, []() { g_keepalive_timer = std::make_shared<Timer>(alive_interval, []() {
getStatisticJson([](const Value &data) mutable {
ArgsType body; ArgsType body;
body["data"] = getStatisticJson(); body["data"] = data;
//执行hook //执行hook
do_http_hook(hook_server_keepalive, body, nullptr); do_http_hook(hook_server_keepalive, body, nullptr);
});
return true; return true;
}, nullptr); }, nullptr);
} }

View File

@ -8,12 +8,12 @@
* may be found in the AUTHORS file in the root of the source tree. * may be found in the AUTHORS file in the root of the source tree.
*/ */
#include <stdio.h>
#include "Common/config.h" #include "Common/config.h"
#include "Util/util.h" #include "Util/util.h"
#include "Util/logger.h" #include "Util/logger.h"
#include "Util/onceToken.h" #include "Util/onceToken.h"
#include "Util/NoticeCenter.h" #include "Util/NoticeCenter.h"
#include "Network/sockutil.h"
using namespace toolkit; using namespace toolkit;
@ -318,31 +318,67 @@ const string kWaitTrackReady = "wait_track_ready";
#ifdef ENABLE_MEM_DEBUG #ifdef ENABLE_MEM_DEBUG
static atomic<uint64_t> mem_usage(0); extern "C" {
extern void *__real_malloc(size_t);
uint64_t getTotalMemUsage() { extern void __real_free(void *);
return mem_usage.load(); extern void *__real_realloc(void *ptr, size_t c);
void *__wrap_malloc(size_t c);
void __wrap_free(void *ptr);
void *__wrap_calloc(size_t __nmemb, size_t __size);
void *__wrap_realloc(void *ptr, size_t c);
} }
extern "C" { class MemAllocInfo {
public:
static atomic<uint64_t> total_mem_usage;
atomic<uint64_t> mem_usage{0};
};
#include <stdio.h> atomic<uint64_t> MemAllocInfo::total_mem_usage{0};
#define MAGIC_BYTES 0xFEFDFCFB
#define MAGIC_BYTES_SIZE 4
#define MEM_PREFIX_SIZE 8
extern void *__real_malloc(size_t); static thread_local MemAllocInfo s_alloc_info;
extern void __real_free(void *);
extern void *__real_realloc(void *ptr, size_t c); uint64_t getTotalMemUsage() {
return MemAllocInfo::total_mem_usage.load();
}
uint64_t getThisThreadMemUsage() {
return s_alloc_info.mem_usage.load();
}
#if defined(_WIN32)
#pragma pack(push, 1)
#endif // defined(_WIN32)
class MemCookie {
public:
static constexpr uint32_t kMagic = 0xFEFDFCFB;
uint32_t magic;
uint32_t size;
MemAllocInfo *alloc_info;
char ptr;
}PACKED;
#if defined(_WIN32)
#pragma pack(pop)
#endif // defined(_WIN32)
#define MEM_OFFSET (sizeof(MemCookie) - 1)
void init_cookie(MemCookie *cookie, size_t c) {
MemAllocInfo::total_mem_usage += c;
s_alloc_info.mem_usage += c;
cookie->magic = MemCookie::kMagic;
cookie->size = c;
cookie->alloc_info = &s_alloc_info;
}
void *__wrap_malloc(size_t c) { void *__wrap_malloc(size_t c) {
c += MEM_PREFIX_SIZE; c += MEM_OFFSET;
char *ret = (char *) __real_malloc(c); auto cookie = (MemCookie *) __real_malloc(c);
if (ret) { if (cookie) {
mem_usage += c; init_cookie(cookie, c);
*((uint32_t *) (ret)) = MAGIC_BYTES; return &cookie->ptr;
*((uint32_t *) (ret + MAGIC_BYTES_SIZE)) = c;
return ret + MEM_PREFIX_SIZE;
} }
return nullptr; return nullptr;
} }
@ -351,13 +387,13 @@ void __wrap_free(void *ptr) {
if (!ptr) { if (!ptr) {
return; return;
} }
ptr = (char *) ptr - MEM_PREFIX_SIZE; auto cookie = (MemCookie *) ((char *) ptr - MEM_OFFSET);
uint32_t magic = *((uint32_t *) (ptr)); if (cookie->magic != MemCookie::kMagic) {
if (magic != MAGIC_BYTES) {
throw std::invalid_argument("attempt to free invalid memory"); throw std::invalid_argument("attempt to free invalid memory");
} }
mem_usage -= *((uint32_t *) ((char *) ptr + MAGIC_BYTES_SIZE)); MemAllocInfo::total_mem_usage -= cookie->size;
__real_free(ptr); cookie->alloc_info->mem_usage -= cookie->size;
__real_free(cookie);
} }
void *__wrap_calloc(size_t __nmemb, size_t __size) { void *__wrap_calloc(size_t __nmemb, size_t __size) {
@ -369,30 +405,28 @@ void *__wrap_calloc(size_t __nmemb, size_t __size) {
return ret; return ret;
} }
void *__wrap_realloc(void *ptr, size_t c){ void *__wrap_realloc(void *ptr, size_t c) {
if (!ptr) { if (!ptr) {
return malloc(c); return malloc(c);
} }
c += MEM_PREFIX_SIZE;
ptr = (char *) ptr - MEM_PREFIX_SIZE;
uint32_t magic = *((uint32_t *) (ptr)); auto cookie = (MemCookie *) ((char *) ptr - MEM_OFFSET);
if (magic != MAGIC_BYTES) { if (cookie->magic != MemCookie::kMagic) {
throw std::invalid_argument("attempt to realloc invalid memory"); throw std::invalid_argument("attempt to realloc invalid memory");
} }
auto old_size = *((uint32_t *) ((char *) ptr + MAGIC_BYTES_SIZE));
char *ret = (char *) __real_realloc(ptr, c);
if (ret) {
mem_usage += c - old_size;
*((uint32_t *) (ret)) = MAGIC_BYTES;
*((uint32_t *) (ret + MAGIC_BYTES_SIZE)) = c;
return ret + MEM_PREFIX_SIZE;
}
free(ptr);
mem_usage -= old_size;
return nullptr;
}
MemAllocInfo::total_mem_usage -= cookie->size;
cookie->alloc_info->mem_usage -= cookie->size;
c += MEM_OFFSET;
cookie = (MemCookie *) __real_realloc(cookie, c);
if (cookie) {
init_cookie(cookie, c);
return &cookie->ptr;
}
free(cookie);
return nullptr;
} }
void *operator new(std::size_t size) { void *operator new(std::size_t size) {