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 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 static const int kProfilerStackSize = 64 * KB; | 45 static const int kProfilerStackSize = 64 * KB; |
46 | 46 |
47 | 47 |
48 ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator) | 48 ProfilerEventsProcessor::ProfilerEventsProcessor(ProfileGenerator* generator) |
49 : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)), | 49 : Thread(Thread::Options("v8:ProfEvntProc", kProfilerStackSize)), |
50 generator_(generator), | 50 generator_(generator), |
51 running_(true), | 51 running_(true), |
52 ticks_buffer_(sizeof(TickSampleEventRecord), | 52 ticks_buffer_(sizeof(TickSampleEventRecord), |
53 kTickSamplesBufferChunkSize, | 53 kTickSamplesBufferChunkSize, |
54 kTickSamplesBufferChunksCount), | 54 kTickSamplesBufferChunksCount), |
55 enqueue_order_(0) { | 55 last_code_event_id_(0), last_processed_code_event_id_(0) { |
56 } | 56 } |
57 | 57 |
58 | 58 |
59 void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) { | 59 void ProfilerEventsProcessor::Enqueue(const CodeEventsContainer& event) { |
60 event.generic.order = ++enqueue_order_; | 60 event.generic.order = ++last_code_event_id_; |
61 events_buffer_.Enqueue(event); | 61 events_buffer_.Enqueue(event); |
62 } | 62 } |
63 | 63 |
64 | 64 |
65 void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate) { | 65 void ProfilerEventsProcessor::AddCurrentStack(Isolate* isolate) { |
66 TickSampleEventRecord record(enqueue_order_); | 66 TickSampleEventRecord record(last_code_event_id_); |
67 TickSample* sample = &record.sample; | 67 TickSample* sample = &record.sample; |
68 sample->state = isolate->current_vm_state(); | 68 sample->state = isolate->current_vm_state(); |
69 sample->pc = reinterpret_cast<Address>(sample); // Not NULL. | 69 sample->pc = reinterpret_cast<Address>(sample); // Not NULL. |
70 for (StackTraceFrameIterator it(isolate); | 70 for (StackTraceFrameIterator it(isolate); |
71 !it.done() && sample->frames_count < TickSample::kMaxFramesCount; | 71 !it.done() && sample->frames_count < TickSample::kMaxFramesCount; |
72 it.Advance()) { | 72 it.Advance()) { |
73 sample->stack[sample->frames_count++] = it.frame()->pc(); | 73 sample->stack[sample->frames_count++] = it.frame()->pc(); |
74 } | 74 } |
75 ticks_from_vm_buffer_.Enqueue(record); | 75 ticks_from_vm_buffer_.Enqueue(record); |
76 } | 76 } |
77 | 77 |
78 | 78 |
79 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() { |
80 CodeEventsContainer record; | 87 CodeEventsContainer record; |
81 if (events_buffer_.Dequeue(&record)) { | 88 if (events_buffer_.Dequeue(&record)) { |
82 switch (record.generic.type) { | 89 switch (record.generic.type) { |
83 #define PROFILER_TYPE_CASE(type, clss) \ | 90 #define PROFILER_TYPE_CASE(type, clss) \ |
84 case CodeEventRecord::type: \ | 91 case CodeEventRecord::type: \ |
85 record.clss##_.UpdateCodeMap(generator_->code_map()); \ | 92 record.clss##_.UpdateCodeMap(generator_->code_map()); \ |
86 break; | 93 break; |
87 | 94 |
88 CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE) | 95 CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE) |
89 | 96 |
90 #undef PROFILER_TYPE_CASE | 97 #undef PROFILER_TYPE_CASE |
91 default: return true; // Skip record. | 98 default: return true; // Skip record. |
92 } | 99 } |
93 *dequeue_order = record.generic.order; | 100 last_processed_code_event_id_ = record.generic.order; |
94 return true; | 101 return true; |
95 } | 102 } |
96 return false; | 103 return false; |
97 } | 104 } |
98 | 105 |
99 | 106 |
100 bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) { | 107 bool ProfilerEventsProcessor::ProcessTicks() { |
101 while (true) { | 108 while (true) { |
102 if (!ticks_from_vm_buffer_.IsEmpty() | 109 if (!ticks_from_vm_buffer_.IsEmpty() |
103 && ticks_from_vm_buffer_.Peek()->order == dequeue_order) { | 110 && ticks_from_vm_buffer_.Peek()->order == |
| 111 last_processed_code_event_id_) { |
104 TickSampleEventRecord record; | 112 TickSampleEventRecord record; |
105 ticks_from_vm_buffer_.Dequeue(&record); | 113 ticks_from_vm_buffer_.Dequeue(&record); |
106 generator_->RecordTickSample(record.sample); | 114 generator_->RecordTickSample(record.sample); |
107 } | 115 } |
108 | 116 |
109 const TickSampleEventRecord* rec = | 117 const TickSampleEventRecord* rec = |
110 TickSampleEventRecord::cast(ticks_buffer_.StartDequeue()); | 118 TickSampleEventRecord::cast(ticks_buffer_.StartDequeue()); |
111 if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty(); | 119 if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty(); |
112 // 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 |
113 // 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 |
114 // 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 |
115 // 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 |
116 // feet. | 124 // feet. |
117 TickSampleEventRecord record = *rec; | 125 TickSampleEventRecord record = *rec; |
118 if (record.order == dequeue_order) { | 126 if (record.order != last_processed_code_event_id_) return true; |
119 // A paranoid check to make sure that we don't get a memory overrun | 127 |
120 // in case of frames_count having a wild value. | 128 // A paranoid check to make sure that we don't get a memory overrun |
121 if (record.sample.frames_count < 0 | 129 // in case of frames_count having a wild value. |
122 || record.sample.frames_count > TickSample::kMaxFramesCount) | 130 if (record.sample.frames_count < 0 |
123 record.sample.frames_count = 0; | 131 || record.sample.frames_count > TickSample::kMaxFramesCount) |
124 generator_->RecordTickSample(record.sample); | 132 record.sample.frames_count = 0; |
125 ticks_buffer_.FinishDequeue(); | 133 generator_->RecordTickSample(record.sample); |
126 } else { | 134 ticks_buffer_.FinishDequeue(); |
127 return true; | |
128 } | |
129 } | 135 } |
130 } | 136 } |
131 | 137 |
132 | 138 |
133 void ProfilerEventsProcessor::Run() { | 139 void ProfilerEventsProcessor::Run() { |
134 unsigned dequeue_order = 0; | |
135 | |
136 while (running_) { | 140 while (running_) { |
137 // Process ticks until we have any. | 141 // Process ticks until we have any. |
138 if (ProcessTicks(dequeue_order)) { | 142 if (ProcessTicks()) { |
139 // All ticks of the current dequeue_order are processed, | 143 // All ticks of the current last_processed_code_event_id_ are processed, |
140 // proceed to the next code event. | 144 // proceed to the next code event. |
141 ProcessCodeEvent(&dequeue_order); | 145 ProcessCodeEvent(); |
142 } | 146 } |
143 YieldCPU(); | 147 YieldCPU(); |
144 } | 148 } |
145 | 149 |
146 // Process remaining tick events. | 150 // Process remaining tick events. |
147 ticks_buffer_.FlushResidualRecords(); | 151 ticks_buffer_.FlushResidualRecords(); |
148 // Perform processing until we have tick events, skip remaining code events. | 152 do { |
149 while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { } | 153 ProcessTicks(); |
| 154 } while (ProcessCodeEvent()); |
150 } | 155 } |
151 | 156 |
152 | 157 |
153 int CpuProfiler::GetProfilesCount() { | 158 int CpuProfiler::GetProfilesCount() { |
154 // The count of profiles doesn't depend on a security token. | 159 // The count of profiles doesn't depend on a security token. |
155 return profiles_->Profiles(TokenEnumerator::kNoSecurityToken)->length(); | 160 return profiles_->Profiles(TokenEnumerator::kNoSecurityToken)->length(); |
156 } | 161 } |
157 | 162 |
158 | 163 |
159 CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) { | 164 CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) { |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
498 | 503 |
499 void CpuProfiler::StopProcessor() { | 504 void CpuProfiler::StopProcessor() { |
500 Logger* logger = isolate_->logger(); | 505 Logger* logger = isolate_->logger(); |
501 Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_); | 506 Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_); |
502 sampler->DecreaseProfilingDepth(); | 507 sampler->DecreaseProfilingDepth(); |
503 if (need_to_stop_sampler_) { | 508 if (need_to_stop_sampler_) { |
504 sampler->Stop(); | 509 sampler->Stop(); |
505 need_to_stop_sampler_ = false; | 510 need_to_stop_sampler_ = false; |
506 } | 511 } |
507 is_profiling_ = false; | 512 is_profiling_ = false; |
508 processor_->Stop(); | 513 processor_->StopSynchronously(); |
509 processor_->Join(); | |
510 delete processor_; | 514 delete processor_; |
511 delete generator_; | 515 delete generator_; |
512 processor_ = NULL; | 516 processor_ = NULL; |
513 generator_ = NULL; | 517 generator_ = NULL; |
514 logger->logging_nesting_ = saved_logging_nesting_; | 518 logger->logging_nesting_ = saved_logging_nesting_; |
515 } | 519 } |
516 | 520 |
517 | 521 |
518 void CpuProfiler::LogBuiltins() { | 522 void CpuProfiler::LogBuiltins() { |
519 Builtins* builtins = isolate_->builtins(); | 523 Builtins* builtins = isolate_->builtins(); |
520 ASSERT(builtins->is_initialized()); | 524 ASSERT(builtins->is_initialized()); |
521 for (int i = 0; i < Builtins::builtin_count; i++) { | 525 for (int i = 0; i < Builtins::builtin_count; i++) { |
522 CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN); | 526 CodeEventsContainer evt_rec(CodeEventRecord::REPORT_BUILTIN); |
523 ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_; | 527 ReportBuiltinEventRecord* rec = &evt_rec.ReportBuiltinEventRecord_; |
524 Builtins::Name id = static_cast<Builtins::Name>(i); | 528 Builtins::Name id = static_cast<Builtins::Name>(i); |
525 rec->start = builtins->builtin(id)->address(); | 529 rec->start = builtins->builtin(id)->address(); |
526 rec->builtin_id = id; | 530 rec->builtin_id = id; |
527 processor_->Enqueue(evt_rec); | 531 processor_->Enqueue(evt_rec); |
528 } | 532 } |
529 } | 533 } |
530 | 534 |
531 | 535 |
532 } } // namespace v8::internal | 536 } } // namespace v8::internal |
OLD | NEW |