Use libmemory_trace for writing trace data.
Also, add a time value for thread done.
Test: All unit tests pass.
Change-Id: I088b9dfaea1b7054ace64b14ac840923479f60a9
diff --git a/libc/malloc_debug/Android.bp b/libc/malloc_debug/Android.bp
index 3828c28..5d61801 100644
--- a/libc/malloc_debug/Android.bp
+++ b/libc/malloc_debug/Android.bp
@@ -79,6 +79,10 @@
"libmemunreachable",
],
+ whole_static_libs: [
+ "libmemory_trace",
+ ],
+
shared_libs: [
"libunwindstack",
],
diff --git a/libc/malloc_debug/Nanotime.h b/libc/malloc_debug/Nanotime.h
new file mode 100644
index 0000000..d7c3f60
--- /dev/null
+++ b/libc/malloc_debug/Nanotime.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <time.h>
+
+static inline __always_inline uint64_t Nanotime() {
+ struct timespec t = {};
+ clock_gettime(CLOCK_MONOTONIC, &t);
+ return static_cast<uint64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
+}
diff --git a/libc/malloc_debug/RecordData.cpp b/libc/malloc_debug/RecordData.cpp
index 79e051b..1641732 100644
--- a/libc/malloc_debug/RecordData.cpp
+++ b/libc/malloc_debug/RecordData.cpp
@@ -39,72 +39,19 @@
#include <mutex>
#include <android-base/stringprintf.h>
+#include <memory_trace/MemoryTrace.h>
#include "Config.h"
#include "DebugData.h"
+#include "Nanotime.h"
#include "RecordData.h"
#include "debug_disable.h"
#include "debug_log.h"
-RecordEntry::RecordEntry() : tid_(gettid()) {
-}
-
-bool ThreadCompleteEntry::Write(int fd) const {
- return dprintf(fd, "%d: thread_done 0x0\n", tid_) > 0;
-}
-
-AllocEntry::AllocEntry(void* pointer, uint64_t start_ns, uint64_t end_ns)
- : pointer_(pointer), start_ns_(start_ns), end_ns_(end_ns) {}
-
-MallocEntry::MallocEntry(void* pointer, size_t size, uint64_t start_ns, uint64_t end_ns)
- : AllocEntry(pointer, start_ns, end_ns), size_(size) {}
-
-bool MallocEntry::Write(int fd) const {
- return dprintf(fd, "%d: malloc %p %zu %" PRIu64 " %" PRIu64 "\n", tid_, pointer_, size_,
- start_ns_, end_ns_) > 0;
-}
-
-FreeEntry::FreeEntry(void* pointer, uint64_t start_ns, uint64_t end_ns)
- : AllocEntry(pointer, start_ns, end_ns) {}
-
-bool FreeEntry::Write(int fd) const {
- return dprintf(fd, "%d: free %p %" PRIu64 " %" PRIu64 "\n", tid_, pointer_, start_ns_, end_ns_) >
- 0;
-}
-
-CallocEntry::CallocEntry(void* pointer, size_t nmemb, size_t size, uint64_t start_ns,
- uint64_t end_ns)
- : MallocEntry(pointer, size, start_ns, end_ns), nmemb_(nmemb) {}
-
-bool CallocEntry::Write(int fd) const {
- return dprintf(fd, "%d: calloc %p %zu %zu %" PRIu64 " %" PRIu64 "\n", tid_, pointer_, nmemb_,
- size_, start_ns_, end_ns_) > 0;
-}
-
-ReallocEntry::ReallocEntry(void* pointer, size_t size, void* old_pointer, uint64_t start_ns,
- uint64_t end_ns)
- : MallocEntry(pointer, size, start_ns, end_ns), old_pointer_(old_pointer) {}
-
-bool ReallocEntry::Write(int fd) const {
- return dprintf(fd, "%d: realloc %p %p %zu %" PRIu64 " %" PRIu64 "\n", tid_, pointer_,
- old_pointer_, size_, start_ns_, end_ns_) > 0;
-}
-
-// aligned_alloc, posix_memalign, memalign, pvalloc, valloc all recorded with this class.
-MemalignEntry::MemalignEntry(void* pointer, size_t size, size_t alignment, uint64_t start_ns,
- uint64_t end_ns)
- : MallocEntry(pointer, size, start_ns, end_ns), alignment_(alignment) {}
-
-bool MemalignEntry::Write(int fd) const {
- return dprintf(fd, "%d: memalign %p %zu %zu %" PRIu64 " %" PRIu64 "\n", tid_, pointer_,
- alignment_, size_, start_ns_, end_ns_) > 0;
-}
-
struct ThreadData {
- ThreadData(RecordData* record_data, ThreadCompleteEntry* entry)
- : record_data(record_data), entry(entry) {}
- RecordData* record_data;
- ThreadCompleteEntry* entry;
+ ThreadData(RecordData* record_data) : record_data(record_data) {}
+
+ RecordData* record_data = nullptr;
size_t count = 0;
};
@@ -117,7 +64,8 @@
if (thread_data->count == 4) {
ScopedDisableDebugCalls disable;
- thread_data->record_data->AddEntryOnly(thread_data->entry);
+ thread_data->record_data->AddEntryOnly(memory_trace::Entry{
+ .tid = gettid(), .type = memory_trace::THREAD_DONE, .end_ns = Nanotime()});
delete thread_data;
} else {
pthread_setspecific(thread_data->record_data->key(), data);
@@ -159,7 +107,7 @@
}
for (size_t i = 0; i < cur_index_; i++) {
- if (!entries_[i]->Write(dump_fd)) {
+ if (!memory_trace::WriteEntryToFd(dump_fd, entries_[i])) {
error_log("Failed to write record alloc information: %s", strerror(errno));
break;
}
@@ -201,23 +149,23 @@
pthread_key_delete(key_);
}
-void RecordData::AddEntryOnly(const RecordEntry* entry) {
+void RecordData::AddEntryOnly(const memory_trace::Entry& entry) {
std::lock_guard<std::mutex> entries_lock(entries_lock_);
if (cur_index_ == entries_.size()) {
// Maxed out, throw the entry away.
return;
}
- entries_[cur_index_++].reset(entry);
+ entries_[cur_index_++] = entry;
if (cur_index_ == entries_.size()) {
info_log("Maximum number of records added, all new operations will be dropped.");
}
}
-void RecordData::AddEntry(const RecordEntry* entry) {
+void RecordData::AddEntry(const memory_trace::Entry& entry) {
void* data = pthread_getspecific(key_);
if (data == nullptr) {
- ThreadData* thread_data = new ThreadData(this, new ThreadCompleteEntry());
+ ThreadData* thread_data = new ThreadData(this);
pthread_setspecific(key_, thread_data);
}
diff --git a/libc/malloc_debug/RecordData.h b/libc/malloc_debug/RecordData.h
index 7efa1f7..f4b0d82 100644
--- a/libc/malloc_debug/RecordData.h
+++ b/libc/malloc_debug/RecordData.h
@@ -39,117 +39,9 @@
#include <string>
#include <vector>
+#include <memory_trace/MemoryTrace.h>
#include <platform/bionic/macros.h>
-class RecordEntry {
- public:
- RecordEntry();
- virtual ~RecordEntry() = default;
-
- virtual bool Write(int fd) const = 0;
-
- protected:
- pid_t tid_;
-
- private:
- BIONIC_DISALLOW_COPY_AND_ASSIGN(RecordEntry);
-};
-
-class ThreadCompleteEntry : public RecordEntry {
- public:
- ThreadCompleteEntry() = default;
- virtual ~ThreadCompleteEntry() = default;
-
- bool Write(int fd) const override;
-
- private:
- BIONIC_DISALLOW_COPY_AND_ASSIGN(ThreadCompleteEntry);
-};
-
-class AllocEntry : public RecordEntry {
- public:
- explicit AllocEntry(void* pointer, uint64_t st, uint64_t et);
- virtual ~AllocEntry() = default;
-
- protected:
- void* pointer_;
-
- // The start/end time of this operation.
- uint64_t start_ns_;
- uint64_t end_ns_;
-
- private:
- BIONIC_DISALLOW_COPY_AND_ASSIGN(AllocEntry);
-};
-
-class MallocEntry : public AllocEntry {
- public:
- MallocEntry(void* pointer, size_t size, uint64_t st, uint64_t et);
- virtual ~MallocEntry() = default;
-
- bool Write(int fd) const override;
-
- protected:
- size_t size_;
-
- private:
- BIONIC_DISALLOW_COPY_AND_ASSIGN(MallocEntry);
-};
-
-class FreeEntry : public AllocEntry {
- public:
- explicit FreeEntry(void* pointer, uint64_t st, uint64_t et);
- virtual ~FreeEntry() = default;
-
- bool Write(int fd) const override;
-
- private:
- BIONIC_DISALLOW_COPY_AND_ASSIGN(FreeEntry);
-};
-
-class CallocEntry : public MallocEntry {
- public:
- CallocEntry(void* pointer, size_t nmemb, size_t size, uint64_t st, uint64_t et);
- virtual ~CallocEntry() = default;
-
- bool Write(int fd) const override;
-
- protected:
- size_t nmemb_;
-
- private:
- BIONIC_DISALLOW_COPY_AND_ASSIGN(CallocEntry);
-};
-
-class ReallocEntry : public MallocEntry {
- public:
- ReallocEntry(void* pointer, size_t size, void* old_pointer, uint64_t st, uint64_t et);
- virtual ~ReallocEntry() = default;
-
- bool Write(int fd) const override;
-
- protected:
- void* old_pointer_;
-
- private:
- BIONIC_DISALLOW_COPY_AND_ASSIGN(ReallocEntry);
-};
-
-// aligned_alloc, posix_memalign, memalign, pvalloc, valloc all recorded with this class.
-class MemalignEntry : public MallocEntry {
- public:
- MemalignEntry(void* pointer, size_t size, size_t alignment, uint64_t st, uint64_t et);
- virtual ~MemalignEntry() = default;
-
- bool Write(int fd) const override;
-
- protected:
- size_t alignment_;
-
- private:
- BIONIC_DISALLOW_COPY_AND_ASSIGN(MemalignEntry);
-};
-
class Config;
class RecordData {
@@ -159,8 +51,8 @@
bool Initialize(const Config& config);
- void AddEntry(const RecordEntry* entry);
- void AddEntryOnly(const RecordEntry* entry);
+ void AddEntry(const memory_trace::Entry& entry);
+ void AddEntryOnly(const memory_trace::Entry& entry);
const std::string& file() { return file_; }
pthread_key_t key() { return key_; }
@@ -176,7 +68,7 @@
std::mutex entries_lock_;
pthread_key_t key_;
- std::vector<std::unique_ptr<const RecordEntry>> entries_;
+ std::vector<memory_trace::Entry> entries_;
size_t cur_index_;
std::string file_;
diff --git a/libc/malloc_debug/malloc_debug.cpp b/libc/malloc_debug/malloc_debug.cpp
index 3743852..c183897 100644
--- a/libc/malloc_debug/malloc_debug.cpp
+++ b/libc/malloc_debug/malloc_debug.cpp
@@ -54,6 +54,7 @@
#include "Config.h"
#include "DebugData.h"
#include "LogAllocatorStats.h"
+#include "Nanotime.h"
#include "Unreachable.h"
#include "UnwindBacktrace.h"
#include "backtrace.h"
@@ -70,12 +71,6 @@
const MallocDispatch* g_dispatch;
-static inline __always_inline uint64_t Nanotime() {
- struct timespec t = {};
- clock_gettime(CLOCK_MONOTONIC, &t);
- return static_cast<uint64_t>(t.tv_sec) * 1000000000LL + t.tv_nsec;
-}
-
namespace {
// A TimedResult contains the result of from malloc end_ns al. functions and the
// start/end timestamps.
@@ -598,8 +593,13 @@
TimedResult result = InternalMalloc(size);
if (g_debug->config().options() & RECORD_ALLOCS) {
- g_debug->record->AddEntry(new MallocEntry(result.getValue<void*>(), size,
- result.GetStartTimeNS(), result.GetEndTimeNS()));
+ g_debug->record->AddEntry(
+ memory_trace::Entry{.tid = gettid(),
+ .type = memory_trace::MALLOC,
+ .ptr = reinterpret_cast<uint64_t>(result.getValue<void*>()),
+ .size = size,
+ .start_ns = result.GetStartTimeNS(),
+ .end_ns = result.GetEndTimeNS()});
}
return result.getValue<void*>();
@@ -687,8 +687,11 @@
TimedResult result = InternalFree(pointer);
if (g_debug->config().options() & RECORD_ALLOCS) {
- g_debug->record->AddEntry(
- new FreeEntry(pointer, result.GetStartTimeNS(), result.GetEndTimeNS()));
+ g_debug->record->AddEntry(memory_trace::Entry{.tid = gettid(),
+ .type = memory_trace::FREE,
+ .ptr = reinterpret_cast<uint64_t>(pointer),
+ .start_ns = result.GetStartTimeNS(),
+ .end_ns = result.GetEndTimeNS()});
}
}
@@ -771,8 +774,13 @@
}
if (g_debug->config().options() & RECORD_ALLOCS) {
- g_debug->record->AddEntry(new MemalignEntry(pointer, bytes, alignment,
- result.GetStartTimeNS(), result.GetEndTimeNS()));
+ g_debug->record->AddEntry(memory_trace::Entry{.tid = gettid(),
+ .type = memory_trace::MEMALIGN,
+ .ptr = reinterpret_cast<uint64_t>(pointer),
+ .size = bytes,
+ .u.align = alignment,
+ .start_ns = result.GetStartTimeNS(),
+ .end_ns = result.GetEndTimeNS()});
}
}
@@ -791,11 +799,16 @@
if (pointer == nullptr) {
TimedResult result = InternalMalloc(bytes);
- if (g_debug->config().options() & RECORD_ALLOCS) {
- g_debug->record->AddEntry(new ReallocEntry(result.getValue<void*>(), bytes, nullptr,
- result.GetStartTimeNS(), result.GetEndTimeNS()));
- }
pointer = result.getValue<void*>();
+ if (g_debug->config().options() & RECORD_ALLOCS) {
+ g_debug->record->AddEntry(memory_trace::Entry{.tid = gettid(),
+ .type = memory_trace::REALLOC,
+ .ptr = reinterpret_cast<uint64_t>(pointer),
+ .size = bytes,
+ .u.old_ptr = 0,
+ .start_ns = result.GetStartTimeNS(),
+ .end_ns = result.GetEndTimeNS()});
+ }
return pointer;
}
@@ -807,8 +820,14 @@
TimedResult result = InternalFree(pointer);
if (g_debug->config().options() & RECORD_ALLOCS) {
- g_debug->record->AddEntry(new ReallocEntry(nullptr, bytes, pointer, result.GetStartTimeNS(),
- result.GetEndTimeNS()));
+ g_debug->record->AddEntry(
+ memory_trace::Entry{.tid = gettid(),
+ .type = memory_trace::REALLOC,
+ .ptr = 0,
+ .size = 0,
+ .u.old_ptr = reinterpret_cast<uint64_t>(pointer),
+ .start_ns = result.GetStartTimeNS(),
+ .end_ns = result.GetEndTimeNS()});
}
return nullptr;
@@ -905,8 +924,13 @@
}
if (g_debug->config().options() & RECORD_ALLOCS) {
- g_debug->record->AddEntry(new ReallocEntry(new_pointer, bytes, pointer, result.GetStartTimeNS(),
- result.GetEndTimeNS()));
+ g_debug->record->AddEntry(memory_trace::Entry{.tid = gettid(),
+ .type = memory_trace::REALLOC,
+ .ptr = reinterpret_cast<uint64_t>(new_pointer),
+ .size = bytes,
+ .u.old_ptr = reinterpret_cast<uint64_t>(pointer),
+ .start_ns = result.GetStartTimeNS(),
+ .end_ns = result.GetEndTimeNS()});
}
return new_pointer;
@@ -962,8 +986,13 @@
}
if (g_debug->config().options() & RECORD_ALLOCS) {
- g_debug->record->AddEntry(
- new CallocEntry(pointer, nmemb, bytes, result.GetStartTimeNS(), result.GetEndTimeNS()));
+ g_debug->record->AddEntry(memory_trace::Entry{.tid = gettid(),
+ .type = memory_trace::CALLOC,
+ .ptr = reinterpret_cast<uint64_t>(pointer),
+ .size = bytes,
+ .u.n_elements = nmemb,
+ .start_ns = result.GetStartTimeNS(),
+ .end_ns = result.GetEndTimeNS()});
}
if (pointer != nullptr && g_debug->TrackPointers()) {