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 "content/public/browser/browser_thread.h" 22 #include "content/public/browser/web_ui.h" 23 #include "extensions/common/value_builder.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 569