| Index: runtime/vm/profiler_service.h
|
| diff --git a/runtime/vm/profiler_service.h b/runtime/vm/profiler_service.h
|
| index 19f01b622fee85975a79325066fce04e0ae34411..62612bb1e23232eb54f47c3647c07974dfaad19b 100644
|
| --- a/runtime/vm/profiler_service.h
|
| +++ b/runtime/vm/profiler_service.h
|
| @@ -8,20 +8,266 @@
|
| #include "vm/allocation.h"
|
| #include "vm/code_observers.h"
|
| #include "vm/globals.h"
|
| +#include "vm/growable_array.h"
|
| +#include "vm/object.h"
|
| #include "vm/tags.h"
|
| #include "vm/thread_interrupter.h"
|
|
|
| -// Profile VM Service.
|
| +// CPU Profile model and service protocol bits.
|
| // NOTE: For sampling and stack walking related code, see profiler.h.
|
|
|
| namespace dart {
|
|
|
| // Forward declarations.
|
| +class Code;
|
| +class Function;
|
| class JSONArray;
|
| class JSONStream;
|
| -class ProfilerCodeRegionTable;
|
| +class ProfileFunctionTable;
|
| +class ProfileCodeTable;
|
| +class RawCode;
|
| +class RawFunction;
|
| +class SampleFilter;
|
|
|
| -class ProfilerService : public AllStatic {
|
| +// Profile data related to a |Function|.
|
| +class ProfileFunction : public ZoneAllocated {
|
| + public:
|
| + enum Kind {
|
| + kDartFunction, // Dart function.
|
| + kNativeFunction, // Synthetic function for Native (C/C++).
|
| + kTagFunction, // Synthetic function for a VM or User tag.
|
| + kStubFunction, // Synthetic function for stub code.
|
| + kUnknownFunction, // A singleton function for unknown objects.
|
| + };
|
| +
|
| + ProfileFunction(Kind kind,
|
| + const char* name,
|
| + const Function& function,
|
| + const intptr_t table_index);
|
| +
|
| + const char* name() const {
|
| + ASSERT(name_ != NULL);
|
| + return name_;
|
| + }
|
| +
|
| + RawFunction* function() const {
|
| + return function_.raw();
|
| + }
|
| +
|
| + intptr_t table_index() const {
|
| + return table_index_;
|
| + }
|
| +
|
| + Kind kind() const {
|
| + return kind_;
|
| + }
|
| +
|
| + intptr_t exclusive_ticks() const { return exclusive_ticks_; }
|
| + intptr_t inclusive_ticks() const { return inclusive_ticks_; }
|
| +
|
| + void IncInclusiveTicks() {
|
| + inclusive_ticks_++;
|
| + }
|
| +
|
| + void Tick(bool exclusive, intptr_t inclusive_serial);
|
| +
|
| + static const char* KindToCString(Kind kind);
|
| +
|
| + void PrintToJSONArray(JSONArray* functions);
|
| +
|
| + private:
|
| + const Kind kind_;
|
| + const char* name_;
|
| + const Function& function_;
|
| + const intptr_t table_index_;
|
| + ZoneGrowableArray<intptr_t> profile_codes_;
|
| +
|
| + intptr_t exclusive_ticks_;
|
| + intptr_t inclusive_ticks_;
|
| + intptr_t inclusive_serial_;
|
| +
|
| + void PrintToJSONObject(JSONObject* func);
|
| + // A |ProfileCode| that contains this function.
|
| + void AddProfileCode(intptr_t code_table_index);
|
| +
|
| + friend class ProfileCode;
|
| + friend class ProfileBuilder;
|
| +};
|
| +
|
| +
|
| +class ProfileCodeAddress {
|
| + public:
|
| + explicit ProfileCodeAddress(uword pc);
|
| +
|
| + void Tick(bool exclusive);
|
| +
|
| + uword pc() const { return pc_; }
|
| + intptr_t exclusive_ticks() const { return exclusive_ticks_; }
|
| + intptr_t inclusive_ticks() const { return inclusive_ticks_; }
|
| +
|
| + private:
|
| + uword pc_;
|
| + intptr_t exclusive_ticks_;
|
| + intptr_t inclusive_ticks_;
|
| +};
|
| +
|
| +
|
| +// Profile data related to a |Code|.
|
| +class ProfileCode : public ZoneAllocated {
|
| + public:
|
| + enum Kind {
|
| + kDartCode, // Live Dart code.
|
| + kCollectedCode, // Dead Dart code.
|
| + kNativeCode, // Native code.
|
| + kReusedCode, // Dead Dart code that has been reused by new kDartCode.
|
| + kTagCode, // A special kind of code representing a tag.
|
| + };
|
| +
|
| + ProfileCode(Kind kind,
|
| + uword start,
|
| + uword end,
|
| + int64_t timestamp,
|
| + const Code& code);
|
| +
|
| + Kind kind() const { return kind_; }
|
| +
|
| + uword start() const { return start_; }
|
| + void set_start(uword start) { start_ = start; }
|
| +
|
| + uword end() const { return end_; }
|
| + void set_end(uword end) { end_ = end; }
|
| +
|
| + void AdjustExtent(uword start, uword end);
|
| +
|
| + bool Contains(uword pc) const {
|
| + return (pc >= start_) && (pc < end_);
|
| + }
|
| +
|
| + bool Overlaps(const ProfileCode* other) const;
|
| +
|
| + int64_t compile_timestamp() const { return compile_timestamp_; }
|
| + void set_compile_timestamp(int64_t timestamp) {
|
| + compile_timestamp_ = timestamp;
|
| + }
|
| +
|
| + intptr_t exclusive_ticks() const { return exclusive_ticks_; }
|
| + void set_exclusive_ticks(intptr_t exclusive_ticks) {
|
| + exclusive_ticks_ = exclusive_ticks;
|
| + }
|
| + void IncExclusiveTicks() {
|
| + exclusive_ticks_++;
|
| + }
|
| +
|
| + intptr_t inclusive_ticks() const { return inclusive_ticks_; }
|
| + void set_inclusive_ticks(intptr_t inclusive_ticks) {
|
| + inclusive_ticks_ = inclusive_ticks;
|
| + }
|
| + void IncInclusiveTicks() {
|
| + inclusive_ticks_++;
|
| + }
|
| +
|
| + bool IsOptimizedDart() const;
|
| + RawCode* code() const {
|
| + return code_.raw();
|
| + }
|
| +
|
| + const char* name() const { return name_; }
|
| + void SetName(const char* name);
|
| + void GenerateAndSetSymbolName(const char* prefix);
|
| +
|
| + static const char* KindToCString(Kind kind);
|
| +
|
| + void PrintToJSONArray(JSONArray* codes);
|
| +
|
| + private:
|
| + void Tick(uword pc, bool exclusive, intptr_t serial);
|
| + void TickAddress(uword pc, bool exclusive);
|
| +
|
| + ProfileFunction* SetFunctionAndName(ProfileFunctionTable* table);
|
| +
|
| + ProfileFunction* function() const {
|
| + return function_;
|
| + }
|
| +
|
| + void PrintNativeCode(JSONObject* profile_code_obj);
|
| + void PrintCollectedCode(JSONObject* profile_code_obj);
|
| + void PrintOverwrittenCode(JSONObject* profile_code_obj);
|
| + void PrintTagCode(JSONObject* profile_code_obj);
|
| +
|
| + void set_code_table_index(intptr_t index) { code_table_index_ = index; }
|
| + intptr_t code_table_index() const { return code_table_index_; }
|
| +
|
| + const Kind kind_;
|
| + uword start_;
|
| + uword end_;
|
| + intptr_t exclusive_ticks_;
|
| + intptr_t inclusive_ticks_;
|
| + intptr_t inclusive_serial_;
|
| +
|
| + const Code& code_;
|
| + const char* name_;
|
| + int64_t compile_timestamp_;
|
| + ProfileFunction* function_;
|
| + intptr_t code_table_index_;
|
| + ZoneGrowableArray<ProfileCodeAddress> address_ticks_;
|
| +
|
| + friend class ProfileBuilder;
|
| +};
|
| +
|
| +
|
| +// Stack traces are organized in a trie. This holds information about one node
|
| +// in the trie. A node in a tree represents a stack frame and a path in the tree
|
| +// represents a stack trace. Each unique stack trace appears in the tree once
|
| +// and each node has a count indicating how many times this has been observed.
|
| +// The index can be used to look up a |ProfileFunction| or |ProfileCode|.
|
| +// A node can have zero or more children. Depending on the kind of trie the
|
| +// children are callers or callees of the current node.
|
| +class ProfileTrieNode : public ZoneAllocated {
|
| + public:
|
| + explicit ProfileTrieNode(intptr_t index);
|
| + virtual ~ProfileTrieNode();
|
| +
|
| + virtual void PrintToJSONArray(JSONArray* array) const = 0;
|
| +
|
| + // Index into function or code tables.
|
| + intptr_t table_index() const { return table_index_; }
|
| +
|
| + intptr_t count() const { return count_; }
|
| +
|
| + void Tick() {
|
| + count_++;
|
| + }
|
| +
|
| + intptr_t NumChildren() const {
|
| + return children_.length();
|
| + }
|
| +
|
| + ProfileTrieNode* At(intptr_t i) {
|
| + return children_.At(i);
|
| + }
|
| +
|
| + protected:
|
| + void SortChildren();
|
| +
|
| + static int ProfileTrieNodeCompare(ProfileTrieNode* const* a,
|
| + ProfileTrieNode* const* b) {
|
| + ASSERT(a != NULL);
|
| + ASSERT(b != NULL);
|
| + return (*b)->count() - (*a)->count();
|
| + }
|
| +
|
| +
|
| + intptr_t table_index_;
|
| + intptr_t count_;
|
| + ZoneGrowableArray<ProfileTrieNode*> children_;
|
| +
|
| + friend class ProfileBuilder;
|
| +};
|
| +
|
| +
|
| +// The model for a profile. Most of the model is zone allocated, therefore
|
| +// a zone must be created that lives longer than this object.
|
| +class Profile : public ValueObject {
|
| public:
|
| enum TagOrder {
|
| kNoTags,
|
| @@ -31,8 +277,57 @@ class ProfilerService : public AllStatic {
|
| kVMUser
|
| };
|
|
|
| + enum TrieKind {
|
| + kExclusiveCode,
|
| + kExclusiveFunction,
|
| + kInclusiveCode,
|
| + kInclusiveFunction,
|
| + kNumTrieKinds,
|
| + };
|
| +
|
| + explicit Profile(Isolate* isolate);
|
| +
|
| + // Build a filtered model using |filter| with the specified |tag_order|.
|
| + void Build(SampleFilter* filter, TagOrder tag_order);
|
| +
|
| + // After building:
|
| + int64_t min_time() const { return min_time_; }
|
| + int64_t max_time() const { return max_time_; }
|
| + int64_t GetTimeSpan() const {
|
| + return max_time() - min_time();
|
| + }
|
| + intptr_t sample_count() const { return sample_count_; }
|
| +
|
| + ProfileFunction* GetFunction(intptr_t index);
|
| + ProfileCode* GetCode(intptr_t index);
|
| + ProfileTrieNode* GetTrieRoot(TrieKind trie_kind);
|
| +
|
| + void PrintJSON(JSONStream* stream);
|
| +
|
| + private:
|
| + Isolate* isolate_;
|
| + ProfileCodeTable* live_code_;
|
| + ProfileCodeTable* dead_code_;
|
| + ProfileCodeTable* tag_code_;
|
| + ProfileFunctionTable* functions_;
|
| + intptr_t dead_code_index_offset_;
|
| + intptr_t tag_code_index_offset_;
|
| +
|
| + ProfileTrieNode* roots_[kNumTrieKinds];
|
| +
|
| + int64_t min_time_;
|
| + int64_t max_time_;
|
| +
|
| + intptr_t sample_count_;
|
| +
|
| + friend class ProfileBuilder;
|
| +};
|
| +
|
| +
|
| +class ProfilerService : public AllStatic {
|
| + public:
|
| static void PrintJSON(JSONStream* stream,
|
| - TagOrder tag_order);
|
| + Profile::TagOrder tag_order);
|
|
|
| static void ClearSamples();
|
| };
|
|
|