summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--base/tracked_objects.cc123
-rw-r--r--base/tracked_objects.h53
-rw-r--r--base/tracked_objects_unittest.cc48
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\":{"