OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 27 matching lines...) Expand all Loading... |
38 #include "../include/v8-profiler.h" | 38 #include "../include/v8-profiler.h" |
39 | 39 |
40 namespace v8 { | 40 namespace v8 { |
41 namespace internal { | 41 namespace internal { |
42 | 42 |
43 static const int kTickSamplesBufferChunkSize = 64 * KB; | 43 static const int kTickSamplesBufferChunkSize = 64 * KB; |
44 static const int kTickSamplesBufferChunksCount = 16; | 44 static const int kTickSamplesBufferChunksCount = 16; |
45 static const int kProfilerStackSize = 64 * KB; | 45 static const int kProfilerStackSize = 64 * KB; |
46 | 46 |
47 | 47 |
48 ProfilerEventsProcessor::ProfilerEventsProcessor( | 48 ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator) |
49 ProfileGenerator* generator, CpuProfilesCollection* profiles) | |
50 : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)), | 49 : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)), |
51 generator_(generator), | 50 generator_(generator), |
52 profiles_(profiles), | |
53 running_(true), | 51 running_(true), |
54 ticks_buffer_(sizeof(TickSampleEventRecord), | 52 ticks_buffer_(sizeof(TickSampleEventRecord), |
55 kTickSamplesBufferChunkSize, | 53 kTickSamplesBufferChunkSize, |
56 kTickSamplesBufferChunksCount), | 54 kTickSamplesBufferChunksCount), |
57 enqueue_order_(0) { | 55 last_code_event_id_(0), last_processed_code_event_id_(0) { |
58 } | 56 } |
59 | 57 |
60 | 58 |
61 void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag, | 59 void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) { |
62 const char* prefix, | 60 event.generic.order = ++last_code_event_id_; |
63 Name* name, | 61 events_buffer_.Enqueue(event); |
64 Address start) { | |
65 if (FilterOutCodeCreateEvent(tag)) return; | |
66 CodeEventsContainer evt_rec; | |
67 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | |
68 rec->type = CodeEventRecord::CODE_CREATION; | |
69 rec->order = ++enqueue_order_; | |
70 rec->start = start; | |
71 rec->entry = profiles_->NewCodeEntry(tag, prefix, name); | |
72 rec->size = 1; | |
73 rec->shared = NULL; | |
74 events_buffer_.Enqueue(evt_rec); | |
75 } | 62 } |
76 | 63 |
77 | 64 |
78 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag, | 65 void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate) { |
79 Name* name, | 66 TickSampleEventRecord record(last_code_event_id_); |
80 String* resource_name, | |
81 int line_number, | |
82 Address start, | |
83 unsigned size, | |
84 Address shared, | |
85 CompilationInfo* info) { | |
86 if (FilterOutCodeCreateEvent(tag)) return; | |
87 CodeEventsContainer evt_rec; | |
88 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | |
89 rec->type = CodeEventRecord::CODE_CREATION; | |
90 rec->order = ++enqueue_order_; | |
91 rec->start = start; | |
92 rec->entry = profiles_->NewCodeEntry(tag, name, resource_name, line_number); | |
93 if (info) { | |
94 rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges()); | |
95 } | |
96 rec->size = size; | |
97 rec->shared = shared; | |
98 events_buffer_.Enqueue(evt_rec); | |
99 } | |
100 | |
101 | |
102 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag, | |
103 const char* name, | |
104 Address start, | |
105 unsigned size) { | |
106 if (FilterOutCodeCreateEvent(tag)) return; | |
107 CodeEventsContainer evt_rec; | |
108 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | |
109 rec->type = CodeEventRecord::CODE_CREATION; | |
110 rec->order = ++enqueue_order_; | |
111 rec->start = start; | |
112 rec->entry = profiles_->NewCodeEntry(tag, name); | |
113 rec->size = size; | |
114 rec->shared = NULL; | |
115 events_buffer_.Enqueue(evt_rec); | |
116 } | |
117 | |
118 | |
119 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag, | |
120 int args_count, | |
121 Address start, | |
122 unsigned size) { | |
123 if (FilterOutCodeCreateEvent(tag)) return; | |
124 CodeEventsContainer evt_rec; | |
125 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | |
126 rec->type = CodeEventRecord::CODE_CREATION; | |
127 rec->order = ++enqueue_order_; | |
128 rec->start = start; | |
129 rec->entry = profiles_->NewCodeEntry(tag, args_count); | |
130 rec->size = size; | |
131 rec->shared = NULL; | |
132 events_buffer_.Enqueue(evt_rec); | |
133 } | |
134 | |
135 | |
136 void ProfilerEventsProcessor::CodeMoveEvent(Address from, Address to) { | |
137 CodeEventsContainer evt_rec; | |
138 CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_; | |
139 rec->type = CodeEventRecord::CODE_MOVE; | |
140 rec->order = ++enqueue_order_; | |
141 rec->from = from; | |
142 rec->to = to; | |
143 events_buffer_.Enqueue(evt_rec); | |
144 } | |
145 | |
146 | |
147 void ProfilerEventsProcessor::SharedFunctionInfoMoveEvent(Address from, | |
148 Address to) { | |
149 CodeEventsContainer evt_rec; | |
150 SharedFunctionInfoMoveEventRecord* rec = | |
151 &evt_rec.SharedFunctionInfoMoveEventRecord_; | |
152 rec->type = CodeEventRecord::SHARED_FUNC_MOVE; | |
153 rec->order = ++enqueue_order_; | |
154 rec->from = from; | |
155 rec->to = to; | |
156 events_buffer_.Enqueue(evt_rec); | |
157 } | |
158 | |
159 | |
160 void ProfilerEventsProcessor::RegExpCodeCreateEvent( | |
161 Logger::LogEventsAndTags tag, | |
162 const char* prefix, | |
163 String* name, | |
164 Address start, | |
165 unsigned size) { | |
166 if (FilterOutCodeCreateEvent(tag)) return; | |
167 CodeEventsContainer evt_rec; | |
168 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | |
169 rec->type = CodeEventRecord::CODE_CREATION; | |
170 rec->order = ++enqueue_order_; | |
171 rec->start = start; | |
172 rec->entry = profiles_->NewCodeEntry(tag, prefix, name); | |
173 rec->size = size; | |
174 events_buffer_.Enqueue(evt_rec); | |
175 } | |
176 | |
177 | |
178 void ProfilerEventsProcessor::AddCurrentStack() { | |
179 TickSampleEventRecord record(enqueue_order_); | |
180 TickSample* sample = &record.sample; | 67 TickSample* sample = &record.sample; |
181 Isolate* isolate = Isolate::Current(); | |
182 sample->state = isolate->current_vm_state(); | 68 sample->state = isolate->current_vm_state(); |
183 sample->pc = reinterpret_cast<Address>(sample); // Not NULL. | 69 sample->pc = reinterpret_cast<Address>(sample); // Not NULL. |
184 for (StackTraceFrameIterator it(isolate); | 70 for (StackTraceFrameIterator it(isolate); |
185 !it.done() && sample->frames_count < TickSample::kMaxFramesCount; | 71 !it.done() && sample->frames_count < TickSample::kMaxFramesCount; |
186 it.Advance()) { | 72 it.Advance()) { |
187 sample->stack[sample->frames_count++] = it.frame()->pc(); | 73 sample->stack[sample->frames_count++] = it.frame()->pc(); |
188 } | 74 } |
189 ticks_from_vm_buffer_.Enqueue(record); | 75 ticks_from_vm_buffer_.Enqueue(record); |
190 } | 76 } |
191 | 77 |
192 | 78 |
193 bool ProfilerEventsProcessor::ProcessCodeEvent(unsigned* dequeue_order) { | 79 void ProfilerEventsProcessor::StopSynchronously() { |
| 80 if (!running_) return; |
| 81 running_ = false; |
| 82 Join(); |
| 83 } |
| 84 |
| 85 |
| 86 bool ProfilerEventsProcessor::ProcessCodeEvent() { |
194 CodeEventsContainer record; | 87 CodeEventsContainer record; |
195 if (events_buffer_.Dequeue(&record)) { | 88 if (events_buffer_.Dequeue(&record)) { |
196 switch (record.generic.type) { | 89 switch (record.generic.type) { |
197 #define PROFILER_TYPE_CASE(type, clss) \ | 90 #define PROFILER_TYPE_CASE(type, clss) \ |
198 case CodeEventRecord::type: \ | 91 case CodeEventRecord::type: \ |
199 record.clss##_.UpdateCodeMap(generator_->code_map()); \ | 92 record.clss##_.UpdateCodeMap(generator_->code_map()); \ |
200 break; | 93 break; |
201 | 94 |
202 CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE) | 95 CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE) |
203 | 96 |
204 #undef PROFILER_TYPE_CASE | 97 #undef PROFILER_TYPE_CASE |
205 default: return true; // Skip record. | 98 default: return true; // Skip record. |
206 } | 99 } |
207 *dequeue_order = record.generic.order; | 100 last_processed_code_event_id_ = record.generic.order; |
208 return true; | 101 return true; |
209 } | 102 } |
210 return false; | 103 return false; |
211 } | 104 } |
212 | 105 |
213 | 106 |
214 bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) { | 107 bool ProfilerEventsProcessor::ProcessTicks() { |
215 while (true) { | 108 while (true) { |
216 if (!ticks_from_vm_buffer_.IsEmpty() | 109 if (!ticks_from_vm_buffer_.IsEmpty() |
217 && ticks_from_vm_buffer_.Peek()->order == dequeue_order) { | 110 && ticks_from_vm_buffer_.Peek()->order == |
| 111 last_processed_code_event_id_) { |
218 TickSampleEventRecord record; | 112 TickSampleEventRecord record; |
219 ticks_from_vm_buffer_.Dequeue(&record); | 113 ticks_from_vm_buffer_.Dequeue(&record); |
220 generator_->RecordTickSample(record.sample); | 114 generator_->RecordTickSample(record.sample); |
221 } | 115 } |
222 | 116 |
223 const TickSampleEventRecord* rec = | 117 const TickSampleEventRecord* rec = |
224 TickSampleEventRecord::cast(ticks_buffer_.StartDequeue()); | 118 TickSampleEventRecord::cast(ticks_buffer_.StartDequeue()); |
225 if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty(); | 119 if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty(); |
226 // Make a local copy of tick sample record to ensure that it won't | 120 // Make a local copy of tick sample record to ensure that it won't |
227 // be modified as we are processing it. This is possible as the | 121 // be modified as we are processing it. This is possible as the |
228 // sampler writes w/o any sync to the queue, so if the processor | 122 // sampler writes w/o any sync to the queue, so if the processor |
229 // will get far behind, a record may be modified right under its | 123 // will get far behind, a record may be modified right under its |
230 // feet. | 124 // feet. |
231 TickSampleEventRecord record = *rec; | 125 TickSampleEventRecord record = *rec; |
232 if (record.order == dequeue_order) { | 126 if (record.order != last_processed_code_event_id_) return true; |
233 // A paranoid check to make sure that we don't get a memory overrun | 127 |
234 // in case of frames_count having a wild value. | 128 // A paranoid check to make sure that we don't get a memory overrun |
235 if (record.sample.frames_count < 0 | 129 // in case of frames_count having a wild value. |
236 || record.sample.frames_count > TickSample::kMaxFramesCount) | 130 if (record.sample.frames_count < 0 |
237 record.sample.frames_count = 0; | 131 || record.sample.frames_count > TickSample::kMaxFramesCount) |
238 generator_->RecordTickSample(record.sample); | 132 record.sample.frames_count = 0; |
239 ticks_buffer_.FinishDequeue(); | 133 generator_->RecordTickSample(record.sample); |
240 } else { | 134 ticks_buffer_.FinishDequeue(); |
241 return true; | |
242 } | |
243 } | 135 } |
244 } | 136 } |
245 | 137 |
246 | 138 |
247 void ProfilerEventsProcessor::Run() { | 139 void ProfilerEventsProcessor::Run() { |
248 unsigned dequeue_order = 0; | |
249 | |
250 while (running_) { | 140 while (running_) { |
251 // Process ticks until we have any. | 141 // Process ticks until we have any. |
252 if (ProcessTicks(dequeue_order)) { | 142 if (ProcessTicks()) { |
253 // All ticks of the current dequeue_order are processed, | 143 // All ticks of the current last_processed_code_event_id_ are processed, |
254 // proceed to the next code event. | 144 // proceed to the next code event. |
255 ProcessCodeEvent(&dequeue_order); | 145 ProcessCodeEvent(); |
256 } | 146 } |
257 YieldCPU(); | 147 YieldCPU(); |
258 } | 148 } |
259 | 149 |
260 // Process remaining tick events. | 150 // Process remaining tick events. |
261 ticks_buffer_.FlushResidualRecords(); | 151 ticks_buffer_.FlushResidualRecords(); |
262 // Perform processing until we have tick events, skip remaining code events. | 152 do { |
263 while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { } | 153 ProcessTicks(); |
| 154 } while (ProcessCodeEvent()); |
264 } | 155 } |
265 | 156 |
266 | 157 |
267 int CpuProfiler::GetProfilesCount() { | 158 int CpuProfiler::GetProfilesCount() { |
268 // The count of profiles doesn't depend on a security token. | 159 // The count of profiles doesn't depend on a security token. |
269 return profiles_->Profiles(TokenEnumerator::kNoSecurityToken)->length(); | 160 return profiles_->profiles()->length(); |
270 } | 161 } |
271 | 162 |
272 | 163 |
273 CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) { | 164 CpuProfile* CpuProfiler::GetProfile(int index) { |
274 const int token = token_enumerator_->GetTokenId(security_token); | 165 return profiles_->profiles()->at(index); |
275 return profiles_->Profiles(token)->at(index); | |
276 } | 166 } |
277 | 167 |
278 | 168 |
279 CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid) { | |
280 const int token = token_enumerator_->GetTokenId(security_token); | |
281 return profiles_->GetProfile(token, uid); | |
282 } | |
283 | |
284 | |
285 TickSample* CpuProfiler::TickSampleEvent() { | 169 TickSample* CpuProfiler::TickSampleEvent() { |
286 if (is_profiling_) return processor_->TickSampleEvent(); | 170 if (is_profiling_) return processor_->TickSampleEvent(); |
287 return NULL; | 171 return NULL; |
288 } | 172 } |
289 | 173 |
290 | 174 |
291 void CpuProfiler::DeleteAllProfiles() { | 175 void CpuProfiler::DeleteAllProfiles() { |
292 if (is_profiling_) StopProcessor(); | 176 if (is_profiling_) StopProcessor(); |
293 ResetProfiles(); | 177 ResetProfiles(); |
294 } | 178 } |
295 | 179 |
296 | 180 |
297 void CpuProfiler::DeleteProfile(CpuProfile* profile) { | 181 void CpuProfiler::DeleteProfile(CpuProfile* profile) { |
298 profiles_->RemoveProfile(profile); | 182 profiles_->RemoveProfile(profile); |
299 delete profile; | 183 delete profile; |
300 } | 184 } |
301 | 185 |
302 | 186 |
303 bool CpuProfiler::HasDetachedProfiles() { | 187 static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag) { |
304 return profiles_->HasDetachedProfiles(); | 188 return FLAG_prof_browser_mode |
| 189 && (tag != Logger::CALLBACK_TAG |
| 190 && tag != Logger::FUNCTION_TAG |
| 191 && tag != Logger::LAZY_COMPILE_TAG |
| 192 && tag != Logger::REG_EXP_TAG |
| 193 && tag != Logger::SCRIPT_TAG); |
305 } | 194 } |
306 | 195 |
307 | 196 |
308 void CpuProfiler::CallbackEvent(Name* name, Address entry_point) { | 197 void CpuProfiler::CallbackEvent(Name* name, Address entry_point) { |
309 processor_->CallbackCreateEvent( | 198 if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return; |
310 Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point); | 199 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
| 200 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
| 201 rec->start = entry_point; |
| 202 rec->entry = profiles_->NewCodeEntry( |
| 203 Logger::CALLBACK_TAG, |
| 204 profiles_->GetName(name)); |
| 205 rec->size = 1; |
| 206 rec->shared = NULL; |
| 207 processor_->Enqueue(evt_rec); |
311 } | 208 } |
312 | 209 |
313 | 210 |
314 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, | 211 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, |
315 Code* code, const char* comment) { | 212 Code* code, |
316 processor_->CodeCreateEvent( | 213 const char* name) { |
317 tag, comment, code->address(), code->ExecutableSize()); | 214 if (FilterOutCodeCreateEvent(tag)) return; |
| 215 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
| 216 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
| 217 rec->start = code->address(); |
| 218 rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name)); |
| 219 rec->size = code->ExecutableSize(); |
| 220 rec->shared = NULL; |
| 221 processor_->Enqueue(evt_rec); |
318 } | 222 } |
319 | 223 |
320 | 224 |
321 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, | 225 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, |
322 Code* code, Name* name) { | 226 Code* code, |
323 processor_->CodeCreateEvent( | 227 Name* name) { |
324 tag, | 228 if (FilterOutCodeCreateEvent(tag)) return; |
325 name, | 229 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
326 isolate_->heap()->empty_string(), | 230 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
327 v8::CpuProfileNode::kNoLineNumberInfo, | 231 rec->start = code->address(); |
328 code->address(), | 232 rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name)); |
329 code->ExecutableSize(), | 233 rec->size = code->ExecutableSize(); |
330 NULL, | 234 rec->shared = NULL; |
331 NULL); | 235 processor_->Enqueue(evt_rec); |
332 } | 236 } |
333 | 237 |
334 | 238 |
335 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, | 239 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, |
336 Code* code, | 240 Code* code, |
337 SharedFunctionInfo* shared, | 241 SharedFunctionInfo* shared, |
338 CompilationInfo* info, | 242 CompilationInfo* info, |
339 Name* name) { | 243 Name* name) { |
340 processor_->CodeCreateEvent( | 244 if (FilterOutCodeCreateEvent(tag)) return; |
341 tag, | 245 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
342 name, | 246 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
343 isolate_->heap()->empty_string(), | 247 rec->start = code->address(); |
344 v8::CpuProfileNode::kNoLineNumberInfo, | 248 rec->entry = profiles_->NewCodeEntry(tag, profiles_->GetFunctionName(name)); |
345 code->address(), | 249 if (info) { |
346 code->ExecutableSize(), | 250 rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges()); |
347 shared->address(), | 251 } |
348 info); | 252 if (shared->script()->IsScript()) { |
| 253 ASSERT(Script::cast(shared->script())); |
| 254 Script* script = Script::cast(shared->script()); |
| 255 rec->entry->set_script_id(script->id()->value()); |
| 256 } |
| 257 rec->size = code->ExecutableSize(); |
| 258 rec->shared = shared->address(); |
| 259 processor_->Enqueue(evt_rec); |
349 } | 260 } |
350 | 261 |
351 | 262 |
352 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, | 263 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, |
353 Code* code, | 264 Code* code, |
354 SharedFunctionInfo* shared, | 265 SharedFunctionInfo* shared, |
355 CompilationInfo* info, | 266 CompilationInfo* info, |
356 String* source, int line) { | 267 String* source, int line) { |
357 processor_->CodeCreateEvent( | 268 if (FilterOutCodeCreateEvent(tag)) return; |
| 269 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
| 270 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
| 271 rec->start = code->address(); |
| 272 rec->entry = profiles_->NewCodeEntry( |
358 tag, | 273 tag, |
359 shared->DebugName(), | 274 profiles_->GetFunctionName(shared->DebugName()), |
360 source, | 275 CodeEntry::kEmptyNamePrefix, |
361 line, | 276 profiles_->GetName(source), |
362 code->address(), | 277 line); |
363 code->ExecutableSize(), | 278 if (info) { |
364 shared->address(), | 279 rec->entry->set_no_frame_ranges(info->ReleaseNoFrameRanges()); |
365 info); | 280 } |
| 281 ASSERT(Script::cast(shared->script())); |
| 282 Script* script = Script::cast(shared->script()); |
| 283 rec->entry->set_script_id(script->id()->value()); |
| 284 rec->size = code->ExecutableSize(); |
| 285 rec->shared = shared->address(); |
| 286 processor_->Enqueue(evt_rec); |
366 } | 287 } |
367 | 288 |
368 | 289 |
369 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, | 290 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, |
370 Code* code, int args_count) { | 291 Code* code, |
371 processor_->CodeCreateEvent( | 292 int args_count) { |
| 293 if (FilterOutCodeCreateEvent(tag)) return; |
| 294 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
| 295 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
| 296 rec->start = code->address(); |
| 297 rec->entry = profiles_->NewCodeEntry( |
372 tag, | 298 tag, |
373 args_count, | 299 profiles_->GetName(args_count), |
374 code->address(), | 300 "args_count: "); |
375 code->ExecutableSize()); | 301 rec->size = code->ExecutableSize(); |
| 302 rec->shared = NULL; |
| 303 processor_->Enqueue(evt_rec); |
376 } | 304 } |
377 | 305 |
378 | 306 |
379 void CpuProfiler::CodeMoveEvent(Address from, Address to) { | 307 void CpuProfiler::CodeMoveEvent(Address from, Address to) { |
380 processor_->CodeMoveEvent(from, to); | 308 CodeEventsContainer evt_rec(CodeEventRecord::CODE_MOVE); |
| 309 CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_; |
| 310 rec->from = from; |
| 311 rec->to = to; |
| 312 processor_->Enqueue(evt_rec); |
381 } | 313 } |
382 | 314 |
383 | 315 |
384 void CpuProfiler::CodeDeleteEvent(Address from) { | 316 void CpuProfiler::CodeDeleteEvent(Address from) { |
385 } | 317 } |
386 | 318 |
387 | 319 |
388 void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) { | 320 void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) { |
389 processor_->SharedFunctionInfoMoveEvent(from, to); | 321 CodeEventsContainer evt_rec(CodeEventRecord::SHARED_FUNC_MOVE); |
| 322 SharedFunctionInfoMoveEventRecord* rec = |
| 323 &evt_rec.SharedFunctionInfoMoveEventRecord_; |
| 324 rec->from = from; |
| 325 rec->to = to; |
| 326 processor_->Enqueue(evt_rec); |
390 } | 327 } |
391 | 328 |
392 | 329 |
393 void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) { | 330 void CpuProfiler::GetterCallbackEvent(Name* name, Address entry_point) { |
394 processor_->CallbackCreateEvent( | 331 if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return; |
395 Logger::CALLBACK_TAG, "get ", name, entry_point); | 332 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
| 333 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
| 334 rec->start = entry_point; |
| 335 rec->entry = profiles_->NewCodeEntry( |
| 336 Logger::CALLBACK_TAG, |
| 337 profiles_->GetName(name), |
| 338 "get "); |
| 339 rec->size = 1; |
| 340 rec->shared = NULL; |
| 341 processor_->Enqueue(evt_rec); |
396 } | 342 } |
397 | 343 |
398 | 344 |
399 void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) { | 345 void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) { |
400 processor_->RegExpCodeCreateEvent( | 346 if (FilterOutCodeCreateEvent(Logger::REG_EXP_TAG)) return; |
| 347 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
| 348 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
| 349 rec->start = code->address(); |
| 350 rec->entry = profiles_->NewCodeEntry( |
401 Logger::REG_EXP_TAG, | 351 Logger::REG_EXP_TAG, |
402 "RegExp: ", | 352 profiles_->GetName(source), |
403 source, | 353 "RegExp: "); |
404 code->address(), | 354 rec->size = code->ExecutableSize(); |
405 code->ExecutableSize()); | 355 processor_->Enqueue(evt_rec); |
406 } | 356 } |
407 | 357 |
408 | 358 |
409 void CpuProfiler::SetterCallbackEvent(Name* name, Address entry_point) { | 359 void CpuProfiler::SetterCallbackEvent(Name* name, Address entry_point) { |
410 processor_->CallbackCreateEvent( | 360 if (FilterOutCodeCreateEvent(Logger::CALLBACK_TAG)) return; |
411 Logger::CALLBACK_TAG, "set ", name, entry_point); | 361 CodeEventsContainer evt_rec(CodeEventRecord::CODE_CREATION); |
| 362 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
| 363 rec->start = entry_point; |
| 364 rec->entry = profiles_->NewCodeEntry( |
| 365 Logger::CALLBACK_TAG, |
| 366 profiles_->GetName(name), |
| 367 "set "); |
| 368 rec->size = 1; |
| 369 rec->shared = NULL; |
| 370 processor_->Enqueue(evt_rec); |
412 } | 371 } |
413 | 372 |
414 | 373 |
415 CpuProfiler::CpuProfiler(Isolate* isolate) | 374 CpuProfiler::CpuProfiler(Isolate* isolate) |
416 : isolate_(isolate), | 375 : isolate_(isolate), |
417 profiles_(new CpuProfilesCollection()), | 376 profiles_(new CpuProfilesCollection()), |
418 next_profile_uid_(1), | 377 next_profile_uid_(1), |
419 token_enumerator_(new TokenEnumerator()), | |
420 generator_(NULL), | 378 generator_(NULL), |
421 processor_(NULL), | 379 processor_(NULL), |
422 need_to_stop_sampler_(false), | 380 need_to_stop_sampler_(false), |
423 is_profiling_(false) { | 381 is_profiling_(false) { |
424 } | 382 } |
425 | 383 |
426 | 384 |
| 385 CpuProfiler::CpuProfiler(Isolate* isolate, |
| 386 CpuProfilesCollection* test_profiles, |
| 387 ProfileGenerator* test_generator, |
| 388 ProfilerEventsProcessor* test_processor) |
| 389 : isolate_(isolate), |
| 390 profiles_(test_profiles), |
| 391 next_profile_uid_(1), |
| 392 generator_(test_generator), |
| 393 processor_(test_processor), |
| 394 need_to_stop_sampler_(false), |
| 395 is_profiling_(false) { |
| 396 } |
| 397 |
| 398 |
427 CpuProfiler::~CpuProfiler() { | 399 CpuProfiler::~CpuProfiler() { |
428 delete token_enumerator_; | 400 ASSERT(!is_profiling_); |
429 delete profiles_; | 401 delete profiles_; |
430 } | 402 } |
431 | 403 |
432 | 404 |
433 void CpuProfiler::ResetProfiles() { | 405 void CpuProfiler::ResetProfiles() { |
434 delete profiles_; | 406 delete profiles_; |
435 profiles_ = new CpuProfilesCollection(); | 407 profiles_ = new CpuProfilesCollection(); |
436 } | 408 } |
437 | 409 |
| 410 |
438 void CpuProfiler::StartProfiling(const char* title, bool record_samples) { | 411 void CpuProfiler::StartProfiling(const char* title, bool record_samples) { |
439 if (profiles_->StartProfiling(title, next_profile_uid_++, record_samples)) { | 412 if (profiles_->StartProfiling(title, next_profile_uid_++, record_samples)) { |
440 StartProcessorIfNotStarted(); | 413 StartProcessorIfNotStarted(); |
441 } | 414 } |
442 processor_->AddCurrentStack(); | 415 processor_->AddCurrentStack(isolate_); |
443 } | 416 } |
444 | 417 |
445 | 418 |
446 void CpuProfiler::StartProfiling(String* title, bool record_samples) { | 419 void CpuProfiler::StartProfiling(String* title, bool record_samples) { |
447 StartProfiling(profiles_->GetName(title), record_samples); | 420 StartProfiling(profiles_->GetName(title), record_samples); |
448 } | 421 } |
449 | 422 |
450 | 423 |
451 void CpuProfiler::StartProcessorIfNotStarted() { | 424 void CpuProfiler::StartProcessorIfNotStarted() { |
452 if (processor_ == NULL) { | 425 if (processor_ == NULL) { |
| 426 Logger* logger = isolate_->logger(); |
453 // Disable logging when using the new implementation. | 427 // Disable logging when using the new implementation. |
454 saved_logging_nesting_ = isolate_->logger()->logging_nesting_; | 428 saved_logging_nesting_ = logger->logging_nesting_; |
455 isolate_->logger()->logging_nesting_ = 0; | 429 logger->logging_nesting_ = 0; |
456 generator_ = new ProfileGenerator(profiles_); | 430 generator_ = new ProfileGenerator(profiles_); |
457 processor_ = new ProfilerEventsProcessor(generator_, profiles_); | 431 processor_ = new ProfilerEventsProcessor(generator_); |
458 is_profiling_ = true; | 432 is_profiling_ = true; |
459 processor_->StartSynchronously(); | 433 processor_->StartSynchronously(); |
460 // Enumerate stuff we already have in the heap. | 434 // Enumerate stuff we already have in the heap. |
461 if (isolate_->heap()->HasBeenSetUp()) { | 435 ASSERT(isolate_->heap()->HasBeenSetUp()); |
462 if (!FLAG_prof_browser_mode) { | 436 if (!FLAG_prof_browser_mode) { |
463 isolate_->logger()->LogCodeObjects(); | 437 logger->LogCodeObjects(); |
464 } | |
465 isolate_->logger()->LogCompiledFunctions(); | |
466 isolate_->logger()->LogAccessorCallbacks(); | |
467 } | 438 } |
| 439 logger->LogCompiledFunctions(); |
| 440 logger->LogAccessorCallbacks(); |
| 441 LogBuiltins(); |
468 // Enable stack sampling. | 442 // Enable stack sampling. |
469 Sampler* sampler = isolate_->logger()->sampler(); | 443 Sampler* sampler = logger->sampler(); |
470 sampler->IncreaseProfilingDepth(); | 444 sampler->IncreaseProfilingDepth(); |
471 if (!sampler->IsActive()) { | 445 if (!sampler->IsActive()) { |
472 sampler->Start(); | 446 sampler->Start(); |
473 need_to_stop_sampler_ = true; | 447 need_to_stop_sampler_ = true; |
474 } | 448 } |
475 } | 449 } |
476 } | 450 } |
477 | 451 |
478 | 452 |
479 CpuProfile* CpuProfiler::StopProfiling(const char* title) { | 453 CpuProfile* CpuProfiler::StopProfiling(const char* title) { |
480 if (!is_profiling_) return NULL; | 454 if (!is_profiling_) return NULL; |
481 const double actual_sampling_rate = generator_->actual_sampling_rate(); | 455 const double actual_sampling_rate = generator_->actual_sampling_rate(); |
482 StopProcessorIfLastProfile(title); | 456 StopProcessorIfLastProfile(title); |
483 CpuProfile* result = | 457 CpuProfile* result = profiles_->StopProfiling(title, actual_sampling_rate); |
484 profiles_->StopProfiling(TokenEnumerator::kNoSecurityToken, | |
485 title, | |
486 actual_sampling_rate); | |
487 if (result != NULL) { | 458 if (result != NULL) { |
488 result->Print(); | 459 result->Print(); |
489 } | 460 } |
490 return result; | 461 return result; |
491 } | 462 } |
492 | 463 |
493 | 464 |
494 CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) { | 465 CpuProfile* CpuProfiler::StopProfiling(String* title) { |
495 if (!is_profiling_) return NULL; | 466 if (!is_profiling_) return NULL; |
496 const double actual_sampling_rate = generator_->actual_sampling_rate(); | 467 const double actual_sampling_rate = generator_->actual_sampling_rate(); |
497 const char* profile_title = profiles_->GetName(title); | 468 const char* profile_title = profiles_->GetName(title); |
498 StopProcessorIfLastProfile(profile_title); | 469 StopProcessorIfLastProfile(profile_title); |
499 int token = token_enumerator_->GetTokenId(security_token); | 470 return profiles_->StopProfiling(profile_title, actual_sampling_rate); |
500 return profiles_->StopProfiling(token, profile_title, actual_sampling_rate); | |
501 } | 471 } |
502 | 472 |
503 | 473 |
504 void CpuProfiler::StopProcessorIfLastProfile(const char* title) { | 474 void CpuProfiler::StopProcessorIfLastProfile(const char* title) { |
505 if (profiles_->IsLastProfile(title)) StopProcessor(); | 475 if (profiles_->IsLastProfile(title)) StopProcessor(); |
506 } | 476 } |
507 | 477 |
508 | 478 |
509 void CpuProfiler::StopProcessor() { | 479 void CpuProfiler::StopProcessor() { |
510 Logger* logger = isolate_->logger(); | 480 Logger* logger = isolate_->logger(); |
511 Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_); | 481 Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_); |
512 sampler->DecreaseProfilingDepth(); | 482 sampler->DecreaseProfilingDepth(); |
513 if (need_to_stop_sampler_) { | 483 if (need_to_stop_sampler_) { |
514 sampler->Stop(); | 484 sampler->Stop(); |
515 need_to_stop_sampler_ = false; | 485 need_to_stop_sampler_ = false; |
516 } | 486 } |
517 is_profiling_ = false; | 487 is_profiling_ = false; |
518 processor_->Stop(); | 488 processor_->StopSynchronously(); |
519 processor_->Join(); | |
520 delete processor_; | 489 delete processor_; |
521 delete generator_; | 490 delete generator_; |
522 processor_ = NULL; | 491 processor_ = NULL; |
523 generator_ = NULL; | 492 generator_ = NULL; |
524 logger->logging_nesting_ = saved_logging_nesting_; | 493 logger->logging_nesting_ = saved_logging_nesting_; |
525 } | 494 } |
526 | 495 |
527 | 496 |
| 497 void CpuProfiler::LogBuiltins() { |
| 498 Builtins* builtins = isolate_->builtins(); |
| 499 ASSERT(builtins->is_initialized()); |
| 500 for (int i = 0; i < Builtins::builtin_count; i++) { |
| 501 CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN); |
| 502 ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_; |
| 503 Builtins::Name id = static_cast<Builtins::Name>(i); |
| 504 rec->start = builtins->builtin(id)->address(); |
| 505 rec->builtin_id = id; |
| 506 processor_->Enqueue(evt_rec); |
| 507 } |
| 508 } |
| 509 |
| 510 |
528 } } // namespace v8::internal | 511 } } // namespace v8::internal |
OLD | NEW |