OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2016 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/profiler-listener.h" |
| 6 |
| 7 #include "src/deoptimizer.h" |
| 8 #include "src/interpreter/source-position-table.h" |
5 #include "src/profiler/cpu-profiler.h" | 9 #include "src/profiler/cpu-profiler.h" |
6 | 10 #include "src/profiler/profile-generator-inl.h" |
7 #include "src/debug/debug.h" | |
8 #include "src/deoptimizer.h" | |
9 #include "src/frames-inl.h" | |
10 #include "src/locked-queue-inl.h" | |
11 #include "src/log-inl.h" | |
12 #include "src/profiler/cpu-profiler-inl.h" | |
13 #include "src/vm-state-inl.h" | |
14 | |
15 #include "include/v8-profiler.h" | |
16 | 11 |
17 namespace v8 { | 12 namespace v8 { |
18 namespace internal { | 13 namespace internal { |
19 | 14 |
20 static const int kProfilerStackSize = 64 * KB; | 15 ProfilerListener::ProfilerListener(Isolate* isolate) |
| 16 : function_and_resource_names_(isolate->heap()) {} |
21 | 17 |
22 | 18 ProfilerListener::~ProfilerListener() { |
23 ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator, | 19 for (auto code_entry : code_entries_) { |
24 sampler::Sampler* sampler, | 20 delete code_entry; |
25 base::TimeDelta period) | |
26 : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)), | |
27 generator_(generator), | |
28 sampler_(sampler), | |
29 running_(1), | |
30 period_(period), | |
31 last_code_event_id_(0), | |
32 last_processed_code_event_id_(0) {} | |
33 | |
34 | |
35 ProfilerEventsProcessor::~ProfilerEventsProcessor() {} | |
36 | |
37 | |
38 void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) { | |
39 event.generic.order = last_code_event_id_.Increment(1); | |
40 events_buffer_.Enqueue(event); | |
41 } | |
42 | |
43 | |
44 void ProfilerEventsProcessor::AddDeoptStack(Isolate* isolate, Address from, | |
45 int fp_to_sp_delta) { | |
46 TickSampleEventRecord record(last_code_event_id_.Value()); | |
47 RegisterState regs; | |
48 Address fp = isolate->c_entry_fp(isolate->thread_local_top()); | |
49 regs.sp = fp - fp_to_sp_delta; | |
50 regs.fp = fp; | |
51 regs.pc = from; | |
52 record.sample.Init(isolate, regs, TickSample::kSkipCEntryFrame, false); | |
53 ticks_from_vm_buffer_.Enqueue(record); | |
54 } | |
55 | |
56 void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate, | |
57 bool update_stats) { | |
58 TickSampleEventRecord record(last_code_event_id_.Value()); | |
59 RegisterState regs; | |
60 StackFrameIterator it(isolate); | |
61 if (!it.done()) { | |
62 StackFrame* frame = it.frame(); | |
63 regs.sp = frame->sp(); | |
64 regs.fp = frame->fp(); | |
65 regs.pc = frame->pc(); | |
66 } | |
67 record.sample.Init(isolate, regs, TickSample::kSkipCEntryFrame, update_stats); | |
68 ticks_from_vm_buffer_.Enqueue(record); | |
69 } | |
70 | |
71 | |
72 void ProfilerEventsProcessor::StopSynchronously() { | |
73 if (!base::NoBarrier_AtomicExchange(&running_, 0)) return; | |
74 Join(); | |
75 } | |
76 | |
77 | |
78 bool ProfilerEventsProcessor::ProcessCodeEvent() { | |
79 CodeEventsContainer record; | |
80 if (events_buffer_.Dequeue(&record)) { | |
81 switch (record.generic.type) { | |
82 #define PROFILER_TYPE_CASE(type, clss) \ | |
83 case CodeEventRecord::type: \ | |
84 record.clss##_.UpdateCodeMap(generator_->code_map()); \ | |
85 break; | |
86 | |
87 CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE) | |
88 | |
89 #undef PROFILER_TYPE_CASE | |
90 default: return true; // Skip record. | |
91 } | |
92 last_processed_code_event_id_ = record.generic.order; | |
93 return true; | |
94 } | |
95 return false; | |
96 } | |
97 | |
98 ProfilerEventsProcessor::SampleProcessingResult | |
99 ProfilerEventsProcessor::ProcessOneSample() { | |
100 TickSampleEventRecord record1; | |
101 if (ticks_from_vm_buffer_.Peek(&record1) && | |
102 (record1.order == last_processed_code_event_id_)) { | |
103 TickSampleEventRecord record; | |
104 ticks_from_vm_buffer_.Dequeue(&record); | |
105 generator_->RecordTickSample(record.sample); | |
106 return OneSampleProcessed; | |
107 } | |
108 | |
109 const TickSampleEventRecord* record = ticks_buffer_.Peek(); | |
110 if (record == NULL) { | |
111 if (ticks_from_vm_buffer_.IsEmpty()) return NoSamplesInQueue; | |
112 return FoundSampleForNextCodeEvent; | |
113 } | |
114 if (record->order != last_processed_code_event_id_) { | |
115 return FoundSampleForNextCodeEvent; | |
116 } | |
117 generator_->RecordTickSample(record->sample); | |
118 ticks_buffer_.Remove(); | |
119 return OneSampleProcessed; | |
120 } | |
121 | |
122 | |
123 void ProfilerEventsProcessor::Run() { | |
124 while (!!base::NoBarrier_Load(&running_)) { | |
125 base::TimeTicks nextSampleTime = | |
126 base::TimeTicks::HighResolutionNow() + period_; | |
127 base::TimeTicks now; | |
128 SampleProcessingResult result; | |
129 // Keep processing existing events until we need to do next sample | |
130 // or the ticks buffer is empty. | |
131 do { | |
132 result = ProcessOneSample(); | |
133 if (result == FoundSampleForNextCodeEvent) { | |
134 // All ticks of the current last_processed_code_event_id_ are | |
135 // processed, proceed to the next code event. | |
136 ProcessCodeEvent(); | |
137 } | |
138 now = base::TimeTicks::HighResolutionNow(); | |
139 } while (result != NoSamplesInQueue && now < nextSampleTime); | |
140 | |
141 if (nextSampleTime > now) { | |
142 #if V8_OS_WIN | |
143 // Do not use Sleep on Windows as it is very imprecise. | |
144 // Could be up to 16ms jitter, which is unacceptable for the purpose. | |
145 while (base::TimeTicks::HighResolutionNow() < nextSampleTime) { | |
146 } | |
147 #else | |
148 base::OS::Sleep(nextSampleTime - now); | |
149 #endif | |
150 } | |
151 | |
152 // Schedule next sample. sampler_ is NULL in tests. | |
153 if (sampler_) sampler_->DoSample(); | |
154 } | |
155 | |
156 // Process remaining tick events. | |
157 do { | |
158 SampleProcessingResult result; | |
159 do { | |
160 result = ProcessOneSample(); | |
161 } while (result == OneSampleProcessed); | |
162 } while (ProcessCodeEvent()); | |
163 } | |
164 | |
165 | |
166 void* ProfilerEventsProcessor::operator new(size_t size) { | |
167 return AlignedAlloc(size, V8_ALIGNOF(ProfilerEventsProcessor)); | |
168 } | |
169 | |
170 | |
171 void ProfilerEventsProcessor::operator delete(void* ptr) { | |
172 AlignedFree(ptr); | |
173 } | |
174 | |
175 | |
176 int CpuProfiler::GetProfilesCount() { | |
177 // The count of profiles doesn't depend on a security token. | |
178 return profiles_->profiles()->length(); | |
179 } | |
180 | |
181 | |
182 CpuProfile* CpuProfiler::GetProfile(int index) { | |
183 return profiles_->profiles()->at(index); | |
184 } | |
185 | |
186 | |
187 void CpuProfiler::DeleteAllProfiles() { | |
188 if (is_profiling_) StopProcessor(); | |
189 ResetProfiles(); | |
190 } | |
191 | |
192 | |
193 void CpuProfiler::DeleteProfile(CpuProfile* profile) { | |
194 profiles_->RemoveProfile(profile); | |
195 delete profile; | |
196 if (profiles_->profiles()->is_empty() && !is_profiling_) { | |
197 // If this was the last profile, clean up all accessory data as well. | |
198 ResetProfiles(); | |
199 } | 21 } |
200 } | 22 } |
201 | 23 |
202 | 24 void ProfilerListener::CallbackEvent(Name* name, Address entry_point) { |
203 void CpuProfiler::CallbackEvent(Name* name, Address entry_point) { | |
204 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); | 25 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
205 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | 26 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
206 rec->start = entry_point; | 27 rec->start = entry_point; |
207 rec->entry = profiles_->NewCodeEntry(CodeEventListener::CALLBACK_TAG, | 28 rec->entry = NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name)); |
208 profiles_->GetName(name)); | |
209 rec->size = 1; | 29 rec->size = 1; |
210 processor_->Enqueue(evt_rec); | 30 DispatchCodeEvent(evt_rec); |
211 } | 31 } |
212 | 32 |
213 void CpuProfiler::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, | 33 void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, |
214 AbstractCode* code, const char* name) { | 34 AbstractCode* code, const char* name) { |
215 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); | 35 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
216 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | 36 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
217 rec->start = code->address(); | 37 rec->start = code->address(); |
218 rec->entry = profiles_->NewCodeEntry( | 38 rec->entry = NewCodeEntry( |
219 tag, profiles_->GetFunctionName(name), CodeEntry::kEmptyNamePrefix, | 39 tag, GetFunctionName(name), CodeEntry::kEmptyNamePrefix, |
220 CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, | 40 CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, |
221 CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); | 41 CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); |
222 RecordInliningInfo(rec->entry, code); | 42 RecordInliningInfo(rec->entry, code); |
223 rec->size = code->ExecutableSize(); | 43 rec->size = code->ExecutableSize(); |
224 processor_->Enqueue(evt_rec); | 44 DispatchCodeEvent(evt_rec); |
225 } | 45 } |
226 | 46 |
227 void CpuProfiler::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, | 47 void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, |
228 AbstractCode* code, Name* name) { | 48 AbstractCode* code, Name* name) { |
229 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); | 49 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
230 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | 50 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
231 rec->start = code->address(); | 51 rec->start = code->address(); |
232 rec->entry = profiles_->NewCodeEntry( | 52 rec->entry = NewCodeEntry( |
233 tag, profiles_->GetFunctionName(name), CodeEntry::kEmptyNamePrefix, | 53 tag, GetFunctionName(name), CodeEntry::kEmptyNamePrefix, |
234 CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, | 54 CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, |
235 CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); | 55 CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); |
236 RecordInliningInfo(rec->entry, code); | 56 RecordInliningInfo(rec->entry, code); |
237 rec->size = code->ExecutableSize(); | 57 rec->size = code->ExecutableSize(); |
238 processor_->Enqueue(evt_rec); | 58 DispatchCodeEvent(evt_rec); |
239 } | 59 } |
240 | 60 |
241 void CpuProfiler::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, | 61 void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, |
242 AbstractCode* code, | 62 AbstractCode* code, |
243 SharedFunctionInfo* shared, | 63 SharedFunctionInfo* shared, |
244 Name* script_name) { | 64 Name* script_name) { |
245 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); | 65 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
246 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | 66 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
247 rec->start = code->address(); | 67 rec->start = code->address(); |
248 rec->entry = profiles_->NewCodeEntry( | 68 rec->entry = NewCodeEntry( |
249 tag, profiles_->GetFunctionName(shared->DebugName()), | 69 tag, GetFunctionName(shared->DebugName()), CodeEntry::kEmptyNamePrefix, |
250 CodeEntry::kEmptyNamePrefix, | 70 GetName(InferScriptName(script_name, shared)), |
251 profiles_->GetName(InferScriptName(script_name, shared)), | |
252 CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo, | 71 CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo, |
253 NULL, code->instruction_start()); | 72 NULL, code->instruction_start()); |
254 RecordInliningInfo(rec->entry, code); | 73 RecordInliningInfo(rec->entry, code); |
255 rec->entry->FillFunctionInfo(shared); | 74 rec->entry->FillFunctionInfo(shared); |
256 rec->size = code->ExecutableSize(); | 75 rec->size = code->ExecutableSize(); |
257 processor_->Enqueue(evt_rec); | 76 DispatchCodeEvent(evt_rec); |
258 } | 77 } |
259 | 78 |
260 void CpuProfiler::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, | 79 void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, |
261 AbstractCode* abstract_code, | 80 AbstractCode* abstract_code, |
262 SharedFunctionInfo* shared, Name* script_name, | 81 SharedFunctionInfo* shared, |
263 int line, int column) { | 82 Name* script_name, int line, |
| 83 int column) { |
264 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); | 84 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
265 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | 85 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
266 rec->start = abstract_code->address(); | 86 rec->start = abstract_code->address(); |
267 Script* script = Script::cast(shared->script()); | 87 Script* script = Script::cast(shared->script()); |
268 JITLineInfoTable* line_table = NULL; | 88 JITLineInfoTable* line_table = NULL; |
269 if (script) { | 89 if (script) { |
270 if (abstract_code->IsCode()) { | 90 if (abstract_code->IsCode()) { |
271 Code* code = abstract_code->GetCode(); | 91 Code* code = abstract_code->GetCode(); |
272 int start_position = shared->start_position(); | 92 int start_position = shared->start_position(); |
273 int end_position = shared->end_position(); | 93 int end_position = shared->end_position(); |
(...skipping 18 matching lines...) Expand all Loading... |
292 line_table = new JITLineInfoTable(); | 112 line_table = new JITLineInfoTable(); |
293 interpreter::SourcePositionTableIterator it( | 113 interpreter::SourcePositionTableIterator it( |
294 bytecode->source_position_table()); | 114 bytecode->source_position_table()); |
295 for (; !it.done(); it.Advance()) { | 115 for (; !it.done(); it.Advance()) { |
296 int line_number = script->GetLineNumber(it.source_position()) + 1; | 116 int line_number = script->GetLineNumber(it.source_position()) + 1; |
297 int pc_offset = it.bytecode_offset() + BytecodeArray::kHeaderSize; | 117 int pc_offset = it.bytecode_offset() + BytecodeArray::kHeaderSize; |
298 line_table->SetPosition(pc_offset, line_number); | 118 line_table->SetPosition(pc_offset, line_number); |
299 } | 119 } |
300 } | 120 } |
301 } | 121 } |
302 rec->entry = profiles_->NewCodeEntry( | 122 rec->entry = NewCodeEntry( |
303 tag, profiles_->GetFunctionName(shared->DebugName()), | 123 tag, GetFunctionName(shared->DebugName()), CodeEntry::kEmptyNamePrefix, |
304 CodeEntry::kEmptyNamePrefix, | 124 GetName(InferScriptName(script_name, shared)), line, column, line_table, |
305 profiles_->GetName(InferScriptName(script_name, shared)), line, column, | 125 abstract_code->instruction_start()); |
306 line_table, abstract_code->instruction_start()); | |
307 RecordInliningInfo(rec->entry, abstract_code); | 126 RecordInliningInfo(rec->entry, abstract_code); |
308 RecordDeoptInlinedFrames(rec->entry, abstract_code); | 127 RecordDeoptInlinedFrames(rec->entry, abstract_code); |
309 rec->entry->FillFunctionInfo(shared); | 128 rec->entry->FillFunctionInfo(shared); |
310 rec->size = abstract_code->ExecutableSize(); | 129 rec->size = abstract_code->ExecutableSize(); |
311 processor_->Enqueue(evt_rec); | 130 DispatchCodeEvent(evt_rec); |
312 } | 131 } |
313 | 132 |
314 void CpuProfiler::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, | 133 void ProfilerListener::CodeCreateEvent(CodeEventListener::LogEventsAndTags tag, |
315 AbstractCode* code, int args_count) { | 134 AbstractCode* code, int args_count) { |
316 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); | 135 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
317 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | 136 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
318 rec->start = code->address(); | 137 rec->start = code->address(); |
319 rec->entry = profiles_->NewCodeEntry( | 138 rec->entry = NewCodeEntry( |
320 tag, profiles_->GetName(args_count), "args_count: ", | 139 tag, GetName(args_count), "args_count: ", CodeEntry::kEmptyResourceName, |
321 CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, | 140 CpuProfileNode::kNoLineNumberInfo, CpuProfileNode::kNoColumnNumberInfo, |
322 CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); | 141 NULL, code->instruction_start()); |
323 RecordInliningInfo(rec->entry, code); | 142 RecordInliningInfo(rec->entry, code); |
324 rec->size = code->ExecutableSize(); | 143 rec->size = code->ExecutableSize(); |
325 processor_->Enqueue(evt_rec); | 144 DispatchCodeEvent(evt_rec); |
326 } | 145 } |
327 | 146 |
328 void CpuProfiler::CodeMoveEvent(AbstractCode* from, Address to) { | 147 void ProfilerListener::CodeMoveEvent(AbstractCode* from, Address to) { |
329 CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE); | 148 CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE); |
330 CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_; | 149 CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_; |
331 rec->from = from->address(); | 150 rec->from = from->address(); |
332 rec->to = to; | 151 rec->to = to; |
333 processor_->Enqueue(evt_rec); | 152 DispatchCodeEvent(evt_rec); |
334 } | 153 } |
335 | 154 |
336 void CpuProfiler::CodeDisableOptEvent(AbstractCode* code, | 155 void ProfilerListener::CodeDisableOptEvent(AbstractCode* code, |
337 SharedFunctionInfo* shared) { | 156 SharedFunctionInfo* shared) { |
338 CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT); | 157 CodeEventsContainer evt_rec(CodeEventRecord::CODE_DISABLE_OPT); |
339 CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_; | 158 CodeDisableOptEventRecord* rec = &evt_rec.CodeDisableOptEventRecord_; |
340 rec->start = code->address(); | 159 rec->start = code->address(); |
341 rec->bailout_reason = GetBailoutReason(shared->disable_optimization_reason()); | 160 rec->bailout_reason = GetBailoutReason(shared->disable_optimization_reason()); |
342 processor_->Enqueue(evt_rec); | 161 DispatchCodeEvent(evt_rec); |
343 } | 162 } |
344 | 163 |
345 void CpuProfiler::CodeDeoptEvent(Code* code, Address pc, int fp_to_sp_delta) { | 164 void ProfilerListener::CodeDeoptEvent(Code* code, Address pc, |
| 165 int fp_to_sp_delta) { |
346 CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT); | 166 CodeEventsContainer evt_rec(CodeEventRecord::CODE_DEOPT); |
347 CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_; | 167 CodeDeoptEventRecord* rec = &evt_rec.CodeDeoptEventRecord_; |
348 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc); | 168 Deoptimizer::DeoptInfo info = Deoptimizer::GetDeoptInfo(code, pc); |
349 rec->start = code->address(); | 169 rec->start = code->address(); |
350 rec->deopt_reason = Deoptimizer::GetDeoptReason(info.deopt_reason); | 170 rec->deopt_reason = Deoptimizer::GetDeoptReason(info.deopt_reason); |
351 rec->position = info.position; | 171 rec->position = info.position; |
352 rec->deopt_id = info.deopt_id; | 172 rec->deopt_id = info.deopt_id; |
353 processor_->Enqueue(evt_rec); | 173 rec->pc = reinterpret_cast<void*>(pc); |
354 processor_->AddDeoptStack(isolate_, pc, fp_to_sp_delta); | 174 rec->fp_to_sp_delta = fp_to_sp_delta; |
| 175 DispatchCodeEvent(evt_rec); |
355 } | 176 } |
356 | 177 |
357 void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) { | 178 void ProfilerListener::GetterCallbackEvent(Name* name, Address entry_point) { |
358 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); | 179 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
359 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | 180 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
360 rec->start = entry_point; | 181 rec->start = entry_point; |
361 rec->entry = profiles_->NewCodeEntry(CodeEventListener::CALLBACK_TAG, | 182 rec->entry = |
362 profiles_->GetName(name), "get "); | 183 NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name), "get "); |
363 rec->size = 1; | 184 rec->size = 1; |
364 processor_->Enqueue(evt_rec); | 185 DispatchCodeEvent(evt_rec); |
365 } | 186 } |
366 | 187 |
367 void CpuProfiler::RegExpCodeCreateEvent(AbstractCode* code, String* source) { | 188 void ProfilerListener::RegExpCodeCreateEvent(AbstractCode* code, |
| 189 String* source) { |
368 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); | 190 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
369 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | 191 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
370 rec->start = code->address(); | 192 rec->start = code->address(); |
371 rec->entry = profiles_->NewCodeEntry( | 193 rec->entry = NewCodeEntry( |
372 CodeEventListener::REG_EXP_TAG, profiles_->GetName(source), "RegExp: ", | 194 CodeEventListener::REG_EXP_TAG, GetName(source), "RegExp: ", |
373 CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, | 195 CodeEntry::kEmptyResourceName, CpuProfileNode::kNoLineNumberInfo, |
374 CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); | 196 CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); |
375 rec->size = code->ExecutableSize(); | 197 rec->size = code->ExecutableSize(); |
376 processor_->Enqueue(evt_rec); | 198 DispatchCodeEvent(evt_rec); |
377 } | 199 } |
378 | 200 |
379 | 201 void ProfilerListener::SetterCallbackEvent(Name* name, Address entry_point) { |
380 void CpuProfiler::SetterCallbackEvent(Name* name, Address entry_point) { | |
381 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); | 202 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
382 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | 203 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
383 rec->start = entry_point; | 204 rec->start = entry_point; |
384 rec->entry = profiles_->NewCodeEntry(CodeEventListener::CALLBACK_TAG, | 205 rec->entry = |
385 profiles_->GetName(name), "set "); | 206 NewCodeEntry(CodeEventListener::CALLBACK_TAG, GetName(name), "set "); |
386 rec->size = 1; | 207 rec->size = 1; |
387 processor_->Enqueue(evt_rec); | 208 DispatchCodeEvent(evt_rec); |
388 } | 209 } |
389 | 210 |
390 Name* CpuProfiler::InferScriptName(Name* name, SharedFunctionInfo* info) { | 211 Name* ProfilerListener::InferScriptName(Name* name, SharedFunctionInfo* info) { |
391 if (name->IsString() && String::cast(name)->length()) return name; | 212 if (name->IsString() && String::cast(name)->length()) return name; |
392 if (!info->script()->IsScript()) return name; | 213 if (!info->script()->IsScript()) return name; |
393 Object* source_url = Script::cast(info->script())->source_url(); | 214 Object* source_url = Script::cast(info->script())->source_url(); |
394 return source_url->IsName() ? Name::cast(source_url) : name; | 215 return source_url->IsName() ? Name::cast(source_url) : name; |
395 } | 216 } |
396 | 217 |
397 void CpuProfiler::RecordInliningInfo(CodeEntry* entry, | 218 void ProfilerListener::RecordInliningInfo(CodeEntry* entry, |
398 AbstractCode* abstract_code) { | 219 AbstractCode* abstract_code) { |
399 if (!abstract_code->IsCode()) return; | 220 if (!abstract_code->IsCode()) return; |
400 Code* code = abstract_code->GetCode(); | 221 Code* code = abstract_code->GetCode(); |
401 if (code->kind() != Code::OPTIMIZED_FUNCTION) return; | 222 if (code->kind() != Code::OPTIMIZED_FUNCTION) return; |
402 DeoptimizationInputData* deopt_input_data = | 223 DeoptimizationInputData* deopt_input_data = |
403 DeoptimizationInputData::cast(code->deoptimization_data()); | 224 DeoptimizationInputData::cast(code->deoptimization_data()); |
404 int deopt_count = deopt_input_data->DeoptCount(); | 225 int deopt_count = deopt_input_data->DeoptCount(); |
405 for (int i = 0; i < deopt_count; i++) { | 226 for (int i = 0; i < deopt_count; i++) { |
406 int pc_offset = deopt_input_data->Pc(i)->value(); | 227 int pc_offset = deopt_input_data->Pc(i)->value(); |
407 if (pc_offset == -1) continue; | 228 if (pc_offset == -1) continue; |
408 int translation_index = deopt_input_data->TranslationIndex(i)->value(); | 229 int translation_index = deopt_input_data->TranslationIndex(i)->value(); |
(...skipping 12 matching lines...) Expand all Loading... |
421 it.Skip(Translation::NumberOfOperandsFor(opcode)); | 242 it.Skip(Translation::NumberOfOperandsFor(opcode)); |
422 continue; | 243 continue; |
423 } | 244 } |
424 it.Next(); // Skip ast_id | 245 it.Next(); // Skip ast_id |
425 int shared_info_id = it.Next(); | 246 int shared_info_id = it.Next(); |
426 it.Next(); // Skip height | 247 it.Next(); // Skip height |
427 SharedFunctionInfo* shared_info = SharedFunctionInfo::cast( | 248 SharedFunctionInfo* shared_info = SharedFunctionInfo::cast( |
428 deopt_input_data->LiteralArray()->get(shared_info_id)); | 249 deopt_input_data->LiteralArray()->get(shared_info_id)); |
429 if (!depth++) continue; // Skip the current function itself. | 250 if (!depth++) continue; // Skip the current function itself. |
430 CodeEntry* inline_entry = new CodeEntry( | 251 CodeEntry* inline_entry = new CodeEntry( |
431 entry->tag(), profiles_->GetFunctionName(shared_info->DebugName()), | 252 entry->tag(), GetFunctionName(shared_info->DebugName()), |
432 CodeEntry::kEmptyNamePrefix, entry->resource_name(), | 253 CodeEntry::kEmptyNamePrefix, entry->resource_name(), |
433 CpuProfileNode::kNoLineNumberInfo, | 254 CpuProfileNode::kNoLineNumberInfo, |
434 CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); | 255 CpuProfileNode::kNoColumnNumberInfo, NULL, code->instruction_start()); |
435 inline_entry->FillFunctionInfo(shared_info); | 256 inline_entry->FillFunctionInfo(shared_info); |
436 inline_stack.push_back(inline_entry); | 257 inline_stack.push_back(inline_entry); |
437 } | 258 } |
438 if (!inline_stack.empty()) { | 259 if (!inline_stack.empty()) { |
439 entry->AddInlineStack(pc_offset, inline_stack); | 260 entry->AddInlineStack(pc_offset, inline_stack); |
440 DCHECK(inline_stack.empty()); | 261 DCHECK(inline_stack.empty()); |
441 } | 262 } |
442 } | 263 } |
443 } | 264 } |
444 | 265 |
445 void CpuProfiler::RecordDeoptInlinedFrames(CodeEntry* entry, | 266 void ProfilerListener::RecordDeoptInlinedFrames(CodeEntry* entry, |
446 AbstractCode* abstract_code) { | 267 AbstractCode* abstract_code) { |
447 if (abstract_code->kind() != AbstractCode::OPTIMIZED_FUNCTION) return; | 268 if (abstract_code->kind() != AbstractCode::OPTIMIZED_FUNCTION) return; |
448 Code* code = abstract_code->GetCode(); | 269 Code* code = abstract_code->GetCode(); |
449 DeoptimizationInputData* deopt_input_data = | 270 DeoptimizationInputData* deopt_input_data = |
450 DeoptimizationInputData::cast(code->deoptimization_data()); | 271 DeoptimizationInputData::cast(code->deoptimization_data()); |
451 int const mask = RelocInfo::ModeMask(RelocInfo::DEOPT_ID); | 272 int const mask = RelocInfo::ModeMask(RelocInfo::DEOPT_ID); |
452 for (RelocIterator rit(code, mask); !rit.done(); rit.next()) { | 273 for (RelocIterator rit(code, mask); !rit.done(); rit.next()) { |
453 RelocInfo* reloc_info = rit.rinfo(); | 274 RelocInfo* reloc_info = rit.rinfo(); |
454 DCHECK(RelocInfo::IsDeoptId(reloc_info->rmode())); | 275 DCHECK(RelocInfo::IsDeoptId(reloc_info->rmode())); |
455 int deopt_id = static_cast<int>(reloc_info->data()); | 276 int deopt_id = static_cast<int>(reloc_info->data()); |
456 int translation_index = | 277 int translation_index = |
(...skipping 26 matching lines...) Expand all Loading... |
483 CodeEntry::DeoptInlinedFrame frame = {source_position, script_id}; | 304 CodeEntry::DeoptInlinedFrame frame = {source_position, script_id}; |
484 inlined_frames.push_back(frame); | 305 inlined_frames.push_back(frame); |
485 } | 306 } |
486 if (!inlined_frames.empty() && !entry->HasDeoptInlinedFramesFor(deopt_id)) { | 307 if (!inlined_frames.empty() && !entry->HasDeoptInlinedFramesFor(deopt_id)) { |
487 entry->AddDeoptInlinedFrames(deopt_id, inlined_frames); | 308 entry->AddDeoptInlinedFrames(deopt_id, inlined_frames); |
488 DCHECK(inlined_frames.empty()); | 309 DCHECK(inlined_frames.empty()); |
489 } | 310 } |
490 } | 311 } |
491 } | 312 } |
492 | 313 |
493 CpuProfiler::CpuProfiler(Isolate* isolate) | 314 CodeEntry* ProfilerListener::NewCodeEntry( |
494 : isolate_(isolate), | 315 CodeEventListener::LogEventsAndTags tag, const char* name, |
495 sampling_interval_(base::TimeDelta::FromMicroseconds( | 316 const char* name_prefix, const char* resource_name, int line_number, |
496 FLAG_cpu_profiler_sampling_interval)), | 317 int column_number, JITLineInfoTable* line_info, Address instruction_start) { |
497 profiles_(new CpuProfilesCollection(isolate)), | 318 CodeEntry* code_entry = |
498 is_profiling_(false) { | 319 new CodeEntry(tag, name, name_prefix, resource_name, line_number, |
499 profiles_->set_cpu_profiler(this); | 320 column_number, line_info, instruction_start); |
| 321 code_entries_.push_back(code_entry); |
| 322 return code_entry; |
500 } | 323 } |
501 | 324 |
502 CpuProfiler::CpuProfiler(Isolate* isolate, CpuProfilesCollection* test_profiles, | 325 void ProfilerListener::AddObserver(CodeEventObserver* observer) { |
503 ProfileGenerator* test_generator, | 326 if (std::find(observers_.begin(), observers_.end(), observer) != |
504 ProfilerEventsProcessor* test_processor) | 327 observers_.end()) |
505 : isolate_(isolate), | 328 return; |
506 sampling_interval_(base::TimeDelta::FromMicroseconds( | 329 observers_.push_back(observer); |
507 FLAG_cpu_profiler_sampling_interval)), | |
508 profiles_(test_profiles), | |
509 generator_(test_generator), | |
510 processor_(test_processor), | |
511 is_profiling_(false) { | |
512 profiles_->set_cpu_profiler(this); | |
513 } | 330 } |
514 | 331 |
515 CpuProfiler::~CpuProfiler() { | 332 void ProfilerListener::RemoveObserver(CodeEventObserver* observer) { |
516 DCHECK(!is_profiling_); | 333 auto it = std::find(observers_.begin(), observers_.end(), observer); |
| 334 if (it == observers_.end()) return; |
| 335 observers_.erase(it); |
517 } | 336 } |
518 | 337 |
519 void CpuProfiler::set_sampling_interval(base::TimeDelta value) { | |
520 DCHECK(!is_profiling_); | |
521 sampling_interval_ = value; | |
522 } | |
523 | |
524 void CpuProfiler::ResetProfiles() { | |
525 profiles_.reset(new CpuProfilesCollection(isolate_)); | |
526 profiles_->set_cpu_profiler(this); | |
527 } | |
528 | |
529 void CpuProfiler::CollectSample() { | |
530 if (processor_) { | |
531 processor_->AddCurrentStack(isolate_); | |
532 } | |
533 } | |
534 | |
535 void CpuProfiler::StartProfiling(const char* title, bool record_samples) { | |
536 if (profiles_->StartProfiling(title, record_samples)) { | |
537 StartProcessorIfNotStarted(); | |
538 } | |
539 } | |
540 | |
541 | |
542 void CpuProfiler::StartProfiling(String* title, bool record_samples) { | |
543 StartProfiling(profiles_->GetName(title), record_samples); | |
544 isolate_->debug()->feature_tracker()->Track(DebugFeatureTracker::kProfiler); | |
545 } | |
546 | |
547 | |
548 void CpuProfiler::StartProcessorIfNotStarted() { | |
549 if (processor_) { | |
550 processor_->AddCurrentStack(isolate_); | |
551 return; | |
552 } | |
553 Logger* logger = isolate_->logger(); | |
554 // Disable logging when using the new implementation. | |
555 saved_is_logging_ = logger->is_logging_; | |
556 logger->is_logging_ = false; | |
557 sampler::Sampler* sampler = logger->sampler(); | |
558 generator_.reset(new ProfileGenerator(profiles_.get())); | |
559 processor_.reset(new ProfilerEventsProcessor(generator_.get(), sampler, | |
560 sampling_interval_)); | |
561 is_profiling_ = true; | |
562 isolate_->set_is_profiling(true); | |
563 // Enumerate stuff we already have in the heap. | |
564 DCHECK(isolate_->heap()->HasBeenSetUp()); | |
565 isolate_->code_event_dispatcher()->AddListener(this); | |
566 if (!FLAG_prof_browser_mode) { | |
567 logger->LogCodeObjects(); | |
568 } | |
569 logger->LogCompiledFunctions(); | |
570 logger->LogAccessorCallbacks(); | |
571 LogBuiltins(); | |
572 // Enable stack sampling. | |
573 sampler->SetHasProcessingThread(true); | |
574 sampler->IncreaseProfilingDepth(); | |
575 processor_->AddCurrentStack(isolate_); | |
576 processor_->StartSynchronously(); | |
577 } | |
578 | |
579 | |
580 CpuProfile* CpuProfiler::StopProfiling(const char* title) { | |
581 if (!is_profiling_) return nullptr; | |
582 StopProcessorIfLastProfile(title); | |
583 CpuProfile* result = profiles_->StopProfiling(title); | |
584 if (result) { | |
585 result->Print(); | |
586 } | |
587 return result; | |
588 } | |
589 | |
590 | |
591 CpuProfile* CpuProfiler::StopProfiling(String* title) { | |
592 if (!is_profiling_) return nullptr; | |
593 const char* profile_title = profiles_->GetName(title); | |
594 StopProcessorIfLastProfile(profile_title); | |
595 return profiles_->StopProfiling(profile_title); | |
596 } | |
597 | |
598 | |
599 void CpuProfiler::StopProcessorIfLastProfile(const char* title) { | |
600 if (profiles_->IsLastProfile(title)) { | |
601 StopProcessor(); | |
602 } | |
603 } | |
604 | |
605 | |
606 void CpuProfiler::StopProcessor() { | |
607 Logger* logger = isolate_->logger(); | |
608 sampler::Sampler* sampler = | |
609 reinterpret_cast<sampler::Sampler*>(logger->ticker_); | |
610 is_profiling_ = false; | |
611 isolate_->set_is_profiling(false); | |
612 isolate_->code_event_dispatcher()->RemoveListener(this); | |
613 processor_->StopSynchronously(); | |
614 processor_.reset(); | |
615 generator_.reset(); | |
616 sampler->SetHasProcessingThread(false); | |
617 sampler->DecreaseProfilingDepth(); | |
618 logger->is_logging_ = saved_is_logging_; | |
619 } | |
620 | |
621 | |
622 void CpuProfiler::LogBuiltins() { | |
623 Builtins* builtins = isolate_->builtins(); | |
624 DCHECK(builtins->is_initialized()); | |
625 for (int i = 0; i < Builtins::builtin_count; i++) { | |
626 CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN); | |
627 ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_; | |
628 Builtins::Name id = static_cast<Builtins::Name>(i); | |
629 rec->start = builtins->builtin(id)->address(); | |
630 rec->builtin_id = id; | |
631 processor_->Enqueue(evt_rec); | |
632 } | |
633 } | |
634 | |
635 | |
636 } // namespace internal | 338 } // namespace internal |
637 } // namespace v8 | 339 } // namespace v8 |
OLD | NEW |