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

Side by Side Diff: runtime/vm/coverage.cc

Issue 324843004: Significantly improve performance of code coverage tool by precomputing a map token_pos->line numbe… (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 6 years, 6 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/coverage.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/coverage.h" 5 #include "vm/coverage.h"
6 6
7 #include "include/dart_api.h" 7 #include "include/dart_api.h"
8 8
9 #include "vm/compiler.h" 9 #include "vm/compiler.h"
10 #include "vm/isolate.h" 10 #include "vm/isolate.h"
11 #include "vm/json_stream.h" 11 #include "vm/json_stream.h"
12 #include "vm/object.h" 12 #include "vm/object.h"
13 #include "vm/object_store.h" 13 #include "vm/object_store.h"
14 14
15 namespace dart { 15 namespace dart {
16 16
17 DEFINE_FLAG(charp, coverage_dir, NULL, 17 DEFINE_FLAG(charp, coverage_dir, NULL,
18 "Enable writing coverage data into specified directory."); 18 "Enable writing coverage data into specified directory.");
19 19
20 20
21 // map[token_pos] -> line-number.
22 static void ComputeTokenPosToLineNumberMap(const Script& script,
23 GrowableArray<intptr_t>* map) {
24 const TokenStream& tkns = TokenStream::Handle(script.tokens());
25 const intptr_t len = ExternalTypedData::Handle(tkns.GetStream()).Length();
26 map->Clear();
27 for (intptr_t i = 0; i < len; i++) {
28 map->Add(-1);
29 }
30 TokenStream::Iterator tkit(tkns, 0, TokenStream::Iterator::kAllTokens);
31 intptr_t cur_line = script.line_offset() + 1;
32 while (tkit.CurrentTokenKind() != Token::kEOS) {
33 (*map)[tkit.CurrentPosition()] = cur_line;
34 if (tkit.CurrentTokenKind() == Token::kNEWLINE) {
35 cur_line++;
36 }
37 tkit.Advance();
38 }
39 }
40
41
21 void CodeCoverage::CompileAndAdd(const Function& function, 42 void CodeCoverage::CompileAndAdd(const Function& function,
22 const JSONArray& hits_arr) { 43 const JSONArray& hits_arr,
44 const GrowableArray<intptr_t>& pos_to_line) {
23 Isolate* isolate = Isolate::Current(); 45 Isolate* isolate = Isolate::Current();
24 if (!function.HasCode()) { 46 if (!function.HasCode()) {
25 // If the function should not be compiled or if the compilation failed, 47 // If the function should not be compiled or if the compilation failed,
26 // then just skip this method. 48 // then just skip this method.
27 // TODO(iposva): Maybe we should skip synthesized methods in general too. 49 // TODO(iposva): Maybe we should skip synthesized methods in general too.
28 if (function.is_abstract() || function.IsRedirectingFactory()) { 50 if (function.is_abstract() || function.IsRedirectingFactory()) {
29 return; 51 return;
30 } 52 }
31 if (function.IsNonImplicitClosureFunction() && 53 if (function.IsNonImplicitClosureFunction() &&
32 (function.context_scope() == ContextScope::null())) { 54 (function.context_scope() == ContextScope::null())) {
33 // TODO(iposva): This can arise if we attempt to compile an inner function 55 // TODO(iposva): This can arise if we attempt to compile an inner function
34 // before we have compiled its enclosing function or if the enclosing 56 // before we have compiled its enclosing function or if the enclosing
35 // function failed to compile. 57 // function failed to compile.
36 OS::Print("### Coverage skipped compiling: %s\n", function.ToCString()); 58 OS::Print("### Coverage skipped compiling: %s\n", function.ToCString());
37 return; 59 return;
38 } 60 }
39 const Error& err = Error::Handle( 61 const Error& err = Error::Handle(
40 isolate, Compiler::CompileFunction(isolate, function)); 62 isolate, Compiler::CompileFunction(isolate, function));
41 if (!err.IsNull()) { 63 if (!err.IsNull()) {
42 OS::Print("### Coverage failed compiling:\n%s\n", err.ToErrorCString()); 64 OS::Print("### Coverage failed compiling:\n%s\n", err.ToErrorCString());
43 return; 65 return;
44 } 66 }
45 } 67 }
46 ASSERT(function.HasCode()); 68 ASSERT(function.HasCode());
47 69
48 // Print the hit counts for all IC datas. 70 // Print the hit counts for all IC datas.
49 const Script& script = Script::Handle(function.script());
50 const Code& code = Code::Handle(function.unoptimized_code()); 71 const Code& code = Code::Handle(function.unoptimized_code());
51 const Array& ic_array = Array::Handle(code.ExtractTypeFeedbackArray()); 72 const Array& ic_array = Array::Handle(code.ExtractTypeFeedbackArray());
52 const PcDescriptors& descriptors = PcDescriptors::Handle( 73 const PcDescriptors& descriptors = PcDescriptors::Handle(
53 code.pc_descriptors()); 74 code.pc_descriptors());
54 ICData& ic_data = ICData::Handle(); 75 ICData& ic_data = ICData::Handle();
55 76
56 for (int j = 0; j < descriptors.Length(); j++) { 77 for (int j = 0; j < descriptors.Length(); j++) {
57 HANDLESCOPE(isolate); 78 HANDLESCOPE(isolate);
58 PcDescriptors::Kind kind = descriptors.DescriptorKind(j); 79 PcDescriptors::Kind kind = descriptors.DescriptorKind(j);
59 // Only IC based calls have counting. 80 // Only IC based calls have counting.
60 if ((kind == PcDescriptors::kIcCall) || 81 if ((kind == PcDescriptors::kIcCall) ||
61 (kind == PcDescriptors::kUnoptStaticCall)) { 82 (kind == PcDescriptors::kUnoptStaticCall)) {
62 intptr_t deopt_id = descriptors.DeoptId(j); 83 intptr_t deopt_id = descriptors.DeoptId(j);
63 ic_data ^= ic_array.At(deopt_id); 84 ic_data ^= ic_array.At(deopt_id);
64 if (!ic_data.IsNull()) { 85 if (!ic_data.IsNull()) {
65 intptr_t token_pos = descriptors.TokenPos(j); 86 intptr_t token_pos = descriptors.TokenPos(j);
66 intptr_t line = -1; 87 intptr_t line = pos_to_line[token_pos];
67 script.GetTokenLocation(token_pos, &line, NULL); 88 #if defined(DEBUG)
89 const Script& script = Script::Handle(function.script());
90 intptr_t test_line = -1;
91 script.GetTokenLocation(token_pos, &test_line, NULL);
92 ASSERT(test_line == line);
93 #endif
68 hits_arr.AddValue(line); 94 hits_arr.AddValue(line);
69 hits_arr.AddValue(ic_data.AggregateCount()); 95 hits_arr.AddValue(ic_data.AggregateCount());
70 } 96 }
71 } 97 }
72 } 98 }
73 } 99 }
74 100
75 101
76 void CodeCoverage::PrintClass(const Class& cls, const JSONArray& jsarr) { 102 void CodeCoverage::PrintClass(const Class& cls, const JSONArray& jsarr) {
77 Isolate* isolate = Isolate::Current(); 103 Isolate* isolate = Isolate::Current();
78 Array& functions = Array::Handle(cls.functions()); 104 Array& functions = Array::Handle(cls.functions());
79 ASSERT(!functions.IsNull()); 105 ASSERT(!functions.IsNull());
80 Function& function = Function::Handle(); 106 Function& function = Function::Handle();
81 Script& script = Script::Handle(); 107 Script& script = Script::Handle();
82 String& saved_url = String::Handle(); 108 String& saved_url = String::Handle();
83 String& url = String::Handle(); 109 String& url = String::Handle();
84 110 GrowableArray<intptr_t> pos_to_line;
85 int i = 0; 111 int i = 0;
86 while (i < functions.Length()) { 112 while (i < functions.Length()) {
87 HANDLESCOPE(isolate); 113 HANDLESCOPE(isolate);
88 function ^= functions.At(i); 114 function ^= functions.At(i);
89 JSONObject jsobj(&jsarr); 115 JSONObject jsobj(&jsarr);
90 script = function.script(); 116 script = function.script();
117 ComputeTokenPosToLineNumberMap(script, &pos_to_line);
91 saved_url = script.url(); 118 saved_url = script.url();
92 jsobj.AddProperty("source", saved_url.ToCString()); 119 jsobj.AddProperty("source", saved_url.ToCString());
93 jsobj.AddProperty("script", script); 120 jsobj.AddProperty("script", script);
94 JSONArray hits_arr(&jsobj, "hits"); 121 JSONArray hits_arr(&jsobj, "hits");
95 122
96 // We stay within this loop while we are seeing functions from the same 123 // We stay within this loop while we are seeing functions from the same
97 // source URI. 124 // source URI.
98 while (i < functions.Length()) { 125 while (i < functions.Length()) {
99 function ^= functions.At(i); 126 function ^= functions.At(i);
100 script = function.script(); 127 script = function.script();
101 url = script.url(); 128 url = script.url();
102 if (!url.Equals(saved_url)) { 129 if (!url.Equals(saved_url)) {
130 pos_to_line.Clear();
103 break; 131 break;
104 } 132 }
105 CompileAndAdd(function, hits_arr); 133 CompileAndAdd(function, hits_arr, pos_to_line);
106 if (function.HasImplicitClosureFunction()) { 134 if (function.HasImplicitClosureFunction()) {
107 function = function.ImplicitClosureFunction(); 135 function = function.ImplicitClosureFunction();
108 CompileAndAdd(function, hits_arr); 136 CompileAndAdd(function, hits_arr, pos_to_line);
109 } 137 }
110 i++; 138 i++;
111 } 139 }
112 } 140 }
113 141
114 GrowableObjectArray& closures = 142 GrowableObjectArray& closures =
115 GrowableObjectArray::Handle(cls.closures()); 143 GrowableObjectArray::Handle(cls.closures());
116 if (!closures.IsNull()) { 144 if (!closures.IsNull()) {
117 i = 0; 145 i = 0;
146 pos_to_line.Clear();
118 // We need to keep rechecking the length of the closures array, as handling 147 // We need to keep rechecking the length of the closures array, as handling
119 // a closure potentially adds new entries to the end. 148 // a closure potentially adds new entries to the end.
120 while (i < closures.Length()) { 149 while (i < closures.Length()) {
121 HANDLESCOPE(isolate); 150 HANDLESCOPE(isolate);
122 function ^= closures.At(i); 151 function ^= closures.At(i);
123 JSONObject jsobj(&jsarr); 152 JSONObject jsobj(&jsarr);
124 script = function.script(); 153 script = function.script();
154 ComputeTokenPosToLineNumberMap(script, &pos_to_line);
125 saved_url = script.url(); 155 saved_url = script.url();
126 jsobj.AddProperty("source", saved_url.ToCString()); 156 jsobj.AddProperty("source", saved_url.ToCString());
127 jsobj.AddProperty("script", script); 157 jsobj.AddProperty("script", script);
128 JSONArray hits_arr(&jsobj, "hits"); 158 JSONArray hits_arr(&jsobj, "hits");
129 159
130 // We stay within this loop while we are seeing functions from the same 160 // We stay within this loop while we are seeing functions from the same
131 // source URI. 161 // source URI.
132 while (i < closures.Length()) { 162 while (i < closures.Length()) {
133 function ^= closures.At(i); 163 function ^= closures.At(i);
134 script = function.script(); 164 script = function.script();
135 url = script.url(); 165 url = script.url();
136 if (!url.Equals(saved_url)) { 166 if (!url.Equals(saved_url)) {
167 pos_to_line.Clear();
137 break; 168 break;
138 } 169 }
139 CompileAndAdd(function, hits_arr); 170 CompileAndAdd(function, hits_arr, pos_to_line);
140 i++; 171 i++;
141 } 172 }
142 } 173 }
143 } 174 }
144 } 175 }
145 176
146 177
147 void CodeCoverage::Write(Isolate* isolate) { 178 void CodeCoverage::Write(Isolate* isolate) {
148 if (FLAG_coverage_dir == NULL) { 179 if (FLAG_coverage_dir == NULL) {
149 return; 180 return;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
196 // functions. 227 // functions.
197 PrintClass(cls, jsarr); 228 PrintClass(cls, jsarr);
198 } 229 }
199 } 230 }
200 } 231 }
201 } 232 }
202 } 233 }
203 234
204 235
205 } // namespace dart 236 } // namespace dart
OLDNEW
« no previous file with comments | « runtime/vm/coverage.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698