Home | History | Annotate | Download | only in performance_monitor
      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   std::vector<TimeRange> intervals = db->GetActiveIntervals(start, end);
    231 
    232   for (std::vector<TimeRange>::iterator it = intervals.begin();
    233        it != intervals.end(); ++it) {
    234     DictionaryValue* interval_value = new DictionaryValue();
    235     interval_value->SetDouble("start", it->start.ToJsTime());
    236     interval_value->SetDouble("end", it->end.ToJsTime());
    237     results->Append(interval_value);
    238   }
    239 }
    240 
    241 // Queries the PerformanceMonitor database for events of type |event_type|
    242 // between |start| and |end| times, creates a new event with localized keys
    243 // for display, and appends the results to |results|.
    244 void DoGetEvents(ListValue* results,
    245                  const std::set<EventType>& event_types,
    246                  const base::Time& start,
    247                  const base::Time& end) {
    248   Database* db = PerformanceMonitor::GetInstance()->database();
    249 
    250   for (std::set<EventType>::const_iterator iter = event_types.begin();
    251        iter != event_types.end(); ++iter) {
    252     DictionaryValue* event_results = new DictionaryValue();
    253     event_results->SetInteger("eventId", static_cast<int>(*iter));
    254     ListValue* events = new ListValue();
    255     event_results->Set("events", events);
    256     results->Append(event_results);
    257 
    258     Database::EventVector event_vector = db->GetEvents(*iter, start, end);
    259 
    260     for (Database::EventVector::iterator event = event_vector.begin();
    261          event != event_vector.end(); ++event) {
    262       DictionaryValue* localized_event = new DictionaryValue();
    263 
    264       for (DictionaryValue::Iterator data(*(*event)->data()); !data.IsAtEnd();
    265            data.Advance()) {
    266         Value* value = NULL;
    267 
    268         // The property 'eventType' is set in HandleGetEvents as part of the
    269         // entire result set, so we don't need to include this here in the
    270         // event.
    271         if (data.key() == "eventType")
    272           continue;
    273         else if (data.key() == "time") {
    274           // The property 'time' is also used computationally, but must be
    275           // converted to JS-style time.
    276           double time = 0.0;
    277           if (!data.value().GetAsDouble(&time)) {
    278             LOG(ERROR) << "Failed to get 'time' field from event.";
    279             continue;
    280           }
    281           value = Value::CreateDoubleValue(
    282               base::Time::FromInternalValue(
    283                   static_cast<int64>(time)).ToJsTime());
    284         } else {
    285           // All other values are user-facing, so we create a new value for
    286           // localized display.
    287           DictionaryValue* localized_value = new DictionaryValue();
    288           localized_value->SetString(
    289               "label",
    290               GetLocalizedStringFromEventProperty(data.key()));
    291           localized_value->SetWithoutPathExpansion("value",
    292                                                    data.value().DeepCopy());
    293           value = localized_value;
    294         }
    295 
    296         localized_event->SetWithoutPathExpansion(data.key(), value);
    297       }
    298       events->Append(localized_event);
    299     }
    300   }
    301 }
    302 
    303 // Populates results with a dictionary for each metric requested. The dictionary
    304 // includes a metric id, the maximum value for the metric, and a list of lists
    305 // of metric points, with each sublist containing the aggregated data for an
    306 // interval for which PerformanceMonitor was active. This will also convert
    307 // time to JS-style time.
    308 void DoGetMetrics(ListValue* results,
    309                   const std::set<MetricType>& metric_types,
    310                   const base::Time& start,
    311                   const base::Time& end,
    312                   const base::TimeDelta& resolution,
    313                   AggregationMethod aggregation_method) {
    314   Database* db = PerformanceMonitor::GetInstance()->database();
    315   std::vector<TimeRange> intervals = db->GetActiveIntervals(start, end);
    316 
    317   // For each metric type, populate a new dictionary and append it to results.
    318   for (std::set<MetricType>::const_iterator metric_type = metric_types.begin();
    319        metric_type != metric_types.end(); ++metric_type) {
    320     double conversion_factor =
    321         GetConversionFactor(*GetUnitDetails(GetUnitForMetricType(*metric_type)),
    322                             *GetUnitDetails(GetUnitForMetricCategory(
    323                                 GetCategoryForMetric(*metric_type))));
    324 
    325     DictionaryValue* metric_set = new DictionaryValue();
    326     metric_set->SetInteger("metricId", static_cast<int>(*metric_type));
    327     metric_set->SetDouble(
    328         "maxValue",
    329         db->GetMaxStatsForActivityAndMetric(*metric_type) * conversion_factor);
    330 
    331     // Retrieve all metrics in the database, and aggregate them into a series
    332     // of points for each active interval.
    333     scoped_ptr<Database::MetricVector> metric_vector =
    334         db->GetStatsForActivityAndMetric(*metric_type, start, end);
    335 
    336     scoped_ptr<VectorOfMetricVectors> aggregated_metrics =
    337         AggregateMetric(*metric_type,
    338                         metric_vector.get(),
    339                         start,
    340                         intervals,
    341                         resolution,
    342                         aggregation_method);
    343 
    344     // The JS-side expects a list to be present, even if there are no metrics.
    345     if (!aggregated_metrics) {
    346       metric_set->Set("metrics", new ListValue());
    347       results->Append(metric_set);
    348       continue;
    349     }
    350 
    351     ListValue* metric_points_by_interval = new ListValue();
    352 
    353     // For each metric point, record it in the expected format for the JS-side
    354     // (a dictionary of time and value, with time as a JS-style time), and
    355     // convert the values to be display-friendly.
    356     for (VectorOfMetricVectors::const_iterator metric_series =
    357              aggregated_metrics->begin();
    358          metric_series != aggregated_metrics->end(); ++metric_series) {
    359       ListValue* series_value = new ListValue();
    360       for (Database::MetricVector::const_iterator metric_point =
    361                metric_series->begin();
    362            metric_point != metric_series->end(); ++metric_point) {
    363         DictionaryValue* point_value = new DictionaryValue();
    364         point_value->SetDouble("time", metric_point->time.ToJsTime());
    365         point_value->SetDouble("value",
    366                                metric_point->value * conversion_factor);
    367         series_value->Append(point_value);
    368       }
    369       metric_points_by_interval->Append(series_value);
    370     }
    371 
    372     metric_set->Set("metrics", metric_points_by_interval);
    373     results->Append(metric_set);
    374   }
    375 }
    376 
    377 }  // namespace
    378 
    379 PerformanceMonitorHandler::PerformanceMonitorHandler() {
    380   // If we are not running the --run-performance-monitor flag, we will not have
    381   // started PerformanceMonitor.
    382   if (!PerformanceMonitor::initialized())
    383     PerformanceMonitor::GetInstance()->Start();
    384 }
    385 
    386 PerformanceMonitorHandler::~PerformanceMonitorHandler() {}
    387 
    388 void PerformanceMonitorHandler::RegisterMessages() {
    389   web_ui()->RegisterMessageCallback(
    390       "getActiveIntervals",
    391       base::Bind(&PerformanceMonitorHandler::HandleGetActiveIntervals,
    392                  AsWeakPtr()));
    393   web_ui()->RegisterMessageCallback(
    394       "getFlagEnabled",
    395       base::Bind(&PerformanceMonitorHandler::HandleGetFlagEnabled,
    396                  AsWeakPtr()));
    397   web_ui()->RegisterMessageCallback(
    398       "getAggregationTypes",
    399       base::Bind(&PerformanceMonitorHandler::HandleGetAggregationTypes,
    400                  AsWeakPtr()));
    401   web_ui()->RegisterMessageCallback(
    402       "getEventTypes",
    403       base::Bind(&PerformanceMonitorHandler::HandleGetEventTypes,
    404                  AsWeakPtr()));
    405   web_ui()->RegisterMessageCallback(
    406       "getEvents",
    407       base::Bind(&PerformanceMonitorHandler::HandleGetEvents,
    408                  AsWeakPtr()));
    409   web_ui()->RegisterMessageCallback(
    410       "getMetricTypes",
    411       base::Bind(&PerformanceMonitorHandler::HandleGetMetricTypes,
    412                  AsWeakPtr()));
    413   web_ui()->RegisterMessageCallback(
    414       "getMetrics",
    415       base::Bind(&PerformanceMonitorHandler::HandleGetMetrics,
    416                  AsWeakPtr()));
    417 }
    418 
    419 void PerformanceMonitorHandler::ReturnResults(const std::string& function,
    420                                  const Value* results) {
    421   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    422   web_ui()->CallJavascriptFunction(function, *results);
    423 }
    424 
    425 void PerformanceMonitorHandler::HandleGetActiveIntervals(
    426     const ListValue* args) {
    427   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    428   CHECK_EQ(2u, args->GetSize());
    429   double double_time = 0.0;
    430   CHECK(args->GetDouble(0, &double_time));
    431   base::Time start = base::Time::FromJsTime(double_time);
    432   CHECK(args->GetDouble(1, &double_time));
    433   base::Time end = base::Time::FromJsTime(double_time);
    434 
    435   ListValue* results = new ListValue();
    436   util::PostTaskToDatabaseThreadAndReply(
    437       FROM_HERE,
    438       base::Bind(&DoGetActiveIntervals, results, start, end),
    439       base::Bind(&PerformanceMonitorHandler::ReturnResults, AsWeakPtr(),
    440                  "PerformanceMonitor.getActiveIntervalsCallback",
    441                  base::Owned(results)));
    442 }
    443 
    444 void PerformanceMonitorHandler::HandleGetFlagEnabled(const ListValue* args) {
    445   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    446   CHECK_EQ(0u, args->GetSize());
    447   scoped_ptr<Value> value(Value::CreateBooleanValue(
    448       CommandLine::ForCurrentProcess()->HasSwitch(
    449           switches::kPerformanceMonitorGathering)));
    450   ReturnResults("PerformanceMonitor.getFlagEnabledCallback", value.get());
    451 }
    452 
    453 void PerformanceMonitorHandler::HandleGetAggregationTypes(
    454     const ListValue* args) {
    455   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    456   CHECK_EQ(0u, args->GetSize());
    457   ListValue results;
    458   for (int i = 0; i < AGGREGATION_METHOD_NUMBER_OF_METHODS; ++i) {
    459     results.Append(
    460         GetAggregationMethod(static_cast<AggregationMethod>(i)).release());
    461   }
    462 
    463   ReturnResults(
    464       "PerformanceMonitor.getAggregationTypesCallback", &results);
    465 }
    466 
    467 void PerformanceMonitorHandler::HandleGetEventTypes(const ListValue* args) {
    468   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    469   CHECK_EQ(0u, args->GetSize());
    470   ListValue results;
    471   for (int i = 0; i < EVENT_CATEGORY_NUMBER_OF_CATEGORIES; ++i)
    472     results.Append(GetEventCategory(static_cast<EventCategory>(i)).release());
    473 
    474   ReturnResults("PerformanceMonitor.getEventTypesCallback", &results);
    475 }
    476 
    477 void PerformanceMonitorHandler::HandleGetEvents(const ListValue* args) {
    478   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    479   CHECK_EQ(3u, args->GetSize());
    480 
    481   const ListValue* event_type_list;
    482   CHECK(args->GetList(0, &event_type_list));
    483   std::set<EventType> event_types;
    484   for (ListValue::const_iterator iter = event_type_list->begin();
    485        iter != event_type_list->end(); ++iter) {
    486     double event_type_double = 0.0;
    487     CHECK((*iter)->GetAsDouble(&event_type_double));
    488     CHECK(event_type_double < EVENT_NUMBER_OF_EVENTS &&
    489         event_type_double > EVENT_UNDEFINED);
    490     event_types.insert(
    491         static_cast<EventType>(static_cast<int>(event_type_double)));
    492   }
    493 
    494   double double_time = 0.0;
    495   CHECK(args->GetDouble(1, &double_time));
    496   base::Time start = base::Time::FromJsTime(double_time);
    497   CHECK(args->GetDouble(2, &double_time));
    498   base::Time end = base::Time::FromJsTime(double_time);
    499 
    500   ListValue* results = new ListValue();
    501   util::PostTaskToDatabaseThreadAndReply(
    502       FROM_HERE,
    503       base::Bind(&DoGetEvents, results, event_types, start, end),
    504       base::Bind(&PerformanceMonitorHandler::ReturnResults, AsWeakPtr(),
    505                  "PerformanceMonitor.getEventsCallback",
    506                  base::Owned(results)));
    507 }
    508 
    509 void PerformanceMonitorHandler::HandleGetMetricTypes(const ListValue* args) {
    510   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    511   CHECK_EQ(0u, args->GetSize());
    512   ListValue results;
    513   for (int i = 0; i < METRIC_CATEGORY_NUMBER_OF_CATEGORIES; ++i)
    514     results.Append(GetMetricCategory(static_cast<MetricCategory>(i)).release());
    515 
    516   ReturnResults("PerformanceMonitor.getMetricTypesCallback", &results);
    517 }
    518 
    519 void PerformanceMonitorHandler::HandleGetMetrics(const ListValue* args) {
    520   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    521   CHECK_EQ(5u, args->GetSize());
    522 
    523   const ListValue* metric_type_list;
    524   CHECK(args->GetList(0, &metric_type_list));
    525   std::set<MetricType> metric_types;
    526   for (ListValue::const_iterator iter = metric_type_list->begin();
    527        iter != metric_type_list->end(); ++iter) {
    528     double metric_type_double = 0.0;
    529     CHECK((*iter)->GetAsDouble(&metric_type_double));
    530     CHECK(metric_type_double < METRIC_NUMBER_OF_METRICS &&
    531           metric_type_double > METRIC_UNDEFINED);
    532     metric_types.insert(
    533         static_cast<MetricType>(static_cast<int>(metric_type_double)));
    534   }
    535 
    536   double time_double = 0.0;
    537   CHECK(args->GetDouble(1, &time_double));
    538   base::Time start = base::Time::FromJsTime(time_double);
    539   CHECK(args->GetDouble(2, &time_double));
    540   base::Time end = base::Time::FromJsTime(time_double);
    541 
    542   double resolution_in_milliseconds = 0.0;
    543   CHECK(args->GetDouble(3, &resolution_in_milliseconds));
    544   base::TimeDelta resolution =
    545       base::TimeDelta::FromMilliseconds(resolution_in_milliseconds);
    546 
    547   double aggregation_double = 0.0;
    548   CHECK(args->GetDouble(4, &aggregation_double));
    549   CHECK(aggregation_double < AGGREGATION_METHOD_NUMBER_OF_METHODS &&
    550         aggregation_double >= 0);
    551   AggregationMethod aggregation_method =
    552       static_cast<AggregationMethod>(static_cast<int>(aggregation_double));
    553 
    554   ListValue* results = new ListValue();
    555   util::PostTaskToDatabaseThreadAndReply(
    556       FROM_HERE,
    557       base::Bind(&DoGetMetrics, results, metric_types,
    558                  start, end, resolution, aggregation_method),
    559       base::Bind(&PerformanceMonitorHandler::ReturnResults, AsWeakPtr(),
    560                  "PerformanceMonitor.getMetricsCallback",
    561                  base::Owned(results)));
    562 }
    563 
    564 }  // namespace performance_monitor
    565