| OLD | NEW | 
|---|
| 1 // Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2017, the Dart project authors.  Please see the AUTHORS file | 
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a | 
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "platform/globals.h" | 5 #include "platform/globals.h" | 
| 6 | 6 | 
| 7 #if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) &&                         \ | 7 #if defined(DART_USE_TCMALLOC) && !defined(PRODUCT) | 
| 8     !defined(TARGET_ARCH_DBC) && !defined(TARGET_OS_FUCHSIA) |  | 
| 9 | 8 | 
| 10 #include "platform/assert.h" | 9 #include "platform/assert.h" | 
|  | 10 #include "vm/class_finalizer.h" | 
| 11 #include "vm/globals.h" | 11 #include "vm/globals.h" | 
| 12 #include "vm/malloc_hooks.h" | 12 #include "vm/malloc_hooks.h" | 
| 13 #include "vm/os.h" | 13 #include "vm/symbols.h" | 
| 14 #include "vm/profiler.h" |  | 
| 15 #include "vm/profiler_service.h" |  | 
| 16 #include "vm/unit_test.h" | 14 #include "vm/unit_test.h" | 
| 17 | 15 | 
| 18 namespace dart { | 16 namespace dart { | 
| 19 | 17 | 
| 20 static void MallocHookTestBufferInitializer(volatile char* buffer, | 18 static void MallocHookTestBufferInitializer(volatile char* buffer, | 
| 21                                             uintptr_t size) { | 19                                             uintptr_t size) { | 
| 22   // Run through the buffer and do something. If we don't do this and the memory | 20   // Run through the buffer and do something. If we don't do this and the memory | 
| 23   // in buffer isn't touched, the tcmalloc hooks won't be called. | 21   // in buffer isn't touched, the tcmalloc hooks won't be called. | 
| 24   for (uintptr_t i = 0; i < size; ++i) { | 22   for (uintptr_t i = 0; i < size; ++i) { | 
| 25     buffer[i] = i; | 23     buffer[i] = i; | 
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 59   MallocHooks::InitOnce(); | 57   MallocHooks::InitOnce(); | 
| 60   const intptr_t pre_hook_buffer_size = 3; | 58   const intptr_t pre_hook_buffer_size = 3; | 
| 61   char* pre_hook_buffer = new char[pre_hook_buffer_size]; | 59   char* pre_hook_buffer = new char[pre_hook_buffer_size]; | 
| 62   MallocHookTestBufferInitializer(pre_hook_buffer, pre_hook_buffer_size); | 60   MallocHookTestBufferInitializer(pre_hook_buffer, pre_hook_buffer_size); | 
| 63 | 61 | 
| 64   MallocHooks::ResetStats(); | 62   MallocHooks::ResetStats(); | 
| 65   EXPECT_EQ(0L, MallocHooks::allocation_count()); | 63   EXPECT_EQ(0L, MallocHooks::allocation_count()); | 
| 66   EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes()); | 64   EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes()); | 
| 67 | 65 | 
| 68   const intptr_t buffer_size = 10; | 66   const intptr_t buffer_size = 10; | 
| 69   char* buffer = new char[buffer_size]; | 67   volatile char* buffer = new char[buffer_size]; | 
| 70   MallocHookTestBufferInitializer(buffer, buffer_size); | 68   MallocHookTestBufferInitializer(buffer, buffer_size); | 
| 71 | 69 | 
| 72   EXPECT_EQ(1L, MallocHooks::allocation_count()); | 70   EXPECT_EQ(1L, MallocHooks::allocation_count()); | 
| 73   EXPECT_EQ(static_cast<intptr_t>(sizeof(char) * buffer_size), | 71   EXPECT_EQ(static_cast<intptr_t>(sizeof(char) * buffer_size), | 
| 74             MallocHooks::heap_allocated_memory_in_bytes()); | 72             MallocHooks::heap_allocated_memory_in_bytes()); | 
| 75 | 73 | 
| 76   delete[] pre_hook_buffer; | 74   delete[] pre_hook_buffer; | 
| 77   EXPECT_EQ(1L, MallocHooks::allocation_count()); | 75   EXPECT_EQ(1L, MallocHooks::allocation_count()); | 
| 78   EXPECT_EQ(static_cast<intptr_t>(sizeof(char) * buffer_size), | 76   EXPECT_EQ(static_cast<intptr_t>(sizeof(char) * buffer_size), | 
| 79             MallocHooks::heap_allocated_memory_in_bytes()); | 77             MallocHooks::heap_allocated_memory_in_bytes()); | 
| 80 | 78 | 
| 81 | 79 | 
| 82   delete[] buffer; | 80   delete[] buffer; | 
| 83   EXPECT_EQ(0L, MallocHooks::allocation_count()); | 81   EXPECT_EQ(0L, MallocHooks::allocation_count()); | 
| 84   EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes()); | 82   EXPECT_EQ(0L, MallocHooks::heap_allocated_memory_in_bytes()); | 
| 85   MallocHooks::TearDown(); | 83   MallocHooks::TearDown(); | 
| 86 | 84 | 
| 87   FLAG_enable_malloc_hooks = enable_malloc_hooks_saved; | 85   FLAG_enable_malloc_hooks = enable_malloc_hooks_saved; | 
| 88 } | 86 } | 
| 89 | 87 | 
| 90 |  | 
| 91 VM_UNIT_TEST_CASE(StackTraceMallocHookSimpleTest) { |  | 
| 92   bool stack_traces_enabled = MallocHooks::stack_trace_collection_enabled(); |  | 
| 93   MallocHooks::set_stack_trace_collection_enabled(true); |  | 
| 94 |  | 
| 95   MallocHooks::ResetStats(); |  | 
| 96   ASSERT(MallocHooks::ProfilingEnabled()); |  | 
| 97 |  | 
| 98   char* var = static_cast<char*>(malloc(16 * sizeof(char))); |  | 
| 99   Sample* sample = MallocHooks::GetSample(var); |  | 
| 100   EXPECT(sample != NULL); |  | 
| 101 |  | 
| 102   free(var); |  | 
| 103   sample = MallocHooks::GetSample(var); |  | 
| 104   EXPECT(sample == NULL); |  | 
| 105   MallocHooks::set_stack_trace_collection_enabled(stack_traces_enabled); |  | 
| 106 } |  | 
| 107 |  | 
| 108 |  | 
| 109 static char* DART_NOINLINE StackTraceLengthHelper(uintptr_t* end_address) { |  | 
| 110   char* var = static_cast<char*>(malloc(16 * sizeof(char))); |  | 
| 111   *end_address = OS::GetProgramCounter(); |  | 
| 112   return var; |  | 
| 113 } |  | 
| 114 |  | 
| 115 |  | 
| 116 VM_UNIT_TEST_CASE(StackTraceMallocHookLengthTest) { |  | 
| 117   bool stack_traces_enabled = MallocHooks::stack_trace_collection_enabled(); |  | 
| 118   MallocHooks::set_stack_trace_collection_enabled(true); |  | 
| 119 |  | 
| 120   uintptr_t test_start_address = |  | 
| 121       reinterpret_cast<uintptr_t>(Dart_TestStackTraceMallocHookLengthTest); |  | 
| 122   uintptr_t helper_start_address = |  | 
| 123       reinterpret_cast<uintptr_t>(StackTraceLengthHelper); |  | 
| 124   uintptr_t helper_end_address = 0; |  | 
| 125 |  | 
| 126   MallocHooks::ResetStats(); |  | 
| 127   ASSERT(MallocHooks::ProfilingEnabled()); |  | 
| 128 |  | 
| 129   char* var = StackTraceLengthHelper(&helper_end_address); |  | 
| 130   Sample* sample = MallocHooks::GetSample(var); |  | 
| 131   EXPECT(sample != NULL); |  | 
| 132   uintptr_t test_end_address = OS::GetProgramCounter(); |  | 
| 133 |  | 
| 134   // Ensure that all stack frames are where we expect them to be in the sample. |  | 
| 135   // If they aren't, the kSkipCount constant in malloc_hooks.cc is likely |  | 
| 136   // incorrect. |  | 
| 137   uword address = sample->At(0); |  | 
| 138   bool first_result = |  | 
| 139       (helper_start_address <= address) && (helper_end_address >= address); |  | 
| 140   EXPECT(first_result); |  | 
| 141   address = sample->At(1); |  | 
| 142   bool second_result = |  | 
| 143       (test_start_address <= address) && (test_end_address >= address); |  | 
| 144   EXPECT(second_result); |  | 
| 145 |  | 
| 146   if (!(first_result && second_result)) { |  | 
| 147     OS::PrintErr( |  | 
| 148         "If this test is failing, it's likely that the value set for" |  | 
| 149         "the number of frames to skip in malloc_hooks.cc is " |  | 
| 150         "incorrect for this configuration/platform. This value can be" |  | 
| 151         " found in malloc_hooks.cc in the AllocationInfo class, and " |  | 
| 152         "is stored in the kSkipCount constant."); |  | 
| 153   } |  | 
| 154 |  | 
| 155   free(var); |  | 
| 156   MallocHooks::set_stack_trace_collection_enabled(stack_traces_enabled); |  | 
| 157 } |  | 
| 158 |  | 
| 159 |  | 
| 160 ISOLATE_UNIT_TEST_CASE(StackTraceMallocHookSimpleJSONTest) { |  | 
| 161   bool stack_traces_enabled = MallocHooks::stack_trace_collection_enabled(); |  | 
| 162   MallocHooks::set_stack_trace_collection_enabled(true); |  | 
| 163   MallocHooks::ResetStats(); |  | 
| 164   ASSERT(MallocHooks::ProfilingEnabled()); |  | 
| 165   ClearProfileVisitor cpv(Isolate::Current()); |  | 
| 166   Profiler::sample_buffer()->VisitSamples(&cpv); |  | 
| 167 |  | 
| 168   char* var = static_cast<char*>(malloc(16 * sizeof(char))); |  | 
| 169   JSONStream js; |  | 
| 170   ProfilerService::PrintNativeAllocationJSON(&js, Profile::kNoTags, -1, -1); |  | 
| 171   const char* json = js.ToCString(); |  | 
| 172 |  | 
| 173   // Check that all the stack frames from the current down to main are actually |  | 
| 174   // present in the profile. This is just a simple sanity check to make sure |  | 
| 175   // that the ProfileTrie has a representation of the stack trace collected when |  | 
| 176   // var is allocated. More intense testing is already done in profiler_test.cc. |  | 
| 177   EXPECT_SUBSTRING("\"dart::Dart_TestStackTraceMallocHookSimpleJSONTest()\"", |  | 
| 178                    json); |  | 
| 179   EXPECT_SUBSTRING("\"dart::TestCase::Run()\"", json); |  | 
| 180   EXPECT_SUBSTRING("\"dart::TestCaseBase::RunTest()\"", json); |  | 
| 181   EXPECT_SUBSTRING("\"main\"", json); |  | 
| 182 |  | 
| 183   free(var); |  | 
| 184   MallocHooks::set_stack_trace_collection_enabled(stack_traces_enabled); |  | 
| 185 } |  | 
| 186 |  | 
| 187 };  // namespace dart | 88 };  // namespace dart | 
| 188 | 89 | 
| 189 #endif  // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) | 90 #endif  // defined(DART_USE_TCMALLOC) && !defined(PRODUCT) | 
| OLD | NEW | 
|---|