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