| Index: src/profile-generator.h
|
| diff --git a/src/profile-generator.h b/src/profile-generator.h
|
| index b02ba8575ef94e5e3e2c20cceb35fede20a50c13..bd5b0cd24f64fba67eaf68a5c2ed805810072391 100644
|
| --- a/src/profile-generator.h
|
| +++ b/src/profile-generator.h
|
| @@ -70,9 +70,11 @@ class CodeEntry {
|
| };
|
|
|
|
|
| +class ProfileTree;
|
| +
|
| class ProfileNode {
|
| public:
|
| - INLINE(explicit ProfileNode(CodeEntry* entry));
|
| + INLINE(ProfileNode(ProfileTree* tree, CodeEntry* entry));
|
|
|
| ProfileNode* FindChild(CodeEntry* entry);
|
| ProfileNode* FindOrAddChild(CodeEntry* entry);
|
| @@ -80,9 +82,11 @@ class ProfileNode {
|
| INLINE(void IncreaseTotalTicks(unsigned amount)) { total_ticks_ += amount; }
|
|
|
| INLINE(CodeEntry* entry() const) { return entry_; }
|
| - INLINE(unsigned total_ticks() const) { return total_ticks_; }
|
| INLINE(unsigned self_ticks() const) { return self_ticks_; }
|
| + INLINE(unsigned total_ticks() const) { return total_ticks_; }
|
| INLINE(const List<ProfileNode*>* children() const) { return &children_list_; }
|
| + double GetSelfMillis() const;
|
| + double GetTotalMillis() const;
|
|
|
| void Print(int indent);
|
|
|
| @@ -95,6 +99,7 @@ class ProfileNode {
|
| return static_cast<int32_t>(reinterpret_cast<intptr_t>(entry));
|
| }
|
|
|
| + ProfileTree* tree_;
|
| CodeEntry* entry_;
|
| unsigned total_ticks_;
|
| unsigned self_ticks_;
|
| @@ -115,7 +120,11 @@ class ProfileTree {
|
| void AddPathFromStart(const Vector<CodeEntry*>& path);
|
| void CalculateTotalTicks();
|
|
|
| + double TicksToMillis(unsigned ticks) const {
|
| + return ticks * ms_to_ticks_scale_;
|
| + }
|
| ProfileNode* root() const { return root_; }
|
| + void SetTickRatePerMs(double ticks_per_ms);
|
|
|
| void ShortPrint();
|
| void Print() {
|
| @@ -124,10 +133,11 @@ class ProfileTree {
|
|
|
| private:
|
| template <typename Callback>
|
| - void TraverseBreadthFirstPostOrder(Callback* callback);
|
| + void TraverseDepthFirstPostOrder(Callback* callback);
|
|
|
| CodeEntry root_entry_;
|
| ProfileNode* root_;
|
| + double ms_to_ticks_scale_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(ProfileTree);
|
| };
|
| @@ -141,12 +151,15 @@ class CpuProfile {
|
| // Add pc -> ... -> main() call path to the profile.
|
| void AddPath(const Vector<CodeEntry*>& path);
|
| void CalculateTotalTicks();
|
| + void SetActualSamplingRate(double actual_sampling_rate);
|
|
|
| INLINE(const char* title() const) { return title_; }
|
| INLINE(unsigned uid() const) { return uid_; }
|
| INLINE(const ProfileTree* top_down() const) { return &top_down_; }
|
| INLINE(const ProfileTree* bottom_up() const) { return &bottom_up_; }
|
|
|
| + void UpdateTicksScale();
|
| +
|
| void ShortPrint();
|
| void Print();
|
|
|
| @@ -208,8 +221,8 @@ class CpuProfilesCollection {
|
|
|
| bool StartProfiling(const char* title, unsigned uid);
|
| bool StartProfiling(String* title, unsigned uid);
|
| - CpuProfile* StopProfiling(const char* title);
|
| - CpuProfile* StopProfiling(String* title);
|
| + CpuProfile* StopProfiling(const char* title, double actual_sampling_rate);
|
| + CpuProfile* StopProfiling(String* title, double actual_sampling_rate);
|
| INLINE(List<CpuProfile*>* profiles()) { return &profiles_; }
|
| CpuProfile* GetProfile(unsigned uid);
|
| inline bool is_last_profile();
|
| @@ -256,6 +269,42 @@ class CpuProfilesCollection {
|
| };
|
|
|
|
|
| +class SampleRateCalculator {
|
| + public:
|
| + SampleRateCalculator()
|
| + : result_(Logger::kSamplingIntervalMs * kResultScale),
|
| + ticks_per_ms_(Logger::kSamplingIntervalMs),
|
| + measurements_count_(0),
|
| + wall_time_query_countdown_(1) {
|
| + }
|
| +
|
| + double ticks_per_ms() {
|
| + return result_ / static_cast<double>(kResultScale);
|
| + }
|
| + void Tick();
|
| + void UpdateMeasurements(double current_time);
|
| +
|
| + // Instead of querying current wall time each tick,
|
| + // we use this constant to control query intervals.
|
| + static const unsigned kWallTimeQueryIntervalMs = 100;
|
| +
|
| + private:
|
| + // As the result needs to be accessed from a different thread, we
|
| + // use type that guarantees atomic writes to memory. There should
|
| + // be <= 1000 ticks per second, thus storing a value of a 10 ** 5
|
| + // order should provide enough precision while keeping away from a
|
| + // potential overflow.
|
| + static const int kResultScale = 100000;
|
| +
|
| + AtomicWord result_;
|
| + // All other fields are accessed only from the sampler thread.
|
| + double ticks_per_ms_;
|
| + unsigned measurements_count_;
|
| + unsigned wall_time_query_countdown_;
|
| + double last_wall_time_;
|
| +};
|
| +
|
| +
|
| class ProfileGenerator {
|
| public:
|
| explicit ProfileGenerator(CpuProfilesCollection* profiles);
|
| @@ -287,6 +336,11 @@ class ProfileGenerator {
|
|
|
| INLINE(CodeMap* code_map()) { return &code_map_; }
|
|
|
| + INLINE(void Tick()) { sample_rate_calc_.Tick(); }
|
| + INLINE(double actual_sampling_rate()) {
|
| + return sample_rate_calc_.ticks_per_ms();
|
| + }
|
| +
|
| static const char* kAnonymousFunctionName;
|
| static const char* kProgramEntryName;
|
| static const char* kGarbageCollectorEntryName;
|
| @@ -298,6 +352,7 @@ class ProfileGenerator {
|
| CodeMap code_map_;
|
| CodeEntry* program_entry_;
|
| CodeEntry* gc_entry_;
|
| + SampleRateCalculator sample_rate_calc_;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(ProfileGenerator);
|
| };
|
|
|