1 // Copyright 2012 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 // This is a unittest set for type_profiler. It is independent from other 6 // tests and executed manually like allocator_unittests since type_profiler_map 7 // used in type_profiler is a singleton (like TCMalloc's heap-profiler), and 8 // it requires RTTI and different compiling/linking options from others 9 // 10 // It tests that the profiler doesn't fail in suspicous cases. For example, 11 // 'new' is not profiled, but 'delete' for the created object is profiled. 12 13 #if defined(TYPE_PROFILING) 14 15 #include "base/allocator/type_profiler.h" 16 #include "base/allocator/type_profiler_control.h" 17 #include "base/allocator/type_profiler_tcmalloc.h" 18 #include "base/basictypes.h" 19 #include "testing/gtest/include/gtest/gtest.h" 20 #include "third_party/tcmalloc/chromium/src/gperftools/type_profiler_map.h" 21 22 namespace base { 23 namespace type_profiler { 24 25 class TypeProfilerTest : public testing::Test { 26 public: 27 TypeProfilerTest() {} 28 29 void SetInterceptFunctions() { 30 InterceptFunctions::SetFunctions(NewInterceptForTCMalloc, 31 DeleteInterceptForTCMalloc); 32 } 33 34 void ResetInterceptFunctions() { 35 InterceptFunctions::ResetFunctions(); 36 } 37 38 void SetUp() { 39 SetInterceptFunctions(); 40 } 41 42 void TearDown() { 43 ResetInterceptFunctions(); 44 } 45 46 protected: 47 static const size_t kDummyArraySize; 48 static const void* const kConstNull; 49 50 private: 51 DISALLOW_COPY_AND_ASSIGN(TypeProfilerTest); 52 }; 53 54 const size_t TypeProfilerTest::kDummyArraySize = 10; 55 const void* const TypeProfilerTest::kConstNull = static_cast<const void*>(NULL); 56 57 TEST_F(TypeProfilerTest, TestNormalProfiling) { 58 int* dummy = new int(48); 59 const std::type_info* type; 60 61 type = LookupType(dummy); 62 ASSERT_NE(kConstNull, type); 63 EXPECT_STREQ(typeid(int).name(), type->name()); 64 delete dummy; 65 66 type = LookupType(dummy); 67 EXPECT_EQ(kConstNull, type); 68 } 69 70 TEST_F(TypeProfilerTest, TestNormalArrayProfiling) { 71 int* dummy = new int[kDummyArraySize]; 72 const std::type_info* type; 73 74 type = LookupType(dummy); 75 ASSERT_NE(kConstNull, type); 76 // For an array, the profiler remembers its base type. 77 EXPECT_STREQ(typeid(int).name(), type->name()); 78 delete[] dummy; 79 80 type = LookupType(dummy); 81 EXPECT_EQ(kConstNull, type); 82 } 83 84 TEST_F(TypeProfilerTest, TestRepeatedNewAndDelete) { 85 int *dummy[kDummyArraySize]; 86 const std::type_info* type; 87 for (int i = 0; i < kDummyArraySize; ++i) 88 dummy[i] = new int(i); 89 90 for (int i = 0; i < kDummyArraySize; ++i) { 91 type = LookupType(dummy[i]); 92 ASSERT_NE(kConstNull, type); 93 EXPECT_STREQ(typeid(int).name(), type->name()); 94 } 95 96 for (int i = 0; i < kDummyArraySize; ++i) { 97 delete dummy[i]; 98 type = LookupType(dummy[i]); 99 ASSERT_EQ(kConstNull, type); 100 } 101 } 102 103 TEST_F(TypeProfilerTest, TestMultipleNewWithDroppingDelete) { 104 static const size_t large_size = 256 * 1024; 105 106 char* dummy_char = new char[large_size / sizeof(*dummy_char)]; 107 const std::type_info* type; 108 109 type = LookupType(dummy_char); 110 ASSERT_NE(kConstNull, type); 111 EXPECT_STREQ(typeid(char).name(), type->name()); 112 113 // Call "::operator delete" directly to drop __op_delete_intercept__. 114 ::operator delete[](dummy_char); 115 116 type = LookupType(dummy_char); 117 ASSERT_NE(kConstNull, type); 118 EXPECT_STREQ(typeid(char).name(), type->name()); 119 120 // Allocates a little different size. 121 int* dummy_int = new int[large_size / sizeof(*dummy_int) - 1]; 122 123 // We expect that tcmalloc returns the same address for these large (over 32k) 124 // allocation calls. It usually happens, but maybe probablistic. 125 ASSERT_EQ(static_cast<void*>(dummy_char), static_cast<void*>(dummy_int)) << 126 "two new (malloc) calls didn't return the same address; retry it."; 127 128 type = LookupType(dummy_int); 129 ASSERT_NE(kConstNull, type); 130 EXPECT_STREQ(typeid(int).name(), type->name()); 131 132 delete[] dummy_int; 133 134 type = LookupType(dummy_int); 135 EXPECT_EQ(kConstNull, type); 136 } 137 138 TEST_F(TypeProfilerTest, TestProfileDeleteWithoutProfiledNew) { 139 // 'dummy' should be new'ed in this test before intercept functions are set. 140 ResetInterceptFunctions(); 141 142 int* dummy = new int(48); 143 const std::type_info* type; 144 145 // Set intercept functions again after 'dummy' is new'ed. 146 SetInterceptFunctions(); 147 148 delete dummy; 149 150 type = LookupType(dummy); 151 EXPECT_EQ(kConstNull, type); 152 153 ResetInterceptFunctions(); 154 } 155 156 TEST_F(TypeProfilerTest, TestProfileNewWithoutProfiledDelete) { 157 int* dummy = new int(48); 158 const std::type_info* type; 159 160 EXPECT_TRUE(Controller::IsProfiling()); 161 162 // Stop profiling before deleting 'dummy'. 163 Controller::Stop(); 164 EXPECT_FALSE(Controller::IsProfiling()); 165 166 delete dummy; 167 168 // NOTE: We accept that a profile entry remains when a profiled object is 169 // deleted after Controller::Stop(). 170 type = LookupType(dummy); 171 ASSERT_NE(kConstNull, type); 172 EXPECT_STREQ(typeid(int).name(), type->name()); 173 174 Controller::Restart(); 175 EXPECT_TRUE(Controller::IsProfiling()); 176 177 // Remove manually since 'dummy' is not removed from type_profiler_map. 178 EraseType(dummy); 179 } 180 181 } // namespace type_profiler 182 } // namespace base 183 184 #endif // defined(TYPE_PROFILING) 185 186 int main(int argc, char** argv) { 187 testing::InitGoogleTest(&argc, argv); 188 return RUN_ALL_TESTS(); 189 } 190