diff options
-rw-r--r-- | base/tracked_objects.cc | 123 | ||||
-rw-r--r-- | base/tracked_objects.h | 53 | ||||
-rw-r--r-- | base/tracked_objects_unittest.cc | 48 |
3 files changed, 176 insertions, 48 deletions
diff --git a/base/tracked_objects.cc b/base/tracked_objects.cc index 7c04747..2885eb0 100644 --- a/base/tracked_objects.cc +++ b/base/tracked_objects.cc @@ -31,35 +31,27 @@ static const ThreadData::Status kInitialStartupState = ThreadData::ACTIVE; } // anonymous namespace. //------------------------------------------------------------------------------ -// Death data tallies durations when a death takes place. +// DeathData tallies durations when a death takes place. void DeathData::RecordDeath(const Duration& queue_duration, const Duration& run_duration) { ++count_; - queue_duration_ += queue_duration; - run_duration_ += run_duration; + queue_time_.AddDuration(queue_duration); + run_time_.AddDuration(run_duration); } int DeathData::AverageMsRunDuration() const { - if (run_duration_ == Duration() || !count_) - return 0; - // Add half of denominator to achieve rounding. - return static_cast<int>(run_duration_.InMilliseconds() + count_ / 2) / - count_; + return run_time_.AverageMsDuration(count_); } int DeathData::AverageMsQueueDuration() const { - if (queue_duration_ == Duration() || !count_) - return 0; - // Add half of denominator to achieve rounding. - return (static_cast<int>(queue_duration_.InMilliseconds() + count_ / 2) / - count_); + return queue_time_.AverageMsDuration(count_); } void DeathData::AddDeathData(const DeathData& other) { count_ += other.count_; - queue_duration_ += other.queue_duration_; - run_duration_ += other.run_duration_; + queue_time_.AddData(other.queue_time_); + run_time_.AddData(other.run_time_); } void DeathData::WriteHTML(std::string* output) const { @@ -67,33 +59,74 @@ void DeathData::WriteHTML(std::string* output) const { return; base::StringAppendF(output, "%s:%d, ", (count_ == 1) ? "Life" : "Lives", count_); - // Be careful to leave static_casts intact, as the type returned by - // InMilliseconds() may not always be an int, even if it can generally fit - // into an int. - base::StringAppendF(output, "Run:%dms(%dms/life) ", - static_cast<int>(run_duration_.InMilliseconds()), - AverageMsRunDuration()); - base::StringAppendF(output, "Queue:%dms(%dms/life) ", - static_cast<int>(queue_duration_.InMilliseconds()), - AverageMsQueueDuration()); + output->append("Run:"); + run_time_.WriteHTML(count_, output); + + output->append("Queue:"); + queue_time_.WriteHTML(count_, output); } base::DictionaryValue* DeathData::ToValue() const { base::DictionaryValue* dictionary = new base::DictionaryValue; dictionary->Set("count", base::Value::CreateIntegerValue(count_)); dictionary->Set("run_ms", - base::Value::CreateIntegerValue(run_duration_.InMilliseconds())); + base::Value::CreateIntegerValue(run_time_.duration().InMilliseconds())); dictionary->Set("queue_ms", - base::Value::CreateIntegerValue(queue_duration_.InMilliseconds())); + base::Value::CreateIntegerValue(queue_time_.duration().InMilliseconds())); + dictionary->Set("run_ms_max", + base::Value::CreateIntegerValue(run_time_.max().InMilliseconds())); + dictionary->Set("queue_ms_max", + base::Value::CreateIntegerValue(queue_time_.max().InMilliseconds())); return dictionary; } void DeathData::Clear() { count_ = 0; - queue_duration_ = Duration(); - run_duration_ = Duration(); + run_time_.Clear(); + queue_time_.Clear(); +} + +//------------------------------------------------------------------------------ + +void DeathData::Data::WriteHTML(int count, std::string* output) const { + // Be careful to leave static_casts intact, as the type returned by + // InMilliseconds() may not always be an int, even if it can generally fit + // into an int. + base::StringAppendF(output, "%dms", + static_cast<int>(duration_.InMilliseconds())); + if (count == 1) { + output->append(" "); + return; + } + base::StringAppendF(output, "(%dms/life,max:%dms) ", + AverageMsDuration(count), + static_cast<int>(max_.InMilliseconds())); +} + +void DeathData::Data::AddData(const Data& other) { + duration_ += other.duration_; + if (max_ > other.max_) + return; + max_ = other.max_; } +void DeathData::Data::AddDuration(const Duration& duration) { + duration_ += duration; + if (max_ > duration) + return; + max_ = duration; +} + +int DeathData::Data::AverageMsDuration(int count) const { + if (duration_ == Duration() || !count) + return 0; + return static_cast<int>(duration_.InMilliseconds() + count / 2) / count; +} + +void DeathData::Data::Clear() { + duration_ = Duration(); + max_ = Duration(); +} //------------------------------------------------------------------------------ BirthOnThread::BirthOnThread(const Location& location, const ThreadData& current) @@ -156,7 +189,7 @@ ThreadData::ThreadData() thread_number = ++thread_number_counter_; } base::StringAppendF(&thread_name_, "WorkerThread-%d", thread_number); - PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. + PushToHeadOfList(); // Which sets real incarnation_count_for_pool_. } ThreadData::~ThreadData() {} @@ -268,8 +301,10 @@ void ThreadData::WriteHTML(const std::string& query, std::string* output) { "<li><b>Count</b> Number of instances seen." "<li><b>Duration</b> Average duration in ms of Run() time." "<li><b>TotalDuration</b> Summed durations in ms of Run() times." + "<li><b>MaxDuration</b> Largest duration in ms of Run() times." "<li><b>AverageQueueDuration</b> Average duration in ms of queueing time." - "<li><b>TotalQueueDuration</b> Summed durations in ms of Run() times." + "<li><b>TotalQueueDuration</b> Summed queuing durations in ms." + "<li><b>MaxQueueDuration</b> Largest duration in ms of queueing times." "<li><b>Birth</b> Thread on which the task was constructed." "<li><b>Death</b> Thread on which the task was run and deleted." "<li><b>File</b> File in which the task was contructed." @@ -833,10 +868,14 @@ Comparator::Selector Comparator::FindSelector(const std::string& keyword) { return TOTAL_RUN_DURATION; if (0 == keyword.compare("duration")) return AVERAGE_RUN_DURATION; + if (0 == keyword.compare("maxduration")) + return MAX_RUN_DURATION; if (0 == keyword.compare("totalqueueduration")) return TOTAL_QUEUE_DURATION; if (0 == keyword.compare("averagequeueduration")) return AVERAGE_QUEUE_DURATION; + if (0 == keyword.compare("maxqueueduration")) + return MAX_QUEUE_DURATION; if (0 == keyword.compare("birth")) return BIRTH_THREAD; if (0 == keyword.compare("death")) @@ -919,6 +958,13 @@ bool Comparator::operator()(const Snapshot& left, return left.run_duration() > right.run_duration(); break; + case MAX_RUN_DURATION: + if (!left.count() || !right.count()) + break; + if (left.run_duration_max() != right.run_duration_max()) + return left.run_duration_max() > right.run_duration_max(); + break; + case AVERAGE_QUEUE_DURATION: if (!left.count() || !right.count()) break; @@ -933,6 +979,13 @@ bool Comparator::operator()(const Snapshot& left, return left.queue_duration() > right.queue_duration(); break; + case MAX_QUEUE_DURATION: + if (!left.count() || !right.count()) + break; + if (left.queue_duration_max() != right.queue_duration_max()) + return left.queue_duration_max() > right.queue_duration_max(); + break; + default: break; } @@ -962,6 +1015,8 @@ bool Comparator::Equivalent(const Snapshot& left, break; case BIRTH_FILE: + if (!required_.empty()) + break; // No reason to aggregate when we've filtered out some. if (left.location().file_name() != right.location().file_name()) { int comp = strcmp(left.location().file_name(), right.location().file_name()); @@ -971,6 +1026,8 @@ bool Comparator::Equivalent(const Snapshot& left, break; case BIRTH_FUNCTION: + if (!required_.empty()) + break; // No reason to aggregate when we've filtered out some. if (left.location().function_name() != right.location().function_name()) { int comp = strcmp(left.location().function_name(), right.location().function_name()); @@ -982,8 +1039,10 @@ bool Comparator::Equivalent(const Snapshot& left, case COUNT: case AVERAGE_RUN_DURATION: case TOTAL_RUN_DURATION: + case MAX_RUN_DURATION: case AVERAGE_QUEUE_DURATION: case TOTAL_QUEUE_DURATION: + case MAX_QUEUE_DURATION: // We don't produce separate aggretation when only counts or times differ. break; @@ -1101,6 +1160,10 @@ bool Comparator::ParseQuery(const std::string& query) { SetSubgroupTiebreaker(COUNT); SetSubgroupTiebreaker(AVERAGE_RUN_DURATION); SetSubgroupTiebreaker(TOTAL_RUN_DURATION); + SetSubgroupTiebreaker(MAX_RUN_DURATION); + SetSubgroupTiebreaker(AVERAGE_QUEUE_DURATION); + SetSubgroupTiebreaker(TOTAL_QUEUE_DURATION); + SetSubgroupTiebreaker(MAX_QUEUE_DURATION); SetSubgroupTiebreaker(BIRTH_THREAD); SetSubgroupTiebreaker(DEATH_THREAD); SetSubgroupTiebreaker(BIRTH_FUNCTION); diff --git a/base/tracked_objects.h b/base/tracked_objects.h index a3735d2..46986e6 100644 --- a/base/tracked_objects.h +++ b/base/tracked_objects.h @@ -333,10 +333,12 @@ class BASE_EXPORT DeathData { // Metrics accessors. int count() const { return count_; } - Duration run_duration() const { return run_duration_; } + Duration run_duration() const { return run_time_.duration(); } int AverageMsRunDuration() const; - Duration queue_duration() const { return queue_duration_; } + Duration run_duration_max() const { return run_time_.max(); } + Duration queue_duration() const { return queue_time_.duration(); } int AverageMsQueueDuration() const; + Duration queue_duration_max() const { return queue_time_.max(); } // Accumulate metrics from other into this. This method is never used on // realtime statistics, and only used in snapshots and aggregatinos. @@ -353,9 +355,40 @@ class BASE_EXPORT DeathData { void Clear(); private: - int count_; // Number of destructions. - Duration run_duration_; // Sum of all Run()time durations. - Duration queue_duration_; // Sum of all queue time durations. + // DeathData::Data is a helper class, useful when different metrics need to be + // aggregated, such as queueing times, or run times. + class Data { + public: + Data() {} + ~Data() {} + + Duration duration() const { return duration_; } + Duration max() const { return max_; } + + // Emits HTML formated description of members, assuming |count| instances + // when calculating averages. + void WriteHTML(int count, std::string* output) const; + + // Agggegate data into our state. + void AddData(const Data& other); + void AddDuration(const Duration& duration); + + // Central helper function for calculating averages (correctly, in only one + // place). + int AverageMsDuration(int count) const; + + // Resets all members to zero. + void Clear(); + + private: + Duration duration_; // Sum of all durations seen. + Duration max_; // Largest singular duration seen. + }; + + + int count_; // Number of deaths seen. + Data run_time_; // Data about run time durations. + Data queue_time_; // Data about queueing times durations. }; //------------------------------------------------------------------------------ @@ -383,13 +416,19 @@ class BASE_EXPORT Snapshot { int count() const { return death_data_.count(); } Duration run_duration() const { return death_data_.run_duration(); } - Duration queue_duration() const { return death_data_.queue_duration(); } int AverageMsRunDuration() const { return death_data_.AverageMsRunDuration(); } + Duration run_duration_max() const { + return death_data_.run_duration_max(); + } + Duration queue_duration() const { return death_data_.queue_duration(); } int AverageMsQueueDuration() const { return death_data_.AverageMsQueueDuration(); } + Duration queue_duration_max() const { + return death_data_.queue_duration_max(); + } // Emit contents for use in a line of HTML void WriteHTML(std::string* output) const; @@ -509,6 +548,8 @@ class BASE_EXPORT Comparator { TOTAL_RUN_DURATION = 128, AVERAGE_QUEUE_DURATION = 256, TOTAL_QUEUE_DURATION = 512, + MAX_RUN_DURATION = 1024, + MAX_QUEUE_DURATION = 2048, // Imediate action keywords. RESET_ALL_DATA = -1, diff --git a/base/tracked_objects_unittest.cc b/base/tracked_objects_unittest.cc index 5866f84..67302fc 100644 --- a/base/tracked_objects_unittest.cc +++ b/base/tracked_objects_unittest.cc @@ -149,14 +149,22 @@ TEST_F(TrackedObjectsTest, DeathDataTest) { std::string output; data->WriteHTML(&output); - std::string results = "Lives:2, Run:84ms(42ms/life) Queue:16ms(8ms/life) "; - EXPECT_EQ(output, results); + std::string results = "Lives:2, " + "Run:84ms(42ms/life,max:42ms) " + "Queue:16ms(8ms/life,max:8ms) "; + EXPECT_EQ(results, output); scoped_ptr<base::Value> value(data->ToValue()); std::string json; base::JSONWriter::Write(value.get(), false, &json); - std::string birth_only_result = "{\"count\":2,\"queue_ms\":16,\"run_ms\":84}"; - EXPECT_EQ(json, birth_only_result); + std::string birth_only_result = "{" + "\"count\":2," + "\"queue_ms\":16," + "\"queue_ms_max\":8," + "\"run_ms\":84," + "\"run_ms_max\":42" + "}"; + EXPECT_EQ(birth_only_result, json); } TEST_F(TrackedObjectsTest, DeactivatedBirthOnlyToValueWorkerThread) { @@ -231,7 +239,9 @@ TEST_F(TrackedObjectsTest, BirthOnlyToValueWorkerThread) { "\"death_data\":{" "\"count\":1," "\"queue_ms\":0," - "\"run_ms\":0" + "\"queue_ms_max\":0," + "\"run_ms\":0," + "\"run_ms_max\":0" "}," "\"death_thread\":\"Still_Alive\"," "\"location\":{" @@ -269,7 +279,9 @@ TEST_F(TrackedObjectsTest, BirthOnlyToValueMainThread) { "\"death_data\":{" "\"count\":1," "\"queue_ms\":0," - "\"run_ms\":0" + "\"queue_ms_max\":0," + "\"run_ms\":0," + "\"run_ms_max\":0" "}," "\"death_thread\":\"Still_Alive\"," "\"location\":{" @@ -320,7 +332,9 @@ TEST_F(TrackedObjectsTest, LifeCycleToValueMainThread) { "\"death_data\":{" "\"count\":1," "\"queue_ms\":4," - "\"run_ms\":2" + "\"queue_ms_max\":4," + "\"run_ms\":2," + "\"run_ms_max\":2" "}," "\"death_thread\":\"SomeMainThreadName\"," "\"location\":{" @@ -378,7 +392,9 @@ TEST_F(TrackedObjectsTest, LifeCycleMidDeactivatedToValueMainThread) { "\"death_data\":{" "\"count\":1," "\"queue_ms\":4," - "\"run_ms\":2" + "\"queue_ms_max\":4," + "\"run_ms\":2," + "\"run_ms_max\":2" "}," "\"death_thread\":\"SomeMainThreadName\"," "\"location\":{" @@ -463,7 +479,9 @@ TEST_F(TrackedObjectsTest, LifeCycleToValueWorkerThread) { "\"death_data\":{" "\"count\":1," "\"queue_ms\":4," - "\"run_ms\":2" + "\"queue_ms_max\":4," + "\"run_ms\":2," + "\"run_ms_max\":2" "}," "\"death_thread\":\"WorkerThread-1\"," "\"location\":{" @@ -522,7 +540,9 @@ TEST_F(TrackedObjectsTest, TwoLives) { "\"death_data\":{" "\"count\":2," "\"queue_ms\":8," - "\"run_ms\":4" + "\"queue_ms_max\":4," + "\"run_ms\":4," + "\"run_ms_max\":2" "}," "\"death_thread\":\"SomeFileThreadName\"," "\"location\":{" @@ -577,7 +597,9 @@ TEST_F(TrackedObjectsTest, DifferentLives) { "\"death_data\":{" "\"count\":1," "\"queue_ms\":4," - "\"run_ms\":2" + "\"queue_ms_max\":4," + "\"run_ms\":2," + "\"run_ms_max\":2" "}," "\"death_thread\":\"SomeFileThreadName\"," "\"location\":{" @@ -591,7 +613,9 @@ TEST_F(TrackedObjectsTest, DifferentLives) { "\"death_data\":{" "\"count\":1," "\"queue_ms\":0," - "\"run_ms\":0" + "\"queue_ms_max\":0," + "\"run_ms\":0," + "\"run_ms_max\":0" "}," "\"death_thread\":\"Still_Alive\"," "\"location\":{" |