1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/debug/trace_event_memory.h" 6 7 #include <sstream> 8 #include <string> 9 10 #include "base/debug/trace_event_impl.h" 11 #include "base/message_loop/message_loop.h" 12 #include "testing/gtest/include/gtest/gtest.h" 13 14 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) 15 #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h" 16 #endif 17 18 namespace base { 19 namespace debug { 20 21 // Tests for the trace event memory tracking system. Exists as a class so it 22 // can be a friend of TraceMemoryController. 23 class TraceMemoryTest : public testing::Test { 24 public: 25 TraceMemoryTest() {} 26 virtual ~TraceMemoryTest() {} 27 28 private: 29 DISALLOW_COPY_AND_ASSIGN(TraceMemoryTest); 30 }; 31 32 ////////////////////////////////////////////////////////////////////////////// 33 34 #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED) 35 36 TEST_F(TraceMemoryTest, TraceMemoryController) { 37 MessageLoop message_loop; 38 39 // Start with no observers of the TraceLog. 40 EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); 41 42 // Creating a controller adds it to the TraceLog observer list. 43 scoped_ptr<TraceMemoryController> controller( 44 new TraceMemoryController( 45 message_loop.message_loop_proxy(), 46 ::HeapProfilerWithPseudoStackStart, 47 ::HeapProfilerStop, 48 ::GetHeapProfile)); 49 EXPECT_EQ(1u, TraceLog::GetInstance()->GetObserverCountForTest()); 50 EXPECT_TRUE( 51 TraceLog::GetInstance()->HasEnabledStateObserver(controller.get())); 52 53 // By default the observer isn't dumping memory profiles. 54 EXPECT_FALSE(controller->IsTimerRunningForTest()); 55 56 // Simulate enabling tracing. 57 controller->StartProfiling(); 58 message_loop.RunUntilIdle(); 59 EXPECT_TRUE(controller->IsTimerRunningForTest()); 60 61 // Simulate disabling tracing. 62 controller->StopProfiling(); 63 message_loop.RunUntilIdle(); 64 EXPECT_FALSE(controller->IsTimerRunningForTest()); 65 66 // Deleting the observer removes it from the TraceLog observer list. 67 controller.reset(); 68 EXPECT_EQ(0u, TraceLog::GetInstance()->GetObserverCountForTest()); 69 } 70 71 TEST_F(TraceMemoryTest, ScopedTraceMemory) { 72 ScopedTraceMemory::InitForTest(); 73 74 // Start with an empty stack. 75 EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest()); 76 77 { 78 // Push an item. 79 ScopedTraceMemory scope1("cat1", "name1"); 80 EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest()); 81 EXPECT_EQ("cat1", ScopedTraceMemory::GetScopeDataForTest(0).category); 82 EXPECT_EQ("name1", ScopedTraceMemory::GetScopeDataForTest(0).name); 83 84 { 85 // One more item. 86 ScopedTraceMemory scope2("cat2", "name2"); 87 EXPECT_EQ(2, ScopedTraceMemory::GetStackDepthForTest()); 88 EXPECT_EQ("cat2", ScopedTraceMemory::GetScopeDataForTest(1).category); 89 EXPECT_EQ("name2", ScopedTraceMemory::GetScopeDataForTest(1).name); 90 } 91 92 // Ended scope 2. 93 EXPECT_EQ(1, ScopedTraceMemory::GetStackDepthForTest()); 94 } 95 96 // Ended scope 1. 97 EXPECT_EQ(0, ScopedTraceMemory::GetStackDepthForTest()); 98 99 ScopedTraceMemory::CleanupForTest(); 100 } 101 102 void TestDeepScopeNesting(int current, int depth) { 103 EXPECT_EQ(current, ScopedTraceMemory::GetStackDepthForTest()); 104 ScopedTraceMemory scope("category", "name"); 105 if (current < depth) 106 TestDeepScopeNesting(current + 1, depth); 107 EXPECT_EQ(current + 1, ScopedTraceMemory::GetStackDepthForTest()); 108 } 109 110 TEST_F(TraceMemoryTest, DeepScopeNesting) { 111 ScopedTraceMemory::InitForTest(); 112 113 // Ensure really deep scopes don't crash. 114 TestDeepScopeNesting(0, 100); 115 116 ScopedTraceMemory::CleanupForTest(); 117 } 118 119 #endif // defined(TRACE_MEMORY_SUPPORTED) 120 121 ///////////////////////////////////////////////////////////////////////////// 122 123 TEST_F(TraceMemoryTest, AppendHeapProfileTotalsAsTraceFormat) { 124 // Empty input gives empty output. 125 std::string empty_output; 126 AppendHeapProfileTotalsAsTraceFormat("", &empty_output); 127 EXPECT_EQ("", empty_output); 128 129 // Typical case. 130 const char input[] = 131 "heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile"; 132 const std::string kExpectedOutput = 133 "{\"current_allocs\": 357, \"current_bytes\": 55227, \"trace\": \"\"}"; 134 std::string output; 135 AppendHeapProfileTotalsAsTraceFormat(input, &output); 136 EXPECT_EQ(kExpectedOutput, output); 137 } 138 139 TEST_F(TraceMemoryTest, AppendHeapProfileLineAsTraceFormat) { 140 // Empty input gives empty output. 141 std::string empty_output; 142 EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("", &empty_output)); 143 EXPECT_EQ("", empty_output); 144 145 // Invalid input returns false. 146 std::string junk_output; 147 EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat("junk", &junk_output)); 148 149 // Input with normal category and name entries. 150 const char kCategory[] = "category"; 151 const char kName[] = "name"; 152 std::ostringstream input; 153 input << " 68: 4195 [ 1087: 98009] @ " << &kCategory << " " 154 << &kName; 155 const std::string kExpectedOutput = 156 ",\n" 157 "{" 158 "\"current_allocs\": 68, " 159 "\"current_bytes\": 4195, " 160 "\"trace\": \"name \"" 161 "}"; 162 std::string output; 163 EXPECT_TRUE( 164 AppendHeapProfileLineAsTraceFormat(input.str().c_str(), &output)); 165 EXPECT_EQ(kExpectedOutput, output); 166 167 // Input with with the category "toplevel". 168 // TODO(jamescook): Eliminate this special case and move the logic to the 169 // trace viewer code. 170 const char kTaskCategory[] = "toplevel"; 171 const char kTaskName[] = "TaskName"; 172 std::ostringstream input2; 173 input2 << " 68: 4195 [ 1087: 98009] @ " << &kTaskCategory << " " 174 << &kTaskName; 175 const std::string kExpectedOutput2 = 176 ",\n" 177 "{" 178 "\"current_allocs\": 68, " 179 "\"current_bytes\": 4195, " 180 "\"trace\": \"TaskName->PostTask \"" 181 "}"; 182 std::string output2; 183 EXPECT_TRUE( 184 AppendHeapProfileLineAsTraceFormat(input2.str().c_str(), &output2)); 185 EXPECT_EQ(kExpectedOutput2, output2); 186 187 // Zero current allocations is skipped. 188 std::ostringstream zero_input; 189 zero_input << " 0: 0 [ 1087: 98009] @ " << &kCategory << " " 190 << &kName; 191 std::string zero_output; 192 EXPECT_FALSE(AppendHeapProfileLineAsTraceFormat(zero_input.str().c_str(), 193 &zero_output)); 194 EXPECT_EQ("", zero_output); 195 } 196 197 TEST_F(TraceMemoryTest, AppendHeapProfileAsTraceFormat) { 198 // Empty input gives empty output. 199 std::string empty_output; 200 AppendHeapProfileAsTraceFormat("", &empty_output); 201 EXPECT_EQ("", empty_output); 202 203 // Typical case. 204 const char input[] = 205 "heap profile: 357: 55227 [ 14653: 2624014] @ heapprofile\n" 206 " 95: 40940 [ 649: 114260] @\n" 207 " 77: 32546 [ 742: 106234] @ 0x0 0x0\n" 208 " 0: 0 [ 132: 4236] @ 0x0\n" 209 "\n" 210 "MAPPED_LIBRARIES:\n" 211 "1be411fc1000-1be4139e4000 rw-p 00000000 00:00 0\n" 212 "1be4139e4000-1be4139e5000 ---p 00000000 00:00 0\n"; 213 const std::string kExpectedOutput = 214 "[{" 215 "\"current_allocs\": 357, " 216 "\"current_bytes\": 55227, " 217 "\"trace\": \"\"},\n" 218 "{\"current_allocs\": 95, " 219 "\"current_bytes\": 40940, " 220 "\"trace\": \"\"},\n" 221 "{\"current_allocs\": 77, " 222 "\"current_bytes\": 32546, " 223 "\"trace\": \"null \"" 224 "}]\n"; 225 std::string output; 226 AppendHeapProfileAsTraceFormat(input, &output); 227 EXPECT_EQ(kExpectedOutput, output); 228 } 229 230 TEST_F(TraceMemoryTest, StringFromHexAddress) { 231 EXPECT_STREQ("null", StringFromHexAddress("0x0")); 232 EXPECT_STREQ("error", StringFromHexAddress("not an address")); 233 const char kHello[] = "hello"; 234 std::ostringstream hex_address; 235 hex_address << &kHello; 236 EXPECT_STREQ(kHello, StringFromHexAddress(hex_address.str())); 237 } 238 239 } // namespace debug 240 } // namespace base 241