The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / runtime-profiler.cc @ f230a1cf

History | View | Annotate | Download (15.5 KB)

1
// Copyright 2012 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 "bootstrapper.h"
34
#include "code-stubs.h"
35
#include "compilation-cache.h"
36
#include "execution.h"
37
#include "full-codegen.h"
38
#include "global-handles.h"
39
#include "isolate-inl.h"
40
#include "mark-compact.h"
41
#include "platform.h"
42
#include "scopeinfo.h"
43

    
44
namespace v8 {
45
namespace internal {
46

    
47

    
48
// Optimization sampler constants.
49
static const int kSamplerFrameCount = 2;
50

    
51
// Constants for statistical profiler.
52
static const int kSamplerFrameWeight[kSamplerFrameCount] = { 2, 1 };
53

    
54
static const int kSamplerTicksBetweenThresholdAdjustment = 32;
55

    
56
static const int kSamplerThresholdInit = 3;
57
static const int kSamplerThresholdMin = 1;
58
static const int kSamplerThresholdDelta = 1;
59

    
60
static const int kSamplerThresholdSizeFactorInit = 3;
61

    
62
static const int kSizeLimit = 1500;
63

    
64
// Constants for counter based profiler.
65

    
66
// Number of times a function has to be seen on the stack before it is
67
// optimized.
68
static const int kProfilerTicksBeforeOptimization = 2;
69
// If the function optimization was disabled due to high deoptimization count,
70
// but the function is hot and has been seen on the stack this number of times,
71
// then we try to reenable optimization for this function.
72
static const int kProfilerTicksBeforeReenablingOptimization = 250;
73
// If a function does not have enough type info (according to
74
// FLAG_type_info_threshold), but has seen a huge number of ticks,
75
// optimize it as it is.
76
static const int kTicksWhenNotEnoughTypeInfo = 100;
77
// We only have one byte to store the number of ticks.
78
STATIC_ASSERT(kProfilerTicksBeforeOptimization < 256);
79
STATIC_ASSERT(kProfilerTicksBeforeReenablingOptimization < 256);
80
STATIC_ASSERT(kTicksWhenNotEnoughTypeInfo < 256);
81

    
82
// Maximum size in bytes of generate code for a function to allow OSR.
83
static const int kOSRCodeSizeAllowanceBase =
84
    100 * FullCodeGenerator::kCodeSizeMultiplier;
85

    
86
static const int kOSRCodeSizeAllowancePerTick =
87
    3 * FullCodeGenerator::kCodeSizeMultiplier;
88

    
89
// Maximum size in bytes of generated code for a function to be optimized
90
// the very first time it is seen on the stack.
91
static const int kMaxSizeEarlyOpt =
92
    5 * FullCodeGenerator::kCodeSizeMultiplier;
93

    
94

    
95
RuntimeProfiler::RuntimeProfiler(Isolate* isolate)
96
    : isolate_(isolate),
97
      sampler_threshold_(kSamplerThresholdInit),
98
      sampler_threshold_size_factor_(kSamplerThresholdSizeFactorInit),
99
      sampler_ticks_until_threshold_adjustment_(
100
          kSamplerTicksBetweenThresholdAdjustment),
101
      sampler_window_position_(0),
102
      any_ic_changed_(false),
103
      code_generated_(false) {
104
  ClearSampleBuffer();
105
}
106

    
107

    
108
static void GetICCounts(Code* shared_code,
109
                        int* ic_with_type_info_count,
110
                        int* ic_total_count,
111
                        int* percentage) {
112
  *ic_total_count = 0;
113
  *ic_with_type_info_count = 0;
114
  Object* raw_info = shared_code->type_feedback_info();
115
  if (raw_info->IsTypeFeedbackInfo()) {
116
    TypeFeedbackInfo* info = TypeFeedbackInfo::cast(raw_info);
117
    *ic_with_type_info_count = info->ic_with_type_info_count();
118
    *ic_total_count = info->ic_total_count();
119
  }
120
  *percentage = *ic_total_count > 0
121
      ? 100 * *ic_with_type_info_count / *ic_total_count
122
      : 100;
123
}
124

    
125

    
126
void RuntimeProfiler::Optimize(JSFunction* function, const char* reason) {
127
  ASSERT(function->IsOptimizable());
128

    
129
  if (FLAG_trace_opt && function->PassesFilter(FLAG_hydrogen_filter)) {
130
    PrintF("[marking ");
131
    function->ShortPrint();
132
    PrintF(" for recompilation, reason: %s", reason);
133
    if (FLAG_type_info_threshold > 0) {
134
      int typeinfo, total, percentage;
135
      GetICCounts(function->shared()->code(), &typeinfo, &total, &percentage);
136
      PrintF(", ICs with typeinfo: %d/%d (%d%%)", typeinfo, total, percentage);
137
    }
138
    PrintF("]\n");
139
  }
140

    
141

    
142
  if (FLAG_concurrent_recompilation && !isolate_->bootstrapper()->IsActive()) {
143
    if (FLAG_concurrent_osr &&
144
        isolate_->optimizing_compiler_thread()->IsQueuedForOSR(function)) {
145
      // Do not attempt regular recompilation if we already queued this for OSR.
146
      // TODO(yangguo): This is necessary so that we don't install optimized
147
      // code on a function that is already optimized, since OSR and regular
148
      // recompilation race.  This goes away as soon as OSR becomes one-shot.
149
      return;
150
    }
151
    ASSERT(!function->IsInRecompileQueue());
152
    function->MarkForConcurrentRecompilation();
153
  } else {
154
    // The next call to the function will trigger optimization.
155
    function->MarkForLazyRecompilation();
156
  }
157
}
158

    
159

    
160
void RuntimeProfiler::AttemptOnStackReplacement(JSFunction* function) {
161
  // See AlwaysFullCompiler (in compiler.cc) comment on why we need
162
  // Debug::has_break_points().
163
  if (!FLAG_use_osr ||
164
      isolate_->DebuggerHasBreakPoints() ||
165
      function->IsBuiltin()) {
166
    return;
167
  }
168

    
169
  SharedFunctionInfo* shared = function->shared();
170
  // If the code is not optimizable, don't try OSR.
171
  if (!shared->code()->optimizable()) return;
172

    
173
  // We are not prepared to do OSR for a function that already has an
174
  // allocated arguments object.  The optimized code would bypass it for
175
  // arguments accesses, which is unsound.  Don't try OSR.
176
  if (shared->uses_arguments()) return;
177

    
178
  // We're using on-stack replacement: patch the unoptimized code so that
179
  // any back edge in any unoptimized frame will trigger on-stack
180
  // replacement for that frame.
181
  if (FLAG_trace_osr) {
182
    PrintF("[OSR - patching back edges in ");
183
    function->PrintName();
184
    PrintF("]\n");
185
  }
186

    
187
  BackEdgeTable::Patch(isolate_, shared->code());
188
}
189

    
190

    
191
void RuntimeProfiler::ClearSampleBuffer() {
192
  memset(sampler_window_, 0, sizeof(sampler_window_));
193
  memset(sampler_window_weight_, 0, sizeof(sampler_window_weight_));
194
}
195

    
196

    
197
int RuntimeProfiler::LookupSample(JSFunction* function) {
198
  int weight = 0;
199
  for (int i = 0; i < kSamplerWindowSize; i++) {
200
    Object* sample = sampler_window_[i];
201
    if (sample != NULL) {
202
      bool fits = FLAG_lookup_sample_by_shared
203
          ? (function->shared() == JSFunction::cast(sample)->shared())
204
          : (function == JSFunction::cast(sample));
205
      if (fits) {
206
        weight += sampler_window_weight_[i];
207
      }
208
    }
209
  }
210
  return weight;
211
}
212

    
213

    
214
void RuntimeProfiler::AddSample(JSFunction* function, int weight) {
215
  ASSERT(IsPowerOf2(kSamplerWindowSize));
216
  sampler_window_[sampler_window_position_] = function;
217
  sampler_window_weight_[sampler_window_position_] = weight;
218
  sampler_window_position_ = (sampler_window_position_ + 1) &
219
      (kSamplerWindowSize - 1);
220
}
221

    
222

    
223
void RuntimeProfiler::OptimizeNow() {
224
  HandleScope scope(isolate_);
225

    
226
  if (isolate_->DebuggerHasBreakPoints()) return;
227

    
228
  DisallowHeapAllocation no_gc;
229

    
230
  // Run through the JavaScript frames and collect them. If we already
231
  // have a sample of the function, we mark it for optimizations
232
  // (eagerly or lazily).
233
  JSFunction* samples[kSamplerFrameCount];
234
  int sample_count = 0;
235
  int frame_count = 0;
236
  int frame_count_limit = FLAG_watch_ic_patching ? FLAG_frame_count
237
                                                 : kSamplerFrameCount;
238
  for (JavaScriptFrameIterator it(isolate_);
239
       frame_count++ < frame_count_limit && !it.done();
240
       it.Advance()) {
241
    JavaScriptFrame* frame = it.frame();
242
    JSFunction* function = frame->function();
243

    
244
    if (!FLAG_watch_ic_patching) {
245
      // Adjust threshold each time we have processed
246
      // a certain number of ticks.
247
      if (sampler_ticks_until_threshold_adjustment_ > 0) {
248
        sampler_ticks_until_threshold_adjustment_--;
249
        if (sampler_ticks_until_threshold_adjustment_ <= 0) {
250
          // If the threshold is not already at the minimum
251
          // modify and reset the ticks until next adjustment.
252
          if (sampler_threshold_ > kSamplerThresholdMin) {
253
            sampler_threshold_ -= kSamplerThresholdDelta;
254
            sampler_ticks_until_threshold_adjustment_ =
255
                kSamplerTicksBetweenThresholdAdjustment;
256
          }
257
        }
258
      }
259
    }
260

    
261
    SharedFunctionInfo* shared = function->shared();
262
    Code* shared_code = shared->code();
263

    
264
    if (shared_code->kind() != Code::FUNCTION) continue;
265
    if (function->IsInRecompileQueue()) continue;
266

    
267
    if (FLAG_always_osr &&
268
        shared_code->allow_osr_at_loop_nesting_level() == 0) {
269
      // Testing mode: always try an OSR compile for every function.
270
      for (int i = 0; i < Code::kMaxLoopNestingMarker; i++) {
271
        // TODO(titzer): fix AttemptOnStackReplacement to avoid this dumb loop.
272
        shared_code->set_allow_osr_at_loop_nesting_level(i);
273
        AttemptOnStackReplacement(function);
274
      }
275
      // Fall through and do a normal optimized compile as well.
276
    } else if (!frame->is_optimized() &&
277
        (function->IsMarkedForLazyRecompilation() ||
278
         function->IsMarkedForConcurrentRecompilation() ||
279
         function->IsOptimized())) {
280
      // Attempt OSR if we are still running unoptimized code even though the
281
      // the function has long been marked or even already been optimized.
282
      int ticks = shared_code->profiler_ticks();
283
      int allowance = kOSRCodeSizeAllowanceBase +
284
                      ticks * kOSRCodeSizeAllowancePerTick;
285
      if (shared_code->CodeSize() > allowance) {
286
        if (ticks < 255) shared_code->set_profiler_ticks(ticks + 1);
287
      } else {
288
        int nesting = shared_code->allow_osr_at_loop_nesting_level();
289
        if (nesting < Code::kMaxLoopNestingMarker) {
290
          int new_nesting = nesting + 1;
291
          shared_code->set_allow_osr_at_loop_nesting_level(new_nesting);
292
          AttemptOnStackReplacement(function);
293
        }
294
      }
295
      continue;
296
    }
297

    
298
    // Only record top-level code on top of the execution stack and
299
    // avoid optimizing excessively large scripts since top-level code
300
    // will be executed only once.
301
    const int kMaxToplevelSourceSize = 10 * 1024;
302
    if (shared->is_toplevel() &&
303
        (frame_count > 1 || shared->SourceSize() > kMaxToplevelSourceSize)) {
304
      continue;
305
    }
306

    
307
    // Do not record non-optimizable functions.
308
    if (shared->optimization_disabled()) {
309
      if (shared->deopt_count() >= FLAG_max_opt_count) {
310
        // If optimization was disabled due to many deoptimizations,
311
        // then check if the function is hot and try to reenable optimization.
312
        int ticks = shared_code->profiler_ticks();
313
        if (ticks >= kProfilerTicksBeforeReenablingOptimization) {
314
          shared_code->set_profiler_ticks(0);
315
          shared->TryReenableOptimization();
316
        } else {
317
          shared_code->set_profiler_ticks(ticks + 1);
318
        }
319
      }
320
      continue;
321
    }
322
    if (!function->IsOptimizable()) continue;
323

    
324
    if (FLAG_watch_ic_patching) {
325
      int ticks = shared_code->profiler_ticks();
326

    
327
      if (ticks >= kProfilerTicksBeforeOptimization) {
328
        int typeinfo, total, percentage;
329
        GetICCounts(shared_code, &typeinfo, &total, &percentage);
330
        if (percentage >= FLAG_type_info_threshold) {
331
          // If this particular function hasn't had any ICs patched for enough
332
          // ticks, optimize it now.
333
          Optimize(function, "hot and stable");
334
        } else if (ticks >= kTicksWhenNotEnoughTypeInfo) {
335
          Optimize(function, "not much type info but very hot");
336
        } else {
337
          shared_code->set_profiler_ticks(ticks + 1);
338
          if (FLAG_trace_opt_verbose) {
339
            PrintF("[not yet optimizing ");
340
            function->PrintName();
341
            PrintF(", not enough type info: %d/%d (%d%%)]\n",
342
                   typeinfo, total, percentage);
343
          }
344
        }
345
      } else if (!any_ic_changed_ &&
346
                 shared_code->instruction_size() < kMaxSizeEarlyOpt) {
347
        // If no IC was patched since the last tick and this function is very
348
        // small, optimistically optimize it now.
349
        Optimize(function, "small function");
350
      } else {
351
        shared_code->set_profiler_ticks(ticks + 1);
352
      }
353
    } else {  // !FLAG_watch_ic_patching
354
      samples[sample_count++] = function;
355

    
356
      int function_size = function->shared()->SourceSize();
357
      int threshold_size_factor = (function_size > kSizeLimit)
358
          ? sampler_threshold_size_factor_
359
          : 1;
360

    
361
      int threshold = sampler_threshold_ * threshold_size_factor;
362

    
363
      if (LookupSample(function) >= threshold) {
364
        Optimize(function, "sampler window lookup");
365
      }
366
    }
367
  }
368
  if (FLAG_watch_ic_patching) {
369
    any_ic_changed_ = false;
370
  } else {  // !FLAG_watch_ic_patching
371
    // Add the collected functions as samples. It's important not to do
372
    // this as part of collecting them because this will interfere with
373
    // the sample lookup in case of recursive functions.
374
    for (int i = 0; i < sample_count; i++) {
375
      AddSample(samples[i], kSamplerFrameWeight[i]);
376
    }
377
  }
378
}
379

    
380

    
381
void RuntimeProfiler::SetUp() {
382
  if (!FLAG_watch_ic_patching) {
383
    ClearSampleBuffer();
384
  }
385
}
386

    
387

    
388
void RuntimeProfiler::Reset() {
389
  if (!FLAG_watch_ic_patching) {
390
    sampler_threshold_ = kSamplerThresholdInit;
391
    sampler_threshold_size_factor_ = kSamplerThresholdSizeFactorInit;
392
    sampler_ticks_until_threshold_adjustment_ =
393
        kSamplerTicksBetweenThresholdAdjustment;
394
  }
395
}
396

    
397

    
398
void RuntimeProfiler::TearDown() {
399
  // Nothing to do.
400
}
401

    
402

    
403
// Update the pointers in the sampler window after a GC.
404
void RuntimeProfiler::UpdateSamplesAfterScavenge() {
405
  for (int i = 0; i < kSamplerWindowSize; i++) {
406
    Object* function = sampler_window_[i];
407
    if (function != NULL && isolate_->heap()->InNewSpace(function)) {
408
      MapWord map_word = HeapObject::cast(function)->map_word();
409
      if (map_word.IsForwardingAddress()) {
410
        sampler_window_[i] = map_word.ToForwardingAddress();
411
      } else {
412
        sampler_window_[i] = NULL;
413
      }
414
    }
415
  }
416
}
417

    
418

    
419
void RuntimeProfiler::RemoveDeadSamples() {
420
  for (int i = 0; i < kSamplerWindowSize; i++) {
421
    Object* function = sampler_window_[i];
422
    if (function != NULL &&
423
        !Marking::MarkBitFrom(HeapObject::cast(function)).Get()) {
424
      sampler_window_[i] = NULL;
425
    }
426
  }
427
}
428

    
429

    
430
void RuntimeProfiler::UpdateSamplesAfterCompact(ObjectVisitor* visitor) {
431
  for (int i = 0; i < kSamplerWindowSize; i++) {
432
    visitor->VisitPointer(&sampler_window_[i]);
433
  }
434
}
435

    
436

    
437
} }  // namespace v8::internal