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

Side by Side Diff: src/runtime-profiler.cc

Issue 6529055: [Isolates] Merge crankshaft (r5922 from bleeding_edge). (Closed)
Patch Set: Win32 port Created 9 years, 10 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
« no previous file with comments | « src/runtime-profiler.h ('k') | src/safepoint-table.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28 #include "v8.h"
29
30 #include "runtime-profiler.h"
31
32 #include "assembler.h"
33 #include "code-stubs.h"
34 #include "compilation-cache.h"
35 #include "deoptimizer.h"
36 #include "execution.h"
37 #include "global-handles.h"
38 #include "platform.h"
39 #include "scopeinfo.h"
40
41 namespace v8 {
42 namespace internal {
43
44
45 class PendingListNode : public Malloced {
46 public:
47 explicit PendingListNode(JSFunction* function);
48 ~PendingListNode() { Destroy(); }
49
50 PendingListNode* next() const { return next_; }
51 void set_next(PendingListNode* node) { next_ = node; }
52 Handle<JSFunction> function() { return Handle<JSFunction>::cast(function_); }
53
54 // If the function is garbage collected before we've had the chance
55 // to optimize it the weak handle will be null.
56 bool IsValid() { return !function_.is_null(); }
57
58 // Returns the number of microseconds this node has been pending.
59 int Delay() const { return static_cast<int>(OS::Ticks() - start_); }
60
61 private:
62 void Destroy();
63 static void WeakCallback(v8::Persistent<v8::Value> object, void* data);
64
65 PendingListNode* next_;
66 Handle<Object> function_; // Weak handle.
67 int64_t start_;
68 };
69
70
71 // Optimization sampler constants.
72 static const int kSamplerFrameCount = 2;
73 static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
74
75 static const int kSamplerTicksDelta = 32;
76
77 static const int kSamplerThresholdInit = 3;
78 static const int kSamplerThresholdMin = 1;
79 static const int kSamplerThresholdDelta = 1;
80
81 static const int kSamplerThresholdSizeFactorInit = 3;
82 static const int kSamplerThresholdSizeFactorMin = 1;
83 static const int kSamplerThresholdSizeFactorDelta = 1;
84
85 static const int kSizeLimit = 1500;
86
87
88 PendingListNode::PendingListNode(JSFunction* function) : next_(NULL) {
89 GlobalHandles* global_handles = Isolate::Current()->global_handles();
90 function_ = global_handles->Create(function);
91 start_ = OS::Ticks();
92 global_handles->MakeWeak(function_.location(), this, &WeakCallback);
93 }
94
95
96 void PendingListNode::Destroy() {
97 if (!IsValid()) return;
98 GlobalHandles* global_handles = Isolate::Current()->global_handles();
99 global_handles->Destroy(function_.location());
100 function_= Handle<Object>::null();
101 }
102
103
104 void PendingListNode::WeakCallback(v8::Persistent<v8::Value>, void* data) {
105 reinterpret_cast<PendingListNode*>(data)->Destroy();
106 }
107
108
109 static bool IsOptimizable(JSFunction* function) {
110 Code* code = function->code();
111 return code->kind() == Code::FUNCTION && code->optimizable();
112 }
113
114
115 Atomic32 RuntimeProfiler::state_ = 0;
116 // TODO(isolates): Create the semaphore lazily and clean it up when no
117 // longer required.
118 Semaphore* RuntimeProfiler::semaphore_ = OS::CreateSemaphore(0);
119
120
121 RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
122 : isolate_(isolate),
123 sampler_threshold_(kSamplerThresholdInit),
124 sampler_threshold_size_factor_(kSamplerThresholdSizeFactorInit),
125 sampler_window_position_(0),
126 optimize_soon_list_(NULL) {
127 ClearSampleBuffer();
128 }
129
130
131 bool RuntimeProfiler::IsEnabled() {
132 return V8::UseCrankshaft() && FLAG_opt;
133 }
134
135
136 void RuntimeProfiler::Optimize(JSFunction* function, bool eager, int delay) {
137 ASSERT(IsOptimizable(function));
138 if (FLAG_trace_opt) {
139 PrintF("[marking (%s) ", eager ? "eagerly" : "lazily");
140 function->PrintName();
141 PrintF(" for recompilation");
142 if (delay > 0) {
143 PrintF(" (delayed %0.3f ms)", static_cast<double>(delay) / 1000);
144 }
145 PrintF("]\n");
146 }
147
148 // The next call to the function will trigger optimization.
149 function->MarkForLazyRecompilation();
150 }
151
152
153 void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) {
154 // See AlwaysFullCompiler (in compiler.cc) comment on why we need
155 // Debug::has_break_points().
156 ASSERT(function->IsMarkedForLazyRecompilation());
157 if (!FLAG_use_osr ||
158 isolate_->debug()->has_break_points() ||
159 function->IsBuiltin()) {
160 return;
161 }
162
163 SharedFunctionInfo* shared = function->shared();
164 // If the code is not optimizable, don't try OSR.
165 if (!shared->code()->optimizable()) return;
166
167 // We are not prepared to do OSR for a function that already has an
168 // allocated arguments object. The optimized code would bypass it for
169 // arguments accesses, which is unsound. Don't try OSR.
170 if (shared->scope_info()->HasArgumentsShadow()) return;
171
172 // We're using on-stack replacement: patch the unoptimized code so that
173 // any back edge in any unoptimized frame will trigger on-stack
174 // replacement for that frame.
175 if (FLAG_trace_osr) {
176 PrintF("[patching stack checks in ");
177 function->PrintName();
178 PrintF(" for on-stack replacement]\n");
179 }
180
181 // Get the stack check stub code object to match against. We aren't
182 // prepared to generate it, but we don't expect to have to.
183 StackCheckStub check_stub;
184 Object* check_code;
185 MaybeObject* maybe_check_code = check_stub.TryGetCode();
186 if (maybe_check_code->ToObject(&check_code)) {
187 Code* replacement_code =
188 isolate_->builtins()->builtin(Builtins::OnStackReplacement);
189 Code* unoptimized_code = shared->code();
190 // Iterate the unoptimized code and patch every stack check except at
191 // the function entry. This code assumes the function entry stack
192 // check appears first i.e., is not deferred or otherwise reordered.
193 bool first = true;
194 for (RelocIterator it(unoptimized_code, RelocInfo::kCodeTargetMask);
195 !it.done();
196 it.next()) {
197 RelocInfo* rinfo = it.rinfo();
198 if (rinfo->target_address() == Code::cast(check_code)->entry()) {
199 if (first) {
200 first = false;
201 } else {
202 Deoptimizer::PatchStackCheckCode(rinfo, replacement_code);
203 }
204 }
205 }
206 }
207 }
208
209
210 void RuntimeProfiler::ClearSampleBuffer() {
211 memset(sampler_window_, 0, sizeof(sampler_window_));
212 memset(sampler_window_weight_, 0, sizeof(sampler_window_weight_));
213 }
214
215
216 void RuntimeProfiler::ClearSampleBufferNewSpaceEntries() {
217 for (int i = 0; i < kSamplerWindowSize; i++) {
218 if (isolate_->heap()->InNewSpace(sampler_window_[i])) {
219 sampler_window_[i] = NULL;
220 sampler_window_weight_[i] = 0;
221 }
222 }
223 }
224
225
226 int RuntimeProfiler::LookupSample(JSFunction* function) {
227 int weight = 0;
228 for (int i = 0; i < kSamplerWindowSize; i++) {
229 JSFunction* sample = sampler_window_[i];
230 if (sample != NULL) {
231 if (function == sample) {
232 weight += sampler_window_weight_[i];
233 }
234 }
235 }
236 return weight;
237 }
238
239
240 void RuntimeProfiler::AddSample(JSFunction* function, int weight) {
241 ASSERT(IsPowerOf2(kSamplerWindowSize));
242 sampler_window_[sampler_window_position_] = function;
243 sampler_window_weight_[sampler_window_position_] = weight;
244 sampler_window_position_ = (sampler_window_position_ + 1) &
245 (kSamplerWindowSize - 1);
246 }
247
248
249 void RuntimeProfiler::OptimizeNow() {
250 HandleScope scope(isolate_);
251 PendingListNode* current = optimize_soon_list_;
252 while (current != NULL) {
253 PendingListNode* next = current->next();
254 if (current->IsValid()) {
255 Handle<JSFunction> function = current->function();
256 int delay = current->Delay();
257 if (IsOptimizable(*function)) {
258 Optimize(*function, true, delay);
259 }
260 }
261 delete current;
262 current = next;
263 }
264 optimize_soon_list_ = NULL;
265
266 // Run through the JavaScript frames and collect them. If we already
267 // have a sample of the function, we mark it for optimizations
268 // (eagerly or lazily).
269 JSFunction* samples[kSamplerFrameCount];
270 int count = 0;
271 for (JavaScriptFrameIterator it;
272 count < kSamplerFrameCount && !it.done();
273 it.Advance()) {
274 JavaScriptFrame* frame = it.frame();
275 JSFunction* function = JSFunction::cast(frame->function());
276 int function_size = function->shared()->SourceSize();
277 int threshold_size_factor;
278 if (function_size > kSizeLimit) {
279 threshold_size_factor = sampler_threshold_size_factor_;
280 } else {
281 threshold_size_factor = 1;
282 }
283
284 int threshold = sampler_threshold_ * threshold_size_factor;
285 samples[count++] = function;
286 if (function->IsMarkedForLazyRecompilation()) {
287 Code* unoptimized = function->shared()->code();
288 int nesting = unoptimized->allow_osr_at_loop_nesting_level();
289 if (nesting == 0) AttemptOnStackReplacement(function);
290 int new_nesting = Min(nesting + 1, Code::kMaxLoopNestingMarker);
291 unoptimized->set_allow_osr_at_loop_nesting_level(new_nesting);
292 } else if (LookupSample(function) >= threshold) {
293 if (IsOptimizable(function)) {
294 Optimize(function, false, 0);
295 isolate_->compilation_cache()->MarkForEagerOptimizing(
296 Handle<JSFunction>(function, isolate_));
297 }
298 }
299 }
300
301 // Add the collected functions as samples. It's important not to do
302 // this as part of collecting them because this will interfere with
303 // the sample lookup in case of recursive functions.
304 for (int i = 0; i < count; i++) {
305 AddSample(samples[i], kSamplerFrameWeight[i]);
306 }
307 }
308
309
310 void RuntimeProfiler::OptimizeSoon(JSFunction* function) {
311 if (!IsOptimizable(function)) return;
312 PendingListNode* node = new PendingListNode(function);
313 node->set_next(optimize_soon_list_);
314 optimize_soon_list_ = node;
315 }
316
317
318 void RuntimeProfiler::NotifyTick() {
319 isolate_->stack_guard()->RequestRuntimeProfilerTick();
320 }
321
322
323 void RuntimeProfiler::MarkCompactPrologue(bool is_compacting) {
324 if (is_compacting) {
325 // Clear all samples before mark-sweep-compact because every
326 // function might move.
327 ClearSampleBuffer();
328 } else {
329 // Clear only new space entries on mark-sweep since none of the
330 // old-space functions will move.
331 ClearSampleBufferNewSpaceEntries();
332 }
333 }
334
335
336 void RuntimeProfiler::Setup() {
337 ClearSampleBuffer();
338 // If the ticker hasn't already started, make sure to do so to get
339 // the ticks for the runtime profiler.
340 if (IsEnabled()) isolate_->logger()->EnsureTickerStarted();
341 }
342
343
344 void RuntimeProfiler::Reset() {
345 sampler_threshold_ = kSamplerThresholdInit;
346 sampler_threshold_size_factor_ = kSamplerThresholdSizeFactorInit;
347 }
348
349
350 void RuntimeProfiler::TearDown() {
351 // Nothing to do.
352 }
353
354
355 Object** RuntimeProfiler::SamplerWindowAddress() {
356 return reinterpret_cast<Object**>(sampler_window_);
357 }
358
359
360 int RuntimeProfiler::SamplerWindowSize() {
361 return kSamplerWindowSize;
362 }
363
364
365 void RuntimeProfiler::HandleWakeUp(Isolate* isolate) {
366 // The profiler thread must still be waiting.
367 ASSERT(NoBarrier_Load(&state_) >= 0);
368 // In IsolateEnteredJS we have already incremented the counter and
369 // undid the decrement done by the profiler thread. Increment again
370 // to get the right count of active isolates.
371 NoBarrier_AtomicIncrement(&state_, 1);
372 semaphore_->Signal();
373 isolate->ResetEagerOptimizingData();
374 }
375
376
377 bool RuntimeProfiler::IsSomeIsolateInJS() {
378 return NoBarrier_Load(&state_) > 0;
379 }
380
381
382 bool RuntimeProfiler::WaitForSomeIsolateToEnterJS() {
383 Atomic32 old_state = NoBarrier_CompareAndSwap(&state_, 0, -1);
384 ASSERT(old_state >= -1);
385 if (old_state != 0) return false;
386 semaphore_->Wait();
387 return true;
388 }
389
390
391 void RuntimeProfiler::WakeUpRuntimeProfilerThreadBeforeShutdown() {
392 semaphore_->Signal();
393 }
394
395
396 bool RuntimeProfilerRateLimiter::SuspendIfNecessary() {
397 if (!RuntimeProfiler::IsEnabled()) return false;
398 static const int kNonJSTicksThreshold = 100;
399 if (RuntimeProfiler::IsSomeIsolateInJS()) {
400 non_js_ticks_ = 0;
401 } else {
402 if (non_js_ticks_ < kNonJSTicksThreshold) {
403 ++non_js_ticks_;
404 } else {
405 return RuntimeProfiler::WaitForSomeIsolateToEnterJS();
406 }
407 }
408 return false;
409 }
410
411
412 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/runtime-profiler.h ('k') | src/safepoint-table.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698