| 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 |