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.
5 #include "chrome/browser/task_manager/task_manager.h"
8 #include "base/i18n/number_formatting.h"
9 #include "base/i18n/rtl.h"
10 #include "base/location.h"
11 #include "base/prefs/pref_registry_simple.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/stl_util.h"
15 #include "base/strings/string16.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "base/thread_task_runner_handle.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/private_working_set_snapshot.h"
22 #include "chrome/browser/profiles/profile_manager.h"
23 #include "chrome/browser/profiles/profile_window.h"
24 #include "chrome/browser/task_manager/background_information.h"
25 #include "chrome/browser/task_manager/browser_process_resource_provider.h"
26 #include "chrome/browser/task_manager/child_process_resource_provider.h"
27 #include "chrome/browser/task_manager/extension_information.h"
28 #include "chrome/browser/task_manager/guest_information.h"
29 #include "chrome/browser/task_manager/panel_information.h"
30 #include "chrome/browser/task_manager/printing_information.h"
31 #include "chrome/browser/task_manager/resource_provider.h"
32 #include "chrome/browser/task_manager/tab_contents_information.h"
33 #include "chrome/browser/task_manager/web_contents_resource_provider.h"
34 #include "chrome/browser/ui/browser_navigator.h"
35 #include "chrome/browser/ui/user_manager.h"
36 #include "chrome/common/pref_names.h"
37 #include "chrome/common/url_constants.h"
38 #include "chrome/grit/generated_resources.h"
39 #include "components/nacl/browser/nacl_browser.h"
40 #include "content/public/browser/browser_thread.h"
41 #include "content/public/browser/gpu_data_manager.h"
42 #include "content/public/browser/gpu_data_manager_observer.h"
43 #include "content/public/browser/resource_request_info.h"
44 #include "content/public/browser/web_contents.h"
45 #include "content/public/browser/web_contents_delegate.h"
46 #include "content/public/browser/worker_service.h"
47 #include "content/public/common/result_codes.h"
48 #include "extensions/browser/extension_system.h"
49 #include "third_party/icu/source/i18n/unicode/coll.h"
50 #include "ui/base/l10n/l10n_util.h"
51 #include "ui/base/resource/resource_bundle.h"
52 #include "ui/base/text/bytes_formatting.h"
53 #include "ui/gfx/image/image_skia.h"
54 #include "ui/resources/grit/ui_resources.h"
56 #if defined(OS_MACOSX)
57 #include "content/public/browser/browser_child_process_host.h"
60 using content::BrowserThread
;
61 using content::ResourceRequestInfo
;
62 using content::WebContents
;
63 using task_manager::Resource
;
64 using task_manager::ResourceProvider
;
65 using task_manager::WebContentsInformation
;
72 int ValueCompare(T value1
, T value2
) {
80 // Used when one or both of the results to compare are unavailable.
81 int OrderUnavailableValue(bool v1
, bool v2
) {
87 // Used by TaskManagerModel::CompareValues(). See it for details of return
90 int ValueCompareMember(const TaskManagerModel
* model
,
91 bool (TaskManagerModel::*f
)(int, T
*) const,
96 bool value1_valid
= (model
->*f
)(row1
, &value1
);
97 bool value2_valid
= (model
->*f
)(row2
, &value2
);
98 return value1_valid
&& value2_valid
? ValueCompare(value1
, value2
) :
99 OrderUnavailableValue(value1_valid
, value2_valid
);
102 base::string16
FormatStatsSize(const blink::WebCache::ResourceTypeStat
& stat
) {
103 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT
,
104 ui::FormatBytesWithUnits(stat
.size
, ui::DATA_UNITS_KIBIBYTE
, false),
105 ui::FormatBytesWithUnits(stat
.liveSize
, ui::DATA_UNITS_KIBIBYTE
, false));
108 // Returns true if the specified id should use the first value in the group.
109 bool IsSharedByGroup(int col_id
) {
111 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
112 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
113 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
114 case IDS_TASK_MANAGER_CPU_COLUMN
:
115 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
116 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
117 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
:
118 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
119 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
120 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
121 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
122 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
130 void GetWinGDIHandles(base::ProcessHandle process
,
135 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
136 HANDLE current_process
= GetCurrentProcess();
137 HANDLE process_with_query_rights
;
138 if (DuplicateHandle(current_process
, process
, current_process
,
139 &process_with_query_rights
, PROCESS_QUERY_INFORMATION
,
141 *current
= GetGuiResources(process_with_query_rights
, GR_GDIOBJECTS
);
142 *peak
= GetGuiResources(process_with_query_rights
, GR_GDIOBJECTS_PEAK
);
143 CloseHandle(process_with_query_rights
);
147 void GetWinUSERHandles(base::ProcessHandle process
,
152 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
153 HANDLE current_process
= GetCurrentProcess();
154 HANDLE process_with_query_rights
;
155 if (DuplicateHandle(current_process
, process
, current_process
,
156 &process_with_query_rights
, PROCESS_QUERY_INFORMATION
,
158 *current
= GetGuiResources(process_with_query_rights
, GR_USEROBJECTS
);
159 *peak
= GetGuiResources(process_with_query_rights
, GR_USEROBJECTS_PEAK
);
160 CloseHandle(process_with_query_rights
);
167 class TaskManagerModelGpuDataManagerObserver
168 : public content::GpuDataManagerObserver
{
170 TaskManagerModelGpuDataManagerObserver() {
171 content::GpuDataManager::GetInstance()->AddObserver(this);
174 ~TaskManagerModelGpuDataManagerObserver() override
{
175 content::GpuDataManager::GetInstance()->RemoveObserver(this);
178 static void NotifyVideoMemoryUsageStats(
179 const content::GPUVideoMemoryUsageStats
& video_memory_usage_stats
) {
180 TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats(
181 video_memory_usage_stats
);
184 void OnVideoMemoryUsageStatsUpdate(const content::GPUVideoMemoryUsageStats
&
185 video_memory_usage_stats
) override
{
186 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
187 NotifyVideoMemoryUsageStats(video_memory_usage_stats
);
189 BrowserThread::PostTask(
190 BrowserThread::UI
, FROM_HERE
, base::Bind(
191 &TaskManagerModelGpuDataManagerObserver::
192 NotifyVideoMemoryUsageStats
,
193 video_memory_usage_stats
));
198 TaskManagerModel::PerResourceValues::PerResourceValues()
199 : is_title_valid(false),
200 is_profile_name_valid(false),
202 is_process_id_valid(false),
204 is_webcore_stats_valid(false),
205 is_sqlite_memory_bytes_valid(false),
206 sqlite_memory_bytes(0),
207 is_v8_memory_valid(false),
208 v8_memory_allocated(0),
211 TaskManagerModel::PerResourceValues::~PerResourceValues() {}
213 TaskManagerModel::PerProcessValues::PerProcessValues()
214 : is_cpu_usage_valid(false),
216 is_idle_wakeups_valid(false),
218 is_private_and_shared_valid(false),
221 is_physical_memory_valid(false),
223 is_video_memory_valid(false),
225 video_memory_has_duplicates(false),
226 is_gdi_handles_valid(false),
229 is_user_handles_valid(0),
231 user_handles_peak(0),
232 is_nacl_debug_stub_port_valid(false),
233 nacl_debug_stub_port(0) {}
235 TaskManagerModel::PerProcessValues::~PerProcessValues() {}
237 ////////////////////////////////////////////////////////////////////////////////
238 // TaskManagerModel class
239 ////////////////////////////////////////////////////////////////////////////////
241 TaskManagerModel::TaskManagerModel(TaskManager
* task_manager
)
242 : pending_video_memory_usage_stats_update_(false),
246 is_updating_byte_count_(false) {
248 new task_manager::BrowserProcessResourceProvider(task_manager
));
249 AddResourceProvider(new task_manager::WebContentsResourceProvider(
251 scoped_ptr
<WebContentsInformation
>(
252 new task_manager::BackgroundInformation())));
253 AddResourceProvider(new task_manager::WebContentsResourceProvider(
255 scoped_ptr
<WebContentsInformation
>(
256 new task_manager::TabContentsInformation())));
257 #if defined(ENABLE_PRINT_PREVIEW)
258 AddResourceProvider(new task_manager::WebContentsResourceProvider(
260 scoped_ptr
<WebContentsInformation
>(
261 new task_manager::PrintingInformation())));
262 #endif // ENABLE_PRINT_PREVIEW
263 AddResourceProvider(new task_manager::WebContentsResourceProvider(
265 scoped_ptr
<WebContentsInformation
>(
266 new task_manager::PanelInformation())));
268 new task_manager::ChildProcessResourceProvider(task_manager
));
269 AddResourceProvider(new task_manager::WebContentsResourceProvider(
271 scoped_ptr
<WebContentsInformation
>(
272 new task_manager::ExtensionInformation())));
273 AddResourceProvider(new task_manager::WebContentsResourceProvider(
275 scoped_ptr
<WebContentsInformation
>(
276 new task_manager::GuestInformation())));
278 working_set_snapshot_
.reset(new PrivateWorkingSetSnapshot
);
279 working_set_snapshot_
->AddToMonitorList("chrome");
280 working_set_snapshot_
->AddToMonitorList("nacl64");
284 void TaskManagerModel::AddObserver(TaskManagerModelObserver
* observer
) {
285 observer_list_
.AddObserver(observer
);
288 void TaskManagerModel::RemoveObserver(TaskManagerModelObserver
* observer
) {
289 observer_list_
.RemoveObserver(observer
);
292 int TaskManagerModel::ResourceCount() const {
293 return resources_
.size();
296 int TaskManagerModel::GroupCount() const {
297 return group_map_
.size();
300 int TaskManagerModel::GetNaClDebugStubPort(int index
) const {
301 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
302 PerProcessValues
& values(per_process_cache_
[handle
]);
303 if (!values
.is_nacl_debug_stub_port_valid
) {
304 return nacl::kGdbDebugStubPortUnknown
;
306 return values
.nacl_debug_stub_port
;
309 int64
TaskManagerModel::GetNetworkUsage(int index
) const {
310 return GetNetworkUsage(GetResource(index
));
313 double TaskManagerModel::GetCPUUsage(int index
) const {
314 return GetCPUUsage(GetResource(index
));
317 int TaskManagerModel::GetIdleWakeupsPerSecond(int index
) const {
318 return GetIdleWakeupsPerSecond(GetResource(index
));
321 base::ProcessId
TaskManagerModel::GetProcessId(int index
) const {
322 PerResourceValues
& values(GetPerResourceValues(index
));
323 if (!values
.is_process_id_valid
) {
324 values
.is_process_id_valid
= true;
325 base::ProcessHandle
process(GetResource(index
)->GetProcess());
327 values
.process_id
= base::GetProcId(process
);
328 DCHECK(values
.process_id
);
330 return values
.process_id
;
333 base::ProcessHandle
TaskManagerModel::GetProcess(int index
) const {
334 return GetResource(index
)->GetProcess();
337 base::string16
TaskManagerModel::GetResourceById(int index
, int col_id
) const {
338 if (IsSharedByGroup(col_id
) && !IsResourceFirstInGroup(index
))
339 return base::string16();
342 case IDS_TASK_MANAGER_TASK_COLUMN
:
343 return GetResourceTitle(index
);
345 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN
:
346 return GetResourceProfileName(index
);
348 case IDS_TASK_MANAGER_NET_COLUMN
:
349 return GetResourceNetworkUsage(index
);
351 case IDS_TASK_MANAGER_CPU_COLUMN
:
352 return GetResourceCPUUsage(index
);
354 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
355 return GetResourcePrivateMemory(index
);
357 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
358 return GetResourceSharedMemory(index
);
360 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
361 return GetResourcePhysicalMemory(index
);
363 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
364 return GetResourceProcessId(index
);
366 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
:
367 return GetResourceGDIHandles(index
);
369 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN
:
370 return GetResourceUSERHandles(index
);
372 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN
:
373 return GetResourceIdleWakeupsPerSecond(index
);
375 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
376 return GetResourceWebCoreImageCacheSize(index
);
378 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
379 return GetResourceWebCoreScriptsCacheSize(index
);
381 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
382 return GetResourceWebCoreCSSCacheSize(index
);
384 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
:
385 return GetResourceVideoMemory(index
);
387 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
388 return GetResourceSqliteMemoryUsed(index
);
390 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
391 return GetResourceV8MemoryAllocatedSize(index
);
393 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
394 return GetResourceNaClDebugStubPort(index
);
398 return base::string16();
402 const base::string16
& TaskManagerModel::GetResourceTitle(int index
) const {
403 PerResourceValues
& values
= GetPerResourceValues(index
);
404 if (!values
.is_title_valid
) {
405 values
.is_title_valid
= true;
406 values
.title
= GetResource(index
)->GetTitle();
411 const base::string16
& TaskManagerModel::GetResourceProfileName(
413 PerResourceValues
& values(GetPerResourceValues(index
));
414 if (!values
.is_profile_name_valid
) {
415 values
.is_profile_name_valid
= true;
416 values
.profile_name
= GetResource(index
)->GetProfileName();
418 return values
.profile_name
;
421 base::string16
TaskManagerModel::GetResourceNaClDebugStubPort(int index
) const {
422 int port
= GetNaClDebugStubPort(index
);
423 if (port
== nacl::kGdbDebugStubPortUnknown
) {
424 return base::ASCIIToUTF16("Unknown");
425 } else if (port
== nacl::kGdbDebugStubPortUnused
) {
426 return base::ASCIIToUTF16("N/A");
428 return base::IntToString16(port
);
432 base::string16
TaskManagerModel::GetResourceNetworkUsage(int index
) const {
433 int64 net_usage
= GetNetworkUsage(index
);
435 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
437 return base::ASCIIToUTF16("0");
438 base::string16 net_byte
= ui::FormatSpeed(net_usage
);
439 // Force number string to have LTR directionality.
440 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte
);
443 base::string16
TaskManagerModel::GetResourceCPUUsage(int index
) const {
444 return base::UTF8ToUTF16(base::StringPrintf(
445 #if defined(OS_MACOSX)
446 // Activity Monitor shows %cpu with one decimal digit -- be
447 // consistent with that.
452 GetCPUUsage(GetResource(index
))));
455 base::string16
TaskManagerModel::GetResourcePrivateMemory(int index
) const {
457 if (!GetPrivateMemory(index
, &private_mem
))
458 return base::ASCIIToUTF16("N/A");
459 return GetMemCellText(private_mem
);
462 base::string16
TaskManagerModel::GetResourceSharedMemory(int index
) const {
464 if (!GetSharedMemory(index
, &shared_mem
))
465 return base::ASCIIToUTF16("N/A");
466 return GetMemCellText(shared_mem
);
469 base::string16
TaskManagerModel::GetResourcePhysicalMemory(int index
) const {
471 GetPhysicalMemory(index
, &phys_mem
);
472 return GetMemCellText(phys_mem
);
475 base::string16
TaskManagerModel::GetResourceProcessId(int index
) const {
476 return base::IntToString16(GetProcessId(index
));
479 base::string16
TaskManagerModel::GetResourceGDIHandles(int index
) const {
480 size_t current
, peak
;
481 GetGDIHandles(index
, ¤t
, &peak
);
482 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT
,
483 base::IntToString16(current
), base::IntToString16(peak
));
486 base::string16
TaskManagerModel::GetResourceUSERHandles(int index
) const {
487 size_t current
, peak
;
488 GetUSERHandles(index
, ¤t
, &peak
);
489 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT
,
490 base::IntToString16(current
), base::IntToString16(peak
));
493 base::string16
TaskManagerModel::GetResourceWebCoreImageCacheSize(
495 if (!CacheWebCoreStats(index
))
496 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
497 return FormatStatsSize(GetPerResourceValues(index
).webcore_stats
.images
);
500 base::string16
TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
502 if (!CacheWebCoreStats(index
))
503 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
504 return FormatStatsSize(GetPerResourceValues(index
).webcore_stats
.scripts
);
507 base::string16
TaskManagerModel::GetResourceWebCoreCSSCacheSize(
509 if (!CacheWebCoreStats(index
))
510 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
511 return FormatStatsSize(
512 GetPerResourceValues(index
).webcore_stats
.cssStyleSheets
);
515 base::string16
TaskManagerModel::GetResourceVideoMemory(int index
) const {
518 if (!GetVideoMemory(index
, &video_memory
, &has_duplicates
) || !video_memory
)
519 return base::ASCIIToUTF16("N/A");
520 if (has_duplicates
) {
521 return GetMemCellText(video_memory
) + base::ASCIIToUTF16("*");
523 return GetMemCellText(video_memory
);
526 base::string16
TaskManagerModel::GetResourceSqliteMemoryUsed(int index
) const {
528 if (!GetSqliteMemoryUsedBytes(index
, &bytes
))
529 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
530 return GetMemCellText(bytes
);
533 base::string16
TaskManagerModel::GetResourceIdleWakeupsPerSecond(int index
)
535 return base::FormatNumber(GetIdleWakeupsPerSecond(GetResource(index
)));
538 base::string16
TaskManagerModel::GetResourceV8MemoryAllocatedSize(
540 size_t memory_allocated
= 0, memory_used
= 0;
541 if (!GetV8MemoryUsed(index
, &memory_used
) ||
542 !GetV8Memory(index
, &memory_allocated
))
543 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
544 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT
,
545 ui::FormatBytesWithUnits(memory_allocated
,
546 ui::DATA_UNITS_KIBIBYTE
,
548 ui::FormatBytesWithUnits(memory_used
,
549 ui::DATA_UNITS_KIBIBYTE
,
553 bool TaskManagerModel::GetPrivateMemory(int index
, size_t* result
) const {
555 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
556 if (!CachePrivateAndSharedMemory(handle
))
558 *result
= per_process_cache_
[handle
].private_bytes
;
562 bool TaskManagerModel::GetSharedMemory(int index
, size_t* result
) const {
564 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
565 if (!CachePrivateAndSharedMemory(handle
))
567 *result
= per_process_cache_
[handle
].shared_bytes
;
571 bool TaskManagerModel::GetPhysicalMemory(int index
, size_t* result
) const {
574 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
575 PerProcessValues
& values(per_process_cache_
[handle
]);
577 if (!values
.is_physical_memory_valid
) {
578 base::WorkingSetKBytes ws_usage
;
579 MetricsMap::const_iterator iter
= metrics_map_
.find(handle
);
580 if (iter
== metrics_map_
.end() ||
581 !iter
->second
->GetWorkingSetKBytes(&ws_usage
))
584 values
.is_physical_memory_valid
= true;
585 #if defined(OS_LINUX)
586 // On Linux private memory is also resident. Just use it.
587 values
.physical_memory
= ws_usage
.priv
* 1024;
589 // Memory = working_set.private which is working set minus shareable. This
590 // avoids the unpredictable counting that occurs when calculating memory as
591 // working set minus shared (renderer code counted when one tab is open and
592 // not counted when two or more are open) and it is much more efficient to
593 // calculate on Windows.
594 values
.physical_memory
= iter
->second
->GetWorkingSetSize();
595 values
.physical_memory
-= ws_usage
.shareable
* 1024;
598 *result
= values
.physical_memory
;
602 void TaskManagerModel::GetGDIHandles(int index
,
604 size_t* peak
) const {
608 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
609 PerProcessValues
& values(per_process_cache_
[handle
]);
611 if (!values
.is_gdi_handles_valid
) {
612 GetWinGDIHandles(GetResource(index
)->GetProcess(),
614 &values
.gdi_handles_peak
);
615 values
.is_gdi_handles_valid
= true;
617 *current
= values
.gdi_handles
;
618 *peak
= values
.gdi_handles_peak
;
622 void TaskManagerModel::GetUSERHandles(int index
,
624 size_t* peak
) const {
628 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
629 PerProcessValues
& values(per_process_cache_
[handle
]);
631 if (!values
.is_user_handles_valid
) {
632 GetWinUSERHandles(GetResource(index
)->GetProcess(),
633 &values
.user_handles
,
634 &values
.user_handles_peak
);
635 values
.is_user_handles_valid
= true;
637 *current
= values
.user_handles
;
638 *peak
= values
.user_handles_peak
;
642 bool TaskManagerModel::GetWebCoreCacheStats(
644 blink::WebCache::ResourceTypeStats
* result
) const {
645 if (!CacheWebCoreStats(index
))
647 *result
= GetPerResourceValues(index
).webcore_stats
;
651 bool TaskManagerModel::GetVideoMemory(int index
,
652 size_t* video_memory
,
653 bool* has_duplicates
) const {
655 *has_duplicates
= false;
657 base::ProcessId pid
= GetProcessId(index
);
658 PerProcessValues
& values(
659 per_process_cache_
[GetResource(index
)->GetProcess()]);
660 if (!values
.is_video_memory_valid
) {
661 content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i
=
662 video_memory_usage_stats_
.process_map
.find(pid
);
663 if (i
== video_memory_usage_stats_
.process_map
.end())
665 values
.is_video_memory_valid
= true;
666 values
.video_memory
= i
->second
.video_memory
;
667 values
.video_memory_has_duplicates
= i
->second
.has_duplicates
;
669 *video_memory
= values
.video_memory
;
670 *has_duplicates
= values
.video_memory_has_duplicates
;
674 bool TaskManagerModel::GetSqliteMemoryUsedBytes(
676 size_t* result
) const {
678 PerResourceValues
& values(GetPerResourceValues(index
));
679 if (!values
.is_sqlite_memory_bytes_valid
) {
680 if (!GetResource(index
)->ReportsSqliteMemoryUsed())
682 values
.is_sqlite_memory_bytes_valid
= true;
683 values
.sqlite_memory_bytes
= GetResource(index
)->SqliteMemoryUsedBytes();
685 *result
= values
.sqlite_memory_bytes
;
689 bool TaskManagerModel::GetV8Memory(int index
, size_t* result
) const {
691 if (!CacheV8Memory(index
))
693 *result
= GetPerResourceValues(index
).v8_memory_allocated
;
697 bool TaskManagerModel::GetV8MemoryUsed(int index
, size_t* result
) const {
699 if (!CacheV8Memory(index
))
701 *result
= GetPerResourceValues(index
).v8_memory_used
;
705 bool TaskManagerModel::CanActivate(int index
) const {
706 CHECK_LT(index
, ResourceCount());
707 return GetResourceWebContents(index
) != NULL
;
710 bool TaskManagerModel::IsResourceFirstInGroup(int index
) const {
711 Resource
* resource
= GetResource(index
);
712 GroupMap::const_iterator iter
= group_map_
.find(resource
->GetProcess());
713 DCHECK(iter
!= group_map_
.end());
714 const ResourceList
& group
= iter
->second
;
715 return (group
[0] == resource
);
718 bool TaskManagerModel::IsResourceLastInGroup(int index
) const {
719 Resource
* resource
= GetResource(index
);
720 GroupMap::const_iterator iter
= group_map_
.find(resource
->GetProcess());
721 DCHECK(iter
!= group_map_
.end());
722 const ResourceList
& group
= iter
->second
;
723 return (group
.back() == resource
);
726 gfx::ImageSkia
TaskManagerModel::GetResourceIcon(int index
) const {
727 gfx::ImageSkia icon
= GetResource(index
)->GetIcon();
731 static const gfx::ImageSkia
* default_icon
=
732 ResourceBundle::GetSharedInstance().
733 GetNativeImageNamed(IDR_DEFAULT_FAVICON
).ToImageSkia();
734 return *default_icon
;
737 TaskManagerModel::GroupRange
738 TaskManagerModel::GetGroupRangeForResource(int index
) const {
739 Resource
* resource
= GetResource(index
);
740 GroupMap::const_iterator group_iter
=
741 group_map_
.find(resource
->GetProcess());
742 DCHECK(group_iter
!= group_map_
.end());
743 const ResourceList
& group
= group_iter
->second
;
744 if (group
.size() == 1) {
745 return std::make_pair(index
, 1);
747 for (int i
= index
; i
>= 0; --i
) {
748 if (GetResource(i
) == group
[0])
749 return std::make_pair(i
, group
.size());
752 return std::make_pair(-1, -1);
756 int TaskManagerModel::GetGroupIndexForResource(int index
) const {
757 int group_index
= -1;
758 for (int i
= 0; i
<= index
; ++i
) {
759 if (IsResourceFirstInGroup(i
))
763 DCHECK_NE(group_index
, -1);
767 int TaskManagerModel::GetResourceIndexForGroup(int group_index
,
768 int index_in_group
) const {
769 int group_count
= -1;
770 int count_in_group
= -1;
771 for (int i
= 0; i
< ResourceCount(); ++i
) {
772 if (IsResourceFirstInGroup(i
))
775 if (group_count
== group_index
) {
777 if (count_in_group
== index_in_group
)
779 } else if (group_count
> group_index
) {
788 int TaskManagerModel::CompareValues(int row1
, int row2
, int col_id
) const {
789 CHECK(row1
< ResourceCount() && row2
< ResourceCount());
791 case IDS_TASK_MANAGER_TASK_COLUMN
: {
792 static icu::Collator
* collator
= NULL
;
794 UErrorCode create_status
= U_ZERO_ERROR
;
795 collator
= icu::Collator::createInstance(create_status
);
796 if (!U_SUCCESS(create_status
)) {
801 const base::string16
& title1
= GetResourceTitle(row1
);
802 const base::string16
& title2
= GetResourceTitle(row2
);
803 UErrorCode compare_status
= U_ZERO_ERROR
;
804 UCollationResult compare_result
= collator
->compare(
805 static_cast<const UChar
*>(title1
.c_str()),
806 static_cast<int>(title1
.length()),
807 static_cast<const UChar
*>(title2
.c_str()),
808 static_cast<int>(title2
.length()),
810 DCHECK(U_SUCCESS(compare_status
));
811 return compare_result
;
814 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN
: {
815 const base::string16
& profile1
= GetResourceProfileName(row1
);
816 const base::string16
& profile2
= GetResourceProfileName(row2
);
817 return profile1
.compare(0, profile1
.length(), profile2
, 0,
821 case IDS_TASK_MANAGER_NET_COLUMN
:
822 return ValueCompare(GetNetworkUsage(GetResource(row1
)),
823 GetNetworkUsage(GetResource(row2
)));
825 case IDS_TASK_MANAGER_CPU_COLUMN
:
826 return ValueCompare(GetCPUUsage(GetResource(row1
)),
827 GetCPUUsage(GetResource(row2
)));
829 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
830 return ValueCompareMember(
831 this, &TaskManagerModel::GetPrivateMemory
, row1
, row2
);
833 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
834 return ValueCompareMember(
835 this, &TaskManagerModel::GetSharedMemory
, row1
, row2
);
837 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
838 return ValueCompareMember(
839 this, &TaskManagerModel::GetPhysicalMemory
, row1
, row2
);
841 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
842 return ValueCompare(GetNaClDebugStubPort(row1
),
843 GetNaClDebugStubPort(row2
));
845 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
846 return ValueCompare(GetProcessId(row1
), GetProcessId(row2
));
848 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
: {
849 size_t current1
, peak1
;
850 size_t current2
, peak2
;
851 GetGDIHandles(row1
, ¤t1
, &peak1
);
852 GetGDIHandles(row2
, ¤t2
, &peak2
);
853 return ValueCompare(current1
, current2
);
856 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN
: {
857 size_t current1
, peak1
;
858 size_t current2
, peak2
;
859 GetUSERHandles(row1
, ¤t1
, &peak1
);
860 GetUSERHandles(row2
, ¤t2
, &peak2
);
861 return ValueCompare(current1
, current2
);
864 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN
:
865 return ValueCompare(GetIdleWakeupsPerSecond(row1
),
866 GetIdleWakeupsPerSecond(row2
));
868 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
869 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
870 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
: {
871 bool row1_stats_valid
= CacheWebCoreStats(row1
);
872 bool row2_stats_valid
= CacheWebCoreStats(row2
);
873 if (row1_stats_valid
&& row2_stats_valid
) {
874 const blink::WebCache::ResourceTypeStats
& stats1(
875 GetPerResourceValues(row1
).webcore_stats
);
876 const blink::WebCache::ResourceTypeStats
& stats2(
877 GetPerResourceValues(row2
).webcore_stats
);
879 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
880 return ValueCompare(stats1
.images
.size
, stats2
.images
.size
);
881 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
882 return ValueCompare(stats1
.scripts
.size
, stats2
.scripts
.size
);
883 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
884 return ValueCompare(stats1
.cssStyleSheets
.size
,
885 stats2
.cssStyleSheets
.size
);
891 return OrderUnavailableValue(row1_stats_valid
, row2_stats_valid
);
894 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
: {
898 bool value1_valid
= GetVideoMemory(row1
, &value1
, &has_duplicates
);
899 bool value2_valid
= GetVideoMemory(row2
, &value2
, &has_duplicates
);
900 return value1_valid
&& value2_valid
? ValueCompare(value1
, value2
) :
901 OrderUnavailableValue(value1_valid
, value2_valid
);
904 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
905 return ValueCompareMember(
906 this, &TaskManagerModel::GetV8Memory
, row1
, row2
);
908 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
909 return ValueCompareMember(
910 this, &TaskManagerModel::GetSqliteMemoryUsedBytes
, row1
, row2
);
919 int TaskManagerModel::GetUniqueChildProcessId(int index
) const {
920 return GetResource(index
)->GetUniqueChildProcessId();
923 Resource::Type
TaskManagerModel::GetResourceType(int index
) const {
924 return GetResource(index
)->GetType();
927 WebContents
* TaskManagerModel::GetResourceWebContents(int index
) const {
928 return GetResource(index
)->GetWebContents();
931 void TaskManagerModel::AddResource(Resource
* resource
) {
932 base::ProcessHandle process
= resource
->GetProcess();
935 GroupMap::iterator group_iter
= group_map_
.find(process
);
936 int new_entry_index
= 0;
937 if (group_iter
== group_map_
.end()) {
938 group_map_
.insert(make_pair(process
, ResourceList(1, resource
)));
940 // Not part of a group, just put at the end of the list.
941 resources_
.push_back(resource
);
942 new_entry_index
= static_cast<int>(resources_
.size() - 1);
944 ResourceList
* group_entries
= &(group_iter
->second
);
945 group_entries
->push_back(resource
);
947 // Insert the new entry right after the last entry of its group.
948 ResourceList::iterator iter
=
949 std::find(resources_
.begin(),
951 (*group_entries
)[group_entries
->size() - 2]);
952 DCHECK(iter
!= resources_
.end());
953 new_entry_index
= static_cast<int>(iter
- resources_
.begin()) + 1;
954 resources_
.insert(++iter
, resource
);
957 // Create the ProcessMetrics for this process if needed (not in map).
958 if (metrics_map_
.find(process
) == metrics_map_
.end()) {
959 base::ProcessMetrics
* pm
=
960 #if !defined(OS_MACOSX)
961 base::ProcessMetrics::CreateProcessMetrics(process
);
963 base::ProcessMetrics::CreateProcessMetrics(
964 process
, content::BrowserChildProcessHost::GetPortProvider());
967 metrics_map_
[process
] = pm
;
970 // Notify the table that the contents have changed for it to redraw.
971 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
972 OnItemsAdded(new_entry_index
, 1));
975 void TaskManagerModel::RemoveResource(Resource
* resource
) {
976 base::ProcessHandle process
= resource
->GetProcess();
978 // Find the associated group.
979 GroupMap::iterator group_iter
= group_map_
.find(process
);
980 DCHECK(group_iter
!= group_map_
.end());
981 if (group_iter
== group_map_
.end())
983 ResourceList
& group_entries
= group_iter
->second
;
985 // Remove the entry from the group map.
986 ResourceList::iterator iter
= std::find(group_entries
.begin(),
989 DCHECK(iter
!= group_entries
.end());
990 if (iter
!= group_entries
.end())
991 group_entries
.erase(iter
);
993 // If there are no more entries for that process, do the clean-up.
994 if (group_entries
.empty()) {
995 group_map_
.erase(group_iter
);
997 // Nobody is using this process, we don't need the process metrics anymore.
998 MetricsMap::iterator pm_iter
= metrics_map_
.find(process
);
999 DCHECK(pm_iter
!= metrics_map_
.end());
1000 if (pm_iter
!= metrics_map_
.end()) {
1001 delete pm_iter
->second
;
1002 metrics_map_
.erase(process
);
1006 // Remove the entry from the model list.
1007 iter
= std::find(resources_
.begin(), resources_
.end(), resource
);
1008 DCHECK(iter
!= resources_
.end());
1009 if (iter
!= resources_
.end()) {
1010 int index
= static_cast<int>(iter
- resources_
.begin());
1011 // Notify the observers that the contents will change.
1012 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1013 OnItemsToBeRemoved(index
, 1));
1014 // Now actually remove the entry from the model list.
1015 resources_
.erase(iter
);
1016 // Notify the table that the contents have changed.
1017 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1018 OnItemsRemoved(index
, 1));
1021 // Remove the entry from the network maps.
1022 ResourceValueMap::iterator net_iter
=
1023 current_byte_count_map_
.find(resource
);
1024 if (net_iter
!= current_byte_count_map_
.end())
1025 current_byte_count_map_
.erase(net_iter
);
1028 void TaskManagerModel::StartUpdating() {
1029 // Multiple StartUpdating requests may come in, and we only need to take
1030 // action the first time.
1032 if (update_requests_
> 1)
1034 DCHECK_EQ(1, update_requests_
);
1035 DCHECK_NE(TASK_PENDING
, update_state_
);
1037 // If update_state_ is STOPPING, it means a task is still pending. Setting
1038 // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()).
1039 if (update_state_
== IDLE
) {
1040 base::ThreadTaskRunnerHandle::Get()->PostTask(
1041 FROM_HERE
, base::Bind(&TaskManagerModel::RefreshCallback
, this));
1043 update_state_
= TASK_PENDING
;
1045 // Notify resource providers that we are updating.
1048 if (!resources_
.empty()) {
1049 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1050 OnReadyPeriodicalUpdate());
1053 BrowserThread::PostTask(
1054 BrowserThread::IO
, FROM_HERE
,
1055 base::Bind(&TaskManagerModel::SetUpdatingByteCount
, this, true));
1058 void TaskManagerModel::StopUpdating() {
1059 // Don't actually stop updating until we have heard as many calls as those
1060 // to StartUpdating.
1062 if (update_requests_
> 0)
1064 // Make sure that update_requests_ cannot go negative.
1065 CHECK_EQ(0, update_requests_
);
1066 DCHECK_EQ(TASK_PENDING
, update_state_
);
1067 update_state_
= STOPPING
;
1069 // Notify resource providers that we are done updating.
1072 BrowserThread::PostTask(
1073 BrowserThread::IO
, FROM_HERE
,
1074 base::Bind(&TaskManagerModel::SetUpdatingByteCount
, this, false));
1077 void TaskManagerModel::StartListening() {
1078 // Multiple StartListening requests may come in and we only need to take
1079 // action the first time.
1081 if (listen_requests_
> 1)
1083 DCHECK_EQ(1, listen_requests_
);
1085 // Notify resource providers that we should start listening to events.
1086 for (ResourceProviderList::iterator iter
= providers_
.begin();
1087 iter
!= providers_
.end(); ++iter
) {
1088 (*iter
)->StartUpdating();
1092 void TaskManagerModel::StopListening() {
1093 // Don't actually stop listening until we have heard as many calls as those
1094 // to StartListening.
1096 if (listen_requests_
> 0)
1099 DCHECK_EQ(0, listen_requests_
);
1101 // Notify resource providers that we are done listening.
1102 for (ResourceProviderList::const_iterator iter
= providers_
.begin();
1103 iter
!= providers_
.end(); ++iter
) {
1104 (*iter
)->StopUpdating();
1107 // Must clear the resources before the next attempt to start listening.
1111 void TaskManagerModel::Clear() {
1112 int size
= ResourceCount();
1116 // Clear the groups.
1119 // Clear the process related info.
1120 STLDeleteValues(&metrics_map_
);
1122 // Clear the network maps.
1123 current_byte_count_map_
.clear();
1125 per_resource_cache_
.clear();
1126 per_process_cache_
.clear();
1128 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1129 OnItemsRemoved(0, size
));
1133 void TaskManagerModel::ModelChanged() {
1134 // Notify the table that the contents have changed for it to redraw.
1135 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
, OnModelChanged());
1138 void TaskManagerModel::RefreshPhysicalMemoryFromWorkingSetSnapshot() {
1140 // Collect working-set data for all monitored processes in one operation, to
1141 // avoid the inefficiency of retrieving it one at a time.
1142 working_set_snapshot_
->Sample();
1144 for (size_t i
= 0; i
< resources_
.size(); ++i
) {
1145 size_t private_working_set
=
1146 working_set_snapshot_
->GetPrivateWorkingSet(GetProcessId(i
));
1148 // If working-set data is available then use it. If not then
1149 // GetWorkingSetKBytes will retrieve the data. This is rare except on
1150 // Windows XP where GetWorkingSetKBytes will always be used.
1151 if (private_working_set
) {
1152 // Fill in the cache with the retrieved private working set value.
1153 base::ProcessHandle handle
= GetResource(i
)->GetProcess();
1154 PerProcessValues
& values(per_process_cache_
[handle
]);
1155 values
.is_physical_memory_valid
= true;
1156 // Note that the other memory fields are *not* filled in.
1157 values
.physical_memory
= private_working_set
;
1161 // This is a NOP on other platforms because they can efficiently retrieve
1162 // the private working-set data on a per-process basis.
1166 void TaskManagerModel::Refresh() {
1167 per_resource_cache_
.clear();
1168 per_process_cache_
.clear();
1169 RefreshPhysicalMemoryFromWorkingSetSnapshot();
1171 #if !defined(DISABLE_NACL)
1172 nacl::NaClBrowser
* nacl_browser
= nacl::NaClBrowser::GetInstance();
1173 #endif // !defined(DISABLE_NACL)
1175 // Compute the CPU usage values and check if NaCl GDB debug stub port is
1177 // Note that we compute the CPU usage for all resources (instead of doing it
1178 // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last
1179 // time it was called, and not calling it everytime would skew the value the
1180 // next time it is retrieved (as it would be for more than 1 cycle).
1181 // The same is true for idle wakeups.
1182 for (ResourceList::iterator iter
= resources_
.begin();
1183 iter
!= resources_
.end(); ++iter
) {
1184 base::ProcessHandle process
= (*iter
)->GetProcess();
1185 PerProcessValues
& values(per_process_cache_
[process
]);
1186 #if !defined(DISABLE_NACL)
1187 // Debug stub port doesn't change once known.
1188 if (!values
.is_nacl_debug_stub_port_valid
) {
1189 values
.nacl_debug_stub_port
= nacl_browser
->GetProcessGdbDebugStubPort(
1190 (*iter
)->GetUniqueChildProcessId());
1191 if (values
.nacl_debug_stub_port
!= nacl::kGdbDebugStubPortUnknown
) {
1192 values
.is_nacl_debug_stub_port_valid
= true;
1195 #endif // !defined(DISABLE_NACL)
1196 if (values
.is_cpu_usage_valid
&& values
.is_idle_wakeups_valid
)
1198 MetricsMap::iterator metrics_iter
= metrics_map_
.find(process
);
1199 DCHECK(metrics_iter
!= metrics_map_
.end());
1200 if (!values
.is_cpu_usage_valid
) {
1201 values
.is_cpu_usage_valid
= true;
1202 values
.cpu_usage
= metrics_iter
->second
->GetCPUUsage();
1204 #if defined(OS_MACOSX) || defined(OS_LINUX)
1205 // TODO(port): Implement GetIdleWakeupsPerSecond() on other platforms,
1207 if (!values
.is_idle_wakeups_valid
) {
1208 values
.is_idle_wakeups_valid
= true;
1209 values
.idle_wakeups
= metrics_iter
->second
->GetIdleWakeupsPerSecond();
1211 #endif // defined(OS_MACOSX) || defined(OS_LINUX)
1214 // Send a request to refresh GPU memory consumption values
1215 RefreshVideoMemoryUsageStats();
1217 // Compute the new network usage values.
1218 base::TimeDelta update_time
=
1219 base::TimeDelta::FromMilliseconds(kUpdateTimeMs
);
1220 for (ResourceValueMap::iterator iter
= current_byte_count_map_
.begin();
1221 iter
!= current_byte_count_map_
.end(); ++iter
) {
1222 PerResourceValues
* values
= &(per_resource_cache_
[iter
->first
]);
1223 if (update_time
> base::TimeDelta::FromSeconds(1))
1224 values
->network_usage
= iter
->second
/ update_time
.InSeconds();
1226 values
->network_usage
= iter
->second
* (1 / update_time
.InSeconds());
1228 // Then we reset the current byte count.
1232 // Let resources update themselves if they need to.
1233 for (ResourceList::iterator iter
= resources_
.begin();
1234 iter
!= resources_
.end(); ++iter
) {
1238 if (!resources_
.empty()) {
1239 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1240 OnItemsChanged(0, ResourceCount()));
1244 void TaskManagerModel::NotifyVideoMemoryUsageStats(
1245 const content::GPUVideoMemoryUsageStats
& video_memory_usage_stats
) {
1246 DCHECK(pending_video_memory_usage_stats_update_
);
1247 video_memory_usage_stats_
= video_memory_usage_stats
;
1248 pending_video_memory_usage_stats_update_
= false;
1251 void TaskManagerModel::NotifyBytesRead(const net::URLRequest
& request
,
1253 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1254 if (!is_updating_byte_count_
)
1257 // Only net::URLRequestJob instances created by the ResourceDispatcherHost
1258 // have an associated ResourceRequestInfo and a render frame associated.
1259 // All other jobs will have -1 returned for the render process child and
1260 // routing ids - the jobs may still match a resource based on their origin id,
1261 // otherwise BytesRead() will attribute the activity to the Browser resource.
1262 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(&request
);
1263 int child_id
= -1, route_id
= -1;
1265 info
->GetAssociatedRenderFrame(&child_id
, &route_id
);
1267 // Get the origin PID of the request's originator. This will only be set for
1268 // plugins - for renderer or browser initiated requests it will be zero.
1271 origin_pid
= info
->GetOriginPID();
1273 if (bytes_read_buffer_
.empty()) {
1274 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1275 FROM_HERE
, base::Bind(&TaskManagerModel::NotifyMultipleBytesRead
, this),
1276 base::TimeDelta::FromSeconds(1));
1279 bytes_read_buffer_
.push_back(
1280 BytesReadParam(origin_pid
, child_id
, route_id
, byte_count
));
1283 // This is called on the UI thread.
1284 void TaskManagerModel::NotifyDataReady() {
1285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1286 for (size_t i
= 0; i
< on_data_ready_callbacks_
.size(); ++i
) {
1287 if (!on_data_ready_callbacks_
[i
].is_null())
1288 on_data_ready_callbacks_
[i
].Run();
1291 on_data_ready_callbacks_
.clear();
1294 void TaskManagerModel::RegisterOnDataReadyCallback(
1295 const base::Closure
& callback
) {
1296 on_data_ready_callbacks_
.push_back(callback
);
1299 TaskManagerModel::~TaskManagerModel() {
1300 on_data_ready_callbacks_
.clear();
1303 void TaskManagerModel::RefreshCallback() {
1304 DCHECK_NE(IDLE
, update_state_
);
1306 if (update_state_
== STOPPING
) {
1307 // We have been asked to stop.
1308 update_state_
= IDLE
;
1314 // Schedule the next update.
1315 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
1316 FROM_HERE
, base::Bind(&TaskManagerModel::RefreshCallback
, this),
1317 base::TimeDelta::FromMilliseconds(kUpdateTimeMs
));
1320 void TaskManagerModel::RefreshVideoMemoryUsageStats() {
1321 if (pending_video_memory_usage_stats_update_
)
1324 if (!video_memory_usage_stats_observer_
.get()) {
1325 video_memory_usage_stats_observer_
.reset(
1326 new TaskManagerModelGpuDataManagerObserver());
1328 pending_video_memory_usage_stats_update_
= true;
1329 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate();
1332 int64
TaskManagerModel::GetNetworkUsageForResource(Resource
* resource
) const {
1333 // Returns default of 0 if no network usage.
1334 return per_resource_cache_
[resource
].network_usage
;
1337 void TaskManagerModel::BytesRead(BytesReadParam param
) {
1338 if (update_state_
!= TASK_PENDING
|| listen_requests_
== 0) {
1339 // A notification sneaked in while we were stopping the updating, just
1344 // TODO(jcampan): this should be improved once we have a better way of
1345 // linking a network notification back to the object that initiated it.
1346 Resource
* resource
= NULL
;
1347 for (ResourceProviderList::iterator iter
= providers_
.begin();
1348 iter
!= providers_
.end(); ++iter
) {
1349 resource
= (*iter
)->GetResource(param
.origin_pid
,
1356 if (resource
== NULL
) {
1357 // We can't match a resource to the notification. That might mean the
1358 // tab that started a download was closed, or the request may have had
1359 // no originating resource associated with it in the first place.
1360 // We attribute orphaned/unaccounted activity to the Browser process.
1361 CHECK(param
.origin_pid
|| (param
.child_id
!= -1));
1362 param
.origin_pid
= 0;
1363 param
.child_id
= param
.route_id
= -1;
1368 // We do support network usage, mark the resource as such so it can report 0
1370 if (!resource
->SupportNetworkUsage())
1371 resource
->SetSupportNetworkUsage();
1373 ResourceValueMap::const_iterator iter_res
=
1374 current_byte_count_map_
.find(resource
);
1375 if (iter_res
== current_byte_count_map_
.end())
1376 current_byte_count_map_
[resource
] = param
.byte_count
;
1378 current_byte_count_map_
[resource
] = iter_res
->second
+ param
.byte_count
;
1381 void TaskManagerModel::MultipleBytesRead(
1382 const std::vector
<BytesReadParam
>* params
) {
1383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1384 for (std::vector
<BytesReadParam
>::const_iterator it
= params
->begin();
1385 it
!= params
->end(); ++it
) {
1390 void TaskManagerModel::NotifyMultipleBytesRead() {
1391 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1392 DCHECK(!bytes_read_buffer_
.empty());
1394 std::vector
<BytesReadParam
>* bytes_read_buffer
=
1395 new std::vector
<BytesReadParam
>;
1396 bytes_read_buffer_
.swap(*bytes_read_buffer
);
1397 BrowserThread::PostTask(
1398 BrowserThread::UI
, FROM_HERE
,
1399 base::Bind(&TaskManagerModel::MultipleBytesRead
, this,
1400 base::Owned(bytes_read_buffer
)));
1403 void TaskManagerModel::SetUpdatingByteCount(bool is_updating
) {
1404 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1405 is_updating_byte_count_
= is_updating
;
1408 int64
TaskManagerModel::GetNetworkUsage(Resource
* resource
) const {
1409 int64 net_usage
= GetNetworkUsageForResource(resource
);
1410 if (net_usage
== 0 && !resource
->SupportNetworkUsage())
1415 double TaskManagerModel::GetCPUUsage(Resource
* resource
) const {
1416 const PerProcessValues
& values(per_process_cache_
[resource
->GetProcess()]);
1417 // Returns 0 if not valid, which is fine.
1418 return values
.cpu_usage
;
1421 int TaskManagerModel::GetIdleWakeupsPerSecond(Resource
* resource
) const {
1422 const PerProcessValues
& values(per_process_cache_
[resource
->GetProcess()]);
1423 // Returns 0 if not valid, which is fine.
1424 return values
.idle_wakeups
;
1427 base::string16
TaskManagerModel::GetMemCellText(int64 number
) const {
1428 #if !defined(OS_MACOSX)
1429 base::string16 str
= base::FormatNumber(number
/ 1024);
1431 // Adjust number string if necessary.
1432 base::i18n::AdjustStringForLocaleDirection(&str
);
1433 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT
, str
);
1435 // System expectation is to show "100 kB", "200 MB", etc.
1436 // TODO(thakis): Switch to metric units (as opposed to powers of two).
1437 return ui::FormatBytes(number
);
1441 bool TaskManagerModel::CachePrivateAndSharedMemory(
1442 base::ProcessHandle handle
) const {
1443 PerProcessValues
& values(per_process_cache_
[handle
]);
1444 if (values
.is_private_and_shared_valid
)
1447 MetricsMap::const_iterator iter
= metrics_map_
.find(handle
);
1448 if (iter
== metrics_map_
.end() ||
1449 !iter
->second
->GetMemoryBytes(&values
.private_bytes
,
1450 &values
.shared_bytes
)) {
1454 values
.is_private_and_shared_valid
= true;
1458 bool TaskManagerModel::CacheWebCoreStats(int index
) const {
1459 PerResourceValues
& values(GetPerResourceValues(index
));
1460 if (!values
.is_webcore_stats_valid
) {
1461 if (!GetResource(index
)->ReportsCacheStats())
1463 values
.is_webcore_stats_valid
= true;
1464 values
.webcore_stats
= GetResource(index
)->GetWebCoreCacheStats();
1469 bool TaskManagerModel::CacheV8Memory(int index
) const {
1470 PerResourceValues
& values(GetPerResourceValues(index
));
1471 if (!values
.is_v8_memory_valid
) {
1472 if (!GetResource(index
)->ReportsV8MemoryStats())
1474 values
.is_v8_memory_valid
= true;
1475 values
.v8_memory_allocated
= GetResource(index
)->GetV8MemoryAllocated();
1476 values
.v8_memory_used
= GetResource(index
)->GetV8MemoryUsed();
1481 void TaskManagerModel::AddResourceProvider(ResourceProvider
* provider
) {
1483 providers_
.push_back(provider
);
1486 TaskManagerModel::PerResourceValues
& TaskManagerModel::GetPerResourceValues(
1488 return per_resource_cache_
[GetResource(index
)];
1491 Resource
* TaskManagerModel::GetResource(int index
) const {
1493 CHECK_LT(index
, static_cast<int>(resources_
.size()));
1494 return resources_
[index
];
1497 ////////////////////////////////////////////////////////////////////////////////
1498 // TaskManager class
1499 ////////////////////////////////////////////////////////////////////////////////
1501 void TaskManager::RegisterPrefs(PrefRegistrySimple
* registry
) {
1502 registry
->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement
);
1505 bool TaskManager::IsBrowserProcess(int index
) const {
1506 // If some of the selection is out of bounds, ignore. This may happen when
1507 // killing a process that manages several pages.
1508 return index
< model_
->ResourceCount() &&
1509 model_
->GetProcess(index
) == base::GetCurrentProcessHandle();
1512 void TaskManager::KillProcess(int index
) {
1513 base::ProcessHandle process_handle
= model_
->GetProcess(index
);
1514 DCHECK(process_handle
);
1515 if (process_handle
!= base::GetCurrentProcessHandle()) {
1516 base::Process process
=
1517 base::Process::DeprecatedGetProcessFromHandle(process_handle
);
1518 process
.Terminate(content::RESULT_CODE_KILLED
, false);
1522 void TaskManager::ActivateProcess(int index
) {
1523 // GetResourceWebContents returns a pointer to the relevant web contents for
1524 // the resource. If the index doesn't correspond to any web contents
1525 // (i.e. refers to the Browser process or a plugin), GetWebContents will
1527 WebContents
* chosen_web_contents
= model_
->GetResourceWebContents(index
);
1528 if (chosen_web_contents
&& chosen_web_contents
->GetDelegate())
1529 chosen_web_contents
->GetDelegate()->ActivateContents(chosen_web_contents
);
1532 void TaskManager::AddResource(Resource
* resource
) {
1533 model_
->AddResource(resource
);
1536 void TaskManager::RemoveResource(Resource
* resource
) {
1537 model_
->RemoveResource(resource
);
1540 void TaskManager::OnWindowClosed() {
1541 model_
->StopUpdating();
1544 void TaskManager::ModelChanged() {
1545 model_
->ModelChanged();
1549 TaskManager
* TaskManager::GetInstance() {
1550 return Singleton
<TaskManager
>::get();
1553 void TaskManager::OpenAboutMemory(chrome::HostDesktopType desktop_type
) {
1554 Profile
* profile
= ProfileManager::GetLastUsedProfileAllowedByPolicy();
1555 if (profile
->IsGuestSession() && !g_browser_process
->local_state()->
1556 GetBoolean(prefs::kBrowserGuestModeEnabled
)) {
1557 UserManager::Show(base::FilePath(),
1558 profiles::USER_MANAGER_NO_TUTORIAL
,
1559 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_MEMORY
);
1563 chrome::NavigateParams
params(
1564 profile
, GURL(chrome::kChromeUIMemoryURL
), ui::PAGE_TRANSITION_LINK
);
1565 params
.disposition
= NEW_FOREGROUND_TAB
;
1566 params
.host_desktop_type
= desktop_type
;
1567 chrome::Navigate(¶ms
);
1570 TaskManager::TaskManager()
1571 : model_(new TaskManagerModel(this)) {
1574 TaskManager::~TaskManager() {