mirror of
https://github.com/ZLMediaKit/ZLMediaKit.git
synced 2024-11-22 10:40:05 +08:00
支持线程内存malloc统计 (#1317)
This commit is contained in:
parent
7f649b94e5
commit
878ce87329
@ -1 +1 @@
|
|||||||
Subproject commit 8afa63c31522e031c3d4857f0c723ee4e97447fc
|
Subproject commit f2f79123f23943381009e89b407aa6f8ef683a82
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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, []() {
|
||||||
ArgsType body;
|
getStatisticJson([](const Value &data) mutable {
|
||||||
body["data"] = getStatisticJson();
|
ArgsType body;
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user