Index: runtime/vm/malloc_hooks_test.cc |
diff --git a/runtime/vm/malloc_hooks_test.cc b/runtime/vm/malloc_hooks_test.cc |
index 5054a5047dd0f09c6f4de145c68b79e9b8676740..1226c6921a807ed3be2d354d2a8f36d3e88fd333 100644 |
--- a/runtime/vm/malloc_hooks_test.cc |
+++ b/runtime/vm/malloc_hooks_test.cc |
@@ -6,11 +6,15 @@ |
#if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) |
+#if defined(TARGET_OS_LINUX) |
+#include <execinfo.h> |
+#endif // defined(TARGET_OS_LINUX) |
+ |
#include "platform/assert.h" |
-#include "vm/class_finalizer.h" |
#include "vm/globals.h" |
#include "vm/malloc_hooks.h" |
-#include "vm/symbols.h" |
+#include "vm/profiler.h" |
+#include "vm/profiler_service.h" |
#include "vm/unit_test.h" |
namespace dart { |
@@ -56,7 +60,7 @@ UNIT_TEST_CASE(FreeUnseenMemoryMallocHookTest) { |
EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes()); |
const intptr_t buffer_size = 10; |
- volatile char* buffer = new char[buffer_size]; |
+ char* buffer = new char[buffer_size]; |
MallocHookTestBufferInitializer(buffer, buffer_size); |
EXPECT_EQ(1L, MallocHooks::allocation_count()); |
@@ -75,6 +79,91 @@ UNIT_TEST_CASE(FreeUnseenMemoryMallocHookTest) { |
MallocHooks::TearDown(); |
} |
+ |
+VM_UNIT_TEST_CASE(StackTraceMallocHookSimpleTest) { |
+ MallocHooks::ResetStats(); |
+ ASSERT(MallocHooks::ProfilingEnabled()); |
+ |
+ char* var = static_cast<char*>(malloc(16 * sizeof(char))); |
+ Sample* sample = MallocHooks::GetSample(var); |
+ EXPECT(sample != NULL); |
+ |
+ free(var); |
+ sample = MallocHooks::GetSample(var); |
+ EXPECT(sample == NULL); |
+} |
+ |
+ |
+ISOLATE_UNIT_TEST_CASE(StackTraceMallocHookSimpleJSONTest) { |
+ MallocHooks::ResetStats(); |
+ ASSERT(MallocHooks::ProfilingEnabled()); |
+ ClearProfileVisitor cpv(Isolate::Current()); |
+ Profiler::sample_buffer()->VisitSamples(&cpv); |
+ |
+ char* var = static_cast<char*>(malloc(16 * sizeof(char))); |
+ JSONStream js; |
+ ProfilerService::PrintNativeAllocationJSON(&js, Profile::kNoTags, -1, -1); |
+ const char* json = js.ToCString(); |
+ |
+ // Check that all the stack frames from the current down to main are actually |
+ // present in the profile. This is just a simple sanity check to make sure |
+ // that the ProfileTrie has a representation of the stack trace collected when |
+ // var is allocated. More intense testing is already done in profiler_test.cc. |
+ EXPECT_SUBSTRING("\"dart::Dart_TestStackTraceMallocHookSimpleJSONTest()\"", |
+ json); |
+ EXPECT_SUBSTRING("\"dart::TestCase::Run()\"", json); |
+ EXPECT_SUBSTRING("\"dart::TestCaseBase::RunTest()\"", json); |
+ EXPECT_SUBSTRING("\"main\"", json); |
+ |
+ free(var); |
+} |
+ |
+ |
+#if defined(TARGET_OS_LINUX) |
Cutch
2017/02/15 08:21:00
Not sure if this OS_LINUX test is a good idea
bkonyi
2017/02/16 00:28:28
After reading the comments below, I agree with you
|
+// Helper used to add another frame to the stack before allocating. |
+char* AllocationHelper(void* stack_trace[32]) { |
+ backtrace(stack_trace, 32); |
+ return static_cast<char*>(malloc(16 * sizeof(char))); |
+} |
+ |
+ |
+VM_UNIT_TEST_CASE(StackTraceMallocHookTest) { |
+ MallocHooks::ResetStats(); |
+ ASSERT(MallocHooks::ProfilingEnabled()); |
+ |
+ void* stack_trace[32]; |
+ |
+ // Perform the memory allocation and grab the stack trace created by |
+ // backtrace() for comparison purposes. |
+ char* var = AllocationHelper(stack_trace); |
+ |
+ // Update top pc of the stack trace to match the location that malloc was |
+ // called in AllocationHelper. The rest of the pcs should match without any |
+ // changes. |
+ stack_trace[0] = |
+ reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(stack_trace[0]) + 10); |
Cutch
2017/02/15 08:21:00
this won't be the same across MIPS/ARM/ARM64/etc
|
+ |
+ Sample* sample = MallocHooks::GetSample(var); |
+ ASSERT(sample != NULL); |
+ |
+ while (sample != NULL) { |
+ for (uintptr_t i = 0; i < 8; ++i) { |
Cutch
2017/02/15 08:21:00
Where did 8 come from?
|
+ // Cease comparisons after we pass the frame for main. |
+ if (sample->At(i) == 0) { |
+ break; |
+ } |
+ EXPECT_EQ(reinterpret_cast<uword>(stack_trace[i]), sample->At(i)); |
+ } |
+ |
+ if (!sample->is_continuation_sample()) { |
+ break; |
+ } |
+ sample = Profiler::sample_buffer()->At(sample->continuation_index()); |
+ } |
+ free(var); |
+} |
+#endif // defined(TARGET_OS_LINUX) |
+ |
}; // namespace dart |
#endif // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) |