#include "cpu-profiler.h"
#include <new>
-#include "circular-queue-inl.h"
#include "profile-generator-inl.h"
#include "unbound-queue-inl.h"
}
-TickSample* ProfilerEventsProcessor::TickSampleEvent() {
+TickSample* ProfilerEventsProcessor::StartTickSampleEvent() {
+ if (!ticks_buffer_is_empty_ || ticks_buffer_is_initialized_) return NULL;
+ ticks_buffer_is_initialized_ = true;
generator_->Tick();
- TickSampleEventRecord* evt =
- new(ticks_buffer_.Enqueue()) TickSampleEventRecord(enqueue_order_);
- return &evt->sample;
+ ticks_buffer_ = TickSampleEventRecord(enqueue_order_);
+ return &ticks_buffer_.sample;
+}
+
+
+void ProfilerEventsProcessor::FinishTickSampleEvent() {
+ ASSERT(ticks_buffer_is_initialized_ && ticks_buffer_is_empty_);
+ ticks_buffer_is_empty_ = false;
}
namespace v8 {
namespace internal {
-static const int kEventsBufferSize = 256 * KB;
-static const int kTickSamplesBufferChunkSize = 64 * KB;
-static const int kTickSamplesBufferChunksCount = 16;
static const int kProfilerStackSize = 64 * KB;
sampler_(sampler),
running_(true),
period_in_useconds_(period_in_useconds),
- ticks_buffer_(sizeof(TickSampleEventRecord),
- kTickSamplesBufferChunkSize,
- kTickSamplesBufferChunksCount),
+ ticks_buffer_is_empty_(true),
+ ticks_buffer_is_initialized_(false),
enqueue_order_(0) {
}
}
-bool ProfilerEventsProcessor::ProcessTicks(int64_t stop_time,
- unsigned dequeue_order) {
- while (stop_time == -1 || OS::Ticks() < stop_time) {
+bool ProfilerEventsProcessor::ProcessTicks(unsigned dequeue_order) {
+ while (true) {
if (!ticks_from_vm_buffer_.IsEmpty()
&& ticks_from_vm_buffer_.Peek()->order == dequeue_order) {
TickSampleEventRecord record;
generator_->RecordTickSample(record.sample);
}
- const TickSampleEventRecord* rec =
- TickSampleEventRecord::cast(ticks_buffer_.StartDequeue());
- if (rec == NULL) return !ticks_from_vm_buffer_.IsEmpty();
- // Make a local copy of tick sample record to ensure that it won't
- // be modified as we are processing it. This is possible as the
- // sampler writes w/o any sync to the queue, so if the processor
- // will get far behind, a record may be modified right under its
- // feet.
- TickSampleEventRecord record = *rec;
- if (record.order == dequeue_order) {
+ if (ticks_buffer_is_empty_) return !ticks_from_vm_buffer_.IsEmpty();
+ if (ticks_buffer_.order == dequeue_order) {
// A paranoid check to make sure that we don't get a memory overrun
// in case of frames_count having a wild value.
- if (record.sample.frames_count < 0
- || record.sample.frames_count > TickSample::kMaxFramesCount)
- record.sample.frames_count = 0;
- generator_->RecordTickSample(record.sample);
- ticks_buffer_.FinishDequeue();
+ if (ticks_buffer_.sample.frames_count < 0
+ || ticks_buffer_.sample.frames_count > TickSample::kMaxFramesCount) {
+ ticks_buffer_.sample.frames_count = 0;
+ }
+ generator_->RecordTickSample(ticks_buffer_.sample);
+ ticks_buffer_is_empty_ = true;
+ ticks_buffer_is_initialized_ = false;
} else {
return true;
}
}
- return false;
}
void ProfilerEventsProcessor::ProcessEventsQueue(int64_t stop_time,
unsigned* dequeue_order) {
while (OS::Ticks() < stop_time) {
- if (ProcessTicks(stop_time, *dequeue_order)) {
+ if (ProcessTicks(*dequeue_order)) {
// All ticks of the current dequeue_order are processed,
// proceed to the next code event.
ProcessCodeEvent(dequeue_order);
ProcessEventsQueue(stop_time, &dequeue_order);
}
- // Process remaining tick events.
- ticks_buffer_.FlushResidualRecords();
- // Perform processing until we have tick events, skip remaining code events.
- while (ProcessTicks(-1, dequeue_order) && ProcessCodeEvent(&dequeue_order)) {
- }
+ while (ProcessTicks(dequeue_order) && ProcessCodeEvent(&dequeue_order)) { }
}
}
-TickSample* CpuProfiler::TickSampleEvent(Isolate* isolate) {
+TickSample* CpuProfiler::StartTickSampleEvent(Isolate* isolate) {
if (CpuProfiler::is_profiling(isolate)) {
- return isolate->cpu_profiler()->processor_->TickSampleEvent();
+ return isolate->cpu_profiler()->processor_->StartTickSampleEvent();
} else {
return NULL;
}
}
+void CpuProfiler::FinishTickSampleEvent(Isolate* isolate) {
+ if (CpuProfiler::is_profiling(isolate)) {
+ isolate->cpu_profiler()->processor_->FinishTickSampleEvent();
+ }
+}
+
+
void CpuProfiler::DeleteAllProfiles() {
Isolate* isolate = Isolate::Current();
ASSERT(isolate->cpu_profiler() != NULL);
// Puts current stack into tick sample events buffer.
void AddCurrentStack();
- // Tick sample events are filled directly in the buffer of the circular
- // queue (because the structure is of fixed width, but usually not all
- // stack frame entries are filled.) This method returns a pointer to the
- // next record of the buffer.
- INLINE(TickSample* TickSampleEvent());
+ // StartTickSampleEvent returns a pointer only if the ticks_buffer_ is empty,
+ // FinishTickSampleEvent marks the ticks_buffer_ as filled.
+ // Finish should be called only after successful Start (returning non-NULL
+ // pointer).
+ INLINE(TickSample* StartTickSampleEvent());
+ INLINE(void FinishTickSampleEvent());
private:
union CodeEventsContainer {
// Called from events processing thread (Run() method.)
bool ProcessCodeEvent(unsigned* dequeue_order);
- bool ProcessTicks(int64_t stop_time, unsigned dequeue_order);
+ bool ProcessTicks(unsigned dequeue_order);
void ProcessEventsQueue(int64_t stop_time, unsigned* dequeue_order);
INLINE(static bool FilterOutCodeCreateEvent(Logger::LogEventsAndTags tag));
// Sampling period in microseconds.
const int period_in_useconds_;
UnboundQueue<CodeEventsContainer> events_buffer_;
- SamplingCircularQueue ticks_buffer_;
+ TickSampleEventRecord ticks_buffer_;
+ bool ticks_buffer_is_empty_;
+ bool ticks_buffer_is_initialized_;
UnboundQueue<TickSampleEventRecord> ticks_from_vm_buffer_;
unsigned enqueue_order_;
};
static bool HasDetachedProfiles();
// Invoked from stack sampler (thread or signal handler.)
- static TickSample* TickSampleEvent(Isolate* isolate);
+ // Finish should be called only after successful Start (returning non-NULL
+ // pointer).
+ static TickSample* StartTickSampleEvent(Isolate* isolate);
+ static void FinishTickSampleEvent(Isolate* isolate);
// Must be called via PROFILE macro, otherwise will crash when
// profiling is not enabled.
CONTEXT context;
memset(&context, 0, sizeof(context));
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(sampler->isolate());
+ if (sample == NULL) return;
static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
if (SuspendThread(profiled_thread) == kSuspendFailed) return;
sampler->SampleStack(sample);
sampler->Tick(sample);
}
+ CpuProfiler::FinishTickSampleEvent(sampler->isolate());
ResumeThread(profiled_thread);
}
Sampler* sampler = isolate->logger()->sampler();
if (sampler == NULL || !sampler->IsActive()) return;
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(isolate);
+ if (sample == NULL) return;
// Extracting the sample from the context is extremely machine dependent.
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
#endif
sampler->SampleStack(sample);
sampler->Tick(sample);
+ CpuProfiler::FinishTickSampleEvent(isolate);
}
Sampler* sampler = isolate->logger()->sampler();
if (sampler == NULL || !sampler->IsActive()) return;
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(isolate);
+ if (sample == NULL) return;
// Extracting the sample from the context is extremely machine dependent.
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
#endif // V8_HOST_ARCH_*
sampler->SampleStack(sample);
sampler->Tick(sample);
+ CpuProfiler::FinishTickSampleEvent(isolate);
}
void SampleContext(Sampler* sampler) {
thread_act_t profiled_thread = sampler->platform_data()->profiled_thread();
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(sampler->isolate());
+ if (sample == NULL) return;
if (KERN_SUCCESS != thread_suspend(profiled_thread)) return;
sampler->SampleStack(sample);
sampler->Tick(sample);
}
+ CpuProfiler::FinishTickSampleEvent(sampler->isolate());
thread_resume(profiled_thread);
}
Sampler* sampler = isolate->logger()->sampler();
if (sampler == NULL || !sampler->IsActive()) return;
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(isolate);
+ if (sample == NULL) return;
// Extracting the sample from the context is extremely machine dependent.
sample->state = isolate->current_vm_state();
#endif // __NetBSD__
sampler->SampleStack(sample);
sampler->Tick(sample);
+ CpuProfiler::FinishTickSampleEvent(isolate);
}
Sampler* sampler = isolate->logger()->sampler();
if (sampler == NULL || !sampler->IsActive()) return;
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(isolate);
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(isolate);
+ if (sample == NULL) return;
// Extracting the sample from the context is extremely machine dependent.
ucontext_t* ucontext = reinterpret_cast<ucontext_t*>(context);
sampler->SampleStack(sample);
sampler->Tick(sample);
+ CpuProfiler::FinishTickSampleEvent(isolate);
}
class Sampler::PlatformData : public Malloced {
CONTEXT context;
memset(&context, 0, sizeof(context));
- TickSample sample_obj;
- TickSample* sample = CpuProfiler::TickSampleEvent(sampler->isolate());
- if (sample == NULL) sample = &sample_obj;
+ TickSample* sample = CpuProfiler::StartTickSampleEvent(sampler->isolate());
+ if (sample == NULL) return;
static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
if (SuspendThread(profiled_thread) == kSuspendFailed) return;
sampler->SampleStack(sample);
sampler->Tick(sample);
}
+ CpuProfiler::FinishTickSampleEvent(sampler->isolate());
ResumeThread(profiled_thread);
}
#include "v8.h"
#include "cpu-profiler-inl.h"
#include "cctest.h"
+#include "platform.h"
#include "../include/v8-profiler.h"
using i::CodeEntry;
return reinterpret_cast<i::Address>(n);
}
-static void EnqueueTickSampleEvent(ProfilerEventsProcessor* proc,
- i::Address frame1,
- i::Address frame2 = NULL,
- i::Address frame3 = NULL) {
- i::TickSample* sample = proc->TickSampleEvent();
+static void AddTickSampleEvent(ProfilerEventsProcessor* processor,
+ i::Address frame1,
+ i::Address frame2 = NULL,
+ i::Address frame3 = NULL) {
+ i::TickSample* sample;
+ i::OS::Sleep(20);
+ while ((sample = processor->StartTickSampleEvent()) == NULL) i::OS::Sleep(20);
sample->pc = frame1;
sample->tos = frame1;
sample->frames_count = 0;
sample->stack[1] = frame3;
sample->frames_count = 2;
}
+ processor->FinishTickSampleEvent();
}
namespace {
processor.CodeMoveEvent(ToAddress(0x1400), ToAddress(0x1500));
processor.CodeCreateEvent(i::Logger::STUB_TAG, 3, ToAddress(0x1600), 0x10);
processor.CodeCreateEvent(i::Logger::STUB_TAG, 4, ToAddress(0x1605), 0x10);
- // Enqueue a tick event to enable code events processing.
- EnqueueTickSampleEvent(&processor, ToAddress(0x1000));
+ // Add a tick event to enable code events processing.
+ AddTickSampleEvent(&processor, ToAddress(0x1000));
processor.Stop();
processor.Join();
"ddd",
ToAddress(0x1400),
0x80);
- EnqueueTickSampleEvent(&processor, ToAddress(0x1210));
- EnqueueTickSampleEvent(&processor, ToAddress(0x1305), ToAddress(0x1220));
- EnqueueTickSampleEvent(&processor,
- ToAddress(0x1404),
- ToAddress(0x1305),
- ToAddress(0x1230));
+ AddTickSampleEvent(&processor, ToAddress(0x1210));
+ AddTickSampleEvent(&processor, ToAddress(0x1305), ToAddress(0x1220));
+ AddTickSampleEvent(&processor,
+ ToAddress(0x1404),
+ ToAddress(0x1305),
+ ToAddress(0x1230));
processor.Stop();
processor.Join();
ToAddress(0x1200),
0x80);
- i::TickSample* sample = processor.TickSampleEvent();
+ i::TickSample* sample = processor.StartTickSampleEvent();
sample->pc = ToAddress(0x1200);
sample->tos = 0;
sample->frames_count = i::TickSample::kMaxFramesCount;
for (int i = 0; i < sample->frames_count; ++i) {
sample->stack[i] = ToAddress(0x1200);
}
+ processor.FinishTickSampleEvent();
processor.Stop();
processor.Join();