| OLD | NEW | 
|     1 // Copyright 2013 the V8 project authors. All rights reserved. |     1 // Copyright 2013 the V8 project authors. All rights reserved. | 
|     2 // Use of this source code is governed by a BSD-style license that can be |     2 // Use of this source code is governed by a BSD-style license that can be | 
|     3 // found in the LICENSE file. |     3 // found in the LICENSE file. | 
|     4  |     4  | 
|     5 #include "src/profiler/sampler.h" |     5 #include "src/profiler/sampler.h" | 
|     6  |     6  | 
|     7 #if V8_OS_POSIX && !V8_OS_CYGWIN |     7 #if V8_OS_POSIX && !V8_OS_CYGWIN | 
|     8  |     8  | 
|     9 #define USE_SIGNALS |     9 #define USE_SIGNALS | 
|    10  |    10  | 
| (...skipping 26 matching lines...) Expand all  Loading... | 
|    37 #endif |    37 #endif | 
|    38  |    38  | 
|    39 #elif V8_OS_WIN || V8_OS_CYGWIN |    39 #elif V8_OS_WIN || V8_OS_CYGWIN | 
|    40  |    40  | 
|    41 #include "src/base/win32-headers.h" |    41 #include "src/base/win32-headers.h" | 
|    42  |    42  | 
|    43 #endif |    43 #endif | 
|    44  |    44  | 
|    45 #include "src/atomic-utils.h" |    45 #include "src/atomic-utils.h" | 
|    46 #include "src/base/platform/platform.h" |    46 #include "src/base/platform/platform.h" | 
|    47 #include "src/flags.h" |  | 
|    48 #include "src/frames-inl.h" |  | 
|    49 #include "src/log.h" |  | 
|    50 #include "src/profiler/cpu-profiler-inl.h" |    47 #include "src/profiler/cpu-profiler-inl.h" | 
 |    48 #include "src/profiler/tick-sample.h" | 
|    51 #include "src/simulator.h" |    49 #include "src/simulator.h" | 
|    52 #include "src/v8threads.h" |    50 #include "src/v8threads.h" | 
|    53 #include "src/vm-state-inl.h" |  | 
|    54  |    51  | 
|    55  |    52  | 
|    56 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) |    53 #if V8_OS_ANDROID && !defined(__BIONIC_HAVE_UCONTEXT_T) | 
|    57  |    54  | 
|    58 // Not all versions of Android's C library provide ucontext_t. |    55 // Not all versions of Android's C library provide ucontext_t. | 
|    59 // Detect this and provide custom but compatible definitions. Note that these |    56 // Detect this and provide custom but compatible definitions. Note that these | 
|    60 // follow the GLibc naming convention to access register values from |    57 // follow the GLibc naming convention to access register values from | 
|    61 // mcontext_t. |    58 // mcontext_t. | 
|    62 // |    59 // | 
|    63 // See http://code.google.com/p/android/issues/detail?id=34784 |    60 // See http://code.google.com/p/android/issues/detail?id=34784 | 
| (...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   168   ThreadId profiled_thread_id() { return profiled_thread_id_; } |   165   ThreadId profiled_thread_id() { return profiled_thread_id_; } | 
|   169  |   166  | 
|   170  protected: |   167  protected: | 
|   171   ~PlatformDataCommon() {} |   168   ~PlatformDataCommon() {} | 
|   172  |   169  | 
|   173  private: |   170  private: | 
|   174   ThreadId profiled_thread_id_; |   171   ThreadId profiled_thread_id_; | 
|   175 }; |   172 }; | 
|   176  |   173  | 
|   177  |   174  | 
|   178 bool IsSamePage(byte* ptr1, byte* ptr2) { |  | 
|   179   const uint32_t kPageSize = 4096; |  | 
|   180   uintptr_t mask = ~static_cast<uintptr_t>(kPageSize - 1); |  | 
|   181   return (reinterpret_cast<uintptr_t>(ptr1) & mask) == |  | 
|   182          (reinterpret_cast<uintptr_t>(ptr2) & mask); |  | 
|   183 } |  | 
|   184  |  | 
|   185  |  | 
|   186 // Check if the code at specified address could potentially be a |  | 
|   187 // frame setup code. |  | 
|   188 bool IsNoFrameRegion(Address address) { |  | 
|   189   struct Pattern { |  | 
|   190     int bytes_count; |  | 
|   191     byte bytes[8]; |  | 
|   192     int offsets[4]; |  | 
|   193   }; |  | 
|   194   byte* pc = reinterpret_cast<byte*>(address); |  | 
|   195   static Pattern patterns[] = { |  | 
|   196 #if V8_HOST_ARCH_IA32 |  | 
|   197     // push %ebp |  | 
|   198     // mov %esp,%ebp |  | 
|   199     {3, {0x55, 0x89, 0xe5}, {0, 1, -1}}, |  | 
|   200     // pop %ebp |  | 
|   201     // ret N |  | 
|   202     {2, {0x5d, 0xc2}, {0, 1, -1}}, |  | 
|   203     // pop %ebp |  | 
|   204     // ret |  | 
|   205     {2, {0x5d, 0xc3}, {0, 1, -1}}, |  | 
|   206 #elif V8_HOST_ARCH_X64 |  | 
|   207     // pushq %rbp |  | 
|   208     // movq %rsp,%rbp |  | 
|   209     {4, {0x55, 0x48, 0x89, 0xe5}, {0, 1, -1}}, |  | 
|   210     // popq %rbp |  | 
|   211     // ret N |  | 
|   212     {2, {0x5d, 0xc2}, {0, 1, -1}}, |  | 
|   213     // popq %rbp |  | 
|   214     // ret |  | 
|   215     {2, {0x5d, 0xc3}, {0, 1, -1}}, |  | 
|   216 #endif |  | 
|   217     {0, {}, {}} |  | 
|   218   }; |  | 
|   219   for (Pattern* pattern = patterns; pattern->bytes_count; ++pattern) { |  | 
|   220     for (int* offset_ptr = pattern->offsets; *offset_ptr != -1; ++offset_ptr) { |  | 
|   221       int offset = *offset_ptr; |  | 
|   222       if (!offset || IsSamePage(pc, pc - offset)) { |  | 
|   223         MSAN_MEMORY_IS_INITIALIZED(pc - offset, pattern->bytes_count); |  | 
|   224         if (!memcmp(pc - offset, pattern->bytes, pattern->bytes_count)) |  | 
|   225           return true; |  | 
|   226       } else { |  | 
|   227         // It is not safe to examine bytes on another page as it might not be |  | 
|   228         // allocated thus causing a SEGFAULT. |  | 
|   229         // Check the pattern part that's on the same page and |  | 
|   230         // pessimistically assume it could be the entire pattern match. |  | 
|   231         MSAN_MEMORY_IS_INITIALIZED(pc, pattern->bytes_count - offset); |  | 
|   232         if (!memcmp(pc, pattern->bytes + offset, pattern->bytes_count - offset)) |  | 
|   233           return true; |  | 
|   234       } |  | 
|   235     } |  | 
|   236   } |  | 
|   237   return false; |  | 
|   238 } |  | 
|   239  |  | 
|   240 typedef List<Sampler*> SamplerList; |   175 typedef List<Sampler*> SamplerList; | 
|   241  |   176  | 
|   242 #if defined(USE_SIGNALS) |   177 #if defined(USE_SIGNALS) | 
|   243 class AtomicGuard { |   178 class AtomicGuard { | 
|   244  public: |   179  public: | 
|   245   explicit AtomicGuard(AtomicValue<int>* atomic, bool is_block = true) |   180   explicit AtomicGuard(AtomicValue<int>* atomic, bool is_block = true) | 
|   246       : atomic_(atomic), |   181       : atomic_(atomic), | 
|   247         is_success_(false) { |   182         is_success_(false) { | 
|   248     do { |   183     do { | 
|   249       // Use Acquire_Load to gain mutual exclusion. |   184       // Use Acquire_Load to gain mutual exclusion. | 
| (...skipping 548 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|   798   SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value); |   733   SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value); | 
|   799   for (int i = 0; i < samplers->length(); ++i) { |   734   for (int i = 0; i < samplers->length(); ++i) { | 
|   800     Sampler* sampler = samplers->at(i); |   735     Sampler* sampler = samplers->at(i); | 
|   801     CollectSample(context, sampler); |   736     CollectSample(context, sampler); | 
|   802   } |   737   } | 
|   803 } |   738 } | 
|   804 #endif  // !V8_OS_NACL |   739 #endif  // !V8_OS_NACL | 
|   805 #endif  // USE_SIGNALs |   740 #endif  // USE_SIGNALs | 
|   806  |   741  | 
|   807  |   742  | 
|   808 // |  | 
|   809 // StackTracer implementation |  | 
|   810 // |  | 
|   811 DISABLE_ASAN void TickSample::Init(Isolate* isolate, |  | 
|   812                                    const v8::RegisterState& regs, |  | 
|   813                                    RecordCEntryFrame record_c_entry_frame, |  | 
|   814                                    bool update_stats) { |  | 
|   815   timestamp = base::TimeTicks::HighResolutionNow(); |  | 
|   816   pc = reinterpret_cast<Address>(regs.pc); |  | 
|   817   state = isolate->current_vm_state(); |  | 
|   818   this->update_stats = update_stats; |  | 
|   819  |  | 
|   820   // Avoid collecting traces while doing GC. |  | 
|   821   if (state == GC) return; |  | 
|   822  |  | 
|   823   Address js_entry_sp = isolate->js_entry_sp(); |  | 
|   824   if (js_entry_sp == 0) return;  // Not executing JS now. |  | 
|   825  |  | 
|   826   if (pc && IsNoFrameRegion(pc)) { |  | 
|   827     // Can't collect stack. Mark the sample as spoiled. |  | 
|   828     timestamp = base::TimeTicks(); |  | 
|   829     pc = 0; |  | 
|   830     return; |  | 
|   831   } |  | 
|   832  |  | 
|   833   ExternalCallbackScope* scope = isolate->external_callback_scope(); |  | 
|   834   Address handler = Isolate::handler(isolate->thread_local_top()); |  | 
|   835   // If there is a handler on top of the external callback scope then |  | 
|   836   // we have already entrered JavaScript again and the external callback |  | 
|   837   // is not the top function. |  | 
|   838   if (scope && scope->scope_address() < handler) { |  | 
|   839     external_callback_entry = *scope->callback_entrypoint_address(); |  | 
|   840     has_external_callback = true; |  | 
|   841   } else { |  | 
|   842     // sp register may point at an arbitrary place in memory, make |  | 
|   843     // sure MSAN doesn't complain about it. |  | 
|   844     MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(Address)); |  | 
|   845     // Sample potential return address value for frameless invocation of |  | 
|   846     // stubs (we'll figure out later, if this value makes sense). |  | 
|   847     tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp)); |  | 
|   848     has_external_callback = false; |  | 
|   849   } |  | 
|   850  |  | 
|   851   SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp), |  | 
|   852                             reinterpret_cast<Address>(regs.sp), js_entry_sp); |  | 
|   853   top_frame_type = it.top_frame_type(); |  | 
|   854  |  | 
|   855   SampleInfo info; |  | 
|   856   GetStackSample(isolate, regs, record_c_entry_frame, |  | 
|   857                  reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, &info); |  | 
|   858   frames_count = static_cast<unsigned>(info.frames_count); |  | 
|   859   if (!frames_count) { |  | 
|   860     // It is executing JS but failed to collect a stack trace. |  | 
|   861     // Mark the sample as spoiled. |  | 
|   862     timestamp = base::TimeTicks(); |  | 
|   863     pc = 0; |  | 
|   864   } |  | 
|   865 } |  | 
|   866  |  | 
|   867  |  | 
|   868 void TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs, |  | 
|   869                                 RecordCEntryFrame record_c_entry_frame, |  | 
|   870                                 void** frames, size_t frames_limit, |  | 
|   871                                 v8::SampleInfo* sample_info) { |  | 
|   872   sample_info->frames_count = 0; |  | 
|   873   sample_info->vm_state = isolate->current_vm_state(); |  | 
|   874   if (sample_info->vm_state == GC) return; |  | 
|   875  |  | 
|   876   Address js_entry_sp = isolate->js_entry_sp(); |  | 
|   877   if (js_entry_sp == 0) return;  // Not executing JS now. |  | 
|   878  |  | 
|   879   SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp), |  | 
|   880                             reinterpret_cast<Address>(regs.sp), js_entry_sp); |  | 
|   881   size_t i = 0; |  | 
|   882   if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() && |  | 
|   883       it.top_frame_type() == StackFrame::EXIT) { |  | 
|   884     frames[i++] = isolate->c_function(); |  | 
|   885   } |  | 
|   886   while (!it.done() && i < frames_limit) { |  | 
|   887     if (it.frame()->is_interpreted()) { |  | 
|   888       // For interpreted frames use the bytecode array pointer as the pc. |  | 
|   889       InterpretedFrame* frame = static_cast<InterpretedFrame*>(it.frame()); |  | 
|   890       // Since the sampler can interrupt execution at any point the |  | 
|   891       // bytecode_array might be garbage, so don't dereference it. |  | 
|   892       Address bytecode_array = |  | 
|   893           reinterpret_cast<Address>(frame->GetBytecodeArray()) - kHeapObjectTag; |  | 
|   894       frames[i++] = bytecode_array + BytecodeArray::kHeaderSize + |  | 
|   895                     frame->GetBytecodeOffset(); |  | 
|   896     } else { |  | 
|   897       frames[i++] = it.frame()->pc(); |  | 
|   898     } |  | 
|   899     it.Advance(); |  | 
|   900   } |  | 
|   901   sample_info->frames_count = i; |  | 
|   902 } |  | 
|   903  |  | 
|   904  |  | 
|   905 void Sampler::SetUp() { |   743 void Sampler::SetUp() { | 
|   906 #if defined(USE_SIGNALS) |   744 #if defined(USE_SIGNALS) | 
|   907   SignalHandler::SetUp(); |   745   SignalHandler::SetUp(); | 
|   908 #endif |   746 #endif | 
|   909   SamplerThread::SetUp(); |   747   SamplerThread::SetUp(); | 
|   910 } |   748 } | 
|   911  |   749  | 
|   912  |   750  | 
|   913 void Sampler::TearDown() { |   751 void Sampler::TearDown() { | 
|   914   SamplerThread::TearDown(); |   752   SamplerThread::TearDown(); | 
| (...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
|  1030     SampleStack(state); |   868     SampleStack(state); | 
|  1031   } |   869   } | 
|  1032   ResumeThread(profiled_thread); |   870   ResumeThread(profiled_thread); | 
|  1033 } |   871 } | 
|  1034  |   872  | 
|  1035 #endif  // USE_SIGNALS |   873 #endif  // USE_SIGNALS | 
|  1036  |   874  | 
|  1037  |   875  | 
|  1038 }  // namespace internal |   876 }  // namespace internal | 
|  1039 }  // namespace v8 |   877 }  // namespace v8 | 
| OLD | NEW |