diff --git a/CMakeLists.txt b/CMakeLists.txt index 767679c..02e6653 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ set(ZLMediaKit_ROOT /opt/aarch64-v01c01-linux-gnu-gcc/lib/ZLMediaKit) set(ZLMediaKit_INCLUDE_DIR ${ZLMediaKit_ROOT}/include) set(ZLMediaKit_LIBRARY_DIRS ${ZLMediaKit_ROOT}/lib) -if(${CROSS_BUILD}) +if(CROSS_BUILD) add_subdirectory(Main) endif() add_subdirectory(Tools) diff --git a/Tools/LeakTracer/MemoryAllocationStackTracer.cpp b/Tools/LeakTracer/MemoryAllocationStackTracer.cpp index b906751..49d183e 100644 --- a/Tools/LeakTracer/MemoryAllocationStackTracer.cpp +++ b/Tools/LeakTracer/MemoryAllocationStackTracer.cpp @@ -1,4 +1,6 @@ #include "MemoryAllocationStackTracer.h" +#include "DateTime.h" +#include #include #include #include @@ -10,7 +12,8 @@ void *__wrap_malloc(size_t size) { void *address = __real_malloc(size); auto self = MemoryAllocationStackTracer::instance(); if (address != nullptr && self->enabled()) { - self->push(reinterpret_cast(address), MemoryAllocationStackTracer::Frame()); + self->push(reinterpret_cast(address), + MemoryAllocationStackTracer::Frame(1, static_cast(-1))); } // printf("%p = malloc(%zu)\n", address, size); return address; @@ -26,9 +29,13 @@ void __wrap_free(void *__ptr) { } void *operator new(std::size_t size) { - // printf("void *operator new(std::size_t size),%zu\n", size); - - return malloc(size); + void *address = __real_malloc(size); + auto self = MemoryAllocationStackTracer::instance(); + if (address != nullptr && self->enabled()) { + self->push(reinterpret_cast(address), + MemoryAllocationStackTracer::Frame(1, static_cast(-1))); + } + return address; } void operator delete(void *p) noexcept { @@ -37,8 +44,13 @@ void operator delete(void *p) noexcept { } void *operator new[](std::size_t count) { - // printf("%s", "void *operator new[](std::size_t count)\n"); - return malloc(count); + void *address = __real_malloc(count); + auto self = MemoryAllocationStackTracer::instance(); + if (address != nullptr && self->enabled()) { + self->push(reinterpret_cast(address), + MemoryAllocationStackTracer::Frame(1, static_cast(-1))); + } + return address; } void operator delete[](void *ptr) noexcept { @@ -46,24 +58,39 @@ void operator delete[](void *ptr) noexcept { return free(ptr); } -MemoryAllocationStackTracer *MemoryAllocationStackTracer::m_instance = nullptr; - -void MemoryAllocationStackTracer::start() { - if (!m_enabled) { - m_enabled = true; - } +void operator delete(void *ptr, std::size_t sz, std::align_val_t al) noexcept { + return free(ptr); +} +void operator delete[](void *ptr, std::size_t sz, std::align_val_t al) noexcept { + return free(ptr); } +MemoryAllocationStackTracer *MemoryAllocationStackTracer::m_instance = nullptr; + void MemoryAllocationStackTracer::push(uint64_t address, Frame &&stacktrace) { + if (stacktrace.empty()) return; + auto beginFrame = stacktrace.cbegin()->address(); + if (m_counts.count(beginFrame) <= 0) { + m_counts.insert({beginFrame, 1}); + } else { + m_counts[beginFrame]++; + } + Infomation info; info.time = std::chrono::system_clock::now(); info.frame = std::move(stacktrace); m_stacktraces.insert({address, info}); - // m_stacktraces.insert({address, stacktrace}); } void MemoryAllocationStackTracer::pop(uint64_t address) { if (m_stacktraces.count(address) > 0) { + auto &info = m_stacktraces.at(address); + auto beginFrame = info.frame.cbegin()->address(); + if (m_counts.count(beginFrame) > 0) { + if (m_counts.at(beginFrame) > 0) { + m_counts[beginFrame]--; + } + } m_stacktraces.erase(address); } } @@ -77,22 +104,65 @@ MemoryAllocationStackTracer *MemoryAllocationStackTracer::instance() { } return m_instance; } -void MemoryAllocationStackTracer::dump() { + +std::string MemoryAllocationStackTracer::dump() { using namespace std::chrono; m_enabled = false; - std::cout << "size: " << m_stacktraces.size() << std::endl; + std::ostringstream oss; + oss << "size: " << m_stacktraces.size() << std::endl; int index = 0; auto now = std::chrono::system_clock::now(); - std::ofstream ofs("test.txt"); for (auto &info : m_stacktraces) { - std::ostringstream oss; auto duration = duration_cast(now - info.second.time); oss << "-----index[" << index << "] duration: " << duration.count() << "s:-----" << std::endl; oss << info.second.frame << std::endl; - auto content = oss.str(); - ofs << content; - std::cout << content; index++; } + // aarch64-linux-gnu-addr2line -e build/Tools/LeakTracer/LeakTracer 0x55caea8e4f62 + + for (auto &count : m_counts) { + auto addr_base = boost::stacktrace::detail::get_own_proc_addr_base(count.first); + oss << "address: " << std::hex << (count.first - addr_base) << ", count: " << count.second << std::endl; + } m_enabled = true; + return oss.str(); } + +void MemoryAllocationStackTracer::run() { + using namespace std::chrono; + using namespace std::chrono_literals; + while (!m_exit) { + auto start = system_clock::now(); + + while (!m_exit) { + std::this_thread::sleep_for(50ms); + auto now = system_clock::now(); + auto elapsed = duration_cast(now - start); + if (elapsed <= m_intervals) continue; + + std::ostringstream oss; + oss << m_path << "/" << m_applicationName << "_" << DateTime(start).toString("%Y%m%d%H%M%S") << "-" + << DateTime::currentDateTime().toString("%Y%m%d%H%M%S") << ".dump"; + + std::ofstream ofs(oss.str()); + ofs << dump(); + break; + } + } +} + +void MemoryAllocationStackTracer::stop() { + if (!m_exit) { + m_exit = true; + if (m_thread.joinable()) m_thread.join(); + } + if (m_enabled) { + m_enabled = false; + } + m_stacktraces.clear(); + m_counts.clear(); +} + +MemoryAllocationStackTracer::~MemoryAllocationStackTracer() { + stop(); +} \ No newline at end of file diff --git a/Tools/LeakTracer/MemoryAllocationStackTracer.h b/Tools/LeakTracer/MemoryAllocationStackTracer.h index 4985542..7bc0d64 100644 --- a/Tools/LeakTracer/MemoryAllocationStackTracer.h +++ b/Tools/LeakTracer/MemoryAllocationStackTracer.h @@ -3,6 +3,7 @@ #include #include +#include #include extern "C" { @@ -62,26 +63,62 @@ public: class MemoryAllocationStackTracer { public: using Frame = boost::stacktrace::basic_stacktrace>; + using String = std::basic_string, DebugAllocator>; + using OutStringStream = std::basic_ostringstream, DebugAllocator>; class Infomation { public: std::chrono::system_clock::time_point time; Frame frame; }; + ~MemoryAllocationStackTracer(); static MemoryAllocationStackTracer *instance(); inline bool enabled() const { return m_enabled; } - void start(); - void dump(); + + template + void start(const std::string &path, const std::string &applicationName, + const std::chrono::duration &intervals) { + if (m_exit) { + m_exit = false; + m_thread = std::thread(&MemoryAllocationStackTracer::run, this); + } + m_intervals = std::chrono::duration_cast(intervals); + + if (!m_enabled) { + m_enabled = true; + } + m_path = path; + m_applicationName = applicationName; + } + + void stop(); + + std::string dump(); void push(uint64_t address, Frame &&stacktrace); void pop(uint64_t address); +protected: + void run(); + private: std::unordered_map, std::equal_to, DebugAllocator>> m_stacktraces; + std::unordered_map, + std::equal_to, + DebugAllocator>> + m_counts; + static MemoryAllocationStackTracer *m_instance; + std::string m_path; + std::string m_applicationName; + bool m_exit = true; + std::thread m_thread; + std::chrono::milliseconds m_intervals; + bool m_enabled = false; };