task_manager.cc revision a02191e04bc25c4935f804f2c080ae28663d096d
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/task_manager/task_manager.h" 6 7#include "base/bind.h" 8#include "base/i18n/number_formatting.h" 9#include "base/i18n/rtl.h" 10#include "base/prefs/pref_registry_simple.h" 11#include "base/process/process_metrics.h" 12#include "base/rand_util.h" 13#include "base/stl_util.h" 14#include "base/strings/string16.h" 15#include "base/strings/string_number_conversions.h" 16#include "base/strings/stringprintf.h" 17#include "base/strings/utf_string_conversions.h" 18#include "chrome/browser/browser_process.h" 19#include "chrome/browser/profiles/profile_manager.h" 20#include "chrome/browser/task_manager/background_information.h" 21#include "chrome/browser/task_manager/browser_process_resource_provider.h" 22#include "chrome/browser/task_manager/child_process_resource_provider.h" 23#include "chrome/browser/task_manager/extension_information.h" 24#include "chrome/browser/task_manager/guest_information.h" 25#include "chrome/browser/task_manager/panel_information.h" 26#include "chrome/browser/task_manager/printing_information.h" 27#include "chrome/browser/task_manager/resource_provider.h" 28#include "chrome/browser/task_manager/tab_contents_information.h" 29#include "chrome/browser/task_manager/web_contents_resource_provider.h" 30#include "chrome/browser/task_manager/worker_resource_provider.h" 31#include "chrome/browser/ui/browser_navigator.h" 32#include "chrome/common/pref_names.h" 33#include "chrome/common/url_constants.h" 34#include "content/public/browser/browser_thread.h" 35#include "content/public/browser/gpu_data_manager.h" 36#include "content/public/browser/gpu_data_manager_observer.h" 37#include "content/public/browser/resource_request_info.h" 38#include "content/public/browser/web_contents.h" 39#include "content/public/browser/web_contents_delegate.h" 40#include "content/public/common/result_codes.h" 41#include "extensions/browser/extension_system.h" 42#include "grit/generated_resources.h" 43#include "grit/ui_resources.h" 44#include "third_party/icu/source/i18n/unicode/coll.h" 45#include "ui/base/l10n/l10n_util.h" 46#include "ui/base/resource/resource_bundle.h" 47#include "ui/base/text/bytes_formatting.h" 48#include "ui/gfx/image/image_skia.h" 49 50#if defined(OS_MACOSX) 51#include "content/public/browser/browser_child_process_host.h" 52#endif 53 54using content::BrowserThread; 55using content::ResourceRequestInfo; 56using content::WebContents; 57using task_manager::Resource; 58using task_manager::ResourceProvider; 59using task_manager::WebContentsInformation; 60 61class Profile; 62 63namespace { 64 65template <class T> 66int ValueCompare(T value1, T value2) { 67 if (value1 < value2) 68 return -1; 69 if (value1 == value2) 70 return 0; 71 return 1; 72} 73 74// Used when one or both of the results to compare are unavailable. 75int OrderUnavailableValue(bool v1, bool v2) { 76 if (!v1 && !v2) 77 return 0; 78 return v1 ? 1 : -1; 79} 80 81// Used by TaskManagerModel::CompareValues(). See it for details of return 82// value. 83template <class T> 84int ValueCompareMember(const TaskManagerModel* model, 85 bool (TaskManagerModel::*f)(int, T*) const, 86 int row1, 87 int row2) { 88 T value1; 89 T value2; 90 bool value1_valid = (model->*f)(row1, &value1); 91 bool value2_valid = (model->*f)(row2, &value2); 92 return value1_valid && value2_valid ? ValueCompare(value1, value2) : 93 OrderUnavailableValue(value1_valid, value2_valid); 94} 95 96base::string16 FormatStatsSize(const blink::WebCache::ResourceTypeStat& stat) { 97 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT, 98 ui::FormatBytesWithUnits(stat.size, ui::DATA_UNITS_KIBIBYTE, false), 99 ui::FormatBytesWithUnits(stat.liveSize, ui::DATA_UNITS_KIBIBYTE, false)); 100} 101 102// Returns true if the specified id should use the first value in the group. 103bool IsSharedByGroup(int col_id) { 104 switch (col_id) { 105 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: 106 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: 107 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: 108 case IDS_TASK_MANAGER_CPU_COLUMN: 109 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: 110 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN: 111 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN: 112 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN: 113 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: 114 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: 115 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: 116 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN: 117 return true; 118 default: 119 return false; 120 } 121} 122 123#if defined(OS_WIN) 124void GetWinGDIHandles(base::ProcessHandle process, 125 size_t* current, 126 size_t* peak) { 127 *current = 0; 128 *peak = 0; 129 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights. 130 HANDLE current_process = GetCurrentProcess(); 131 HANDLE process_with_query_rights; 132 if (DuplicateHandle(current_process, process, current_process, 133 &process_with_query_rights, PROCESS_QUERY_INFORMATION, 134 false, 0)) { 135 *current = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS); 136 *peak = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS_PEAK); 137 CloseHandle(process_with_query_rights); 138 } 139} 140 141void GetWinUSERHandles(base::ProcessHandle process, 142 size_t* current, 143 size_t* peak) { 144 *current = 0; 145 *peak = 0; 146 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights. 147 HANDLE current_process = GetCurrentProcess(); 148 HANDLE process_with_query_rights; 149 if (DuplicateHandle(current_process, process, current_process, 150 &process_with_query_rights, PROCESS_QUERY_INFORMATION, 151 false, 0)) { 152 *current = GetGuiResources(process_with_query_rights, GR_USEROBJECTS); 153 *peak = GetGuiResources(process_with_query_rights, GR_USEROBJECTS_PEAK); 154 CloseHandle(process_with_query_rights); 155 } 156} 157#endif 158 159} // namespace 160 161class TaskManagerModelGpuDataManagerObserver 162 : public content::GpuDataManagerObserver { 163 public: 164 TaskManagerModelGpuDataManagerObserver() { 165 content::GpuDataManager::GetInstance()->AddObserver(this); 166 } 167 168 virtual ~TaskManagerModelGpuDataManagerObserver() { 169 content::GpuDataManager::GetInstance()->RemoveObserver(this); 170 } 171 172 static void NotifyVideoMemoryUsageStats( 173 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) { 174 TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats( 175 video_memory_usage_stats); 176 } 177 178 virtual void OnVideoMemoryUsageStatsUpdate( 179 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) 180 OVERRIDE { 181 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 182 NotifyVideoMemoryUsageStats(video_memory_usage_stats); 183 } else { 184 BrowserThread::PostTask( 185 BrowserThread::UI, FROM_HERE, base::Bind( 186 &TaskManagerModelGpuDataManagerObserver:: 187 NotifyVideoMemoryUsageStats, 188 video_memory_usage_stats)); 189 } 190 } 191}; 192 193TaskManagerModel::PerResourceValues::PerResourceValues() 194 : is_nacl_debug_stub_port_valid(false), 195 nacl_debug_stub_port(0), 196 is_title_valid(false), 197 is_profile_name_valid(false), 198 network_usage(0), 199 is_process_id_valid(false), 200 process_id(0), 201 is_goats_teleported_valid(false), 202 goats_teleported(0), 203 is_webcore_stats_valid(false), 204 is_fps_valid(false), 205 fps(0), 206 is_sqlite_memory_bytes_valid(false), 207 sqlite_memory_bytes(0), 208 is_v8_memory_valid(false), 209 v8_memory_allocated(0), 210 v8_memory_used(0) {} 211 212TaskManagerModel::PerResourceValues::~PerResourceValues() {} 213 214TaskManagerModel::PerProcessValues::PerProcessValues() 215 : is_cpu_usage_valid(false), 216 cpu_usage(0), 217 is_idle_wakeups_valid(false), 218 idle_wakeups(0), 219 is_private_and_shared_valid(false), 220 private_bytes(0), 221 shared_bytes(0), 222 is_physical_memory_valid(false), 223 physical_memory(0), 224 is_video_memory_valid(false), 225 video_memory(0), 226 video_memory_has_duplicates(false), 227 is_gdi_handles_valid(false), 228 gdi_handles(0), 229 gdi_handles_peak(0), 230 is_user_handles_valid(0), 231 user_handles(0), 232 user_handles_peak(0) {} 233 234TaskManagerModel::PerProcessValues::~PerProcessValues() {} 235 236//////////////////////////////////////////////////////////////////////////////// 237// TaskManagerModel class 238//////////////////////////////////////////////////////////////////////////////// 239 240TaskManagerModel::TaskManagerModel(TaskManager* task_manager) 241 : pending_video_memory_usage_stats_update_(false), 242 update_requests_(0), 243 listen_requests_(0), 244 update_state_(IDLE), 245 goat_salt_(base::RandUint64()) { 246 AddResourceProvider( 247 new task_manager::BrowserProcessResourceProvider(task_manager)); 248 AddResourceProvider(new task_manager::WebContentsResourceProvider( 249 task_manager, 250 scoped_ptr<WebContentsInformation>( 251 new task_manager::BackgroundInformation()))); 252 AddResourceProvider(new task_manager::WebContentsResourceProvider( 253 task_manager, 254 scoped_ptr<WebContentsInformation>( 255 new task_manager::TabContentsInformation()))); 256 AddResourceProvider(new task_manager::WebContentsResourceProvider( 257 task_manager, 258 scoped_ptr<WebContentsInformation>( 259 new task_manager::PrintingInformation()))); 260 AddResourceProvider(new task_manager::WebContentsResourceProvider( 261 task_manager, 262 scoped_ptr<WebContentsInformation>( 263 new task_manager::PanelInformation()))); 264 AddResourceProvider( 265 new task_manager::ChildProcessResourceProvider(task_manager)); 266 AddResourceProvider(new task_manager::WebContentsResourceProvider( 267 task_manager, 268 scoped_ptr<WebContentsInformation>( 269 new task_manager::ExtensionInformation()))); 270 AddResourceProvider(new task_manager::WebContentsResourceProvider( 271 task_manager, 272 scoped_ptr<WebContentsInformation>( 273 new task_manager::GuestInformation()))); 274 275 AddResourceProvider(new task_manager::WorkerResourceProvider(task_manager)); 276} 277 278void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) { 279 observer_list_.AddObserver(observer); 280} 281 282void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) { 283 observer_list_.RemoveObserver(observer); 284} 285 286int TaskManagerModel::ResourceCount() const { 287 return resources_.size(); 288} 289 290int TaskManagerModel::GroupCount() const { 291 return group_map_.size(); 292} 293 294int TaskManagerModel::GetNaClDebugStubPort(int index) const { 295 PerResourceValues& values(GetPerResourceValues(index)); 296 if (!values.is_nacl_debug_stub_port_valid) { 297 values.is_nacl_debug_stub_port_valid = true; 298 values.nacl_debug_stub_port = GetResource(index)->GetNaClDebugStubPort(); 299 } 300 return values.nacl_debug_stub_port; 301} 302 303int64 TaskManagerModel::GetNetworkUsage(int index) const { 304 return GetNetworkUsage(GetResource(index)); 305} 306 307double TaskManagerModel::GetCPUUsage(int index) const { 308 return GetCPUUsage(GetResource(index)); 309} 310 311int TaskManagerModel::GetIdleWakeupsPerSecond(int index) const { 312 return GetIdleWakeupsPerSecond(GetResource(index)); 313} 314 315base::ProcessId TaskManagerModel::GetProcessId(int index) const { 316 PerResourceValues& values(GetPerResourceValues(index)); 317 if (!values.is_process_id_valid) { 318 values.is_process_id_valid = true; 319 values.process_id = base::GetProcId(GetResource(index)->GetProcess()); 320 } 321 return values.process_id; 322} 323 324base::ProcessHandle TaskManagerModel::GetProcess(int index) const { 325 return GetResource(index)->GetProcess(); 326} 327 328base::string16 TaskManagerModel::GetResourceById(int index, int col_id) const { 329 if (IsSharedByGroup(col_id) && !IsResourceFirstInGroup(index)) 330 return base::string16(); 331 332 switch (col_id) { 333 case IDS_TASK_MANAGER_TASK_COLUMN: 334 return GetResourceTitle(index); 335 336 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN: 337 return GetResourceProfileName(index); 338 339 case IDS_TASK_MANAGER_NET_COLUMN: 340 return GetResourceNetworkUsage(index); 341 342 case IDS_TASK_MANAGER_CPU_COLUMN: 343 return GetResourceCPUUsage(index); 344 345 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: 346 return GetResourcePrivateMemory(index); 347 348 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: 349 return GetResourceSharedMemory(index); 350 351 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: 352 return GetResourcePhysicalMemory(index); 353 354 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: 355 return GetResourceProcessId(index); 356 357 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN: 358 return GetResourceGDIHandles(index); 359 360 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN: 361 return GetResourceUSERHandles(index); 362 363 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN: 364 return GetResourceIdleWakeupsPerSecond(index); 365 366 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: 367 return GetResourceGoatsTeleported(index); 368 369 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: 370 return GetResourceWebCoreImageCacheSize(index); 371 372 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: 373 return GetResourceWebCoreScriptsCacheSize(index); 374 375 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: 376 return GetResourceWebCoreCSSCacheSize(index); 377 378 case IDS_TASK_MANAGER_FPS_COLUMN: 379 return GetResourceFPS(index); 380 381 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN: 382 return GetResourceVideoMemory(index); 383 384 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN: 385 return GetResourceSqliteMemoryUsed(index); 386 387 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN: 388 return GetResourceV8MemoryAllocatedSize(index); 389 390 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN: 391 return GetResourceNaClDebugStubPort(index); 392 393 default: 394 NOTREACHED(); 395 return base::string16(); 396 } 397} 398 399const base::string16& TaskManagerModel::GetResourceTitle(int index) const { 400 PerResourceValues& values = GetPerResourceValues(index); 401 if (!values.is_title_valid) { 402 values.is_title_valid = true; 403 values.title = GetResource(index)->GetTitle(); 404 } 405 return values.title; 406} 407 408const base::string16& TaskManagerModel::GetResourceProfileName( 409 int index) const { 410 PerResourceValues& values(GetPerResourceValues(index)); 411 if (!values.is_profile_name_valid) { 412 values.is_profile_name_valid = true; 413 values.profile_name = GetResource(index)->GetProfileName(); 414 } 415 return values.profile_name; 416} 417 418base::string16 TaskManagerModel::GetResourceNaClDebugStubPort(int index) const { 419 int port = GetNaClDebugStubPort(index); 420 if (port == 0) { 421 return base::ASCIIToUTF16("N/A"); 422 } else { 423 return base::IntToString16(port); 424 } 425} 426 427base::string16 TaskManagerModel::GetResourceNetworkUsage(int index) const { 428 int64 net_usage = GetNetworkUsage(index); 429 if (net_usage == -1) 430 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 431 if (net_usage == 0) 432 return base::ASCIIToUTF16("0"); 433 base::string16 net_byte = ui::FormatSpeed(net_usage); 434 // Force number string to have LTR directionality. 435 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte); 436} 437 438base::string16 TaskManagerModel::GetResourceCPUUsage(int index) const { 439 return base::UTF8ToUTF16(base::StringPrintf( 440#if defined(OS_MACOSX) 441 // Activity Monitor shows %cpu with one decimal digit -- be 442 // consistent with that. 443 "%.1f", 444#else 445 "%.0f", 446#endif 447 GetCPUUsage(GetResource(index)))); 448} 449 450base::string16 TaskManagerModel::GetResourcePrivateMemory(int index) const { 451 size_t private_mem; 452 if (!GetPrivateMemory(index, &private_mem)) 453 return base::ASCIIToUTF16("N/A"); 454 return GetMemCellText(private_mem); 455} 456 457base::string16 TaskManagerModel::GetResourceSharedMemory(int index) const { 458 size_t shared_mem; 459 if (!GetSharedMemory(index, &shared_mem)) 460 return base::ASCIIToUTF16("N/A"); 461 return GetMemCellText(shared_mem); 462} 463 464base::string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const { 465 size_t phys_mem; 466 GetPhysicalMemory(index, &phys_mem); 467 return GetMemCellText(phys_mem); 468} 469 470base::string16 TaskManagerModel::GetResourceProcessId(int index) const { 471 return base::IntToString16(GetProcessId(index)); 472} 473 474base::string16 TaskManagerModel::GetResourceGDIHandles(int index) const { 475 size_t current, peak; 476 GetGDIHandles(index, ¤t, &peak); 477 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT, 478 base::IntToString16(current), base::IntToString16(peak)); 479} 480 481base::string16 TaskManagerModel::GetResourceUSERHandles(int index) const { 482 size_t current, peak; 483 GetUSERHandles(index, ¤t, &peak); 484 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT, 485 base::IntToString16(current), base::IntToString16(peak)); 486} 487 488base::string16 TaskManagerModel::GetResourceWebCoreImageCacheSize( 489 int index) const { 490 if (!CacheWebCoreStats(index)) 491 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 492 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.images); 493} 494 495base::string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize( 496 int index) const { 497 if (!CacheWebCoreStats(index)) 498 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 499 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.scripts); 500} 501 502base::string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize( 503 int index) const { 504 if (!CacheWebCoreStats(index)) 505 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 506 return FormatStatsSize( 507 GetPerResourceValues(index).webcore_stats.cssStyleSheets); 508} 509 510base::string16 TaskManagerModel::GetResourceVideoMemory(int index) const { 511 size_t video_memory; 512 bool has_duplicates; 513 if (!GetVideoMemory(index, &video_memory, &has_duplicates) || !video_memory) 514 return base::ASCIIToUTF16("N/A"); 515 if (has_duplicates) { 516 return GetMemCellText(video_memory) + base::ASCIIToUTF16("*"); 517 } 518 return GetMemCellText(video_memory); 519} 520 521base::string16 TaskManagerModel::GetResourceFPS( 522 int index) const { 523 float fps = 0; 524 if (!GetFPS(index, &fps)) 525 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 526 return base::UTF8ToUTF16(base::StringPrintf("%.0f", fps)); 527} 528 529base::string16 TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const { 530 size_t bytes = 0; 531 if (!GetSqliteMemoryUsedBytes(index, &bytes)) 532 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 533 return GetMemCellText(bytes); 534} 535 536base::string16 TaskManagerModel::GetResourceIdleWakeupsPerSecond(int index) 537 const { 538 return base::FormatNumber(GetIdleWakeupsPerSecond(GetResource(index))); 539} 540 541base::string16 TaskManagerModel::GetResourceGoatsTeleported(int index) const { 542 CHECK_LT(index, ResourceCount()); 543 return base::FormatNumber(GetGoatsTeleported(index)); 544} 545 546base::string16 TaskManagerModel::GetResourceV8MemoryAllocatedSize( 547 int index) const { 548 size_t memory_allocated = 0, memory_used = 0; 549 if (!GetV8MemoryUsed(index, &memory_used) || 550 !GetV8Memory(index, &memory_allocated)) 551 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT); 552 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT, 553 ui::FormatBytesWithUnits(memory_allocated, 554 ui::DATA_UNITS_KIBIBYTE, 555 false), 556 ui::FormatBytesWithUnits(memory_used, 557 ui::DATA_UNITS_KIBIBYTE, 558 false)); 559} 560 561bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const { 562 *result = 0; 563 base::ProcessHandle handle = GetResource(index)->GetProcess(); 564 if (!CachePrivateAndSharedMemory(handle)) 565 return false; 566 *result = per_process_cache_[handle].private_bytes; 567 return true; 568} 569 570bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const { 571 *result = 0; 572 base::ProcessHandle handle = GetResource(index)->GetProcess(); 573 if (!CachePrivateAndSharedMemory(handle)) 574 return false; 575 *result = per_process_cache_[handle].shared_bytes; 576 return true; 577} 578 579bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const { 580 *result = 0; 581 582 base::ProcessHandle handle = GetResource(index)->GetProcess(); 583 PerProcessValues& values(per_process_cache_[handle]); 584 585 if (!values.is_physical_memory_valid) { 586 base::WorkingSetKBytes ws_usage; 587 MetricsMap::const_iterator iter = metrics_map_.find(handle); 588 if (iter == metrics_map_.end() || 589 !iter->second->GetWorkingSetKBytes(&ws_usage)) 590 return false; 591 592 values.is_physical_memory_valid = true; 593#if defined(OS_LINUX) 594 // On Linux private memory is also resident. Just use it. 595 values.physical_memory = ws_usage.priv * 1024; 596#else 597 // Memory = working_set.private + working_set.shareable. 598 // We exclude the shared memory. 599 values.physical_memory = iter->second->GetWorkingSetSize(); 600 values.physical_memory -= ws_usage.shared * 1024; 601#endif 602 } 603 *result = values.physical_memory; 604 return true; 605} 606 607void TaskManagerModel::GetGDIHandles(int index, 608 size_t* current, 609 size_t* peak) const { 610 *current = 0; 611 *peak = 0; 612#if defined(OS_WIN) 613 base::ProcessHandle handle = GetResource(index)->GetProcess(); 614 PerProcessValues& values(per_process_cache_[handle]); 615 616 if (!values.is_gdi_handles_valid) { 617 GetWinGDIHandles(GetResource(index)->GetProcess(), 618 &values.gdi_handles, 619 &values.gdi_handles_peak); 620 values.is_gdi_handles_valid = true; 621 } 622 *current = values.gdi_handles; 623 *peak = values.gdi_handles_peak; 624#endif 625} 626 627void TaskManagerModel::GetUSERHandles(int index, 628 size_t* current, 629 size_t* peak) const { 630 *current = 0; 631 *peak = 0; 632#if defined(OS_WIN) 633 base::ProcessHandle handle = GetResource(index)->GetProcess(); 634 PerProcessValues& values(per_process_cache_[handle]); 635 636 if (!values.is_user_handles_valid) { 637 GetWinUSERHandles(GetResource(index)->GetProcess(), 638 &values.user_handles, 639 &values.user_handles_peak); 640 values.is_user_handles_valid = true; 641 } 642 *current = values.user_handles; 643 *peak = values.user_handles_peak; 644#endif 645} 646 647bool TaskManagerModel::GetWebCoreCacheStats( 648 int index, 649 blink::WebCache::ResourceTypeStats* result) const { 650 if (!CacheWebCoreStats(index)) 651 return false; 652 *result = GetPerResourceValues(index).webcore_stats; 653 return true; 654} 655 656bool TaskManagerModel::GetVideoMemory(int index, 657 size_t* video_memory, 658 bool* has_duplicates) const { 659 *video_memory = 0; 660 *has_duplicates = false; 661 662 base::ProcessId pid = GetProcessId(index); 663 PerProcessValues& values( 664 per_process_cache_[GetResource(index)->GetProcess()]); 665 if (!values.is_video_memory_valid) { 666 content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i = 667 video_memory_usage_stats_.process_map.find(pid); 668 if (i == video_memory_usage_stats_.process_map.end()) 669 return false; 670 values.is_video_memory_valid = true; 671 values.video_memory = i->second.video_memory; 672 values.video_memory_has_duplicates = i->second.has_duplicates; 673 } 674 *video_memory = values.video_memory; 675 *has_duplicates = values.video_memory_has_duplicates; 676 return true; 677} 678 679bool TaskManagerModel::GetFPS(int index, float* result) const { 680 *result = 0; 681 PerResourceValues& values(GetPerResourceValues(index)); 682 if (!values.is_fps_valid) { 683 if (!GetResource(index)->ReportsFPS()) 684 return false; 685 values.is_fps_valid = true; 686 values.fps = GetResource(index)->GetFPS(); 687 } 688 *result = values.fps; 689 return true; 690} 691 692bool TaskManagerModel::GetSqliteMemoryUsedBytes( 693 int index, 694 size_t* result) const { 695 *result = 0; 696 PerResourceValues& values(GetPerResourceValues(index)); 697 if (!values.is_sqlite_memory_bytes_valid) { 698 if (!GetResource(index)->ReportsSqliteMemoryUsed()) 699 return false; 700 values.is_sqlite_memory_bytes_valid = true; 701 values.sqlite_memory_bytes = GetResource(index)->SqliteMemoryUsedBytes(); 702 } 703 *result = values.sqlite_memory_bytes; 704 return true; 705} 706 707bool TaskManagerModel::GetV8Memory(int index, size_t* result) const { 708 *result = 0; 709 if (!CacheV8Memory(index)) 710 return false; 711 *result = GetPerResourceValues(index).v8_memory_allocated; 712 return true; 713} 714 715bool TaskManagerModel::GetV8MemoryUsed(int index, size_t* result) const { 716 *result = 0; 717 if (!CacheV8Memory(index)) 718 return false; 719 *result = GetPerResourceValues(index).v8_memory_used; 720 return true; 721} 722 723bool TaskManagerModel::CanActivate(int index) const { 724 CHECK_LT(index, ResourceCount()); 725 return GetResourceWebContents(index) != NULL; 726} 727 728bool TaskManagerModel::CanInspect(int index) const { 729 return GetResource(index)->CanInspect(); 730} 731 732void TaskManagerModel::Inspect(int index) const { 733 CHECK_LT(index, ResourceCount()); 734 GetResource(index)->Inspect(); 735} 736 737int TaskManagerModel::GetGoatsTeleported(int index) const { 738 PerResourceValues& values(GetPerResourceValues(index)); 739 if (!values.is_goats_teleported_valid) { 740 values.is_goats_teleported_valid = true; 741 values.goats_teleported = goat_salt_ * (index + 1); 742 values.goats_teleported = (values.goats_teleported >> 16) & 255; 743 } 744 return values.goats_teleported; 745} 746 747bool TaskManagerModel::IsResourceFirstInGroup(int index) const { 748 Resource* resource = GetResource(index); 749 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess()); 750 DCHECK(iter != group_map_.end()); 751 const ResourceList* group = iter->second; 752 return ((*group)[0] == resource); 753} 754 755bool TaskManagerModel::IsResourceLastInGroup(int index) const { 756 Resource* resource = GetResource(index); 757 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess()); 758 DCHECK(iter != group_map_.end()); 759 const ResourceList* group = iter->second; 760 return (group->back() == resource); 761} 762 763gfx::ImageSkia TaskManagerModel::GetResourceIcon(int index) const { 764 gfx::ImageSkia icon = GetResource(index)->GetIcon(); 765 if (!icon.isNull()) 766 return icon; 767 768 static gfx::ImageSkia* default_icon = ResourceBundle::GetSharedInstance(). 769 GetImageSkiaNamed(IDR_DEFAULT_FAVICON); 770 return *default_icon; 771} 772 773TaskManagerModel::GroupRange 774TaskManagerModel::GetGroupRangeForResource(int index) const { 775 Resource* resource = GetResource(index); 776 GroupMap::const_iterator group_iter = 777 group_map_.find(resource->GetProcess()); 778 DCHECK(group_iter != group_map_.end()); 779 ResourceList* group = group_iter->second; 780 DCHECK(group); 781 if (group->size() == 1) { 782 return std::make_pair(index, 1); 783 } else { 784 for (int i = index; i >= 0; --i) { 785 if (GetResource(i) == (*group)[0]) 786 return std::make_pair(i, group->size()); 787 } 788 NOTREACHED(); 789 return std::make_pair(-1, -1); 790 } 791} 792 793int TaskManagerModel::GetGroupIndexForResource(int index) const { 794 int group_index = -1; 795 for (int i = 0; i <= index; ++i) { 796 if (IsResourceFirstInGroup(i)) 797 group_index++; 798 } 799 800 DCHECK_NE(group_index, -1); 801 return group_index; 802} 803 804int TaskManagerModel::GetResourceIndexForGroup(int group_index, 805 int index_in_group) const { 806 int group_count = -1; 807 int count_in_group = -1; 808 for (int i = 0; i < ResourceCount(); ++i) { 809 if (IsResourceFirstInGroup(i)) 810 group_count++; 811 812 if (group_count == group_index) { 813 count_in_group++; 814 if (count_in_group == index_in_group) 815 return i; 816 } else if (group_count > group_index) { 817 break; 818 } 819 } 820 821 NOTREACHED(); 822 return -1; 823} 824 825int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const { 826 CHECK(row1 < ResourceCount() && row2 < ResourceCount()); 827 switch (col_id) { 828 case IDS_TASK_MANAGER_TASK_COLUMN: { 829 static icu::Collator* collator = NULL; 830 if (!collator) { 831 UErrorCode create_status = U_ZERO_ERROR; 832 collator = icu::Collator::createInstance(create_status); 833 if (!U_SUCCESS(create_status)) { 834 collator = NULL; 835 NOTREACHED(); 836 } 837 } 838 const base::string16& title1 = GetResourceTitle(row1); 839 const base::string16& title2 = GetResourceTitle(row2); 840 UErrorCode compare_status = U_ZERO_ERROR; 841 UCollationResult compare_result = collator->compare( 842 static_cast<const UChar*>(title1.c_str()), 843 static_cast<int>(title1.length()), 844 static_cast<const UChar*>(title2.c_str()), 845 static_cast<int>(title2.length()), 846 compare_status); 847 DCHECK(U_SUCCESS(compare_status)); 848 return compare_result; 849 } 850 851 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN: { 852 const base::string16& profile1 = GetResourceProfileName(row1); 853 const base::string16& profile2 = GetResourceProfileName(row2); 854 return profile1.compare(0, profile1.length(), profile2, 0, 855 profile2.length()); 856 } 857 858 case IDS_TASK_MANAGER_NET_COLUMN: 859 return ValueCompare(GetNetworkUsage(GetResource(row1)), 860 GetNetworkUsage(GetResource(row2))); 861 862 case IDS_TASK_MANAGER_CPU_COLUMN: 863 return ValueCompare(GetCPUUsage(GetResource(row1)), 864 GetCPUUsage(GetResource(row2))); 865 866 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN: 867 return ValueCompareMember( 868 this, &TaskManagerModel::GetPrivateMemory, row1, row2); 869 870 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN: 871 return ValueCompareMember( 872 this, &TaskManagerModel::GetSharedMemory, row1, row2); 873 874 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN: 875 return ValueCompareMember( 876 this, &TaskManagerModel::GetPhysicalMemory, row1, row2); 877 878 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN: 879 return ValueCompare(GetNaClDebugStubPort(row1), 880 GetNaClDebugStubPort(row2)); 881 882 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN: 883 return ValueCompare(GetProcessId(row1), GetProcessId(row2)); 884 885 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN: { 886 size_t current1, peak1; 887 size_t current2, peak2; 888 GetGDIHandles(row1, ¤t1, &peak1); 889 GetGDIHandles(row2, ¤t2, &peak2); 890 return ValueCompare(current1, current2); 891 } 892 893 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN: { 894 size_t current1, peak1; 895 size_t current2, peak2; 896 GetUSERHandles(row1, ¤t1, &peak1); 897 GetUSERHandles(row2, ¤t2, &peak2); 898 return ValueCompare(current1, current2); 899 } 900 901 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN: 902 return ValueCompare(GetIdleWakeupsPerSecond(row1), 903 GetIdleWakeupsPerSecond(row2)); 904 905 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: 906 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: 907 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: { 908 bool row1_stats_valid = CacheWebCoreStats(row1); 909 bool row2_stats_valid = CacheWebCoreStats(row2); 910 if (row1_stats_valid && row2_stats_valid) { 911 const blink::WebCache::ResourceTypeStats& stats1( 912 GetPerResourceValues(row1).webcore_stats); 913 const blink::WebCache::ResourceTypeStats& stats2( 914 GetPerResourceValues(row2).webcore_stats); 915 switch (col_id) { 916 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN: 917 return ValueCompare(stats1.images.size, stats2.images.size); 918 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN: 919 return ValueCompare(stats1.scripts.size, stats2.scripts.size); 920 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: 921 return ValueCompare(stats1.cssStyleSheets.size, 922 stats2.cssStyleSheets.size); 923 default: 924 NOTREACHED(); 925 return 0; 926 } 927 } 928 return OrderUnavailableValue(row1_stats_valid, row2_stats_valid); 929 } 930 931 case IDS_TASK_MANAGER_FPS_COLUMN: 932 return ValueCompareMember( 933 this, &TaskManagerModel::GetFPS, row1, row2); 934 935 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN: { 936 size_t value1; 937 size_t value2; 938 bool has_duplicates; 939 bool value1_valid = GetVideoMemory(row1, &value1, &has_duplicates); 940 bool value2_valid = GetVideoMemory(row2, &value2, &has_duplicates); 941 return value1_valid && value2_valid ? ValueCompare(value1, value2) : 942 OrderUnavailableValue(value1_valid, value2_valid); 943 } 944 945 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN: 946 return ValueCompare(GetGoatsTeleported(row1), GetGoatsTeleported(row2)); 947 948 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN: 949 return ValueCompareMember( 950 this, &TaskManagerModel::GetV8Memory, row1, row2); 951 952 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN: 953 return ValueCompareMember( 954 this, &TaskManagerModel::GetSqliteMemoryUsedBytes, row1, row2); 955 956 default: 957 NOTREACHED(); 958 break; 959 } 960 return 0; 961} 962 963int TaskManagerModel::GetUniqueChildProcessId(int index) const { 964 return GetResource(index)->GetUniqueChildProcessId(); 965} 966 967Resource::Type TaskManagerModel::GetResourceType(int index) const { 968 return GetResource(index)->GetType(); 969} 970 971WebContents* TaskManagerModel::GetResourceWebContents(int index) const { 972 return GetResource(index)->GetWebContents(); 973} 974 975void TaskManagerModel::AddResource(Resource* resource) { 976 base::ProcessHandle process = resource->GetProcess(); 977 978 ResourceList* group_entries = NULL; 979 GroupMap::const_iterator group_iter = group_map_.find(process); 980 int new_entry_index = 0; 981 if (group_iter == group_map_.end()) { 982 group_entries = new ResourceList(); 983 group_map_[process] = group_entries; 984 group_entries->push_back(resource); 985 986 // Not part of a group, just put at the end of the list. 987 resources_.push_back(resource); 988 new_entry_index = static_cast<int>(resources_.size() - 1); 989 } else { 990 group_entries = group_iter->second; 991 group_entries->push_back(resource); 992 993 // Insert the new entry right after the last entry of its group. 994 ResourceList::iterator iter = 995 std::find(resources_.begin(), 996 resources_.end(), 997 (*group_entries)[group_entries->size() - 2]); 998 DCHECK(iter != resources_.end()); 999 new_entry_index = static_cast<int>(iter - resources_.begin()) + 1; 1000 resources_.insert(++iter, resource); 1001 } 1002 1003 // Create the ProcessMetrics for this process if needed (not in map). 1004 if (metrics_map_.find(process) == metrics_map_.end()) { 1005 base::ProcessMetrics* pm = 1006#if !defined(OS_MACOSX) 1007 base::ProcessMetrics::CreateProcessMetrics(process); 1008#else 1009 base::ProcessMetrics::CreateProcessMetrics( 1010 process, content::BrowserChildProcessHost::GetPortProvider()); 1011#endif 1012 1013 metrics_map_[process] = pm; 1014 } 1015 1016 // Notify the table that the contents have changed for it to redraw. 1017 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 1018 OnItemsAdded(new_entry_index, 1)); 1019} 1020 1021void TaskManagerModel::RemoveResource(Resource* resource) { 1022 base::ProcessHandle process = resource->GetProcess(); 1023 1024 // Find the associated group. 1025 GroupMap::iterator group_iter = group_map_.find(process); 1026 DCHECK(group_iter != group_map_.end()); 1027 ResourceList* group_entries = group_iter->second; 1028 1029 // Remove the entry from the group map. 1030 ResourceList::iterator iter = std::find(group_entries->begin(), 1031 group_entries->end(), 1032 resource); 1033 DCHECK(iter != group_entries->end()); 1034 group_entries->erase(iter); 1035 1036 // If there are no more entries for that process, do the clean-up. 1037 if (group_entries->empty()) { 1038 delete group_entries; 1039 group_map_.erase(process); 1040 1041 // Nobody is using this process, we don't need the process metrics anymore. 1042 MetricsMap::iterator pm_iter = metrics_map_.find(process); 1043 DCHECK(pm_iter != metrics_map_.end()); 1044 if (pm_iter != metrics_map_.end()) { 1045 delete pm_iter->second; 1046 metrics_map_.erase(process); 1047 } 1048 } 1049 1050 // Prepare to remove the entry from the model list. 1051 iter = std::find(resources_.begin(), resources_.end(), resource); 1052 DCHECK(iter != resources_.end()); 1053 int index = static_cast<int>(iter - resources_.begin()); 1054 1055 // Notify the observers that the contents will change. 1056 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 1057 OnItemsToBeRemoved(index, 1)); 1058 1059 // Now actually remove the entry from the model list. 1060 resources_.erase(iter); 1061 1062 // Remove the entry from the network maps. 1063 ResourceValueMap::iterator net_iter = 1064 current_byte_count_map_.find(resource); 1065 if (net_iter != current_byte_count_map_.end()) 1066 current_byte_count_map_.erase(net_iter); 1067 1068 // Notify the table that the contents have changed. 1069 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 1070 OnItemsRemoved(index, 1)); 1071} 1072 1073void TaskManagerModel::StartUpdating() { 1074 // Multiple StartUpdating requests may come in, and we only need to take 1075 // action the first time. 1076 update_requests_++; 1077 if (update_requests_ > 1) 1078 return; 1079 DCHECK_EQ(1, update_requests_); 1080 DCHECK_NE(TASK_PENDING, update_state_); 1081 1082 // If update_state_ is STOPPING, it means a task is still pending. Setting 1083 // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()). 1084 if (update_state_ == IDLE) { 1085 base::MessageLoop::current()->PostTask( 1086 FROM_HERE, 1087 base::Bind(&TaskManagerModel::RefreshCallback, this)); 1088 } 1089 update_state_ = TASK_PENDING; 1090 1091 // Notify resource providers that we are updating. 1092 StartListening(); 1093 1094 if (!resources_.empty()) { 1095 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 1096 OnReadyPeriodicalUpdate()); 1097 } 1098} 1099 1100void TaskManagerModel::StopUpdating() { 1101 // Don't actually stop updating until we have heard as many calls as those 1102 // to StartUpdating. 1103 update_requests_--; 1104 if (update_requests_ > 0) 1105 return; 1106 // Make sure that update_requests_ cannot go negative. 1107 CHECK_EQ(0, update_requests_); 1108 DCHECK_EQ(TASK_PENDING, update_state_); 1109 update_state_ = STOPPING; 1110 1111 // Notify resource providers that we are done updating. 1112 StopListening(); 1113} 1114 1115void TaskManagerModel::StartListening() { 1116 // Multiple StartListening requests may come in and we only need to take 1117 // action the first time. 1118 listen_requests_++; 1119 if (listen_requests_ > 1) 1120 return; 1121 DCHECK_EQ(1, listen_requests_); 1122 1123 // Notify resource providers that we should start listening to events. 1124 for (ResourceProviderList::iterator iter = providers_.begin(); 1125 iter != providers_.end(); ++iter) { 1126 (*iter)->StartUpdating(); 1127 } 1128} 1129 1130void TaskManagerModel::StopListening() { 1131 // Don't actually stop listening until we have heard as many calls as those 1132 // to StartListening. 1133 listen_requests_--; 1134 if (listen_requests_ > 0) 1135 return; 1136 1137 DCHECK_EQ(0, listen_requests_); 1138 1139 // Notify resource providers that we are done listening. 1140 for (ResourceProviderList::const_iterator iter = providers_.begin(); 1141 iter != providers_.end(); ++iter) { 1142 (*iter)->StopUpdating(); 1143 } 1144 1145 // Must clear the resources before the next attempt to start listening. 1146 Clear(); 1147} 1148 1149void TaskManagerModel::Clear() { 1150 int size = ResourceCount(); 1151 if (size > 0) { 1152 resources_.clear(); 1153 1154 // Clear the groups. 1155 STLDeleteValues(&group_map_); 1156 1157 // Clear the process related info. 1158 STLDeleteValues(&metrics_map_); 1159 1160 // Clear the network maps. 1161 current_byte_count_map_.clear(); 1162 1163 per_resource_cache_.clear(); 1164 per_process_cache_.clear(); 1165 1166 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 1167 OnItemsRemoved(0, size)); 1168 } 1169} 1170 1171void TaskManagerModel::ModelChanged() { 1172 // Notify the table that the contents have changed for it to redraw. 1173 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, OnModelChanged()); 1174} 1175 1176void TaskManagerModel::Refresh() { 1177 goat_salt_ = base::RandUint64(); 1178 1179 per_resource_cache_.clear(); 1180 per_process_cache_.clear(); 1181 1182 // Compute the CPU usage values. 1183 // Note that we compute the CPU usage for all resources (instead of doing it 1184 // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last 1185 // time it was called, and not calling it everytime would skew the value the 1186 // next time it is retrieved (as it would be for more than 1 cycle). 1187 // The same is true for idle wakeups. 1188 for (ResourceList::iterator iter = resources_.begin(); 1189 iter != resources_.end(); ++iter) { 1190 base::ProcessHandle process = (*iter)->GetProcess(); 1191 PerProcessValues& values(per_process_cache_[process]); 1192 if (values.is_cpu_usage_valid && values.is_idle_wakeups_valid) 1193 continue; 1194 MetricsMap::iterator metrics_iter = metrics_map_.find(process); 1195 DCHECK(metrics_iter != metrics_map_.end()); 1196 if (!values.is_cpu_usage_valid) { 1197 values.is_cpu_usage_valid = true; 1198 values.cpu_usage = metrics_iter->second->GetCPUUsage(); 1199 } 1200#if defined(OS_MACOSX) 1201 // TODO: Implement GetIdleWakeupsPerSecond() on other platforms, 1202 // crbug.com/120488 1203 if (!values.is_idle_wakeups_valid) { 1204 values.is_idle_wakeups_valid = true; 1205 values.idle_wakeups = metrics_iter->second->GetIdleWakeupsPerSecond(); 1206 } 1207#endif // defined(OS_MACOSX) 1208 } 1209 1210 // Send a request to refresh GPU memory consumption values 1211 RefreshVideoMemoryUsageStats(); 1212 1213 // Compute the new network usage values. 1214 base::TimeDelta update_time = 1215 base::TimeDelta::FromMilliseconds(kUpdateTimeMs); 1216 for (ResourceValueMap::iterator iter = current_byte_count_map_.begin(); 1217 iter != current_byte_count_map_.end(); ++iter) { 1218 PerResourceValues* values = &(per_resource_cache_[iter->first]); 1219 if (update_time > base::TimeDelta::FromSeconds(1)) 1220 values->network_usage = iter->second / update_time.InSeconds(); 1221 else 1222 values->network_usage = iter->second * (1 / update_time.InSeconds()); 1223 1224 // Then we reset the current byte count. 1225 iter->second = 0; 1226 } 1227 1228 // Let resources update themselves if they need to. 1229 for (ResourceList::iterator iter = resources_.begin(); 1230 iter != resources_.end(); ++iter) { 1231 (*iter)->Refresh(); 1232 } 1233 1234 if (!resources_.empty()) { 1235 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, 1236 OnItemsChanged(0, ResourceCount())); 1237 } 1238} 1239 1240void TaskManagerModel::NotifyResourceTypeStats( 1241 base::ProcessId renderer_id, 1242 const blink::WebCache::ResourceTypeStats& stats) { 1243 for (ResourceList::iterator it = resources_.begin(); 1244 it != resources_.end(); ++it) { 1245 if (base::GetProcId((*it)->GetProcess()) == renderer_id) { 1246 (*it)->NotifyResourceTypeStats(stats); 1247 } 1248 } 1249} 1250 1251void TaskManagerModel::NotifyFPS(base::ProcessId renderer_id, 1252 int routing_id, 1253 float fps) { 1254 for (ResourceList::iterator it = resources_.begin(); 1255 it != resources_.end(); ++it) { 1256 if (base::GetProcId((*it)->GetProcess()) == renderer_id && 1257 (*it)->GetRoutingID() == routing_id) { 1258 (*it)->NotifyFPS(fps); 1259 } 1260 } 1261} 1262 1263void TaskManagerModel::NotifyVideoMemoryUsageStats( 1264 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) { 1265 DCHECK(pending_video_memory_usage_stats_update_); 1266 video_memory_usage_stats_ = video_memory_usage_stats; 1267 pending_video_memory_usage_stats_update_ = false; 1268} 1269 1270void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id, 1271 size_t v8_memory_allocated, 1272 size_t v8_memory_used) { 1273 for (ResourceList::iterator it = resources_.begin(); 1274 it != resources_.end(); ++it) { 1275 if (base::GetProcId((*it)->GetProcess()) == renderer_id) { 1276 (*it)->NotifyV8HeapStats(v8_memory_allocated, v8_memory_used); 1277 } 1278 } 1279} 1280 1281void TaskManagerModel::NotifyBytesRead(const net::URLRequest& request, 1282 int byte_count) { 1283 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1284 1285 // Only net::URLRequestJob instances created by the ResourceDispatcherHost 1286 // have an associated ResourceRequestInfo and a render frame associated. 1287 // All other jobs will have -1 returned for the render process child and 1288 // routing ids - the jobs may still match a resource based on their origin id, 1289 // otherwise BytesRead() will attribute the activity to the Browser resource. 1290 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request); 1291 int child_id = -1, route_id = -1; 1292 if (info) 1293 info->GetAssociatedRenderFrame(&child_id, &route_id); 1294 1295 // Get the origin PID of the request's originator. This will only be set for 1296 // plugins - for renderer or browser initiated requests it will be zero. 1297 int origin_pid = 0; 1298 if (info) 1299 origin_pid = info->GetOriginPID(); 1300 1301 if (bytes_read_buffer_.empty()) { 1302 base::MessageLoop::current()->PostDelayedTask( 1303 FROM_HERE, 1304 base::Bind(&TaskManagerModel::NotifyMultipleBytesRead, this), 1305 base::TimeDelta::FromSeconds(1)); 1306 } 1307 1308 bytes_read_buffer_.push_back( 1309 BytesReadParam(origin_pid, child_id, route_id, byte_count)); 1310} 1311 1312// This is called on the UI thread. 1313void TaskManagerModel::NotifyDataReady() { 1314 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1315 for (size_t i = 0; i < on_data_ready_callbacks_.size(); ++i) { 1316 if (!on_data_ready_callbacks_[i].is_null()) 1317 on_data_ready_callbacks_[i].Run(); 1318 } 1319 1320 on_data_ready_callbacks_.clear(); 1321} 1322 1323void TaskManagerModel::RegisterOnDataReadyCallback( 1324 const base::Closure& callback) { 1325 on_data_ready_callbacks_.push_back(callback); 1326} 1327 1328TaskManagerModel::~TaskManagerModel() { 1329 on_data_ready_callbacks_.clear(); 1330} 1331 1332void TaskManagerModel::RefreshCallback() { 1333 DCHECK_NE(IDLE, update_state_); 1334 1335 if (update_state_ == STOPPING) { 1336 // We have been asked to stop. 1337 update_state_ = IDLE; 1338 return; 1339 } 1340 1341 Refresh(); 1342 1343 // Schedule the next update. 1344 base::MessageLoop::current()->PostDelayedTask( 1345 FROM_HERE, 1346 base::Bind(&TaskManagerModel::RefreshCallback, this), 1347 base::TimeDelta::FromMilliseconds(kUpdateTimeMs)); 1348} 1349 1350void TaskManagerModel::RefreshVideoMemoryUsageStats() { 1351 if (pending_video_memory_usage_stats_update_) 1352 return; 1353 1354 if (!video_memory_usage_stats_observer_.get()) { 1355 video_memory_usage_stats_observer_.reset( 1356 new TaskManagerModelGpuDataManagerObserver()); 1357 } 1358 pending_video_memory_usage_stats_update_ = true; 1359 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate(); 1360} 1361 1362int64 TaskManagerModel::GetNetworkUsageForResource(Resource* resource) const { 1363 // Returns default of 0 if no network usage. 1364 return per_resource_cache_[resource].network_usage; 1365} 1366 1367void TaskManagerModel::BytesRead(BytesReadParam param) { 1368 if (update_state_ != TASK_PENDING || listen_requests_ == 0) { 1369 // A notification sneaked in while we were stopping the updating, just 1370 // ignore it. 1371 return; 1372 } 1373 1374 // TODO(jcampan): this should be improved once we have a better way of 1375 // linking a network notification back to the object that initiated it. 1376 Resource* resource = NULL; 1377 for (ResourceProviderList::iterator iter = providers_.begin(); 1378 iter != providers_.end(); ++iter) { 1379 resource = (*iter)->GetResource(param.origin_pid, 1380 param.child_id, 1381 param.route_id); 1382 if (resource) 1383 break; 1384 } 1385 1386 if (resource == NULL) { 1387 // We can't match a resource to the notification. That might mean the 1388 // tab that started a download was closed, or the request may have had 1389 // no originating resource associated with it in the first place. 1390 // We attribute orphaned/unaccounted activity to the Browser process. 1391 CHECK(param.origin_pid || (param.child_id != -1)); 1392 param.origin_pid = 0; 1393 param.child_id = param.route_id = -1; 1394 BytesRead(param); 1395 return; 1396 } 1397 1398 // We do support network usage, mark the resource as such so it can report 0 1399 // instead of N/A. 1400 if (!resource->SupportNetworkUsage()) 1401 resource->SetSupportNetworkUsage(); 1402 1403 ResourceValueMap::const_iterator iter_res = 1404 current_byte_count_map_.find(resource); 1405 if (iter_res == current_byte_count_map_.end()) 1406 current_byte_count_map_[resource] = param.byte_count; 1407 else 1408 current_byte_count_map_[resource] = iter_res->second + param.byte_count; 1409} 1410 1411void TaskManagerModel::MultipleBytesRead( 1412 const std::vector<BytesReadParam>* params) { 1413 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 1414 for (std::vector<BytesReadParam>::const_iterator it = params->begin(); 1415 it != params->end(); ++it) { 1416 BytesRead(*it); 1417 } 1418} 1419 1420void TaskManagerModel::NotifyMultipleBytesRead() { 1421 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); 1422 DCHECK(!bytes_read_buffer_.empty()); 1423 1424 std::vector<BytesReadParam>* bytes_read_buffer = 1425 new std::vector<BytesReadParam>; 1426 bytes_read_buffer_.swap(*bytes_read_buffer); 1427 BrowserThread::PostTask( 1428 BrowserThread::UI, FROM_HERE, 1429 base::Bind(&TaskManagerModel::MultipleBytesRead, this, 1430 base::Owned(bytes_read_buffer))); 1431} 1432 1433int64 TaskManagerModel::GetNetworkUsage(Resource* resource) const { 1434 int64 net_usage = GetNetworkUsageForResource(resource); 1435 if (net_usage == 0 && !resource->SupportNetworkUsage()) 1436 return -1; 1437 return net_usage; 1438} 1439 1440double TaskManagerModel::GetCPUUsage(Resource* resource) const { 1441 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]); 1442 // Returns 0 if not valid, which is fine. 1443 return values.cpu_usage; 1444} 1445 1446int TaskManagerModel::GetIdleWakeupsPerSecond(Resource* resource) const { 1447 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]); 1448 // Returns 0 if not valid, which is fine. 1449 return values.idle_wakeups; 1450} 1451 1452base::string16 TaskManagerModel::GetMemCellText(int64 number) const { 1453#if !defined(OS_MACOSX) 1454 base::string16 str = base::FormatNumber(number / 1024); 1455 1456 // Adjust number string if necessary. 1457 base::i18n::AdjustStringForLocaleDirection(&str); 1458 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT, str); 1459#else 1460 // System expectation is to show "100 kB", "200 MB", etc. 1461 // TODO(thakis): Switch to metric units (as opposed to powers of two). 1462 return ui::FormatBytes(number); 1463#endif 1464} 1465 1466bool TaskManagerModel::CachePrivateAndSharedMemory( 1467 base::ProcessHandle handle) const { 1468 PerProcessValues& values(per_process_cache_[handle]); 1469 if (values.is_private_and_shared_valid) 1470 return true; 1471 1472 MetricsMap::const_iterator iter = metrics_map_.find(handle); 1473 if (iter == metrics_map_.end() || 1474 !iter->second->GetMemoryBytes(&values.private_bytes, 1475 &values.shared_bytes)) { 1476 return false; 1477 } 1478 1479 values.is_private_and_shared_valid = true; 1480 return true; 1481} 1482 1483bool TaskManagerModel::CacheWebCoreStats(int index) const { 1484 PerResourceValues& values(GetPerResourceValues(index)); 1485 if (!values.is_webcore_stats_valid) { 1486 if (!GetResource(index)->ReportsCacheStats()) 1487 return false; 1488 values.is_webcore_stats_valid = true; 1489 values.webcore_stats = GetResource(index)->GetWebCoreCacheStats(); 1490 } 1491 return true; 1492} 1493 1494bool TaskManagerModel::CacheV8Memory(int index) const { 1495 PerResourceValues& values(GetPerResourceValues(index)); 1496 if (!values.is_v8_memory_valid) { 1497 if (!GetResource(index)->ReportsV8MemoryStats()) 1498 return false; 1499 values.is_v8_memory_valid = true; 1500 values.v8_memory_allocated = GetResource(index)->GetV8MemoryAllocated(); 1501 values.v8_memory_used = GetResource(index)->GetV8MemoryUsed(); 1502 } 1503 return true; 1504} 1505 1506void TaskManagerModel::AddResourceProvider(ResourceProvider* provider) { 1507 DCHECK(provider); 1508 providers_.push_back(provider); 1509} 1510 1511TaskManagerModel::PerResourceValues& TaskManagerModel::GetPerResourceValues( 1512 int index) const { 1513 return per_resource_cache_[GetResource(index)]; 1514} 1515 1516Resource* TaskManagerModel::GetResource(int index) const { 1517 CHECK_GE(index, 0); 1518 CHECK_LT(index, static_cast<int>(resources_.size())); 1519 return resources_[index]; 1520} 1521 1522//////////////////////////////////////////////////////////////////////////////// 1523// TaskManager class 1524//////////////////////////////////////////////////////////////////////////////// 1525// static 1526void TaskManager::RegisterPrefs(PrefRegistrySimple* registry) { 1527 registry->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement); 1528} 1529 1530bool TaskManager::IsBrowserProcess(int index) const { 1531 // If some of the selection is out of bounds, ignore. This may happen when 1532 // killing a process that manages several pages. 1533 return index < model_->ResourceCount() && 1534 model_->GetProcess(index) == base::GetCurrentProcessHandle(); 1535} 1536 1537void TaskManager::KillProcess(int index) { 1538 base::ProcessHandle process = model_->GetProcess(index); 1539 DCHECK(process); 1540 if (process != base::GetCurrentProcessHandle()) 1541 base::KillProcess(process, content::RESULT_CODE_KILLED, false); 1542} 1543 1544void TaskManager::ActivateProcess(int index) { 1545 // GetResourceWebContents returns a pointer to the relevant web contents for 1546 // the resource. If the index doesn't correspond to any web contents 1547 // (i.e. refers to the Browser process or a plugin), GetWebContents will 1548 // return NULL. 1549 WebContents* chosen_web_contents = model_->GetResourceWebContents(index); 1550 if (chosen_web_contents && chosen_web_contents->GetDelegate()) 1551 chosen_web_contents->GetDelegate()->ActivateContents(chosen_web_contents); 1552} 1553 1554void TaskManager::AddResource(Resource* resource) { 1555 model_->AddResource(resource); 1556} 1557 1558void TaskManager::RemoveResource(Resource* resource) { 1559 model_->RemoveResource(resource); 1560} 1561 1562void TaskManager::OnWindowClosed() { 1563 model_->StopUpdating(); 1564} 1565 1566void TaskManager::ModelChanged() { 1567 model_->ModelChanged(); 1568} 1569 1570// static 1571TaskManager* TaskManager::GetInstance() { 1572 return Singleton<TaskManager>::get(); 1573} 1574 1575void TaskManager::OpenAboutMemory(chrome::HostDesktopType desktop_type) { 1576 chrome::NavigateParams params( 1577 ProfileManager::GetLastUsedProfileAllowedByPolicy(), 1578 GURL(chrome::kChromeUIMemoryURL), 1579 content::PAGE_TRANSITION_LINK); 1580 params.disposition = NEW_FOREGROUND_TAB; 1581 params.host_desktop_type = desktop_type; 1582 chrome::Navigate(¶ms); 1583} 1584 1585TaskManager::TaskManager() 1586 : model_(new TaskManagerModel(this)) { 1587} 1588 1589TaskManager::~TaskManager() { 1590} 1591