diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc index e9ad1ccfa0d..c75f1362008 100644 --- a/runtime/vm/profiler.cc +++ b/runtime/vm/profiler.cc @@ -965,11 +965,6 @@ void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) { const bool exited_dart_code = ExitedDart(isolate); - if (!exited_dart_code && !FLAG_profile_vm) { - // No Dart frames on stack and we are not profiling the vm. - return; - } - SampleBuffer* sample_buffer = GetSampleBuffer(isolate); if (sample_buffer == NULL) { // Profiler not initialized. @@ -1010,14 +1005,22 @@ void Profiler::RecordAllocation(Isolate* isolate, intptr_t cid) { fp, sp); native_stack_walker.walk(); - } else { - ASSERT(exited_dart_code); + } else if (exited_dart_code) { Sample* sample = SetupSample(isolate, sample_buffer, OSThread::GetCurrentThreadId()); sample->SetAllocationCid(cid); ProfilerDartExitStackWalker dart_exit_stack_walker(isolate, sample); dart_exit_stack_walker.walk(); + } else { + // Fall back. + uintptr_t pc = GetProgramCounter(); + Sample* sample = SetupSample(isolate, + sample_buffer, + OSThread::GetCurrentThreadId()); + sample->SetAllocationCid(cid); + sample->set_vm_tag(VMTag::kEmbedderTagId); + sample->SetAt(0, pc); } } diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc index f0472db3328..1efc6b1cf26 100644 --- a/runtime/vm/profiler_test.cc +++ b/runtime/vm/profiler_test.cc @@ -132,15 +132,27 @@ class AllocationFilter : public SampleFilter { public: explicit AllocationFilter(Isolate* isolate, intptr_t cid) : SampleFilter(isolate), - cid_(cid) { + cid_(cid), + enable_embedder_ticks_(false) { } bool FilterSample(Sample* sample) { - return sample->is_allocation_sample() && (sample->allocation_cid() == cid_); + if (!enable_embedder_ticks_ && + (sample->vm_tag() == VMTag::kEmbedderTagId)) { + // We don't want to see embedder ticks in the test. + return false; + } + return sample->is_allocation_sample() && + (sample->allocation_cid() == cid_); + } + + void set_enable_embedder_ticks(bool enable) { + enable_embedder_ticks_ = enable; } private: intptr_t cid_; + bool enable_embedder_ticks_; }; @@ -693,6 +705,141 @@ TEST_CASE(Profiler_ArrayAllocation) { } +TEST_CASE(Profiler_ContextAllocation) { + DisableNativeProfileScope dnps; + const char* kScript = + "var msg1 = 'a';\n" + "foo() {\n" + " var msg = msg1 + msg1;\n" + " return (x) { return '$msg + $msg'; }(msg);\n" + "}\n"; + Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); + EXPECT_VALID(lib); + Library& root_library = Library::Handle(); + root_library ^= Api::UnwrapHandle(lib); + Isolate* isolate = Isolate::Current(); + + const Class& context_class = + Class::Handle(Object::context_class()); + EXPECT(!context_class.IsNull()); + + Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 0, NULL); + EXPECT_VALID(result); + + { + StackZone zone(isolate); + HANDLESCOPE(isolate); + Profile profile(isolate); + AllocationFilter filter(isolate, context_class.id()); + profile.Build(&filter, Profile::kNoTags); + // We should have no allocation samples. + EXPECT_EQ(0, profile.sample_count()); + } + + context_class.SetTraceAllocation(true); + result = Dart_Invoke(lib, NewString("foo"), 0, NULL); + EXPECT_VALID(result); + + { + StackZone zone(isolate); + HANDLESCOPE(isolate); + Profile profile(isolate); + AllocationFilter filter(isolate, context_class.id()); + profile.Build(&filter, Profile::kNoTags); + // We should have one allocation sample. + EXPECT_EQ(1, profile.sample_count()); + ProfileTrieWalker walker(&profile); + + walker.Reset(Profile::kExclusiveCode); + EXPECT(walker.Down()); + EXPECT_STREQ("foo", walker.CurrentName()); + EXPECT(!walker.Down()); + } + + context_class.SetTraceAllocation(false); + result = Dart_Invoke(lib, NewString("foo"), 0, NULL); + EXPECT_VALID(result); + + { + StackZone zone(isolate); + HANDLESCOPE(isolate); + Profile profile(isolate); + AllocationFilter filter(isolate, context_class.id()); + profile.Build(&filter, Profile::kNoTags); + // We should still only have one allocation sample. + EXPECT_EQ(1, profile.sample_count()); + } +} + + +TEST_CASE(Profiler_ClassAllocation) { + DisableNativeProfileScope dnps; + const char* kScript = + "var msg1 = 'a';\n" + "\n" + "foo() {\n" + " var msg = msg1 + msg1;\n" + " var msg2 = msg + msg;\n" + " return (x, y, z, w) { return '$x + $y + $z'; }(msg, msg2, msg, msg);\n" + "}\n" + "bar() {\n" + " var msg = msg1 + msg1;\n" + " var msg2 = msg + msg;\n" + " return (x, y) { return '$x + $y'; }(msg, msg2);\n" + "}\n"; + + Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL); + EXPECT_VALID(lib); + Library& root_library = Library::Handle(); + root_library ^= Api::UnwrapHandle(lib); + Isolate* isolate = Isolate::Current(); + + const Class& class_class = + Class::Handle(Object::class_class()); + EXPECT(!class_class.IsNull()); + class_class.SetTraceAllocation(true); + + // Invoke "foo" which during compilation, triggers a closure class allocation. + Dart_Handle result = Dart_Invoke(lib, NewString("foo"), 0, NULL); + EXPECT_VALID(result); + + { + StackZone zone(isolate); + HANDLESCOPE(isolate); + Profile profile(isolate); + AllocationFilter filter(isolate, class_class.id()); + filter.set_enable_embedder_ticks(true); + profile.Build(&filter, Profile::kNoTags); + // We should have one allocation sample. + EXPECT_EQ(1, profile.sample_count()); + ProfileTrieWalker walker(&profile); + + walker.Reset(Profile::kExclusiveCode); + EXPECT(walker.Down()); + EXPECT_SUBSTRING("dart::Profiler::RecordAllocation", walker.CurrentName()); + EXPECT(!walker.Down()); + } + + // Disable allocation tracing for Class. + class_class.SetTraceAllocation(false); + + // Invoke "bar" which during compilation, triggers a closure class allocation. + result = Dart_Invoke(lib, NewString("bar"), 0, NULL); + EXPECT_VALID(result); + + { + StackZone zone(isolate); + HANDLESCOPE(isolate); + Profile profile(isolate); + AllocationFilter filter(isolate, class_class.id()); + filter.set_enable_embedder_ticks(true); + profile.Build(&filter, Profile::kNoTags); + // We should still only have one allocation sample. + EXPECT_EQ(1, profile.sample_count()); + } +} + + TEST_CASE(Profiler_TypedArrayAllocation) { DisableNativeProfileScope dnps; const char* kScript =