OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 |
11 // with the distribution. | 11 // with the distribution. |
12 // * Neither the name of Google Inc. nor the names of its | 12 // * Neither the name of Google Inc. nor the names of its |
13 // contributors may be used to endorse or promote products derived | 13 // contributors may be used to endorse or promote products derived |
14 // from this software without specific prior written permission. | 14 // from this software without specific prior written permission. |
15 // | 15 // |
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | 27 |
28 #ifdef ENABLE_CPP_PROFILES_PROCESSOR | |
29 | |
30 #include "v8.h" | 28 #include "v8.h" |
31 | 29 |
32 #include "cpu-profiler-inl.h" | 30 #include "cpu-profiler-inl.h" |
33 | 31 |
| 32 #ifdef ENABLE_CPP_PROFILES_PROCESSOR |
| 33 |
| 34 #include "log-inl.h" |
| 35 |
34 namespace v8 { | 36 namespace v8 { |
35 namespace internal { | 37 namespace internal { |
36 | 38 |
37 static const int kEventsBufferSize = 256*KB; | 39 static const int kEventsBufferSize = 256*KB; |
38 static const int kTickSamplesBufferChunkSize = 64*KB; | 40 static const int kTickSamplesBufferChunkSize = 64*KB; |
39 static const int kTickSamplesBufferChunksCount = 16; | 41 static const int kTickSamplesBufferChunksCount = 16; |
40 | 42 |
41 | 43 |
42 ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator) | 44 ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator) |
43 : generator_(generator), | 45 : generator_(generator), |
44 running_(false), | 46 running_(false), |
45 events_buffer_(kEventsBufferSize), | 47 events_buffer_(kEventsBufferSize), |
46 ticks_buffer_(sizeof(TickSampleEventRecord), | 48 ticks_buffer_(sizeof(TickSampleEventRecord), |
47 kTickSamplesBufferChunkSize, | 49 kTickSamplesBufferChunkSize, |
48 kTickSamplesBufferChunksCount), | 50 kTickSamplesBufferChunksCount), |
49 enqueue_order_(0) { } | 51 enqueue_order_(0) { } |
50 | 52 |
51 | 53 |
| 54 void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag, |
| 55 const char* prefix, |
| 56 String* name, |
| 57 Address start) { |
| 58 CodeEventsContainer evt_rec; |
| 59 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
| 60 rec->type = CodeEventRecord::CODE_CREATION; |
| 61 rec->order = ++enqueue_order_; |
| 62 rec->start = start; |
| 63 rec->entry = generator_->NewCodeEntry(tag, prefix, name); |
| 64 rec->size = 1; |
| 65 events_buffer_.Enqueue(evt_rec); |
| 66 } |
| 67 |
| 68 |
52 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag, | 69 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag, |
53 String* name, | 70 String* name, |
54 String* resource_name, | 71 String* resource_name, |
55 int line_number, | 72 int line_number, |
56 Address start, | 73 Address start, |
57 unsigned size) { | 74 unsigned size) { |
58 CodeEventsContainer evt_rec; | 75 CodeEventsContainer evt_rec; |
59 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; | 76 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_; |
60 rec->type = CodeEventRecord::CODE_CREATION; | 77 rec->type = CodeEventRecord::CODE_CREATION; |
61 rec->order = ++enqueue_order_; | 78 rec->order = ++enqueue_order_; |
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 } | 206 } |
190 YieldCPU(); | 207 YieldCPU(); |
191 } | 208 } |
192 | 209 |
193 // Process remaining tick events. | 210 // Process remaining tick events. |
194 ticks_buffer_.FlushResidualRecords(); | 211 ticks_buffer_.FlushResidualRecords(); |
195 // Perform processing until we have tick events, skip remaining code events. | 212 // Perform processing until we have tick events, skip remaining code events. |
196 while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { } | 213 while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { } |
197 } | 214 } |
198 | 215 |
| 216 |
| 217 CpuProfiler* CpuProfiler::singleton_ = NULL; |
| 218 |
| 219 void CpuProfiler::StartProfiling(const char* title) { |
| 220 ASSERT(singleton_ != NULL); |
| 221 singleton_->StartCollectingProfile(title); |
| 222 } |
| 223 |
| 224 |
| 225 void CpuProfiler::StartProfiling(String* title) { |
| 226 ASSERT(singleton_ != NULL); |
| 227 singleton_->StartCollectingProfile(title); |
| 228 } |
| 229 |
| 230 |
| 231 CpuProfile* CpuProfiler::StopProfiling(const char* title) { |
| 232 ASSERT(singleton_ != NULL); |
| 233 return singleton_->StopCollectingProfile(title); |
| 234 } |
| 235 |
| 236 |
| 237 CpuProfile* CpuProfiler::StopProfiling(String* title) { |
| 238 ASSERT(singleton_ != NULL); |
| 239 return singleton_->StopCollectingProfile(title); |
| 240 } |
| 241 |
| 242 |
| 243 int CpuProfiler::GetProfilesCount() { |
| 244 ASSERT(singleton_ != NULL); |
| 245 return singleton_->profiles_->profiles()->length(); |
| 246 } |
| 247 |
| 248 |
| 249 CpuProfile* CpuProfiler::GetProfile(int index) { |
| 250 ASSERT(singleton_ != NULL); |
| 251 return singleton_->profiles_->profiles()->at(index); |
| 252 } |
| 253 |
| 254 |
| 255 CpuProfile* CpuProfiler::FindProfile(unsigned uid) { |
| 256 ASSERT(singleton_ != NULL); |
| 257 return singleton_->profiles_->GetProfile(uid); |
| 258 } |
| 259 |
| 260 |
| 261 TickSample* CpuProfiler::TickSampleEvent() { |
| 262 ASSERT(singleton_ != NULL); |
| 263 if (singleton_->is_profiling()) { |
| 264 return singleton_->processor_->TickSampleEvent(); |
| 265 } else { |
| 266 return NULL; |
| 267 } |
| 268 } |
| 269 |
| 270 |
| 271 void CpuProfiler::CallbackEvent(String* name, Address entry_point) { |
| 272 singleton_->processor_->CallbackCreateEvent( |
| 273 Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point); |
| 274 } |
| 275 |
| 276 |
| 277 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, |
| 278 Code* code, const char* comment) { |
| 279 singleton_->processor_->CodeCreateEvent( |
| 280 tag, comment, code->address(), code->ExecutableSize()); |
| 281 } |
| 282 |
| 283 |
| 284 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, |
| 285 Code* code, String* name) { |
| 286 singleton_->processor_->CodeCreateEvent( |
| 287 tag, |
| 288 name, |
| 289 Heap::empty_string(), |
| 290 CodeEntry::kNoLineNumberInfo, |
| 291 code->address(), |
| 292 code->ExecutableSize()); |
| 293 } |
| 294 |
| 295 |
| 296 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, |
| 297 Code* code, String* name, |
| 298 String* source, int line) { |
| 299 singleton_->processor_->CodeCreateEvent( |
| 300 tag, |
| 301 name, |
| 302 source, |
| 303 line, |
| 304 code->address(), |
| 305 code->ExecutableSize()); |
| 306 } |
| 307 |
| 308 |
| 309 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag, |
| 310 Code* code, int args_count) { |
| 311 singleton_->processor_->CodeCreateEvent( |
| 312 tag, |
| 313 args_count, |
| 314 code->address(), |
| 315 code->ExecutableSize()); |
| 316 } |
| 317 |
| 318 |
| 319 void CpuProfiler::CodeMoveEvent(Address from, Address to) { |
| 320 singleton_->processor_->CodeMoveEvent(from, to); |
| 321 } |
| 322 |
| 323 |
| 324 void CpuProfiler::CodeDeleteEvent(Address from) { |
| 325 singleton_->processor_->CodeDeleteEvent(from); |
| 326 } |
| 327 |
| 328 |
| 329 void CpuProfiler::FunctionCreateEvent(JSFunction* function) { |
| 330 singleton_->processor_->FunctionCreateEvent( |
| 331 function->address(), function->code()->address()); |
| 332 } |
| 333 |
| 334 |
| 335 void CpuProfiler::FunctionMoveEvent(Address from, Address to) { |
| 336 singleton_->processor_->FunctionMoveEvent(from, to); |
| 337 } |
| 338 |
| 339 |
| 340 void CpuProfiler::FunctionDeleteEvent(Address from) { |
| 341 singleton_->processor_->FunctionDeleteEvent(from); |
| 342 } |
| 343 |
| 344 |
| 345 void CpuProfiler::GetterCallbackEvent(String* name, Address entry_point) { |
| 346 singleton_->processor_->CallbackCreateEvent( |
| 347 Logger::CALLBACK_TAG, "get ", name, entry_point); |
| 348 } |
| 349 |
| 350 |
| 351 void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) { |
| 352 singleton_->processor_->CodeCreateEvent( |
| 353 Logger::REG_EXP_TAG, |
| 354 source, |
| 355 Heap::empty_string(), |
| 356 CodeEntry::kNoLineNumberInfo, |
| 357 code->address(), |
| 358 code->ExecutableSize()); |
| 359 } |
| 360 |
| 361 |
| 362 void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) { |
| 363 singleton_->processor_->CallbackCreateEvent( |
| 364 Logger::CALLBACK_TAG, "set ", name, entry_point); |
| 365 } |
| 366 |
| 367 |
| 368 CpuProfiler::CpuProfiler() |
| 369 : profiles_(new CpuProfilesCollection()), |
| 370 next_profile_uid_(1), |
| 371 generator_(NULL), |
| 372 processor_(NULL) { |
| 373 } |
| 374 |
| 375 |
| 376 CpuProfiler::~CpuProfiler() { |
| 377 delete profiles_; |
| 378 } |
| 379 |
| 380 |
| 381 void CpuProfiler::StartCollectingProfile(const char* title) { |
| 382 if (profiles_->StartProfiling(title, ++next_profile_uid_)) { |
| 383 StartProcessorIfNotStarted(); |
| 384 } |
| 385 } |
| 386 |
| 387 |
| 388 void CpuProfiler::StartCollectingProfile(String* title) { |
| 389 if (profiles_->StartProfiling(title, ++next_profile_uid_)) { |
| 390 StartProcessorIfNotStarted(); |
| 391 } |
| 392 } |
| 393 |
| 394 |
| 395 void CpuProfiler::StartProcessorIfNotStarted() { |
| 396 if (processor_ == NULL) { |
| 397 generator_ = new ProfileGenerator(profiles_); |
| 398 processor_ = new ProfilerEventsProcessor(generator_); |
| 399 processor_->Start(); |
| 400 // Enumerate stuff we already have in the heap. |
| 401 if (Heap::HasBeenSetup()) { |
| 402 Logger::LogCodeObjects(); |
| 403 Logger::LogCompiledFunctions(); |
| 404 Logger::LogFunctionObjects(); |
| 405 Logger::LogAccessorCallbacks(); |
| 406 } |
| 407 // Enable stack sampling. |
| 408 Logger::ticker_->Start(); |
| 409 } |
| 410 } |
| 411 |
| 412 |
| 413 CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) { |
| 414 StopProcessorIfLastProfile(); |
| 415 CpuProfile* result = profiles_->StopProfiling(title); |
| 416 if (result != NULL) { |
| 417 result->Print(); |
| 418 } |
| 419 return result; |
| 420 } |
| 421 |
| 422 |
| 423 CpuProfile* CpuProfiler::StopCollectingProfile(String* title) { |
| 424 StopProcessorIfLastProfile(); |
| 425 return profiles_->StopProfiling(title); |
| 426 } |
| 427 |
| 428 |
| 429 void CpuProfiler::StopProcessorIfLastProfile() { |
| 430 if (profiles_->is_last_profile()) { |
| 431 Logger::ticker_->Stop(); |
| 432 processor_->Stop(); |
| 433 processor_->Join(); |
| 434 delete processor_; |
| 435 delete generator_; |
| 436 processor_ = NULL; |
| 437 generator_ = NULL; |
| 438 } |
| 439 } |
| 440 |
199 } } // namespace v8::internal | 441 } } // namespace v8::internal |
200 | 442 |
201 #endif // ENABLE_CPP_PROFILES_PROCESSOR | 443 #endif // ENABLE_CPP_PROFILES_PROCESSOR |
| 444 |
| 445 namespace v8 { |
| 446 namespace internal { |
| 447 |
| 448 void CpuProfiler::Setup() { |
| 449 #ifdef ENABLE_CPP_PROFILES_PROCESSOR |
| 450 if (singleton_ == NULL) { |
| 451 singleton_ = new CpuProfiler(); |
| 452 } |
| 453 #endif |
| 454 } |
| 455 |
| 456 |
| 457 void CpuProfiler::TearDown() { |
| 458 #ifdef ENABLE_CPP_PROFILES_PROCESSOR |
| 459 if (singleton_ != NULL) { |
| 460 delete singleton_; |
| 461 } |
| 462 singleton_ = NULL; |
| 463 #endif |
| 464 } |
| 465 |
| 466 } } // namespace v8::internal |
OLD | NEW |