Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(863)

Unified Diff: runtime/vm/profiler_test.cc

Issue 1779333004: Add profile data to getSourceReport (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/vm/profiler_service.cc ('k') | runtime/vm/service.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/vm/profiler_test.cc
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index f1518a4766eebf047a36bfebf35048dc1bce4d0f..6f4e0ad40ae67f890501f3988106dd8b13d96e5c 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -9,6 +9,7 @@
#include "vm/globals.h"
#include "vm/profiler.h"
#include "vm/profiler_service.h"
+#include "vm/source_report.h"
#include "vm/unit_test.h"
namespace dart {
@@ -2299,6 +2300,204 @@ TEST_CASE(Profiler_BinaryOperatorSourcePositionOptimized) {
}
}
+
+static void InsertFakeSample(SampleBuffer* sample_buffer,
+ uword* pc_offsets) {
+ ASSERT(sample_buffer != NULL);
+ Isolate* isolate = Isolate::Current();
+ Sample* sample = sample_buffer->ReserveSample();
+ ASSERT(sample != NULL);
+ sample->Init(isolate,
+ OS::GetCurrentMonotonicMicros(),
+ OSThread::Current()->trace_id());
+
+ intptr_t i = 0;
+ while (pc_offsets[i] != 0) {
+ // When we collect a real stack trace, all PCs collected aside from the
+ // executing one (i == 0) are actually return addresses. Return addresses
+ // are one byte beyond the call instruction that is executing. The profiler
+ // accounts for this and subtracts one from these addresses when querying
+ // inline and token position ranges. To be consistent with real stack
+ // traces, we add one byte to all PCs except the executing one.
+ // See OffsetForPC in profiler_service.cc for more context.
+ const intptr_t return_address_offset = i > 0 ? 1 : 0;
+ sample->SetAt(i, pc_offsets[i] + return_address_offset);
+ i++;
+ }
+ sample->SetAt(i, NULL);
+}
+
+
+static uword FindPCForTokenPosition(const Code& code,
+ const CodeSourceMap& code_source_map,
+ TokenPosition tp) {
+ CodeSourceMap::Iterator it(code_source_map);
+
+ while (it.MoveNext()) {
+ if (it.TokenPos() == tp) {
+ return it.PcOffset() + code.EntryPoint();
+ }
+ }
+
+ return 0;
+}
+
+
+TEST_CASE(Profiler_GetSourceReport) {
+ const char* kScript =
+ "doWork(i) => i * i;\n"
+ "main() {\n"
+ " var sum = 0;\n"
+ " for (var i = 0; i < 100; i++) {\n"
+ " sum += doWork(i);\n"
+ " }\n"
+ " return sum;\n"
+ "}\n";
+
+ // Token position of * in `i * i`.
+ const TokenPosition squarePosition = TokenPosition(6);
+
+ // Token position of the call to `doWork`.
+ const TokenPosition callPosition = TokenPosition(39);
+
+ DisableNativeProfileScope dnps;
+ // Disable profiling for this thread.
+ DisableThreadInterruptsScope dtis(Thread::Current());
+
+ SampleBuffer* sample_buffer = Profiler::sample_buffer();
+ EXPECT(sample_buffer != NULL);
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ Library& root_library = Library::Handle();
+ root_library ^= Api::UnwrapHandle(lib);
+
+ // Invoke main so that it gets compiled.
+ Dart_Handle result = Dart_Invoke(lib, NewString("main"), 0, NULL);
+ EXPECT_VALID(result);
+
+ {
+ // Clear the profile for this isolate.
+ ClearProfileVisitor cpv(Isolate::Current());
+ sample_buffer->VisitSamples(&cpv);
+ }
+
+ // Query the code object for main and determine the PC at some token
+ // positions.
+ const Function& main = Function::Handle(GetFunction(root_library, "main"));
+ EXPECT(!main.IsNull());
+
+ const Function& do_work =
+ Function::Handle(GetFunction(root_library, "doWork"));
+ EXPECT(!do_work.IsNull());
+
+ const Script& script = Script::Handle(main.script());
+ EXPECT(!script.IsNull());
+
+ const Code& main_code = Code::Handle(main.CurrentCode());
+ EXPECT(!main_code.IsNull());
+
+ const Code& do_work_code = Code::Handle(do_work.CurrentCode());
+ EXPECT(!do_work_code.IsNull());
+
+ const CodeSourceMap& main_code_source_map =
+ CodeSourceMap::Handle(main_code.code_source_map());
+ EXPECT(!main_code_source_map.IsNull());
+
+ const CodeSourceMap& do_work_code_source_map =
+ CodeSourceMap::Handle(do_work_code.code_source_map());
+ EXPECT(!do_work_code_source_map.IsNull());
+
+ // Dump code source map.
+ CodeSourceMap::Dump(do_work_code_source_map, do_work_code, main);
+ CodeSourceMap::Dump(main_code_source_map, main_code, main);
+
+ // Look up some source token position's pc.
+ uword squarePositionPc =
+ FindPCForTokenPosition(do_work_code,
+ do_work_code_source_map,
+ squarePosition);
+ EXPECT(squarePositionPc != 0);
+
+ uword callPositionPc =
+ FindPCForTokenPosition(main_code, main_code_source_map, callPosition);
+ EXPECT(callPositionPc != 0);
+
+ // Look up some classifying token position's pc.
+ uword controlFlowPc =
+ FindPCForTokenPosition(do_work_code,
+ do_work_code_source_map,
+ TokenPosition::kControlFlow);
+ EXPECT(controlFlowPc != 0);
+
+ uword tempMovePc =
+ FindPCForTokenPosition(main_code,
+ main_code_source_map,
+ TokenPosition::kTempMove);
+ EXPECT(tempMovePc != 0);
+
+ // Insert fake samples.
+
+ // Sample 1:
+ // squarePositionPc exclusive.
+ // callPositionPc inclusive.
+ uword sample1[] = {
+ squarePositionPc, // doWork.
+ callPositionPc, // main.
+ 0
+ };
+
+ // Sample 2:
+ // squarePositionPc exclusive.
+ uword sample2[] = {
+ squarePositionPc, // doWork.
+ 0,
+ };
+
+ // Sample 3:
+ // controlFlowPc exclusive.
+ // callPositionPc inclusive.
+ uword sample3[] = {
+ controlFlowPc, // doWork.
+ callPositionPc, // main.
+ 0
+ };
+
+ // Sample 4:
+ // tempMovePc exclusive.
+ uword sample4[] = {
+ tempMovePc, // main.
+ 0
+ };
+
+ InsertFakeSample(sample_buffer, &sample1[0]);
+ InsertFakeSample(sample_buffer, &sample2[0]);
+ InsertFakeSample(sample_buffer, &sample3[0]);
+ InsertFakeSample(sample_buffer, &sample4[0]);
+
+ // Generate source report for main.
+ SourceReport sourceReport(SourceReport::kProfile);
+ JSONStream js;
+ sourceReport.PrintJSON(&js,
+ script,
+ do_work.token_pos(),
+ main.end_token_pos());
+
+ // Verify positions in do_work.
+ EXPECT_SUBSTRING("\"positions\":[\"ControlFlow\",6]", js.ToCString());
+ // Verify exclusive ticks in do_work.
+ EXPECT_SUBSTRING("\"exclusiveTicks\":[1,2]", js.ToCString());
+ // Verify inclusive ticks in do_work.
+ EXPECT_SUBSTRING("\"inclusiveTicks\":[1,2]", js.ToCString());
+
+ // Verify positions in main.
+ EXPECT_SUBSTRING("\"positions\":[\"TempMove\",39]", js.ToCString());
+ // Verify exclusive ticks in main.
+ EXPECT_SUBSTRING("\"exclusiveTicks\":[1,0]", js.ToCString());
+ // Verify inclusive ticks in main.
+ EXPECT_SUBSTRING("\"inclusiveTicks\":[1,2]", js.ToCString());
+}
+
#endif // !PRODUCT
} // namespace dart
« no previous file with comments | « runtime/vm/profiler_service.cc ('k') | runtime/vm/service.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698