1 // Copyright 2010 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
27
28 #include "v8.h"
29
30 #include "cpu-profiler-inl.h"
31
32 #ifdef ENABLE_LOGGING_AND_PROFILING
33
34 #include "frames-inl.h"
35 #include "hashmap.h"
36 #include "log-inl.h"
37 #include "vm-state-inl.h"
38
39 #include "../include/v8-profiler.h"
40
41 namespace v8 {
42 namespace internal {
43
44 static const int kEventsBufferSize = 256*KB;
45 static const int kTickSamplesBufferChunkSize = 64*KB;
46 static const int kTickSamplesBufferChunksCount = 16;
47
48
ProfilerEventsProcessor(Isolate * isolate,ProfileGenerator * generator)49 ProfilerEventsProcessor::ProfilerEventsProcessor(Isolate* isolate,
50 ProfileGenerator* generator)
51 : Thread(isolate, "v8:ProfEvntProc"),
52 generator_(generator),
53 running_(true),
54 ticks_buffer_(sizeof(TickSampleEventRecord),
55 kTickSamplesBufferChunkSize,
56 kTickSamplesBufferChunksCount),
57 enqueue_order_(0) {
58 }
59
60
CallbackCreateEvent(Logger::LogEventsAndTags tag,const char * prefix,String * name,Address start)61 void ProfilerEventsProcessor::CallbackCreateEvent(Logger::LogEventsAndTags tag,
62 const char* prefix,
63 String* name,
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 = generator_->NewCodeEntry(tag, prefix, name);
72 rec->size = 1;
73 rec->shared = NULL;
74 events_buffer_.Enqueue(evt_rec);
75 }
76
77
CodeCreateEvent(Logger::LogEventsAndTags tag,String * name,String * resource_name,int line_number,Address start,unsigned size,Address shared)78 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
79 String* name,
80 String* resource_name,
81 int line_number,
82 Address start,
83 unsigned size,
84 Address shared) {
85 if (FilterOutCodeCreateEvent(tag)) return;
86 CodeEventsContainer evt_rec;
87 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
88 rec->type = CodeEventRecord::CODE_CREATION;
89 rec->order = ++enqueue_order_;
90 rec->start = start;
91 rec->entry = generator_->NewCodeEntry(tag, name, resource_name, line_number);
92 rec->size = size;
93 rec->shared = shared;
94 events_buffer_.Enqueue(evt_rec);
95 }
96
97
CodeCreateEvent(Logger::LogEventsAndTags tag,const char * name,Address start,unsigned size)98 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
99 const char* name,
100 Address start,
101 unsigned size) {
102 if (FilterOutCodeCreateEvent(tag)) return;
103 CodeEventsContainer evt_rec;
104 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
105 rec->type = CodeEventRecord::CODE_CREATION;
106 rec->order = ++enqueue_order_;
107 rec->start = start;
108 rec->entry = generator_->NewCodeEntry(tag, name);
109 rec->size = size;
110 rec->shared = NULL;
111 events_buffer_.Enqueue(evt_rec);
112 }
113
114
CodeCreateEvent(Logger::LogEventsAndTags tag,int args_count,Address start,unsigned size)115 void ProfilerEventsProcessor::CodeCreateEvent(Logger::LogEventsAndTags tag,
116 int args_count,
117 Address start,
118 unsigned size) {
119 if (FilterOutCodeCreateEvent(tag)) return;
120 CodeEventsContainer evt_rec;
121 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
122 rec->type = CodeEventRecord::CODE_CREATION;
123 rec->order = ++enqueue_order_;
124 rec->start = start;
125 rec->entry = generator_->NewCodeEntry(tag, args_count);
126 rec->size = size;
127 rec->shared = NULL;
128 events_buffer_.Enqueue(evt_rec);
129 }
130
131
CodeMoveEvent(Address from,Address to)132 void ProfilerEventsProcessor::CodeMoveEvent(Address from, Address to) {
133 CodeEventsContainer evt_rec;
134 CodeMoveEventRecord* rec = &evt_rec.CodeMoveEventRecord_;
135 rec->type = CodeEventRecord::CODE_MOVE;
136 rec->order = ++enqueue_order_;
137 rec->from = from;
138 rec->to = to;
139 events_buffer_.Enqueue(evt_rec);
140 }
141
142
CodeDeleteEvent(Address from)143 void ProfilerEventsProcessor::CodeDeleteEvent(Address from) {
144 CodeEventsContainer evt_rec;
145 CodeDeleteEventRecord* rec = &evt_rec.CodeDeleteEventRecord_;
146 rec->type = CodeEventRecord::CODE_DELETE;
147 rec->order = ++enqueue_order_;
148 rec->start = from;
149 events_buffer_.Enqueue(evt_rec);
150 }
151
152
SharedFunctionInfoMoveEvent(Address from,Address to)153 void ProfilerEventsProcessor::SharedFunctionInfoMoveEvent(Address from,
154 Address to) {
155 CodeEventsContainer evt_rec;
156 SharedFunctionInfoMoveEventRecord* rec =
157 &evt_rec.SharedFunctionInfoMoveEventRecord_;
158 rec->type = CodeEventRecord::SHARED_FUNC_MOVE;
159 rec->order = ++enqueue_order_;
160 rec->from = from;
161 rec->to = to;
162 events_buffer_.Enqueue(evt_rec);
163 }
164
165
RegExpCodeCreateEvent(Logger::LogEventsAndTags tag,const char * prefix,String * name,Address start,unsigned size)166 void ProfilerEventsProcessor::RegExpCodeCreateEvent(
167 Logger::LogEventsAndTags tag,
168 const char* prefix,
169 String* name,
170 Address start,
171 unsigned size) {
172 if (FilterOutCodeCreateEvent(tag)) return;
173 CodeEventsContainer evt_rec;
174 CodeCreateEventRecord* rec = &evt_rec.CodeCreateEventRecord_;
175 rec->type = CodeEventRecord::CODE_CREATION;
176 rec->order = ++enqueue_order_;
177 rec->start = start;
178 rec->entry = generator_->NewCodeEntry(tag, prefix, name);
179 rec->size = size;
180 events_buffer_.Enqueue(evt_rec);
181 }
182
183
AddCurrentStack()184 void ProfilerEventsProcessor::AddCurrentStack() {
185 TickSampleEventRecord record;
186 TickSample* sample = &record.sample;
187 Isolate* isolate = Isolate::Current();
188 sample->state = isolate->current_vm_state();
189 sample->pc = reinterpret_cast<Address>(sample); // Not NULL.
190 sample->tos = NULL;
191 sample->has_external_callback = false;
192 sample->frames_count = 0;
193 for (StackTraceFrameIterator it(isolate);
194 !it.done() && sample->frames_count < TickSample::kMaxFramesCount;
195 it.Advance()) {
196 sample->stack[sample->frames_count++] = it.frame()->pc();
197 }
198 record.order = enqueue_order_;
199 ticks_from_vm_buffer_.Enqueue(record);
200 }
201
202
ProcessCodeEvent(unsigned * dequeue_order)203 bool ProfilerEventsProcessor::ProcessCodeEvent(unsigned* dequeue_order) {
204 if (!events_buffer_.IsEmpty()) {
205 CodeEventsContainer record;
206 events_buffer_.Dequeue(&record);
207 switch (record.generic.type) {
208 #define PROFILER_TYPE_CASE(type, clss) \
209 case CodeEventRecord::type: \
210 record.clss##_.UpdateCodeMap(generator_->code_map()); \
211 break;
212
213 CODE_EVENTS_TYPE_LIST(PROFILER_TYPE_CASE)
214
215 #undef PROFILER_TYPE_CASE
216 default: return true; // Skip record.
217 }
218 *dequeue_order = record.generic.order;
219 return true;
220 }
221 return false;
222 }
223
224
ProcessTicks(unsigned dequeue_order)225 bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) {
226 while (true) {
227 if (!ticks_from_vm_buffer_.IsEmpty()
228 && ticks_from_vm_buffer_.Peek()->order == dequeue_order) {
229 TickSampleEventRecord record;
230 ticks_from_vm_buffer_.Dequeue(&record);
231 generator_->RecordTickSample(record.sample);
232 }
233
234 const TickSampleEventRecord* rec =
235 TickSampleEventRecord::cast(ticks_buffer_.StartDequeue());
236 if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty();
237 // Make a local copy of tick sample record to ensure that it won't
238 // be modified as we are processing it. This is possible as the
239 // sampler writes w/o any sync to the queue, so if the processor
240 // will get far behind, a record may be modified right under its
241 // feet.
242 TickSampleEventRecord record = *rec;
243 if (record.order == dequeue_order) {
244 // A paranoid check to make sure that we don't get a memory overrun
245 // in case of frames_count having a wild value.
246 if (record.sample.frames_count < 0
247 || record.sample.frames_count > TickSample::kMaxFramesCount)
248 record.sample.frames_count = 0;
249 generator_->RecordTickSample(record.sample);
250 ticks_buffer_.FinishDequeue();
251 } else {
252 return true;
253 }
254 }
255 }
256
257
Run()258 void ProfilerEventsProcessor::Run() {
259 unsigned dequeue_order = 0;
260
261 while (running_) {
262 // Process ticks until we have any.
263 if (ProcessTicks(dequeue_order)) {
264 // All ticks of the current dequeue_order are processed,
265 // proceed to the next code event.
266 ProcessCodeEvent(&dequeue_order);
267 }
268 YieldCPU();
269 }
270
271 // Process remaining tick events.
272 ticks_buffer_.FlushResidualRecords();
273 // Perform processing until we have tick events, skip remaining code events.
274 while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { }
275 }
276
277
StartProfiling(const char * title)278 void CpuProfiler::StartProfiling(const char* title) {
279 ASSERT(Isolate::Current()->cpu_profiler() != NULL);
280 Isolate::Current()->cpu_profiler()->StartCollectingProfile(title);
281 }
282
283
StartProfiling(String * title)284 void CpuProfiler::StartProfiling(String* title) {
285 ASSERT(Isolate::Current()->cpu_profiler() != NULL);
286 Isolate::Current()->cpu_profiler()->StartCollectingProfile(title);
287 }
288
289
StopProfiling(const char * title)290 CpuProfile* CpuProfiler::StopProfiling(const char* title) {
291 return is_profiling() ?
292 Isolate::Current()->cpu_profiler()->StopCollectingProfile(title) : NULL;
293 }
294
295
StopProfiling(Object * security_token,String * title)296 CpuProfile* CpuProfiler::StopProfiling(Object* security_token, String* title) {
297 return is_profiling() ?
298 Isolate::Current()->cpu_profiler()->StopCollectingProfile(
299 security_token, title) : NULL;
300 }
301
302
GetProfilesCount()303 int CpuProfiler::GetProfilesCount() {
304 ASSERT(Isolate::Current()->cpu_profiler() != NULL);
305 // The count of profiles doesn't depend on a security token.
306 return Isolate::Current()->cpu_profiler()->profiles_->Profiles(
307 TokenEnumerator::kNoSecurityToken)->length();
308 }
309
310
GetProfile(Object * security_token,int index)311 CpuProfile* CpuProfiler::GetProfile(Object* security_token, int index) {
312 ASSERT(Isolate::Current()->cpu_profiler() != NULL);
313 CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
314 const int token = profiler->token_enumerator_->GetTokenId(security_token);
315 return profiler->profiles_->Profiles(token)->at(index);
316 }
317
318
FindProfile(Object * security_token,unsigned uid)319 CpuProfile* CpuProfiler::FindProfile(Object* security_token, unsigned uid) {
320 ASSERT(Isolate::Current()->cpu_profiler() != NULL);
321 CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
322 const int token = profiler->token_enumerator_->GetTokenId(security_token);
323 return profiler->profiles_->GetProfile(token, uid);
324 }
325
326
TickSampleEvent(Isolate * isolate)327 TickSample* CpuProfiler::TickSampleEvent(Isolate* isolate) {
328 if (CpuProfiler::is_profiling(isolate)) {
329 return isolate->cpu_profiler()->processor_->TickSampleEvent();
330 } else {
331 return NULL;
332 }
333 }
334
335
DeleteAllProfiles()336 void CpuProfiler::DeleteAllProfiles() {
337 Isolate* isolate = Isolate::Current();
338 ASSERT(isolate->cpu_profiler() != NULL);
339 if (is_profiling())
340 isolate->cpu_profiler()->StopProcessor();
341 isolate->cpu_profiler()->ResetProfiles();
342 }
343
344
DeleteProfile(CpuProfile * profile)345 void CpuProfiler::DeleteProfile(CpuProfile* profile) {
346 ASSERT(Isolate::Current()->cpu_profiler() != NULL);
347 Isolate::Current()->cpu_profiler()->profiles_->RemoveProfile(profile);
348 delete profile;
349 }
350
351
HasDetachedProfiles()352 bool CpuProfiler::HasDetachedProfiles() {
353 ASSERT(Isolate::Current()->cpu_profiler() != NULL);
354 return Isolate::Current()->cpu_profiler()->profiles_->HasDetachedProfiles();
355 }
356
357
CallbackEvent(String * name,Address entry_point)358 void CpuProfiler::CallbackEvent(String* name, Address entry_point) {
359 Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
360 Logger::CALLBACK_TAG, CodeEntry::kEmptyNamePrefix, name, entry_point);
361 }
362
363
CodeCreateEvent(Logger::LogEventsAndTags tag,Code * code,const char * comment)364 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
365 Code* code, const char* comment) {
366 Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
367 tag, comment, code->address(), code->ExecutableSize());
368 }
369
370
CodeCreateEvent(Logger::LogEventsAndTags tag,Code * code,String * name)371 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
372 Code* code, String* name) {
373 Isolate* isolate = Isolate::Current();
374 isolate->cpu_profiler()->processor_->CodeCreateEvent(
375 tag,
376 name,
377 isolate->heap()->empty_string(),
378 v8::CpuProfileNode::kNoLineNumberInfo,
379 code->address(),
380 code->ExecutableSize(),
381 NULL);
382 }
383
384
CodeCreateEvent(Logger::LogEventsAndTags tag,Code * code,SharedFunctionInfo * shared,String * name)385 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
386 Code* code,
387 SharedFunctionInfo* shared,
388 String* name) {
389 Isolate* isolate = Isolate::Current();
390 isolate->cpu_profiler()->processor_->CodeCreateEvent(
391 tag,
392 name,
393 isolate->heap()->empty_string(),
394 v8::CpuProfileNode::kNoLineNumberInfo,
395 code->address(),
396 code->ExecutableSize(),
397 shared->address());
398 }
399
400
CodeCreateEvent(Logger::LogEventsAndTags tag,Code * code,SharedFunctionInfo * shared,String * source,int line)401 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
402 Code* code,
403 SharedFunctionInfo* shared,
404 String* source, int line) {
405 Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
406 tag,
407 shared->DebugName(),
408 source,
409 line,
410 code->address(),
411 code->ExecutableSize(),
412 shared->address());
413 }
414
415
CodeCreateEvent(Logger::LogEventsAndTags tag,Code * code,int args_count)416 void CpuProfiler::CodeCreateEvent(Logger::LogEventsAndTags tag,
417 Code* code, int args_count) {
418 Isolate::Current()->cpu_profiler()->processor_->CodeCreateEvent(
419 tag,
420 args_count,
421 code->address(),
422 code->ExecutableSize());
423 }
424
425
CodeMoveEvent(Address from,Address to)426 void CpuProfiler::CodeMoveEvent(Address from, Address to) {
427 Isolate::Current()->cpu_profiler()->processor_->CodeMoveEvent(from, to);
428 }
429
430
CodeDeleteEvent(Address from)431 void CpuProfiler::CodeDeleteEvent(Address from) {
432 Isolate::Current()->cpu_profiler()->processor_->CodeDeleteEvent(from);
433 }
434
435
SharedFunctionInfoMoveEvent(Address from,Address to)436 void CpuProfiler::SharedFunctionInfoMoveEvent(Address from, Address to) {
437 CpuProfiler* profiler = Isolate::Current()->cpu_profiler();
438 profiler->processor_->SharedFunctionInfoMoveEvent(from, to);
439 }
440
441
GetterCallbackEvent(String * name,Address entry_point)442 void CpuProfiler::GetterCallbackEvent(String* name, Address entry_point) {
443 Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
444 Logger::CALLBACK_TAG, "get ", name, entry_point);
445 }
446
447
RegExpCodeCreateEvent(Code * code,String * source)448 void CpuProfiler::RegExpCodeCreateEvent(Code* code, String* source) {
449 Isolate::Current()->cpu_profiler()->processor_->RegExpCodeCreateEvent(
450 Logger::REG_EXP_TAG,
451 "RegExp: ",
452 source,
453 code->address(),
454 code->ExecutableSize());
455 }
456
457
SetterCallbackEvent(String * name,Address entry_point)458 void CpuProfiler::SetterCallbackEvent(String* name, Address entry_point) {
459 Isolate::Current()->cpu_profiler()->processor_->CallbackCreateEvent(
460 Logger::CALLBACK_TAG, "set ", name, entry_point);
461 }
462
463
CpuProfiler()464 CpuProfiler::CpuProfiler()
465 : profiles_(new CpuProfilesCollection()),
466 next_profile_uid_(1),
467 token_enumerator_(new TokenEnumerator()),
468 generator_(NULL),
469 processor_(NULL),
470 need_to_stop_sampler_(false),
471 is_profiling_(false) {
472 }
473
474
~CpuProfiler()475 CpuProfiler::~CpuProfiler() {
476 delete token_enumerator_;
477 delete profiles_;
478 }
479
480
ResetProfiles()481 void CpuProfiler::ResetProfiles() {
482 delete profiles_;
483 profiles_ = new CpuProfilesCollection();
484 }
485
StartCollectingProfile(const char * title)486 void CpuProfiler::StartCollectingProfile(const char* title) {
487 if (profiles_->StartProfiling(title, next_profile_uid_++)) {
488 StartProcessorIfNotStarted();
489 }
490 processor_->AddCurrentStack();
491 }
492
493
StartCollectingProfile(String * title)494 void CpuProfiler::StartCollectingProfile(String* title) {
495 StartCollectingProfile(profiles_->GetName(title));
496 }
497
498
StartProcessorIfNotStarted()499 void CpuProfiler::StartProcessorIfNotStarted() {
500 if (processor_ == NULL) {
501 Isolate* isolate = Isolate::Current();
502
503 // Disable logging when using the new implementation.
504 saved_logging_nesting_ = isolate->logger()->logging_nesting_;
505 isolate->logger()->logging_nesting_ = 0;
506 generator_ = new ProfileGenerator(profiles_);
507 processor_ = new ProfilerEventsProcessor(isolate, generator_);
508 NoBarrier_Store(&is_profiling_, true);
509 processor_->Start();
510 // Enumerate stuff we already have in the heap.
511 if (isolate->heap()->HasBeenSetup()) {
512 if (!FLAG_prof_browser_mode) {
513 bool saved_log_code_flag = FLAG_log_code;
514 FLAG_log_code = true;
515 isolate->logger()->LogCodeObjects();
516 FLAG_log_code = saved_log_code_flag;
517 }
518 isolate->logger()->LogCompiledFunctions();
519 isolate->logger()->LogAccessorCallbacks();
520 }
521 // Enable stack sampling.
522 Sampler* sampler = reinterpret_cast<Sampler*>(isolate->logger()->ticker_);
523 if (!sampler->IsActive()) {
524 sampler->Start();
525 need_to_stop_sampler_ = true;
526 }
527 sampler->IncreaseProfilingDepth();
528 }
529 }
530
531
StopCollectingProfile(const char * title)532 CpuProfile* CpuProfiler::StopCollectingProfile(const char* title) {
533 const double actual_sampling_rate = generator_->actual_sampling_rate();
534 StopProcessorIfLastProfile(title);
535 CpuProfile* result =
536 profiles_->StopProfiling(TokenEnumerator::kNoSecurityToken,
537 title,
538 actual_sampling_rate);
539 if (result != NULL) {
540 result->Print();
541 }
542 return result;
543 }
544
545
StopCollectingProfile(Object * security_token,String * title)546 CpuProfile* CpuProfiler::StopCollectingProfile(Object* security_token,
547 String* title) {
548 const double actual_sampling_rate = generator_->actual_sampling_rate();
549 const char* profile_title = profiles_->GetName(title);
550 StopProcessorIfLastProfile(profile_title);
551 int token = token_enumerator_->GetTokenId(security_token);
552 return profiles_->StopProfiling(token, profile_title, actual_sampling_rate);
553 }
554
555
StopProcessorIfLastProfile(const char * title)556 void CpuProfiler::StopProcessorIfLastProfile(const char* title) {
557 if (profiles_->IsLastProfile(title)) StopProcessor();
558 }
559
560
StopProcessor()561 void CpuProfiler::StopProcessor() {
562 Logger* logger = Isolate::Current()->logger();
563 Sampler* sampler = reinterpret_cast<Sampler*>(logger->ticker_);
564 sampler->DecreaseProfilingDepth();
565 if (need_to_stop_sampler_) {
566 sampler->Stop();
567 need_to_stop_sampler_ = false;
568 }
569 processor_->Stop();
570 processor_->Join();
571 delete processor_;
572 delete generator_;
573 processor_ = NULL;
574 NoBarrier_Store(&is_profiling_, false);
575 generator_ = NULL;
576 logger->logging_nesting_ = saved_logging_nesting_;
577 }
578
579 } } // namespace v8::internal
580
581 #endif // ENABLE_LOGGING_AND_PROFILING
582
583 namespace v8 {
584 namespace internal {
585
Setup()586 void CpuProfiler::Setup() {
587 #ifdef ENABLE_LOGGING_AND_PROFILING
588 Isolate* isolate = Isolate::Current();
589 if (isolate->cpu_profiler() == NULL) {
590 isolate->set_cpu_profiler(new CpuProfiler());
591 }
592 #endif
593 }
594
595
TearDown()596 void CpuProfiler::TearDown() {
597 #ifdef ENABLE_LOGGING_AND_PROFILING
598 Isolate* isolate = Isolate::Current();
599 if (isolate->cpu_profiler() != NULL) {
600 delete isolate->cpu_profiler();
601 }
602 isolate->set_cpu_profiler(NULL);
603 #endif
604 }
605
606 } } // namespace v8::internal
607