blob: bec51e648f0f0ab2ec96c07175e085016d2184c2 [file] [log] [blame]
// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef VM_PROFILER_H_
#define VM_PROFILER_H_
#include "platform/hashmap.h"
#include "platform/thread.h"
#include "vm/allocation.h"
#include "vm/code_observers.h"
#include "vm/globals.h"
namespace dart {
// Forward declarations.
class JSONStream;
// Profiler manager.
class ProfilerManager : public AllStatic {
public:
static void InitOnce();
static void Shutdown();
static void SetupIsolateForProfiling(Isolate* isolate);
static void ShutdownIsolateForProfiling(Isolate* isolate);
static void ScheduleIsolate(Isolate* isolate, bool inside_signal = false);
static void DescheduleIsolate(Isolate* isolate);
static void PrintToJSONStream(Isolate* isolate, JSONStream* stream);
static void WriteTracing(Isolate* isolate, const char* name, Dart_Port port);
private:
static const intptr_t kMaxProfiledIsolates = 4096;
static bool initialized_;
static bool shutdown_;
static bool thread_running_;
static Monitor* monitor_;
static Monitor* start_stop_monitor_;
static Isolate** isolates_;
static intptr_t isolates_capacity_;
static intptr_t isolates_size_;
static void ScheduleIsolateHelper(Isolate* isolate);
static void ResizeIsolates(intptr_t new_capacity);
static void AddIsolate(Isolate* isolate);
static intptr_t FindIsolate(Isolate* isolate);
static void RemoveIsolate(intptr_t i);
// Returns the microseconds until the next live timer fires.
static int64_t SampleAndRescheduleIsolates(int64_t current_time);
static void FreeIsolateProfilingData(Isolate* isolate);
static void ThreadMain(uword parameters);
};
class IsolateProfilerData {
public:
static const int64_t kDescheduledCpuUsage = -1;
static const int64_t kNoExpirationTime = -2;
IsolateProfilerData(Isolate* isolate, SampleBuffer* sample_buffer);
~IsolateProfilerData();
int64_t sample_interval_micros() const { return sample_interval_micros_; }
void set_sample_interval_micros(int64_t sample_interval) {
sample_interval_micros_ = sample_interval;
}
bool CanExpire() const {
return timer_expiration_micros_ != kNoExpirationTime;
}
bool ShouldSample(int64_t current_time) const {
return CanExpire() && TimeUntilExpiration(current_time) <= 0;
}
int64_t TimeUntilExpiration(int64_t current_time_micros) const {
ASSERT(CanExpire());
return timer_expiration_micros_ - current_time_micros;
}
void set_cpu_usage(int64_t cpu_usage) {
cpu_usage_ = cpu_usage;
}
void SampledAt(int64_t current_time);
void Scheduled(int64_t current_time, ThreadId thread);
void Descheduled();
int64_t cpu_usage() const { return cpu_usage_; }
int64_t ComputeDeltaAndSetCpuUsage(int64_t cpu_usage) {
int64_t delta = 0;
if (cpu_usage_ != kDescheduledCpuUsage) {
// Only compute the real delta if we are being sampled regularly.
delta = cpu_usage - cpu_usage_;
}
set_cpu_usage(cpu_usage);
return delta;
}
ThreadId thread_id() const { return thread_id_; }
Isolate* isolate() const { return isolate_; }
SampleBuffer* sample_buffer() const { return sample_buffer_; }
void set_sample_buffer(SampleBuffer* sample_buffer) {
sample_buffer_ = sample_buffer;
}
private:
int64_t last_sampled_micros_;
int64_t timer_expiration_micros_;
int64_t sample_interval_micros_;
int64_t cpu_usage_;
ThreadId thread_id_;
Isolate* isolate_;
SampleBuffer* sample_buffer_;
DISALLOW_COPY_AND_ASSIGN(IsolateProfilerData);
};
// Profile sample.
struct Sample {
static const char* kLookupSymbol;
static const char* kNoSymbol;
static const intptr_t kNumStackFrames = 4;
enum SampleState {
kIdle = 0,
kExecuting = 1,
kNumSampleStates
};
int64_t timestamp;
int64_t cpu_usage;
uintptr_t pcs[kNumStackFrames];
uint16_t vm_tags;
uint16_t runtime_tags;
Sample();
};
// Ring buffer of samples. One per isolate.
class SampleBuffer {
public:
static const intptr_t kDefaultBufferCapacity = 120000; // 2 minutes @ 1000hz.
explicit SampleBuffer(intptr_t capacity = kDefaultBufferCapacity);
~SampleBuffer();
intptr_t capacity() const { return capacity_; }
Sample* ReserveSample();
Sample* FirstSample() const;
Sample* NextSample(Sample* sample) const;
Sample* LastSample() const;
private:
Sample* samples_;
intptr_t capacity_;
intptr_t start_;
intptr_t end_;
intptr_t WrapIncrement(intptr_t i) const;
DISALLOW_COPY_AND_ASSIGN(SampleBuffer);
};
class ProfilerSampleStackWalker : public ValueObject {
public:
ProfilerSampleStackWalker(Sample* sample,
uintptr_t stack_lower,
uintptr_t stack_upper,
uintptr_t pc,
uintptr_t fp,
uintptr_t sp);
int walk();
private:
uword* CallerPC(uword* fp);
uword* CallerFP(uword* fp);
bool ValidInstructionPointer(uword* pc);
bool ValidFramePointer(uword* fp);
Sample* sample_;
const uintptr_t stack_lower_;
const uintptr_t stack_upper_;
const uintptr_t original_pc_;
const uintptr_t original_fp_;
const uintptr_t original_sp_;
uintptr_t lower_bound_;
};
} // namespace dart
#endif // VM_PROFILER_H_