Home | History | Annotate | Download | only in debug
      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