1// Copyright 2010 the V8 project authors. All rights reserved. 2// 3// Tests of profiles generator and utilities. 4 5#include "v8.h" 6#include "cpu-profiler-inl.h" 7#include "cctest.h" 8#include "../include/v8-profiler.h" 9 10using i::CodeEntry; 11using i::CpuProfile; 12using i::CpuProfiler; 13using i::CpuProfilesCollection; 14using i::ProfileGenerator; 15using i::ProfileNode; 16using i::ProfilerEventsProcessor; 17using i::TokenEnumerator; 18 19 20TEST(StartStop) { 21 CpuProfilesCollection profiles; 22 ProfileGenerator generator(&profiles); 23 ProfilerEventsProcessor processor(&generator); 24 processor.Start(); 25 processor.Stop(); 26 processor.Join(); 27} 28 29static v8::Persistent<v8::Context> env; 30 31static void InitializeVM() { 32 if (env.IsEmpty()) env = v8::Context::New(); 33 v8::HandleScope scope; 34 env->Enter(); 35} 36 37static inline i::Address ToAddress(int n) { 38 return reinterpret_cast<i::Address>(n); 39} 40 41static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc, 42 i::Address frame1, 43 i::Address frame2 = NULL, 44 i::Address frame3 = NULL) { 45 i::TickSample* sample = proc->TickSampleEvent(); 46 sample->pc = frame1; 47 sample->tos = frame1; 48 sample->frames_count = 0; 49 if (frame2 != NULL) { 50 sample->stack[0] = frame2; 51 sample->frames_count = 1; 52 } 53 if (frame3 != NULL) { 54 sample->stack[1] = frame3; 55 sample->frames_count = 2; 56 } 57} 58 59namespace { 60 61class TestSetup { 62 public: 63 TestSetup() 64 : old_flag_prof_browser_mode_(i::FLAG_prof_browser_mode) { 65 i::FLAG_prof_browser_mode = false; 66 } 67 68 ~TestSetup() { 69 i::FLAG_prof_browser_mode = old_flag_prof_browser_mode_; 70 } 71 72 private: 73 bool old_flag_prof_browser_mode_; 74}; 75 76} // namespace 77 78TEST(CodeEvents) { 79 InitializeVM(); 80 TestSetup test_setup; 81 CpuProfilesCollection profiles; 82 profiles.StartProfiling("", 1); 83 ProfileGenerator generator(&profiles); 84 ProfilerEventsProcessor processor(&generator); 85 processor.Start(); 86 87 // Enqueue code creation events. 88 i::HandleScope scope; 89 const char* aaa_str = "aaa"; 90 i::Handle<i::String> aaa_name = FACTORY->NewStringFromAscii( 91 i::Vector<const char>(aaa_str, i::StrLength(aaa_str))); 92 processor.CodeCreateEvent(i::Logger::FUNCTION_TAG, 93 *aaa_name, 94 HEAP->empty_string(), 95 0, 96 ToAddress(0x1000), 97 0x100, 98 ToAddress(0x10000)); 99 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG, 100 "bbb", 101 ToAddress(0x1200), 102 0x80); 103 processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10); 104 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG, 105 "ddd", 106 ToAddress(0x1400), 107 0x80); 108 processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500)); 109 processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10); 110 processor.CodeCreateEvent(i::Logger::STUB_TAG, 4, ToAddress(0x1605), 0x10); 111 // Enqueue a tick event to enable code events processing. 112 EnqueueTickSampleEvent(&processor, ToAddress(0x1000)); 113 114 processor.Stop(); 115 processor.Join(); 116 117 // Check the state of profile generator. 118 CodeEntry* entry1 = generator.code_map()->FindEntry(ToAddress(0x1000)); 119 CHECK_NE(NULL, entry1); 120 CHECK_EQ(aaa_str, entry1->name()); 121 CodeEntry* entry2 = generator.code_map()->FindEntry(ToAddress(0x1200)); 122 CHECK_NE(NULL, entry2); 123 CHECK_EQ("bbb", entry2->name()); 124 CodeEntry* entry3 = generator.code_map()->FindEntry(ToAddress(0x1300)); 125 CHECK_NE(NULL, entry3); 126 CHECK_EQ("5", entry3->name()); 127 CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1400))); 128 CodeEntry* entry4 = generator.code_map()->FindEntry(ToAddress(0x1500)); 129 CHECK_NE(NULL, entry4); 130 CHECK_EQ("ddd", entry4->name()); 131 CHECK_EQ(NULL, generator.code_map()->FindEntry(ToAddress(0x1600))); 132} 133 134 135template<typename T> 136static int CompareProfileNodes(const T* p1, const T* p2) { 137 return strcmp((*p1)->entry()->name(), (*p2)->entry()->name()); 138} 139 140TEST(TickEvents) { 141 TestSetup test_setup; 142 CpuProfilesCollection profiles; 143 profiles.StartProfiling("", 1); 144 ProfileGenerator generator(&profiles); 145 ProfilerEventsProcessor processor(&generator); 146 processor.Start(); 147 148 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG, 149 "bbb", 150 ToAddress(0x1200), 151 0x80); 152 processor.CodeCreateEvent(i::Logger::STUB_TAG, 5, ToAddress(0x1300), 0x10); 153 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG, 154 "ddd", 155 ToAddress(0x1400), 156 0x80); 157 EnqueueTickSampleEvent(&processor, ToAddress(0x1210)); 158 EnqueueTickSampleEvent(&processor, ToAddress(0x1305), ToAddress(0x1220)); 159 EnqueueTickSampleEvent(&processor, 160 ToAddress(0x1404), 161 ToAddress(0x1305), 162 ToAddress(0x1230)); 163 164 processor.Stop(); 165 processor.Join(); 166 CpuProfile* profile = 167 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1); 168 CHECK_NE(NULL, profile); 169 170 // Check call trees. 171 const i::List<ProfileNode*>* top_down_root_children = 172 profile->top_down()->root()->children(); 173 CHECK_EQ(1, top_down_root_children->length()); 174 CHECK_EQ("bbb", top_down_root_children->last()->entry()->name()); 175 const i::List<ProfileNode*>* top_down_bbb_children = 176 top_down_root_children->last()->children(); 177 CHECK_EQ(1, top_down_bbb_children->length()); 178 CHECK_EQ("5", top_down_bbb_children->last()->entry()->name()); 179 const i::List<ProfileNode*>* top_down_stub_children = 180 top_down_bbb_children->last()->children(); 181 CHECK_EQ(1, top_down_stub_children->length()); 182 CHECK_EQ("ddd", top_down_stub_children->last()->entry()->name()); 183 const i::List<ProfileNode*>* top_down_ddd_children = 184 top_down_stub_children->last()->children(); 185 CHECK_EQ(0, top_down_ddd_children->length()); 186 187 const i::List<ProfileNode*>* bottom_up_root_children_unsorted = 188 profile->bottom_up()->root()->children(); 189 CHECK_EQ(3, bottom_up_root_children_unsorted->length()); 190 i::List<ProfileNode*> bottom_up_root_children(3); 191 bottom_up_root_children.AddAll(*bottom_up_root_children_unsorted); 192 bottom_up_root_children.Sort(&CompareProfileNodes); 193 CHECK_EQ("5", bottom_up_root_children[0]->entry()->name()); 194 CHECK_EQ("bbb", bottom_up_root_children[1]->entry()->name()); 195 CHECK_EQ("ddd", bottom_up_root_children[2]->entry()->name()); 196 const i::List<ProfileNode*>* bottom_up_stub_children = 197 bottom_up_root_children[0]->children(); 198 CHECK_EQ(1, bottom_up_stub_children->length()); 199 CHECK_EQ("bbb", bottom_up_stub_children->last()->entry()->name()); 200 const i::List<ProfileNode*>* bottom_up_bbb_children = 201 bottom_up_root_children[1]->children(); 202 CHECK_EQ(0, bottom_up_bbb_children->length()); 203 const i::List<ProfileNode*>* bottom_up_ddd_children = 204 bottom_up_root_children[2]->children(); 205 CHECK_EQ(1, bottom_up_ddd_children->length()); 206 CHECK_EQ("5", bottom_up_ddd_children->last()->entry()->name()); 207 const i::List<ProfileNode*>* bottom_up_ddd_stub_children = 208 bottom_up_ddd_children->last()->children(); 209 CHECK_EQ(1, bottom_up_ddd_stub_children->length()); 210 CHECK_EQ("bbb", bottom_up_ddd_stub_children->last()->entry()->name()); 211} 212 213 214// http://crbug/51594 215// This test must not crash. 216TEST(CrashIfStoppingLastNonExistentProfile) { 217 InitializeVM(); 218 TestSetup test_setup; 219 CpuProfiler::SetUp(); 220 CpuProfiler::StartProfiling("1"); 221 CpuProfiler::StopProfiling("2"); 222 CpuProfiler::StartProfiling("1"); 223 CpuProfiler::StopProfiling(""); 224 CpuProfiler::TearDown(); 225} 226 227 228// http://code.google.com/p/v8/issues/detail?id=1398 229// Long stacks (exceeding max frames limit) must not be erased. 230TEST(Issue1398) { 231 TestSetup test_setup; 232 CpuProfilesCollection profiles; 233 profiles.StartProfiling("", 1); 234 ProfileGenerator generator(&profiles); 235 ProfilerEventsProcessor processor(&generator); 236 processor.Start(); 237 238 processor.CodeCreateEvent(i::Logger::BUILTIN_TAG, 239 "bbb", 240 ToAddress(0x1200), 241 0x80); 242 243 i::TickSample* sample = processor.TickSampleEvent(); 244 sample->pc = ToAddress(0x1200); 245 sample->tos = 0; 246 sample->frames_count = i::TickSample::kMaxFramesCount; 247 for (int i = 0; i < sample->frames_count; ++i) { 248 sample->stack[i] = ToAddress(0x1200); 249 } 250 251 processor.Stop(); 252 processor.Join(); 253 CpuProfile* profile = 254 profiles.StopProfiling(TokenEnumerator::kNoSecurityToken, "", 1); 255 CHECK_NE(NULL, profile); 256 257 int actual_depth = 0; 258 const ProfileNode* node = profile->top_down()->root(); 259 while (node->children()->length() > 0) { 260 node = node->children()->last(); 261 ++actual_depth; 262 } 263 264 CHECK_EQ(1 + i::TickSample::kMaxFramesCount, actual_depth); // +1 for PC. 265} 266 267 268TEST(DeleteAllCpuProfiles) { 269 InitializeVM(); 270 TestSetup test_setup; 271 CpuProfiler::SetUp(); 272 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 273 CpuProfiler::DeleteAllProfiles(); 274 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 275 276 CpuProfiler::StartProfiling("1"); 277 CpuProfiler::StopProfiling("1"); 278 CHECK_EQ(1, CpuProfiler::GetProfilesCount()); 279 CpuProfiler::DeleteAllProfiles(); 280 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 281 CpuProfiler::StartProfiling("1"); 282 CpuProfiler::StartProfiling("2"); 283 CpuProfiler::StopProfiling("2"); 284 CpuProfiler::StopProfiling("1"); 285 CHECK_EQ(2, CpuProfiler::GetProfilesCount()); 286 CpuProfiler::DeleteAllProfiles(); 287 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 288 289 // Test profiling cancellation by the 'delete' command. 290 CpuProfiler::StartProfiling("1"); 291 CpuProfiler::StartProfiling("2"); 292 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 293 CpuProfiler::DeleteAllProfiles(); 294 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 295 296 CpuProfiler::TearDown(); 297} 298 299 300TEST(DeleteCpuProfile) { 301 v8::HandleScope scope; 302 LocalContext env; 303 304 CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount()); 305 v8::Local<v8::String> name1 = v8::String::New("1"); 306 v8::CpuProfiler::StartProfiling(name1); 307 const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1); 308 CHECK_NE(NULL, p1); 309 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); 310 unsigned uid1 = p1->GetUid(); 311 CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1)); 312 const_cast<v8::CpuProfile*>(p1)->Delete(); 313 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 314 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1)); 315 316 v8::Local<v8::String> name2 = v8::String::New("2"); 317 v8::CpuProfiler::StartProfiling(name2); 318 const v8::CpuProfile* p2 = v8::CpuProfiler::StopProfiling(name2); 319 CHECK_NE(NULL, p2); 320 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); 321 unsigned uid2 = p2->GetUid(); 322 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2)); 323 CHECK_EQ(p2, v8::CpuProfiler::FindProfile(uid2)); 324 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1)); 325 v8::Local<v8::String> name3 = v8::String::New("3"); 326 v8::CpuProfiler::StartProfiling(name3); 327 const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3); 328 CHECK_NE(NULL, p3); 329 CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount()); 330 unsigned uid3 = p3->GetUid(); 331 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3)); 332 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3)); 333 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1)); 334 const_cast<v8::CpuProfile*>(p2)->Delete(); 335 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); 336 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2)); 337 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3)); 338 const_cast<v8::CpuProfile*>(p3)->Delete(); 339 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 340 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3)); 341 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2)); 342 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1)); 343} 344 345 346TEST(DeleteCpuProfileDifferentTokens) { 347 v8::HandleScope scope; 348 LocalContext env; 349 350 CHECK_EQ(0, v8::CpuProfiler::GetProfilesCount()); 351 v8::Local<v8::String> name1 = v8::String::New("1"); 352 v8::CpuProfiler::StartProfiling(name1); 353 const v8::CpuProfile* p1 = v8::CpuProfiler::StopProfiling(name1); 354 CHECK_NE(NULL, p1); 355 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); 356 unsigned uid1 = p1->GetUid(); 357 CHECK_EQ(p1, v8::CpuProfiler::FindProfile(uid1)); 358 v8::Local<v8::String> token1 = v8::String::New("token1"); 359 const v8::CpuProfile* p1_t1 = v8::CpuProfiler::FindProfile(uid1, token1); 360 CHECK_NE(NULL, p1_t1); 361 CHECK_NE(p1, p1_t1); 362 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); 363 const_cast<v8::CpuProfile*>(p1)->Delete(); 364 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 365 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1)); 366 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid1, token1)); 367 const_cast<v8::CpuProfile*>(p1_t1)->Delete(); 368 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 369 370 v8::Local<v8::String> name2 = v8::String::New("2"); 371 v8::CpuProfiler::StartProfiling(name2); 372 v8::Local<v8::String> token2 = v8::String::New("token2"); 373 const v8::CpuProfile* p2_t2 = v8::CpuProfiler::StopProfiling(name2, token2); 374 CHECK_NE(NULL, p2_t2); 375 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); 376 unsigned uid2 = p2_t2->GetUid(); 377 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid2)); 378 const v8::CpuProfile* p2 = v8::CpuProfiler::FindProfile(uid2); 379 CHECK_NE(p2_t2, p2); 380 v8::Local<v8::String> name3 = v8::String::New("3"); 381 v8::CpuProfiler::StartProfiling(name3); 382 const v8::CpuProfile* p3 = v8::CpuProfiler::StopProfiling(name3); 383 CHECK_NE(NULL, p3); 384 CHECK_EQ(2, v8::CpuProfiler::GetProfilesCount()); 385 unsigned uid3 = p3->GetUid(); 386 CHECK_NE(static_cast<int>(uid1), static_cast<int>(uid3)); 387 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3)); 388 const_cast<v8::CpuProfile*>(p2_t2)->Delete(); 389 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); 390 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2)); 391 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3)); 392 const_cast<v8::CpuProfile*>(p2)->Delete(); 393 CHECK_EQ(1, v8::CpuProfiler::GetProfilesCount()); 394 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid2)); 395 CHECK_EQ(p3, v8::CpuProfiler::FindProfile(uid3)); 396 const_cast<v8::CpuProfile*>(p3)->Delete(); 397 CHECK_EQ(0, CpuProfiler::GetProfilesCount()); 398 CHECK_EQ(NULL, v8::CpuProfiler::FindProfile(uid3)); 399} 400