1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/performance_monitor/performance_monitor_handler.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/time/time.h"
11 #include "base/values.h"
12 #include "chrome/browser/performance_monitor/database.h"
13 #include "chrome/browser/performance_monitor/event.h"
14 #include "chrome/browser/performance_monitor/metric.h"
15 #include "chrome/browser/performance_monitor/performance_monitor.h"
16 #include "chrome/browser/performance_monitor/performance_monitor_util.h"
17 #include "chrome/browser/ui/webui/performance_monitor/performance_monitor_l10n.h"
18 #include "chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_constants.h"
19 #include "chrome/browser/ui/webui/performance_monitor/performance_monitor_ui_util.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/extensions/value_builder.h"
22 #include "content/public/browser/browser_thread.h"
23 #include "content/public/browser/web_ui.h"
25 using content::BrowserThread;
27 namespace performance_monitor {
30 std::set<MetricType> GetMetricSetForCategory(MetricCategory category) {
31 std::set<MetricType> metric_set;
33 case METRIC_CATEGORY_CPU:
34 metric_set.insert(METRIC_CPU_USAGE);
36 case METRIC_CATEGORY_MEMORY:
37 metric_set.insert(METRIC_SHARED_MEMORY_USAGE);
38 metric_set.insert(METRIC_PRIVATE_MEMORY_USAGE);
40 case METRIC_CATEGORY_TIMING:
41 metric_set.insert(METRIC_STARTUP_TIME);
42 metric_set.insert(METRIC_TEST_STARTUP_TIME);
43 metric_set.insert(METRIC_SESSION_RESTORE_TIME);
44 metric_set.insert(METRIC_PAGE_LOAD_TIME);
46 case METRIC_CATEGORY_NETWORK:
47 metric_set.insert(METRIC_NETWORK_BYTES_READ);
55 std::set<EventType> GetEventSetForCategory(EventCategory category) {
56 std::set<EventType> event_set;
58 case EVENT_CATEGORY_EXTENSIONS:
59 event_set.insert(EVENT_EXTENSION_INSTALL);
60 event_set.insert(EVENT_EXTENSION_UNINSTALL);
61 event_set.insert(EVENT_EXTENSION_UPDATE);
62 event_set.insert(EVENT_EXTENSION_ENABLE);
63 event_set.insert(EVENT_EXTENSION_DISABLE);
65 case EVENT_CATEGORY_CHROME:
66 event_set.insert(EVENT_CHROME_UPDATE);
68 case EVENT_CATEGORY_EXCEPTIONS:
69 event_set.insert(EVENT_RENDERER_HANG);
70 event_set.insert(EVENT_RENDERER_CRASH);
71 event_set.insert(EVENT_RENDERER_KILLED);
72 event_set.insert(EVENT_UNCLEAN_EXIT);
80 Unit GetUnitForMetricCategory(MetricCategory category) {
82 case METRIC_CATEGORY_CPU:
84 case METRIC_CATEGORY_MEMORY:
85 return UNIT_MEGABYTES;
86 case METRIC_CATEGORY_TIMING:
88 case METRIC_CATEGORY_NETWORK:
89 return UNIT_MEGABYTES;
93 return UNIT_UNDEFINED;
96 MetricCategory GetCategoryForMetric(MetricType type) {
98 case METRIC_CPU_USAGE:
99 return METRIC_CATEGORY_CPU;
100 case METRIC_SHARED_MEMORY_USAGE:
101 case METRIC_PRIVATE_MEMORY_USAGE:
102 return METRIC_CATEGORY_MEMORY;
103 case METRIC_STARTUP_TIME:
104 case METRIC_TEST_STARTUP_TIME:
105 case METRIC_SESSION_RESTORE_TIME:
106 case METRIC_PAGE_LOAD_TIME:
107 return METRIC_CATEGORY_TIMING;
108 case METRIC_NETWORK_BYTES_READ:
109 return METRIC_CATEGORY_NETWORK;
113 return METRIC_CATEGORY_NUMBER_OF_CATEGORIES;
116 Unit GetUnitForMetricType(MetricType type) {
118 case METRIC_CPU_USAGE:
120 case METRIC_SHARED_MEMORY_USAGE:
121 case METRIC_PRIVATE_MEMORY_USAGE:
122 case METRIC_NETWORK_BYTES_READ:
124 case METRIC_STARTUP_TIME:
125 case METRIC_TEST_STARTUP_TIME:
126 case METRIC_SESSION_RESTORE_TIME:
127 case METRIC_PAGE_LOAD_TIME:
128 return UNIT_MICROSECONDS;
132 return UNIT_UNDEFINED;
135 // Returns a dictionary for the aggregation method. Aggregation strategies
136 // contain an id representing the method, and localized strings for the
137 // method name and method description.
138 scoped_ptr<DictionaryValue> GetAggregationMethod(
139 AggregationMethod method) {
140 scoped_ptr<DictionaryValue> value(new DictionaryValue());
141 value->SetInteger("id", method);
142 value->SetString("name", GetLocalizedStringFromAggregationMethod(method));
145 GetLocalizedStringForAggregationMethodDescription(method));
149 // Returns a list of metric details, with one entry per metric. Metric details
150 // are dictionaries which contain the id representing the metric and localized
151 // strings for the metric name and metric description.
152 scoped_ptr<ListValue> GetMetricDetailsForCategory(MetricCategory category) {
153 scoped_ptr<ListValue> value(new ListValue());
154 std::set<MetricType> metric_set = GetMetricSetForCategory(category);
155 for (std::set<MetricType>::const_iterator iter = metric_set.begin();
156 iter != metric_set.end(); ++iter) {
157 DictionaryValue* metric_details = new DictionaryValue();
158 metric_details->SetInteger("metricId", *iter);
159 metric_details->SetString(
160 "name", GetLocalizedStringFromMetricType(*iter));
161 metric_details->SetString(
162 "description", GetLocalizedStringForMetricTypeDescription(*iter));
163 value->Append(metric_details);
168 // Returns a dictionary for the metric category. Metric categories contain
169 // an id representing the category; localized strings for the category name,
170 // the default unit in which the category is measured, and the category's
171 // description; and the metric details for each metric type in the category.
172 scoped_ptr<DictionaryValue> GetMetricCategory(MetricCategory category) {
173 scoped_ptr<DictionaryValue> value(new DictionaryValue());
174 value->SetInteger("metricCategoryId", category);
176 "name", GetLocalizedStringFromMetricCategory(category));
179 GetLocalizedStringFromUnit(GetUnitForMetricCategory(category)));
182 GetLocalizedStringForMetricCategoryDescription(category));
183 value->Set("details", GetMetricDetailsForCategory(category).release());
187 // Returns a list of event types, with one entry per event. Event types
188 // are dictionaries which contain the id representing the event and localized
189 // strings for the event name, event description, and a title suitable for a
191 scoped_ptr<ListValue> GetEventTypesForCategory(EventCategory category) {
192 scoped_ptr<ListValue> value(new ListValue());
193 std::set<EventType> event_set = GetEventSetForCategory(category);
194 for (std::set<EventType>::const_iterator iter = event_set.begin();
195 iter != event_set.end(); ++iter) {
196 DictionaryValue* event_details = new DictionaryValue();
197 event_details->SetInteger("eventId", *iter);
198 event_details->SetString(
199 "name", GetLocalizedStringFromEventType(*iter));
200 event_details->SetString(
201 "description", GetLocalizedStringForEventTypeDescription(*iter));
202 event_details->SetString(
203 "popupTitle", GetLocalizedStringForEventTypeMouseover(*iter));
204 value->Append(event_details);
209 // Returns a dictionary for the event category. Event categories contain an
210 // id representing the category, localized strings for the event name and
211 // event description, and event details for each event type in the category.
212 scoped_ptr<DictionaryValue> GetEventCategory(EventCategory category) {
213 scoped_ptr<DictionaryValue> value(new DictionaryValue());
214 value->SetInteger("eventCategoryId", category);
216 "name", GetLocalizedStringFromEventCategory(category));
219 GetLocalizedStringForEventCategoryDescription(category));
220 value->Set("details", GetEventTypesForCategory(category).release());
224 // Queries the performance monitor database for active intervals between
225 // |start| and |end| times and appends the results to |results|.
226 void DoGetActiveIntervals(ListValue* results,
227 const base::Time& start,
228 const base::Time& end) {
229 Database* db = PerformanceMonitor::GetInstance()->database();
233 std::vector<TimeRange> intervals = db->GetActiveIntervals(start, end);
235 for (std::vector<TimeRange>::iterator it = intervals.begin();
236 it != intervals.end(); ++it) {
237 DictionaryValue* interval_value = new DictionaryValue();
238 interval_value->SetDouble("start", it->start.ToJsTime());
239 interval_value->SetDouble("end", it->end.ToJsTime());
240 results->Append(interval_value);
244 // Queries the PerformanceMonitor database for events of type |event_type|
245 // between |start| and |end| times, creates a new event with localized keys
246 // for display, and appends the results to |results|.
247 void DoGetEvents(ListValue* results,
248 const std::set<EventType>& event_types,
249 const base::Time& start,
250 const base::Time& end) {
251 Database* db = PerformanceMonitor::GetInstance()->database();
255 for (std::set<EventType>::const_iterator iter = event_types.begin();
256 iter != event_types.end(); ++iter) {
257 DictionaryValue* event_results = new DictionaryValue();
258 event_results->SetInteger("eventId", static_cast<int>(*iter));
259 ListValue* events = new ListValue();
260 event_results->Set("events", events);
261 results->Append(event_results);
263 Database::EventVector event_vector = db->GetEvents(*iter, start, end);
265 for (Database::EventVector::iterator event = event_vector.begin();
266 event != event_vector.end(); ++event) {
267 DictionaryValue* localized_event = new DictionaryValue();
269 for (DictionaryValue::Iterator data(*(*event)->data()); !data.IsAtEnd();
273 // The property 'eventType' is set in HandleGetEvents as part of the
274 // entire result set, so we don't need to include this here in the
276 if (data.key() == "eventType")
278 else if (data.key() == "time") {
279 // The property 'time' is also used computationally, but must be
280 // converted to JS-style time.
282 if (!data.value().GetAsDouble(&time)) {
283 LOG(ERROR) << "Failed to get 'time' field from event.";
286 value = Value::CreateDoubleValue(
287 base::Time::FromInternalValue(
288 static_cast<int64>(time)).ToJsTime());
290 // All other values are user-facing, so we create a new value for
291 // localized display.
292 DictionaryValue* localized_value = new DictionaryValue();
293 localized_value->SetString(
295 GetLocalizedStringFromEventProperty(data.key()));
296 localized_value->SetWithoutPathExpansion("value",
297 data.value().DeepCopy());
298 value = localized_value;
301 localized_event->SetWithoutPathExpansion(data.key(), value);
303 events->Append(localized_event);
308 // Populates results with a dictionary for each metric requested. The dictionary
309 // includes a metric id, the maximum value for the metric, and a list of lists
310 // of metric points, with each sublist containing the aggregated data for an
311 // interval for which PerformanceMonitor was active. This will also convert
312 // time to JS-style time.
313 void DoGetMetrics(ListValue* results,
314 const std::set<MetricType>& metric_types,
315 const base::Time& start,
316 const base::Time& end,
317 const base::TimeDelta& resolution,
318 AggregationMethod aggregation_method) {
319 Database* db = PerformanceMonitor::GetInstance()->database();
323 std::vector<TimeRange> intervals = db->GetActiveIntervals(start, end);
325 // For each metric type, populate a new dictionary and append it to results.
326 for (std::set<MetricType>::const_iterator metric_type = metric_types.begin();
327 metric_type != metric_types.end(); ++metric_type) {
328 double conversion_factor =
329 GetConversionFactor(*GetUnitDetails(GetUnitForMetricType(*metric_type)),
330 *GetUnitDetails(GetUnitForMetricCategory(
331 GetCategoryForMetric(*metric_type))));
333 DictionaryValue* metric_set = new DictionaryValue();
334 metric_set->SetInteger("metricId", static_cast<int>(*metric_type));
335 metric_set->SetDouble(
337 db->GetMaxStatsForActivityAndMetric(*metric_type) * conversion_factor);
339 // Retrieve all metrics in the database, and aggregate them into a series
340 // of points for each active interval.
341 scoped_ptr<Database::MetricVector> metric_vector =
342 db->GetStatsForActivityAndMetric(*metric_type, start, end);
344 scoped_ptr<VectorOfMetricVectors> aggregated_metrics =
345 AggregateMetric(*metric_type,
352 // The JS-side expects a list to be present, even if there are no metrics.
353 if (!aggregated_metrics) {
354 metric_set->Set("metrics", new ListValue());
355 results->Append(metric_set);
359 ListValue* metric_points_by_interval = new ListValue();
361 // For each metric point, record it in the expected format for the JS-side
362 // (a dictionary of time and value, with time as a JS-style time), and
363 // convert the values to be display-friendly.
364 for (VectorOfMetricVectors::const_iterator metric_series =
365 aggregated_metrics->begin();
366 metric_series != aggregated_metrics->end(); ++metric_series) {
367 ListValue* series_value = new ListValue();
368 for (Database::MetricVector::const_iterator metric_point =
369 metric_series->begin();
370 metric_point != metric_series->end(); ++metric_point) {
371 DictionaryValue* point_value = new DictionaryValue();
372 point_value->SetDouble("time", metric_point->time.ToJsTime());
373 point_value->SetDouble("value",
374 metric_point->value * conversion_factor);
375 series_value->Append(point_value);
377 metric_points_by_interval->Append(series_value);
380 metric_set->Set("metrics", metric_points_by_interval);
381 results->Append(metric_set);
387 PerformanceMonitorHandler::PerformanceMonitorHandler() {
390 PerformanceMonitorHandler::~PerformanceMonitorHandler() {}
392 void PerformanceMonitorHandler::RegisterMessages() {
393 web_ui()->RegisterMessageCallback(
394 "getActiveIntervals",
395 base::Bind(&PerformanceMonitorHandler::HandleGetActiveIntervals,
397 web_ui()->RegisterMessageCallback(
399 base::Bind(&PerformanceMonitorHandler::HandleGetFlagEnabled,
401 web_ui()->RegisterMessageCallback(
402 "getAggregationTypes",
403 base::Bind(&PerformanceMonitorHandler::HandleGetAggregationTypes,
405 web_ui()->RegisterMessageCallback(
407 base::Bind(&PerformanceMonitorHandler::HandleGetEventTypes,
409 web_ui()->RegisterMessageCallback(
411 base::Bind(&PerformanceMonitorHandler::HandleGetEvents,
413 web_ui()->RegisterMessageCallback(
415 base::Bind(&PerformanceMonitorHandler::HandleGetMetricTypes,
417 web_ui()->RegisterMessageCallback(
419 base::Bind(&PerformanceMonitorHandler::HandleGetMetrics,
423 void PerformanceMonitorHandler::ReturnResults(const std::string& function,
424 const Value* results) {
425 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
426 web_ui()->CallJavascriptFunction(function, *results);
429 void PerformanceMonitorHandler::HandleGetActiveIntervals(
430 const ListValue* args) {
431 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
432 CHECK_EQ(2u, args->GetSize());
433 double double_time = 0.0;
434 CHECK(args->GetDouble(0, &double_time));
435 base::Time start = base::Time::FromJsTime(double_time);
436 CHECK(args->GetDouble(1, &double_time));
437 base::Time end = base::Time::FromJsTime(double_time);
439 ListValue* results = new ListValue();
440 util::PostTaskToDatabaseThreadAndReply(
442 base::Bind(&DoGetActiveIntervals, results, start, end),
443 base::Bind(&PerformanceMonitorHandler::ReturnResults, AsWeakPtr(),
444 "PerformanceMonitor.getActiveIntervalsCallback",
445 base::Owned(results)));
448 void PerformanceMonitorHandler::HandleGetFlagEnabled(const ListValue* args) {
449 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
450 CHECK_EQ(0u, args->GetSize());
451 scoped_ptr<Value> value(Value::CreateBooleanValue(
452 CommandLine::ForCurrentProcess()->HasSwitch(
453 switches::kPerformanceMonitorGathering)));
454 ReturnResults("PerformanceMonitor.getFlagEnabledCallback", value.get());
457 void PerformanceMonitorHandler::HandleGetAggregationTypes(
458 const ListValue* args) {
459 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
460 CHECK_EQ(0u, args->GetSize());
462 for (int i = 0; i < AGGREGATION_METHOD_NUMBER_OF_METHODS; ++i) {
464 GetAggregationMethod(static_cast<AggregationMethod>(i)).release());
468 "PerformanceMonitor.getAggregationTypesCallback", &results);
471 void PerformanceMonitorHandler::HandleGetEventTypes(const ListValue* args) {
472 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
473 CHECK_EQ(0u, args->GetSize());
475 for (int i = 0; i < EVENT_CATEGORY_NUMBER_OF_CATEGORIES; ++i)
476 results.Append(GetEventCategory(static_cast<EventCategory>(i)).release());
478 ReturnResults("PerformanceMonitor.getEventTypesCallback", &results);
481 void PerformanceMonitorHandler::HandleGetEvents(const ListValue* args) {
482 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
483 CHECK_EQ(3u, args->GetSize());
485 const ListValue* event_type_list;
486 CHECK(args->GetList(0, &event_type_list));
487 std::set<EventType> event_types;
488 for (ListValue::const_iterator iter = event_type_list->begin();
489 iter != event_type_list->end(); ++iter) {
490 double event_type_double = 0.0;
491 CHECK((*iter)->GetAsDouble(&event_type_double));
492 CHECK(event_type_double < EVENT_NUMBER_OF_EVENTS &&
493 event_type_double > EVENT_UNDEFINED);
495 static_cast<EventType>(static_cast<int>(event_type_double)));
498 double double_time = 0.0;
499 CHECK(args->GetDouble(1, &double_time));
500 base::Time start = base::Time::FromJsTime(double_time);
501 CHECK(args->GetDouble(2, &double_time));
502 base::Time end = base::Time::FromJsTime(double_time);
504 ListValue* results = new ListValue();
505 util::PostTaskToDatabaseThreadAndReply(
507 base::Bind(&DoGetEvents, results, event_types, start, end),
508 base::Bind(&PerformanceMonitorHandler::ReturnResults, AsWeakPtr(),
509 "PerformanceMonitor.getEventsCallback",
510 base::Owned(results)));
513 void PerformanceMonitorHandler::HandleGetMetricTypes(const ListValue* args) {
514 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
515 CHECK_EQ(0u, args->GetSize());
517 for (int i = 0; i < METRIC_CATEGORY_NUMBER_OF_CATEGORIES; ++i)
518 results.Append(GetMetricCategory(static_cast<MetricCategory>(i)).release());
520 ReturnResults("PerformanceMonitor.getMetricTypesCallback", &results);
523 void PerformanceMonitorHandler::HandleGetMetrics(const ListValue* args) {
524 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
525 CHECK_EQ(5u, args->GetSize());
527 const ListValue* metric_type_list;
528 CHECK(args->GetList(0, &metric_type_list));
529 std::set<MetricType> metric_types;
530 for (ListValue::const_iterator iter = metric_type_list->begin();
531 iter != metric_type_list->end(); ++iter) {
532 double metric_type_double = 0.0;
533 CHECK((*iter)->GetAsDouble(&metric_type_double));
534 CHECK(metric_type_double < METRIC_NUMBER_OF_METRICS &&
535 metric_type_double > METRIC_UNDEFINED);
537 static_cast<MetricType>(static_cast<int>(metric_type_double)));
540 double time_double = 0.0;
541 CHECK(args->GetDouble(1, &time_double));
542 base::Time start = base::Time::FromJsTime(time_double);
543 CHECK(args->GetDouble(2, &time_double));
544 base::Time end = base::Time::FromJsTime(time_double);
546 double resolution_in_milliseconds = 0.0;
547 CHECK(args->GetDouble(3, &resolution_in_milliseconds));
548 base::TimeDelta resolution =
549 base::TimeDelta::FromMilliseconds(resolution_in_milliseconds);
551 double aggregation_double = 0.0;
552 CHECK(args->GetDouble(4, &aggregation_double));
553 CHECK(aggregation_double < AGGREGATION_METHOD_NUMBER_OF_METHODS &&
554 aggregation_double >= 0);
555 AggregationMethod aggregation_method =
556 static_cast<AggregationMethod>(static_cast<int>(aggregation_double));
558 ListValue* results = new ListValue();
559 util::PostTaskToDatabaseThreadAndReply(
561 base::Bind(&DoGetMetrics, results, metric_types,
562 start, end, resolution, aggregation_method),
563 base::Bind(&PerformanceMonitorHandler::ReturnResults, AsWeakPtr(),
564 "PerformanceMonitor.getMetricsCallback",
565 base::Owned(results)));
568 } // namespace performance_monitor