OLD | NEW |
1 // Copyright 2009 the V8 project authors. All rights reserved. | 1 // Copyright 2009 the V8 project authors. All rights reserved. |
2 // | 2 // |
3 // Tests for heap profiler | 3 // Tests for heap profiler |
4 | 4 |
5 #ifdef ENABLE_LOGGING_AND_PROFILING | 5 #ifdef ENABLE_LOGGING_AND_PROFILING |
6 | 6 |
7 #include "v8.h" | 7 #include "v8.h" |
8 #include "heap-profiler.h" | 8 #include "heap-profiler.h" |
9 #include "string-stream.h" | 9 #include "string-stream.h" |
10 #include "cctest.h" | 10 #include "cctest.h" |
11 #include "zone-inl.h" | 11 #include "zone-inl.h" |
| 12 #include "../include/v8-profiler.h" |
12 | 13 |
13 namespace i = v8::internal; | 14 namespace i = v8::internal; |
14 using i::ClustersCoarser; | 15 using i::ClustersCoarser; |
15 using i::JSObjectsCluster; | 16 using i::JSObjectsCluster; |
16 using i::JSObjectsRetainerTree; | 17 using i::JSObjectsRetainerTree; |
17 using i::JSObjectsClusterTree; | 18 using i::JSObjectsClusterTree; |
18 using i::RetainerHeapProfile; | 19 using i::RetainerHeapProfile; |
19 | 20 |
20 | 21 |
21 static void CompileAndRunScript(const char *src) { | 22 static void CompileAndRunScript(const char *src) { |
(...skipping 361 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 // verify each retainer separately. | 384 // verify each retainer separately. |
384 CHECK_EQ(i::StrLength("(global property);1,B;2,C;2"), | 385 CHECK_EQ(i::StrLength("(global property);1,B;2,C;2"), |
385 i::StrLength(retainers_of_a)); | 386 i::StrLength(retainers_of_a)); |
386 CHECK(strstr(retainers_of_a, "(global property);1") != NULL); | 387 CHECK(strstr(retainers_of_a, "(global property);1") != NULL); |
387 CHECK(strstr(retainers_of_a, "B;2") != NULL); | 388 CHECK(strstr(retainers_of_a, "B;2") != NULL); |
388 CHECK(strstr(retainers_of_a, "C;2") != NULL); | 389 CHECK(strstr(retainers_of_a, "C;2") != NULL); |
389 CHECK_EQ("(global property);2", printer.GetRetainers("B")); | 390 CHECK_EQ("(global property);2", printer.GetRetainers("B")); |
390 CHECK_EQ("(global property);1", printer.GetRetainers("C")); | 391 CHECK_EQ("(global property);1", printer.GetRetainers("C")); |
391 } | 392 } |
392 | 393 |
| 394 |
| 395 namespace { |
| 396 |
| 397 class NamedEntriesDetector { |
| 398 public: |
| 399 NamedEntriesDetector() |
| 400 : has_A1(false), has_B1(false), has_C1(false), |
| 401 has_A2(false), has_B2(false), has_C2(false) { |
| 402 } |
| 403 |
| 404 void Apply(i::HeapEntry* entry) { |
| 405 const char* node_name = entry->name(); |
| 406 if (strcmp("A1", node_name) == 0 |
| 407 && entry->GetRetainingPaths()->length() > 0) has_A1 = true; |
| 408 if (strcmp("B1", node_name) == 0 |
| 409 && entry->GetRetainingPaths()->length() > 0) has_B1 = true; |
| 410 if (strcmp("C1", node_name) == 0 |
| 411 && entry->GetRetainingPaths()->length() > 0) has_C1 = true; |
| 412 if (strcmp("A2", node_name) == 0 |
| 413 && entry->GetRetainingPaths()->length() > 0) has_A2 = true; |
| 414 if (strcmp("B2", node_name) == 0 |
| 415 && entry->GetRetainingPaths()->length() > 0) has_B2 = true; |
| 416 if (strcmp("C2", node_name) == 0 |
| 417 && entry->GetRetainingPaths()->length() > 0) has_C2 = true; |
| 418 } |
| 419 |
| 420 bool has_A1; |
| 421 bool has_B1; |
| 422 bool has_C1; |
| 423 bool has_A2; |
| 424 bool has_B2; |
| 425 bool has_C2; |
| 426 }; |
| 427 |
| 428 } // namespace |
| 429 |
| 430 TEST(HeapSnapshot) { |
| 431 v8::HandleScope scope; |
| 432 |
| 433 v8::Handle<v8::String> token1 = v8::String::New("token1"); |
| 434 v8::Handle<v8::Context> env1 = v8::Context::New(); |
| 435 env1->SetSecurityToken(token1); |
| 436 env1->Enter(); |
| 437 |
| 438 CompileAndRunScript( |
| 439 "function A1() {}\n" |
| 440 "function B1(x) { this.x = x; }\n" |
| 441 "function C1(x) { this.x1 = x; this.x2 = x; }\n" |
| 442 "var a1 = new A1();\n" |
| 443 "var b1_1 = new B1(a1), b1_2 = new B1(a1);\n" |
| 444 "var c1 = new C1(a1);"); |
| 445 |
| 446 v8::Handle<v8::String> token2 = v8::String::New("token2"); |
| 447 v8::Handle<v8::Context> env2 = v8::Context::New(); |
| 448 env2->SetSecurityToken(token2); |
| 449 env2->Enter(); |
| 450 |
| 451 CompileAndRunScript( |
| 452 "function A2() {}\n" |
| 453 "function B2(x) { return function() { return typeof x; }; }\n" |
| 454 "function C2(x) { this.x1 = x; this.x2 = x; this[1] = x; }\n" |
| 455 "var a2 = new A2();\n" |
| 456 "var b2_1 = new B2(a2), b2_2 = new B2(a2);\n" |
| 457 "var c2 = new C2(a2);"); |
| 458 const v8::HeapSnapshot* snapshot_env2 = |
| 459 v8::HeapProfiler::TakeSnapshot(v8::String::New("env2")); |
| 460 CHECK_EQ(1, snapshot_env2->GetHead()->GetChildrenCount()); |
| 461 const v8::HeapGraphNode* global_env2 = |
| 462 snapshot_env2->GetHead()->GetChild(0)->GetToNode(); |
| 463 |
| 464 // Verify, that JS global object of env2 doesn't have '..1' |
| 465 // properties, but has '..2' properties. |
| 466 bool has_a1 = false, has_b1_1 = false, has_b1_2 = false, has_c1 = false; |
| 467 bool has_a2 = false, has_b2_1 = false, has_b2_2 = false, has_c2 = false; |
| 468 // This will be needed further. |
| 469 const v8::HeapGraphNode* a2_node = NULL; |
| 470 for (int i = 0, count = global_env2->GetChildrenCount(); i < count; ++i) { |
| 471 const v8::HeapGraphEdge* prop = global_env2->GetChild(i); |
| 472 v8::String::AsciiValue prop_name(prop->GetName()); |
| 473 if (strcmp("a1", *prop_name) == 0) has_a1 = true; |
| 474 if (strcmp("b1_1", *prop_name) == 0) has_b1_1 = true; |
| 475 if (strcmp("b1_2", *prop_name) == 0) has_b1_2 = true; |
| 476 if (strcmp("c1", *prop_name) == 0) has_c1 = true; |
| 477 if (strcmp("a2", *prop_name) == 0) { |
| 478 has_a2 = true; |
| 479 a2_node = prop->GetToNode(); |
| 480 } |
| 481 if (strcmp("b2_1", *prop_name) == 0) has_b2_1 = true; |
| 482 if (strcmp("b2_2", *prop_name) == 0) has_b2_2 = true; |
| 483 if (strcmp("c2", *prop_name) == 0) has_c2 = true; |
| 484 } |
| 485 CHECK(!has_a1); |
| 486 CHECK(!has_b1_1); |
| 487 CHECK(!has_b1_2); |
| 488 CHECK(!has_c1); |
| 489 CHECK(has_a2); |
| 490 CHECK(has_b2_1); |
| 491 CHECK(has_b2_2); |
| 492 CHECK(has_c2); |
| 493 |
| 494 // Verify that anything related to '[ABC]1' is not reachable. |
| 495 NamedEntriesDetector det; |
| 496 i::HeapSnapshot* i_snapshot_env2 = |
| 497 const_cast<i::HeapSnapshot*>( |
| 498 reinterpret_cast<const i::HeapSnapshot*>(snapshot_env2)); |
| 499 i_snapshot_env2->IterateEntries(&det); |
| 500 CHECK(!det.has_A1); |
| 501 CHECK(!det.has_B1); |
| 502 CHECK(!det.has_C1); |
| 503 CHECK(det.has_A2); |
| 504 CHECK(det.has_B2); |
| 505 CHECK(det.has_C2); |
| 506 |
| 507 // Verify 'a2' object retainers. They are: |
| 508 // - (global object).a2 |
| 509 // - c2.x1, c2.x2, c2[1] |
| 510 // - b2_1 and b2_2 closures: via 'x' variable |
| 511 CHECK_EQ(6, a2_node->GetRetainingPathsCount()); |
| 512 bool has_global_obj_a2_ref = false; |
| 513 bool has_c2_x1_ref = false, has_c2_x2_ref = false, has_c2_1_ref = false; |
| 514 bool has_b2_1_x_ref = false, has_b2_2_x_ref = false; |
| 515 for (int i = 0; i < a2_node->GetRetainingPathsCount(); ++i) { |
| 516 const v8::HeapGraphPath* path = a2_node->GetRetainingPath(i); |
| 517 const int edges_count = path->GetEdgesCount(); |
| 518 CHECK_GT(edges_count, 0); |
| 519 const v8::HeapGraphEdge* last_edge = path->GetEdge(edges_count - 1); |
| 520 v8::String::AsciiValue last_edge_name(last_edge->GetName()); |
| 521 if (strcmp("a2", *last_edge_name) == 0 |
| 522 && last_edge->GetType() == v8::HeapGraphEdge::PROPERTY) { |
| 523 has_global_obj_a2_ref = true; |
| 524 continue; |
| 525 } |
| 526 CHECK_GT(edges_count, 1); |
| 527 const v8::HeapGraphEdge* prev_edge = path->GetEdge(edges_count - 2); |
| 528 v8::String::AsciiValue prev_edge_name(prev_edge->GetName()); |
| 529 if (strcmp("x1", *last_edge_name) == 0 |
| 530 && last_edge->GetType() == v8::HeapGraphEdge::PROPERTY |
| 531 && strcmp("c2", *prev_edge_name) == 0) has_c2_x1_ref = true; |
| 532 if (strcmp("x2", *last_edge_name) == 0 |
| 533 && last_edge->GetType() == v8::HeapGraphEdge::PROPERTY |
| 534 && strcmp("c2", *prev_edge_name) == 0) has_c2_x2_ref = true; |
| 535 if (strcmp("1", *last_edge_name) == 0 |
| 536 && last_edge->GetType() == v8::HeapGraphEdge::ELEMENT |
| 537 && strcmp("c2", *prev_edge_name) == 0) has_c2_1_ref = true; |
| 538 if (strcmp("x", *last_edge_name) == 0 |
| 539 && last_edge->GetType() == v8::HeapGraphEdge::CONTEXT_VARIABLE |
| 540 && strcmp("b2_1", *prev_edge_name) == 0) has_b2_1_x_ref = true; |
| 541 if (strcmp("x", *last_edge_name) == 0 |
| 542 && last_edge->GetType() == v8::HeapGraphEdge::CONTEXT_VARIABLE |
| 543 && strcmp("b2_2", *prev_edge_name) == 0) has_b2_2_x_ref = true; |
| 544 } |
| 545 CHECK(has_global_obj_a2_ref); |
| 546 CHECK(has_c2_x1_ref); |
| 547 CHECK(has_c2_x2_ref); |
| 548 CHECK(has_c2_1_ref); |
| 549 CHECK(has_b2_1_x_ref); |
| 550 CHECK(has_b2_2_x_ref); |
| 551 } |
| 552 |
393 #endif // ENABLE_LOGGING_AND_PROFILING | 553 #endif // ENABLE_LOGGING_AND_PROFILING |
OLD | NEW |