- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / performance_monitor / performance_monitor_handler.cc
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.
4
5 #include "chrome/browser/ui/webui/performance_monitor/performance_monitor_handler.h"
6
7 #include "base/bind.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"
24
25 using content::BrowserThread;
26
27 namespace performance_monitor {
28 namespace {
29
30 std::set<MetricType> GetMetricSetForCategory(MetricCategory category) {
31   std::set<MetricType> metric_set;
32   switch (category) {
33     case METRIC_CATEGORY_CPU:
34       metric_set.insert(METRIC_CPU_USAGE);
35       break;
36     case METRIC_CATEGORY_MEMORY:
37       metric_set.insert(METRIC_SHARED_MEMORY_USAGE);
38       metric_set.insert(METRIC_PRIVATE_MEMORY_USAGE);
39       break;
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);
45       break;
46     case METRIC_CATEGORY_NETWORK:
47       metric_set.insert(METRIC_NETWORK_BYTES_READ);
48       break;
49     default:
50       NOTREACHED();
51   }
52   return metric_set;
53 }
54
55 std::set<EventType> GetEventSetForCategory(EventCategory category) {
56   std::set<EventType> event_set;
57   switch (category) {
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);
64       break;
65     case EVENT_CATEGORY_CHROME:
66       event_set.insert(EVENT_CHROME_UPDATE);
67       break;
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);
73       break;
74     default:
75       NOTREACHED();
76   }
77   return event_set;
78 }
79
80 Unit GetUnitForMetricCategory(MetricCategory category) {
81   switch (category) {
82     case METRIC_CATEGORY_CPU:
83       return UNIT_PERCENT;
84     case METRIC_CATEGORY_MEMORY:
85       return UNIT_MEGABYTES;
86     case METRIC_CATEGORY_TIMING:
87       return UNIT_SECONDS;
88     case METRIC_CATEGORY_NETWORK:
89       return UNIT_MEGABYTES;
90     default:
91       NOTREACHED();
92   }
93   return UNIT_UNDEFINED;
94 }
95
96 MetricCategory GetCategoryForMetric(MetricType type) {
97   switch (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;
110     default:
111       NOTREACHED();
112   }
113   return METRIC_CATEGORY_NUMBER_OF_CATEGORIES;
114 }
115
116 Unit GetUnitForMetricType(MetricType type) {
117   switch (type) {
118     case METRIC_CPU_USAGE:
119       return UNIT_PERCENT;
120     case METRIC_SHARED_MEMORY_USAGE:
121     case METRIC_PRIVATE_MEMORY_USAGE:
122     case METRIC_NETWORK_BYTES_READ:
123       return UNIT_BYTES;
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;
129     default:
130       NOTREACHED();
131   }
132   return UNIT_UNDEFINED;
133 }
134
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));
143   value->SetString(
144       "description",
145       GetLocalizedStringForAggregationMethodDescription(method));
146   return value.Pass();
147 }
148
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);
164   }
165   return value.Pass();
166 }
167
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);
175   value->SetString(
176       "name", GetLocalizedStringFromMetricCategory(category));
177   value->SetString(
178       "unit",
179       GetLocalizedStringFromUnit(GetUnitForMetricCategory(category)));
180   value->SetString(
181       "description",
182       GetLocalizedStringForMetricCategoryDescription(category));
183   value->Set("details", GetMetricDetailsForCategory(category).release());
184   return value.Pass();
185 }
186
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
190 // mouseover popup.
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);
205   }
206   return value.Pass();
207 }
208
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);
215   value->SetString(
216       "name", GetLocalizedStringFromEventCategory(category));
217   value->SetString(
218       "description",
219       GetLocalizedStringForEventCategoryDescription(category));
220   value->Set("details", GetEventTypesForCategory(category).release());
221   return value.Pass();
222 }
223
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();
230   if (db == NULL)
231     return;
232
233   std::vector<TimeRange> intervals = db->GetActiveIntervals(start, end);
234
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);
241   }
242 }
243
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();
252   if (db == NULL)
253     return;
254
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);
262
263     Database::EventVector event_vector = db->GetEvents(*iter, start, end);
264
265     for (Database::EventVector::iterator event = event_vector.begin();
266          event != event_vector.end(); ++event) {
267       DictionaryValue* localized_event = new DictionaryValue();
268
269       for (DictionaryValue::Iterator data(*(*event)->data()); !data.IsAtEnd();
270            data.Advance()) {
271         Value* value = NULL;
272
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
275         // event.
276         if (data.key() == "eventType")
277           continue;
278         else if (data.key() == "time") {
279           // The property 'time' is also used computationally, but must be
280           // converted to JS-style time.
281           double time = 0.0;
282           if (!data.value().GetAsDouble(&time)) {
283             LOG(ERROR) << "Failed to get 'time' field from event.";
284             continue;
285           }
286           value = Value::CreateDoubleValue(
287               base::Time::FromInternalValue(
288                   static_cast<int64>(time)).ToJsTime());
289         } else {
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(
294               "label",
295               GetLocalizedStringFromEventProperty(data.key()));
296           localized_value->SetWithoutPathExpansion("value",
297                                                    data.value().DeepCopy());
298           value = localized_value;
299         }
300
301         localized_event->SetWithoutPathExpansion(data.key(), value);
302       }
303       events->Append(localized_event);
304     }
305   }
306 }
307
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();
320   if (db == NULL)
321     return;
322
323   std::vector<TimeRange> intervals = db->GetActiveIntervals(start, end);
324
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))));
332
333     DictionaryValue* metric_set = new DictionaryValue();
334     metric_set->SetInteger("metricId", static_cast<int>(*metric_type));
335     metric_set->SetDouble(
336         "maxValue",
337         db->GetMaxStatsForActivityAndMetric(*metric_type) * conversion_factor);
338
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);
343
344     scoped_ptr<VectorOfMetricVectors> aggregated_metrics =
345         AggregateMetric(*metric_type,
346                         metric_vector.get(),
347                         start,
348                         intervals,
349                         resolution,
350                         aggregation_method);
351
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);
356       continue;
357     }
358
359     ListValue* metric_points_by_interval = new ListValue();
360
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);
376       }
377       metric_points_by_interval->Append(series_value);
378     }
379
380     metric_set->Set("metrics", metric_points_by_interval);
381     results->Append(metric_set);
382   }
383 }
384
385 }  // namespace
386
387 PerformanceMonitorHandler::PerformanceMonitorHandler() {
388 }
389
390 PerformanceMonitorHandler::~PerformanceMonitorHandler() {}
391
392 void PerformanceMonitorHandler::RegisterMessages() {
393   web_ui()->RegisterMessageCallback(
394       "getActiveIntervals",
395       base::Bind(&PerformanceMonitorHandler::HandleGetActiveIntervals,
396                  AsWeakPtr()));
397   web_ui()->RegisterMessageCallback(
398       "getFlagEnabled",
399       base::Bind(&PerformanceMonitorHandler::HandleGetFlagEnabled,
400                  AsWeakPtr()));
401   web_ui()->RegisterMessageCallback(
402       "getAggregationTypes",
403       base::Bind(&PerformanceMonitorHandler::HandleGetAggregationTypes,
404                  AsWeakPtr()));
405   web_ui()->RegisterMessageCallback(
406       "getEventTypes",
407       base::Bind(&PerformanceMonitorHandler::HandleGetEventTypes,
408                  AsWeakPtr()));
409   web_ui()->RegisterMessageCallback(
410       "getEvents",
411       base::Bind(&PerformanceMonitorHandler::HandleGetEvents,
412                  AsWeakPtr()));
413   web_ui()->RegisterMessageCallback(
414       "getMetricTypes",
415       base::Bind(&PerformanceMonitorHandler::HandleGetMetricTypes,
416                  AsWeakPtr()));
417   web_ui()->RegisterMessageCallback(
418       "getMetrics",
419       base::Bind(&PerformanceMonitorHandler::HandleGetMetrics,
420                  AsWeakPtr()));
421 }
422
423 void PerformanceMonitorHandler::ReturnResults(const std::string& function,
424                                  const Value* results) {
425   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
426   web_ui()->CallJavascriptFunction(function, *results);
427 }
428
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);
438
439   ListValue* results = new ListValue();
440   util::PostTaskToDatabaseThreadAndReply(
441       FROM_HERE,
442       base::Bind(&DoGetActiveIntervals, results, start, end),
443       base::Bind(&PerformanceMonitorHandler::ReturnResults, AsWeakPtr(),
444                  "PerformanceMonitor.getActiveIntervalsCallback",
445                  base::Owned(results)));
446 }
447
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());
455 }
456
457 void PerformanceMonitorHandler::HandleGetAggregationTypes(
458     const ListValue* args) {
459   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
460   CHECK_EQ(0u, args->GetSize());
461   ListValue results;
462   for (int i = 0; i < AGGREGATION_METHOD_NUMBER_OF_METHODS; ++i) {
463     results.Append(
464         GetAggregationMethod(static_cast<AggregationMethod>(i)).release());
465   }
466
467   ReturnResults(
468       "PerformanceMonitor.getAggregationTypesCallback", &results);
469 }
470
471 void PerformanceMonitorHandler::HandleGetEventTypes(const ListValue* args) {
472   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
473   CHECK_EQ(0u, args->GetSize());
474   ListValue results;
475   for (int i = 0; i < EVENT_CATEGORY_NUMBER_OF_CATEGORIES; ++i)
476     results.Append(GetEventCategory(static_cast<EventCategory>(i)).release());
477
478   ReturnResults("PerformanceMonitor.getEventTypesCallback", &results);
479 }
480
481 void PerformanceMonitorHandler::HandleGetEvents(const ListValue* args) {
482   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
483   CHECK_EQ(3u, args->GetSize());
484
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);
494     event_types.insert(
495         static_cast<EventType>(static_cast<int>(event_type_double)));
496   }
497
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);
503
504   ListValue* results = new ListValue();
505   util::PostTaskToDatabaseThreadAndReply(
506       FROM_HERE,
507       base::Bind(&DoGetEvents, results, event_types, start, end),
508       base::Bind(&PerformanceMonitorHandler::ReturnResults, AsWeakPtr(),
509                  "PerformanceMonitor.getEventsCallback",
510                  base::Owned(results)));
511 }
512
513 void PerformanceMonitorHandler::HandleGetMetricTypes(const ListValue* args) {
514   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
515   CHECK_EQ(0u, args->GetSize());
516   ListValue results;
517   for (int i = 0; i < METRIC_CATEGORY_NUMBER_OF_CATEGORIES; ++i)
518     results.Append(GetMetricCategory(static_cast<MetricCategory>(i)).release());
519
520   ReturnResults("PerformanceMonitor.getMetricTypesCallback", &results);
521 }
522
523 void PerformanceMonitorHandler::HandleGetMetrics(const ListValue* args) {
524   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
525   CHECK_EQ(5u, args->GetSize());
526
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);
536     metric_types.insert(
537         static_cast<MetricType>(static_cast<int>(metric_type_double)));
538   }
539
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);
545
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);
550
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));
557
558   ListValue* results = new ListValue();
559   util::PostTaskToDatabaseThreadAndReply(
560       FROM_HERE,
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)));
566 }
567
568 }  // namespace performance_monitor