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..669e4b7056f16521f7beaae22707eac994fe489d 100644 |
--- a/test/cctest/test-cpu-profiler.cc |
+++ b/test/cctest/test-cpu-profiler.cc |
@@ -1064,6 +1064,136 @@ TEST(BoundFunctionCall) { |
} |
+static i::SharedFunctionInfo* GetFunctionInfoFromHeap(i::Isolate* isolate, |
+ const char* name) { |
+ CHECK_NE(NULL, isolate); |
+ i::Heap* heap = isolate->heap(); |
+ CHECK_NE(NULL, heap); |
+ |
+ heap->CollectAllGarbage(Heap::kMakeHeapIterableMask, |
+ "GetFunctionInfoFromHeap"); |
+ |
+ 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) |
alph
2014/08/11 12:18:15
It's better to make a v8 heap string out of 'name'
|
+ return sfi; |
+ } |
+ } |
+ |
+ 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(); |
+ i::Factory* factory = isolate->factory(); |
+ 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" |
alph
2014/08/11 12:18:15
This test bound to be flaky as it depends on the t
|
+ " var n = 100*1000;\n" |
+ " while(n > 1) {\n" |
+ " n--;\n" |
+ " this.mmm += n * n * n;\n" |
+ " }\n" |
+ " }\n" |
+ "})(%d)\n", foo_name, 100); |
+ |
+ // Compile the source. The compiled functions with relocation info are |
+ // located in the heap. |
+ CompileRun(source.start()); |
+ |
+ i::SharedFunctionInfo* shared = GetFunctionInfoFromHeap(isolate, foo_name); |
alph
2014/08/11 12:18:15
You can get the JSFunction object out of global co
|
+ CHECK_NE(NULL, shared); |
+ i::Code* foo_code = shared->code(); |
+ CHECK_NE(NULL, foo_code); |
+ |
+ CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap()); |
+ profiles->StartProfiling("", false); |
+ ProfileGenerator generator(profiles); |
+ SmartPointer<ProfilerEventsProcessor> processor(new ProfilerEventsProcessor( |
+ &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100))); |
+ processor->Start(); |
+ CpuProfiler profiler(isolate, profiles, &generator, processor.get()); |
+ |
+ // Enqueue code creation events. |
+ i::Handle<i::String> str = factory->NewStringFromAsciiChecked(foo_name); |
+ int line = 1; |
+ int column = 1; |
+ profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, |
+ foo_code, |
+ shared, |
+ NULL, |
+ *str, |
+ line, |
+ column); |
+ |
+ // Enqueue a tick event to enable code events processing. |
+ EnqueueTickSampleEvent(processor.get(), foo_code->address()); |
+ |
+ processor->StopSynchronously(); |
+ |
+ CpuProfile* profile = profiles->StopProfiling(""); |
+ CHECK_NE(NULL, profile); |
+ |
+ // Check the state of profile generator. |
+ CodeEntry* foo = generator.code_map()->FindEntry(foo_code->address()); |
+ CHECK_NE(NULL, foo); |
+ 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()); |
+ |
+ // Check the hit source lines 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" |