Chromium Code Reviews| Index: test/cctest/test-cpu-profiler.cc |
| diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc |
| index a3e7b8d773a7bc51b11a981ed428621fa872d51f..60995264b672ec282af12691bb8769e91da07ebc 100644 |
| --- a/test/cctest/test-cpu-profiler.cc |
| +++ b/test/cctest/test-cpu-profiler.cc |
| @@ -1064,6 +1064,121 @@ TEST(BoundFunctionCall) { |
| } |
| +static i::Code* GetFunctionCodeFromHeap(i::Isolate* isolate, |
| + const char* name) { |
| + CHECK_NE(NULL, isolate); |
| + i::Heap* heap = isolate->heap(); |
| + CHECK_NE(NULL, heap); |
| + |
| + heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, |
| + "Logger::LogCompiledFunctions"); |
|
yurys
2014/08/08 08:13:23
"GetFunctionCodeFromHeap"
|
| + |
| + i::HandleScope scope(isolate); |
| + i::HeapIterator iterator(heap); |
| + i::DisallowHeapAllocation no_gc; |
| + |
| + // Iterate the heap to find shared function info objects. |
| + for (i::HeapObject* obj = iterator.next(); |
| + obj != NULL; |
| + obj = iterator.next()) { |
| + if (!obj->IsSharedFunctionInfo()) continue; |
| + i::SharedFunctionInfo* sfi = i::SharedFunctionInfo::cast(obj); |
| + if (sfi->is_compiled() |
| + && (!sfi->script()->IsScript() |
| + || i::Script::cast(sfi->script())->HasValidSource())) { |
| + i::Handle<i::String> func_name(sfi->DebugName()); |
| + i::SmartArrayPointer<char> str = |
| + sfi->DebugName()->ToCString(i::DISALLOW_NULLS, |
| + i::ROBUST_STRING_TRAVERSAL); |
| + if (strcmp(str.get(), name) == 0) |
| + return sfi->code(); |
| + } |
| + } |
| + |
| + return NULL; |
| +} |
| + |
| + |
| +// This tests checks distribution of the samples through the source lines. |
| +TEST(TickLines) { |
| + CcTest::InitializeVM(); |
| + LocalContext env; |
| + i::Isolate* isolate = CcTest::i_isolate(); |
| + CpuProfiler* profiler = isolate->cpu_profiler(); |
| + i::HandleScope scope(isolate); |
| + |
| + i::EmbeddedVector<char, 512> source; |
| + const char* foo_name = "foo"; |
| + i::SNPrintF(source, |
| + "(function %s(timeout) {\n" |
| + " this.mmm = 0;\n" |
| + " var start = Date.now();\n" |
| + " while (Date.now() - start < timeout) {\n" |
| + " var n = 100*1000;\n" |
| + " while(n > 1) {\n" |
| + " n--;\n" |
| + " this.mmm += n * n * n;\n" |
| + " }\n" |
| + " }\n" |
| + "})(this)\n", foo_name); |
|
yurys
2014/08/08 08:13:23
'this' passed as timeout looks like an error.
|
| + |
| + // Compile the source. The compiled functions with relocation info are |
| + // located in the heap. |
| + CompileRun(source.start()); |
| + |
| + // The profiler consumes code creation events for all compiled functions |
| + // found in the heap. |
| + profiler->StartProfiling("", false); |
| + |
| + // Enqueue the tick events to add 'foo' function to the profile. |
| + i::Code* foo_code = GetFunctionCodeFromHeap(isolate, foo_name); |
| + CHECK_NE(NULL, foo_code); |
| + i::Address address = foo_code->instruction_start(); |
| + CHECK_NE(NULL, address); |
| + EnqueueTickSampleEvent(profiler->processor(), address); |
| + v8::base::OS::Sleep(100); // Ensure that a new node is added to the profile. |
|
yurys
2014/08/08 08:13:23
We need to use some explicit event instead of Slee
|
| + |
| + // Get a code entry for 'foo' function. |
| + ProfileGenerator* generator = profiler->generator(); |
| + CodeEntry* foo = generator->code_map()->FindEntry(address); |
|
yurys
2014/08/08 08:13:23
This is not thread-safe as code_map is used on the
|
| + CHECK_NE(NULL, foo); |
| + |
| + CpuProfile* profile = profiler->StopProfiling(""); |
| + CHECK_NE(NULL, profile); |
| + |
| + // Firstly, check the underlying code entry for 'foo' function. |
| + CHECK_EQ(foo_name, foo->name()); |
| + const i::JITLineInfoTable* foo_line_info = foo->line_info(); |
| + CHECK_NE(NULL, foo_line_info); |
| + CHECK_EQ(false, foo_line_info->Empty()); |
| + |
| + // Secondly, check the hit source lines are accessible using V8 Public APIs. |
| + const i::ProfileTree* tree = profile->top_down(); |
| + ProfileNode* root = tree->root(); |
| + CHECK_NE(NULL, root); |
| + ProfileNode* foo_node = root->FindChild(foo); |
| + CHECK_NE(NULL, foo_node); |
| + |
| + // Add 10 faked ticks to source line #5. |
| + int hit_line = 5; |
| + int hit_count = 10; |
| + for (int i = 0; i < hit_count; i++) |
| + foo_node->IncrementLineTicks(hit_line); |
| + |
| + unsigned int line_count = foo_node->GetHitLineCount(); |
| + CHECK_EQ(2, line_count); // Expect two hit source lines - #1 and #5. |
| + ScopedVector<v8::CpuProfileNode::LineTick> entries(line_count); |
| + CHECK_EQ(true, foo_node->GetLineTicks(&entries[0], line_count)); |
| + int value = 0; |
| + for (int i = 0; i < entries.length(); i++) |
| + if (entries[i].line == hit_line) { |
| + value = entries[i].hit_count; |
| + break; |
| + } |
| + CHECK_EQ(hit_count, value); |
| +} |
| + |
| + |
| static const char* call_function_test_source = "function bar(iterations) {\n" |
| "}\n" |
| "function start(duration) {\n" |