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

Side by Side Diff: src/profiler/sampler.cc

Issue 1952393002: Split TickSample and Sampler. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Created 4 years, 7 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/profiler/sampler.h ('k') | src/profiler/tick-sample.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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/base/atomic-utils.h" 45 #include "src/base/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
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(base::AtomicValue<int>* atomic, bool is_block = true) 180 explicit AtomicGuard(base::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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
324 } 259 }
325 260
326 HANDLE profiled_thread() { return profiled_thread_; } 261 HANDLE profiled_thread() { return profiled_thread_; }
327 262
328 private: 263 private:
329 HANDLE profiled_thread_; 264 HANDLE profiled_thread_;
330 }; 265 };
331 #endif 266 #endif
332 267
333 268
334 #if defined(USE_SIMULATOR)
335 bool SimulatorHelper::FillRegisters(Isolate* isolate,
336 v8::RegisterState* state) {
337 Simulator *simulator = isolate->thread_local_top()->simulator_;
338 // Check if there is active simulator.
339 if (simulator == NULL) return false;
340 #if V8_TARGET_ARCH_ARM
341 if (!simulator->has_bad_pc()) {
342 state->pc = reinterpret_cast<Address>(simulator->get_pc());
343 }
344 state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
345 state->fp = reinterpret_cast<Address>(simulator->get_register(
346 Simulator::r11));
347 #elif V8_TARGET_ARCH_ARM64
348 state->pc = reinterpret_cast<Address>(simulator->pc());
349 state->sp = reinterpret_cast<Address>(simulator->sp());
350 state->fp = reinterpret_cast<Address>(simulator->fp());
351 #elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
352 if (!simulator->has_bad_pc()) {
353 state->pc = reinterpret_cast<Address>(simulator->get_pc());
354 }
355 state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
356 state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp));
357 #elif V8_TARGET_ARCH_PPC
358 if (!simulator->has_bad_pc()) {
359 state->pc = reinterpret_cast<Address>(simulator->get_pc());
360 }
361 state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
362 state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp));
363 #elif V8_TARGET_ARCH_S390
364 if (!simulator->has_bad_pc()) {
365 state->pc = reinterpret_cast<Address>(simulator->get_pc());
366 }
367 state->sp = reinterpret_cast<Address>(simulator->get_register(Simulator::sp));
368 state->fp = reinterpret_cast<Address>(simulator->get_register(Simulator::fp));
369 #endif
370 if (state->sp == 0 || state->fp == 0) {
371 // It possible that the simulator is interrupted while it is updating
372 // the sp or fp register. ARM64 simulator does this in two steps:
373 // first setting it to zero and then setting it to the new value.
374 // Bailout if sp/fp doesn't contain the new value.
375 //
376 // FIXME: The above doesn't really solve the issue.
377 // If a 64-bit target is executed on a 32-bit host even the final
378 // write is non-atomic, so it might obtain a half of the result.
379 // Moreover as long as the register set code uses memcpy (as of now),
380 // it is not guaranteed to be atomic even when both host and target
381 // are of same bitness.
382 return false;
383 }
384 return true;
385 }
386 #endif // USE_SIMULATOR
387
388
389 #if defined(USE_SIGNALS) 269 #if defined(USE_SIGNALS)
390 270
391 class SignalHandler : public AllStatic { 271 class SignalHandler : public AllStatic {
392 public: 272 public:
393 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); } 273 static void SetUp() { if (!mutex_) mutex_ = new base::Mutex(); }
394 static void TearDown() { delete mutex_; mutex_ = NULL; } 274 static void TearDown() { delete mutex_; mutex_ = NULL; }
395 275
396 static void IncreaseSamplerCount() { 276 static void IncreaseSamplerCount() {
397 base::LockGuard<base::Mutex> lock_guard(mutex_); 277 base::LockGuard<base::Mutex> lock_guard(mutex_);
398 if (++client_count_ == 1) Install(); 278 if (++client_count_ == 1) Install();
(...skipping 405 matching lines...) Expand 10 before | Expand all | Expand 10 after
804 SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value); 684 SamplerList* samplers = reinterpret_cast<SamplerList*>(entry->value);
805 for (int i = 0; i < samplers->length(); ++i) { 685 for (int i = 0; i < samplers->length(); ++i) {
806 Sampler* sampler = samplers->at(i); 686 Sampler* sampler = samplers->at(i);
807 CollectSample(context, sampler); 687 CollectSample(context, sampler);
808 } 688 }
809 } 689 }
810 #endif // !V8_OS_NACL 690 #endif // !V8_OS_NACL
811 #endif // USE_SIGNALs 691 #endif // USE_SIGNALs
812 692
813 693
814 //
815 // StackTracer implementation
816 //
817 DISABLE_ASAN void TickSample::Init(Isolate* isolate,
818 const v8::RegisterState& regs,
819 RecordCEntryFrame record_c_entry_frame,
820 bool update_stats) {
821 timestamp = base::TimeTicks::HighResolutionNow();
822 pc = reinterpret_cast<Address>(regs.pc);
823 state = isolate->current_vm_state();
824 this->update_stats = update_stats;
825
826 // Avoid collecting traces while doing GC.
827 if (state == GC) return;
828
829 Address js_entry_sp = isolate->js_entry_sp();
830 if (js_entry_sp == 0) return; // Not executing JS now.
831
832 if (pc && IsNoFrameRegion(pc)) {
833 // Can't collect stack. Mark the sample as spoiled.
834 timestamp = base::TimeTicks();
835 pc = 0;
836 return;
837 }
838
839 ExternalCallbackScope* scope = isolate->external_callback_scope();
840 Address handler = Isolate::handler(isolate->thread_local_top());
841 // If there is a handler on top of the external callback scope then
842 // we have already entrered JavaScript again and the external callback
843 // is not the top function.
844 if (scope && scope->scope_address() < handler) {
845 external_callback_entry = *scope->callback_entrypoint_address();
846 has_external_callback = true;
847 } else {
848 // sp register may point at an arbitrary place in memory, make
849 // sure MSAN doesn't complain about it.
850 MSAN_MEMORY_IS_INITIALIZED(regs.sp, sizeof(Address));
851 // Sample potential return address value for frameless invocation of
852 // stubs (we'll figure out later, if this value makes sense).
853 tos = Memory::Address_at(reinterpret_cast<Address>(regs.sp));
854 has_external_callback = false;
855 }
856
857 SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
858 reinterpret_cast<Address>(regs.sp), js_entry_sp);
859 top_frame_type = it.top_frame_type();
860
861 SampleInfo info;
862 GetStackSample(isolate, regs, record_c_entry_frame,
863 reinterpret_cast<void**>(&stack[0]), kMaxFramesCount, &info);
864 frames_count = static_cast<unsigned>(info.frames_count);
865 if (!frames_count) {
866 // It is executing JS but failed to collect a stack trace.
867 // Mark the sample as spoiled.
868 timestamp = base::TimeTicks();
869 pc = 0;
870 }
871 }
872
873
874 void TickSample::GetStackSample(Isolate* isolate, const v8::RegisterState& regs,
875 RecordCEntryFrame record_c_entry_frame,
876 void** frames, size_t frames_limit,
877 v8::SampleInfo* sample_info) {
878 sample_info->frames_count = 0;
879 sample_info->vm_state = isolate->current_vm_state();
880 if (sample_info->vm_state == GC) return;
881
882 Address js_entry_sp = isolate->js_entry_sp();
883 if (js_entry_sp == 0) return; // Not executing JS now.
884
885 SafeStackFrameIterator it(isolate, reinterpret_cast<Address>(regs.fp),
886 reinterpret_cast<Address>(regs.sp), js_entry_sp);
887 size_t i = 0;
888 if (record_c_entry_frame == kIncludeCEntryFrame && !it.done() &&
889 it.top_frame_type() == StackFrame::EXIT) {
890 frames[i++] = isolate->c_function();
891 }
892 while (!it.done() && i < frames_limit) {
893 if (it.frame()->is_interpreted()) {
894 // For interpreted frames use the bytecode array pointer as the pc.
895 InterpretedFrame* frame = static_cast<InterpretedFrame*>(it.frame());
896 // Since the sampler can interrupt execution at any point the
897 // bytecode_array might be garbage, so don't dereference it.
898 Address bytecode_array =
899 reinterpret_cast<Address>(frame->GetBytecodeArray()) - kHeapObjectTag;
900 frames[i++] = bytecode_array + BytecodeArray::kHeaderSize +
901 frame->GetBytecodeOffset();
902 } else {
903 frames[i++] = it.frame()->pc();
904 }
905 it.Advance();
906 }
907 sample_info->frames_count = i;
908 }
909
910
911 void Sampler::SetUp() { 694 void Sampler::SetUp() {
912 #if defined(USE_SIGNALS) 695 #if defined(USE_SIGNALS)
913 SignalHandler::SetUp(); 696 SignalHandler::SetUp();
914 #endif 697 #endif
915 SamplerThread::SetUp(); 698 SamplerThread::SetUp();
916 } 699 }
917 700
918 701
919 void Sampler::TearDown() { 702 void Sampler::TearDown() {
920 SamplerThread::TearDown(); 703 SamplerThread::TearDown();
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
1036 SampleStack(state); 819 SampleStack(state);
1037 } 820 }
1038 ResumeThread(profiled_thread); 821 ResumeThread(profiled_thread);
1039 } 822 }
1040 823
1041 #endif // USE_SIGNALS 824 #endif // USE_SIGNALS
1042 825
1043 826
1044 } // namespace internal 827 } // namespace internal
1045 } // namespace v8 828 } // namespace v8
OLDNEW
« no previous file with comments | « src/profiler/sampler.h ('k') | src/profiler/tick-sample.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698