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/prefs/pref_registry_simple.h"
11 #include "base/process/process_metrics.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string16.h"
14 #include "base/strings/string_number_conversions.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chrome/browser/task_manager/background_information.h"
20 #include "chrome/browser/task_manager/browser_process_resource_provider.h"
21 #include "chrome/browser/task_manager/child_process_resource_provider.h"
22 #include "chrome/browser/task_manager/extension_information.h"
23 #include "chrome/browser/task_manager/guest_information.h"
24 #include "chrome/browser/task_manager/panel_information.h"
25 #include "chrome/browser/task_manager/printing_information.h"
26 #include "chrome/browser/task_manager/resource_provider.h"
27 #include "chrome/browser/task_manager/tab_contents_information.h"
28 #include "chrome/browser/task_manager/web_contents_resource_provider.h"
29 #include "chrome/browser/ui/browser_navigator.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/common/url_constants.h"
32 #include "chrome/grit/generated_resources.h"
33 #include "components/nacl/browser/nacl_browser.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/gpu_data_manager.h"
36 #include "content/public/browser/gpu_data_manager_observer.h"
37 #include "content/public/browser/resource_request_info.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/browser/web_contents_delegate.h"
40 #include "content/public/browser/worker_service.h"
41 #include "content/public/common/result_codes.h"
42 #include "extensions/browser/extension_system.h"
43 #include "third_party/icu/source/i18n/unicode/coll.h"
44 #include "ui/base/l10n/l10n_util.h"
45 #include "ui/base/resource/resource_bundle.h"
46 #include "ui/base/text/bytes_formatting.h"
47 #include "ui/gfx/image/image_skia.h"
48 #include "ui/resources/grit/ui_resources.h"
50 #if defined(OS_MACOSX)
51 #include "content/public/browser/browser_child_process_host.h"
54 using content::BrowserThread
;
55 using content::ResourceRequestInfo
;
56 using content::WebContents
;
57 using task_manager::Resource
;
58 using task_manager::ResourceProvider
;
59 using task_manager::WebContentsInformation
;
66 int ValueCompare(T value1
, T value2
) {
74 // Used when one or both of the results to compare are unavailable.
75 int OrderUnavailableValue(bool v1
, bool v2
) {
81 // Used by TaskManagerModel::CompareValues(). See it for details of return
84 int ValueCompareMember(const TaskManagerModel
* model
,
85 bool (TaskManagerModel::*f
)(int, T
*) const,
90 bool value1_valid
= (model
->*f
)(row1
, &value1
);
91 bool value2_valid
= (model
->*f
)(row2
, &value2
);
92 return value1_valid
&& value2_valid
? ValueCompare(value1
, value2
) :
93 OrderUnavailableValue(value1_valid
, value2_valid
);
96 base::string16
FormatStatsSize(const blink::WebCache::ResourceTypeStat
& stat
) {
97 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT
,
98 ui::FormatBytesWithUnits(stat
.size
, ui::DATA_UNITS_KIBIBYTE
, false),
99 ui::FormatBytesWithUnits(stat
.liveSize
, ui::DATA_UNITS_KIBIBYTE
, false));
102 // Returns true if the specified id should use the first value in the group.
103 bool IsSharedByGroup(int col_id
) {
105 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
106 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
107 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
108 case IDS_TASK_MANAGER_CPU_COLUMN
:
109 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
110 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
111 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
:
112 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
113 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
114 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
115 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
116 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
124 void GetWinGDIHandles(base::ProcessHandle process
,
129 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
130 HANDLE current_process
= GetCurrentProcess();
131 HANDLE process_with_query_rights
;
132 if (DuplicateHandle(current_process
, process
, current_process
,
133 &process_with_query_rights
, PROCESS_QUERY_INFORMATION
,
135 *current
= GetGuiResources(process_with_query_rights
, GR_GDIOBJECTS
);
136 *peak
= GetGuiResources(process_with_query_rights
, GR_GDIOBJECTS_PEAK
);
137 CloseHandle(process_with_query_rights
);
141 void GetWinUSERHandles(base::ProcessHandle process
,
146 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
147 HANDLE current_process
= GetCurrentProcess();
148 HANDLE process_with_query_rights
;
149 if (DuplicateHandle(current_process
, process
, current_process
,
150 &process_with_query_rights
, PROCESS_QUERY_INFORMATION
,
152 *current
= GetGuiResources(process_with_query_rights
, GR_USEROBJECTS
);
153 *peak
= GetGuiResources(process_with_query_rights
, GR_USEROBJECTS_PEAK
);
154 CloseHandle(process_with_query_rights
);
161 class TaskManagerModelGpuDataManagerObserver
162 : public content::GpuDataManagerObserver
{
164 TaskManagerModelGpuDataManagerObserver() {
165 content::GpuDataManager::GetInstance()->AddObserver(this);
168 virtual ~TaskManagerModelGpuDataManagerObserver() {
169 content::GpuDataManager::GetInstance()->RemoveObserver(this);
172 static void NotifyVideoMemoryUsageStats(
173 const content::GPUVideoMemoryUsageStats
& video_memory_usage_stats
) {
174 TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats(
175 video_memory_usage_stats
);
178 virtual void OnVideoMemoryUsageStatsUpdate(
179 const content::GPUVideoMemoryUsageStats
& video_memory_usage_stats
)
181 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
182 NotifyVideoMemoryUsageStats(video_memory_usage_stats
);
184 BrowserThread::PostTask(
185 BrowserThread::UI
, FROM_HERE
, base::Bind(
186 &TaskManagerModelGpuDataManagerObserver::
187 NotifyVideoMemoryUsageStats
,
188 video_memory_usage_stats
));
193 TaskManagerModel::PerResourceValues::PerResourceValues()
194 : is_title_valid(false),
195 is_profile_name_valid(false),
197 is_process_id_valid(false),
199 is_webcore_stats_valid(false),
200 is_sqlite_memory_bytes_valid(false),
201 sqlite_memory_bytes(0),
202 is_v8_memory_valid(false),
203 v8_memory_allocated(0),
206 TaskManagerModel::PerResourceValues::~PerResourceValues() {}
208 TaskManagerModel::PerProcessValues::PerProcessValues()
209 : is_cpu_usage_valid(false),
211 is_idle_wakeups_valid(false),
213 is_private_and_shared_valid(false),
216 is_physical_memory_valid(false),
218 is_video_memory_valid(false),
220 video_memory_has_duplicates(false),
221 is_gdi_handles_valid(false),
224 is_user_handles_valid(0),
226 user_handles_peak(0),
227 is_nacl_debug_stub_port_valid(false),
228 nacl_debug_stub_port(0) {}
230 TaskManagerModel::PerProcessValues::~PerProcessValues() {}
232 ////////////////////////////////////////////////////////////////////////////////
233 // TaskManagerModel class
234 ////////////////////////////////////////////////////////////////////////////////
236 TaskManagerModel::TaskManagerModel(TaskManager
* task_manager
)
237 : pending_video_memory_usage_stats_update_(false),
241 is_updating_byte_count_(false) {
243 new task_manager::BrowserProcessResourceProvider(task_manager
));
244 AddResourceProvider(new task_manager::WebContentsResourceProvider(
246 scoped_ptr
<WebContentsInformation
>(
247 new task_manager::BackgroundInformation())));
248 AddResourceProvider(new task_manager::WebContentsResourceProvider(
250 scoped_ptr
<WebContentsInformation
>(
251 new task_manager::TabContentsInformation())));
252 #if defined(ENABLE_FULL_PRINTING)
253 AddResourceProvider(new task_manager::WebContentsResourceProvider(
255 scoped_ptr
<WebContentsInformation
>(
256 new task_manager::PrintingInformation())));
257 #endif // ENABLE_FULL_PRINTING
258 AddResourceProvider(new task_manager::WebContentsResourceProvider(
260 scoped_ptr
<WebContentsInformation
>(
261 new task_manager::PanelInformation())));
263 new task_manager::ChildProcessResourceProvider(task_manager
));
264 AddResourceProvider(new task_manager::WebContentsResourceProvider(
266 scoped_ptr
<WebContentsInformation
>(
267 new task_manager::ExtensionInformation())));
268 AddResourceProvider(new task_manager::WebContentsResourceProvider(
270 scoped_ptr
<WebContentsInformation
>(
271 new task_manager::GuestInformation())));
274 void TaskManagerModel::AddObserver(TaskManagerModelObserver
* observer
) {
275 observer_list_
.AddObserver(observer
);
278 void TaskManagerModel::RemoveObserver(TaskManagerModelObserver
* observer
) {
279 observer_list_
.RemoveObserver(observer
);
282 int TaskManagerModel::ResourceCount() const {
283 return resources_
.size();
286 int TaskManagerModel::GroupCount() const {
287 return group_map_
.size();
290 int TaskManagerModel::GetNaClDebugStubPort(int index
) const {
291 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
292 PerProcessValues
& values(per_process_cache_
[handle
]);
293 if (!values
.is_nacl_debug_stub_port_valid
) {
294 return nacl::kGdbDebugStubPortUnknown
;
296 return values
.nacl_debug_stub_port
;
299 int64
TaskManagerModel::GetNetworkUsage(int index
) const {
300 return GetNetworkUsage(GetResource(index
));
303 double TaskManagerModel::GetCPUUsage(int index
) const {
304 return GetCPUUsage(GetResource(index
));
307 int TaskManagerModel::GetIdleWakeupsPerSecond(int index
) const {
308 return GetIdleWakeupsPerSecond(GetResource(index
));
311 base::ProcessId
TaskManagerModel::GetProcessId(int index
) const {
312 PerResourceValues
& values(GetPerResourceValues(index
));
313 if (!values
.is_process_id_valid
) {
314 values
.is_process_id_valid
= true;
315 values
.process_id
= base::GetProcId(GetResource(index
)->GetProcess());
317 return values
.process_id
;
320 base::ProcessHandle
TaskManagerModel::GetProcess(int index
) const {
321 return GetResource(index
)->GetProcess();
324 base::string16
TaskManagerModel::GetResourceById(int index
, int col_id
) const {
325 if (IsSharedByGroup(col_id
) && !IsResourceFirstInGroup(index
))
326 return base::string16();
329 case IDS_TASK_MANAGER_TASK_COLUMN
:
330 return GetResourceTitle(index
);
332 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN
:
333 return GetResourceProfileName(index
);
335 case IDS_TASK_MANAGER_NET_COLUMN
:
336 return GetResourceNetworkUsage(index
);
338 case IDS_TASK_MANAGER_CPU_COLUMN
:
339 return GetResourceCPUUsage(index
);
341 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
342 return GetResourcePrivateMemory(index
);
344 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
345 return GetResourceSharedMemory(index
);
347 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
348 return GetResourcePhysicalMemory(index
);
350 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
351 return GetResourceProcessId(index
);
353 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
:
354 return GetResourceGDIHandles(index
);
356 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN
:
357 return GetResourceUSERHandles(index
);
359 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN
:
360 return GetResourceIdleWakeupsPerSecond(index
);
362 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
363 return GetResourceWebCoreImageCacheSize(index
);
365 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
366 return GetResourceWebCoreScriptsCacheSize(index
);
368 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
369 return GetResourceWebCoreCSSCacheSize(index
);
371 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
:
372 return GetResourceVideoMemory(index
);
374 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
375 return GetResourceSqliteMemoryUsed(index
);
377 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
378 return GetResourceV8MemoryAllocatedSize(index
);
380 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
381 return GetResourceNaClDebugStubPort(index
);
385 return base::string16();
389 const base::string16
& TaskManagerModel::GetResourceTitle(int index
) const {
390 PerResourceValues
& values
= GetPerResourceValues(index
);
391 if (!values
.is_title_valid
) {
392 values
.is_title_valid
= true;
393 values
.title
= GetResource(index
)->GetTitle();
398 const base::string16
& TaskManagerModel::GetResourceProfileName(
400 PerResourceValues
& values(GetPerResourceValues(index
));
401 if (!values
.is_profile_name_valid
) {
402 values
.is_profile_name_valid
= true;
403 values
.profile_name
= GetResource(index
)->GetProfileName();
405 return values
.profile_name
;
408 base::string16
TaskManagerModel::GetResourceNaClDebugStubPort(int index
) const {
409 int port
= GetNaClDebugStubPort(index
);
410 if (port
== nacl::kGdbDebugStubPortUnknown
) {
411 return base::ASCIIToUTF16("Unknown");
412 } else if (port
== nacl::kGdbDebugStubPortUnused
) {
413 return base::ASCIIToUTF16("N/A");
415 return base::IntToString16(port
);
419 base::string16
TaskManagerModel::GetResourceNetworkUsage(int index
) const {
420 int64 net_usage
= GetNetworkUsage(index
);
422 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
424 return base::ASCIIToUTF16("0");
425 base::string16 net_byte
= ui::FormatSpeed(net_usage
);
426 // Force number string to have LTR directionality.
427 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte
);
430 base::string16
TaskManagerModel::GetResourceCPUUsage(int index
) const {
431 return base::UTF8ToUTF16(base::StringPrintf(
432 #if defined(OS_MACOSX)
433 // Activity Monitor shows %cpu with one decimal digit -- be
434 // consistent with that.
439 GetCPUUsage(GetResource(index
))));
442 base::string16
TaskManagerModel::GetResourcePrivateMemory(int index
) const {
444 if (!GetPrivateMemory(index
, &private_mem
))
445 return base::ASCIIToUTF16("N/A");
446 return GetMemCellText(private_mem
);
449 base::string16
TaskManagerModel::GetResourceSharedMemory(int index
) const {
451 if (!GetSharedMemory(index
, &shared_mem
))
452 return base::ASCIIToUTF16("N/A");
453 return GetMemCellText(shared_mem
);
456 base::string16
TaskManagerModel::GetResourcePhysicalMemory(int index
) const {
458 GetPhysicalMemory(index
, &phys_mem
);
459 return GetMemCellText(phys_mem
);
462 base::string16
TaskManagerModel::GetResourceProcessId(int index
) const {
463 return base::IntToString16(GetProcessId(index
));
466 base::string16
TaskManagerModel::GetResourceGDIHandles(int index
) const {
467 size_t current
, peak
;
468 GetGDIHandles(index
, ¤t
, &peak
);
469 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT
,
470 base::IntToString16(current
), base::IntToString16(peak
));
473 base::string16
TaskManagerModel::GetResourceUSERHandles(int index
) const {
474 size_t current
, peak
;
475 GetUSERHandles(index
, ¤t
, &peak
);
476 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT
,
477 base::IntToString16(current
), base::IntToString16(peak
));
480 base::string16
TaskManagerModel::GetResourceWebCoreImageCacheSize(
482 if (!CacheWebCoreStats(index
))
483 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
484 return FormatStatsSize(GetPerResourceValues(index
).webcore_stats
.images
);
487 base::string16
TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
489 if (!CacheWebCoreStats(index
))
490 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
491 return FormatStatsSize(GetPerResourceValues(index
).webcore_stats
.scripts
);
494 base::string16
TaskManagerModel::GetResourceWebCoreCSSCacheSize(
496 if (!CacheWebCoreStats(index
))
497 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
498 return FormatStatsSize(
499 GetPerResourceValues(index
).webcore_stats
.cssStyleSheets
);
502 base::string16
TaskManagerModel::GetResourceVideoMemory(int index
) const {
505 if (!GetVideoMemory(index
, &video_memory
, &has_duplicates
) || !video_memory
)
506 return base::ASCIIToUTF16("N/A");
507 if (has_duplicates
) {
508 return GetMemCellText(video_memory
) + base::ASCIIToUTF16("*");
510 return GetMemCellText(video_memory
);
513 base::string16
TaskManagerModel::GetResourceSqliteMemoryUsed(int index
) const {
515 if (!GetSqliteMemoryUsedBytes(index
, &bytes
))
516 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
517 return GetMemCellText(bytes
);
520 base::string16
TaskManagerModel::GetResourceIdleWakeupsPerSecond(int index
)
522 return base::FormatNumber(GetIdleWakeupsPerSecond(GetResource(index
)));
525 base::string16
TaskManagerModel::GetResourceV8MemoryAllocatedSize(
527 size_t memory_allocated
= 0, memory_used
= 0;
528 if (!GetV8MemoryUsed(index
, &memory_used
) ||
529 !GetV8Memory(index
, &memory_allocated
))
530 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
531 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT
,
532 ui::FormatBytesWithUnits(memory_allocated
,
533 ui::DATA_UNITS_KIBIBYTE
,
535 ui::FormatBytesWithUnits(memory_used
,
536 ui::DATA_UNITS_KIBIBYTE
,
540 bool TaskManagerModel::GetPrivateMemory(int index
, size_t* result
) const {
542 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
543 if (!CachePrivateAndSharedMemory(handle
))
545 *result
= per_process_cache_
[handle
].private_bytes
;
549 bool TaskManagerModel::GetSharedMemory(int index
, size_t* result
) const {
551 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
552 if (!CachePrivateAndSharedMemory(handle
))
554 *result
= per_process_cache_
[handle
].shared_bytes
;
558 bool TaskManagerModel::GetPhysicalMemory(int index
, size_t* result
) const {
561 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
562 PerProcessValues
& values(per_process_cache_
[handle
]);
564 if (!values
.is_physical_memory_valid
) {
565 base::WorkingSetKBytes ws_usage
;
566 MetricsMap::const_iterator iter
= metrics_map_
.find(handle
);
567 if (iter
== metrics_map_
.end() ||
568 !iter
->second
->GetWorkingSetKBytes(&ws_usage
))
571 values
.is_physical_memory_valid
= true;
572 #if defined(OS_LINUX)
573 // On Linux private memory is also resident. Just use it.
574 values
.physical_memory
= ws_usage
.priv
* 1024;
576 // Memory = working_set.private + working_set.shareable.
577 // We exclude the shared memory.
578 values
.physical_memory
= iter
->second
->GetWorkingSetSize();
579 values
.physical_memory
-= ws_usage
.shared
* 1024;
582 *result
= values
.physical_memory
;
586 void TaskManagerModel::GetGDIHandles(int index
,
588 size_t* peak
) const {
592 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
593 PerProcessValues
& values(per_process_cache_
[handle
]);
595 if (!values
.is_gdi_handles_valid
) {
596 GetWinGDIHandles(GetResource(index
)->GetProcess(),
598 &values
.gdi_handles_peak
);
599 values
.is_gdi_handles_valid
= true;
601 *current
= values
.gdi_handles
;
602 *peak
= values
.gdi_handles_peak
;
606 void TaskManagerModel::GetUSERHandles(int index
,
608 size_t* peak
) const {
612 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
613 PerProcessValues
& values(per_process_cache_
[handle
]);
615 if (!values
.is_user_handles_valid
) {
616 GetWinUSERHandles(GetResource(index
)->GetProcess(),
617 &values
.user_handles
,
618 &values
.user_handles_peak
);
619 values
.is_user_handles_valid
= true;
621 *current
= values
.user_handles
;
622 *peak
= values
.user_handles_peak
;
626 bool TaskManagerModel::GetWebCoreCacheStats(
628 blink::WebCache::ResourceTypeStats
* result
) const {
629 if (!CacheWebCoreStats(index
))
631 *result
= GetPerResourceValues(index
).webcore_stats
;
635 bool TaskManagerModel::GetVideoMemory(int index
,
636 size_t* video_memory
,
637 bool* has_duplicates
) const {
639 *has_duplicates
= false;
641 base::ProcessId pid
= GetProcessId(index
);
642 PerProcessValues
& values(
643 per_process_cache_
[GetResource(index
)->GetProcess()]);
644 if (!values
.is_video_memory_valid
) {
645 content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i
=
646 video_memory_usage_stats_
.process_map
.find(pid
);
647 if (i
== video_memory_usage_stats_
.process_map
.end())
649 values
.is_video_memory_valid
= true;
650 values
.video_memory
= i
->second
.video_memory
;
651 values
.video_memory_has_duplicates
= i
->second
.has_duplicates
;
653 *video_memory
= values
.video_memory
;
654 *has_duplicates
= values
.video_memory_has_duplicates
;
658 bool TaskManagerModel::GetSqliteMemoryUsedBytes(
660 size_t* result
) const {
662 PerResourceValues
& values(GetPerResourceValues(index
));
663 if (!values
.is_sqlite_memory_bytes_valid
) {
664 if (!GetResource(index
)->ReportsSqliteMemoryUsed())
666 values
.is_sqlite_memory_bytes_valid
= true;
667 values
.sqlite_memory_bytes
= GetResource(index
)->SqliteMemoryUsedBytes();
669 *result
= values
.sqlite_memory_bytes
;
673 bool TaskManagerModel::GetV8Memory(int index
, size_t* result
) const {
675 if (!CacheV8Memory(index
))
677 *result
= GetPerResourceValues(index
).v8_memory_allocated
;
681 bool TaskManagerModel::GetV8MemoryUsed(int index
, size_t* result
) const {
683 if (!CacheV8Memory(index
))
685 *result
= GetPerResourceValues(index
).v8_memory_used
;
689 bool TaskManagerModel::CanActivate(int index
) const {
690 CHECK_LT(index
, ResourceCount());
691 return GetResourceWebContents(index
) != NULL
;
694 bool TaskManagerModel::IsResourceFirstInGroup(int index
) const {
695 Resource
* resource
= GetResource(index
);
696 GroupMap::const_iterator iter
= group_map_
.find(resource
->GetProcess());
697 DCHECK(iter
!= group_map_
.end());
698 const ResourceList
& group
= iter
->second
;
699 return (group
[0] == resource
);
702 bool TaskManagerModel::IsResourceLastInGroup(int index
) const {
703 Resource
* resource
= GetResource(index
);
704 GroupMap::const_iterator iter
= group_map_
.find(resource
->GetProcess());
705 DCHECK(iter
!= group_map_
.end());
706 const ResourceList
& group
= iter
->second
;
707 return (group
.back() == resource
);
710 gfx::ImageSkia
TaskManagerModel::GetResourceIcon(int index
) const {
711 gfx::ImageSkia icon
= GetResource(index
)->GetIcon();
715 static const gfx::ImageSkia
* default_icon
=
716 ResourceBundle::GetSharedInstance().
717 GetNativeImageNamed(IDR_DEFAULT_FAVICON
).ToImageSkia();
718 return *default_icon
;
721 TaskManagerModel::GroupRange
722 TaskManagerModel::GetGroupRangeForResource(int index
) const {
723 Resource
* resource
= GetResource(index
);
724 GroupMap::const_iterator group_iter
=
725 group_map_
.find(resource
->GetProcess());
726 DCHECK(group_iter
!= group_map_
.end());
727 const ResourceList
& group
= group_iter
->second
;
728 if (group
.size() == 1) {
729 return std::make_pair(index
, 1);
731 for (int i
= index
; i
>= 0; --i
) {
732 if (GetResource(i
) == group
[0])
733 return std::make_pair(i
, group
.size());
736 return std::make_pair(-1, -1);
740 int TaskManagerModel::GetGroupIndexForResource(int index
) const {
741 int group_index
= -1;
742 for (int i
= 0; i
<= index
; ++i
) {
743 if (IsResourceFirstInGroup(i
))
747 DCHECK_NE(group_index
, -1);
751 int TaskManagerModel::GetResourceIndexForGroup(int group_index
,
752 int index_in_group
) const {
753 int group_count
= -1;
754 int count_in_group
= -1;
755 for (int i
= 0; i
< ResourceCount(); ++i
) {
756 if (IsResourceFirstInGroup(i
))
759 if (group_count
== group_index
) {
761 if (count_in_group
== index_in_group
)
763 } else if (group_count
> group_index
) {
772 int TaskManagerModel::CompareValues(int row1
, int row2
, int col_id
) const {
773 CHECK(row1
< ResourceCount() && row2
< ResourceCount());
775 case IDS_TASK_MANAGER_TASK_COLUMN
: {
776 static icu::Collator
* collator
= NULL
;
778 UErrorCode create_status
= U_ZERO_ERROR
;
779 collator
= icu::Collator::createInstance(create_status
);
780 if (!U_SUCCESS(create_status
)) {
785 const base::string16
& title1
= GetResourceTitle(row1
);
786 const base::string16
& title2
= GetResourceTitle(row2
);
787 UErrorCode compare_status
= U_ZERO_ERROR
;
788 UCollationResult compare_result
= collator
->compare(
789 static_cast<const UChar
*>(title1
.c_str()),
790 static_cast<int>(title1
.length()),
791 static_cast<const UChar
*>(title2
.c_str()),
792 static_cast<int>(title2
.length()),
794 DCHECK(U_SUCCESS(compare_status
));
795 return compare_result
;
798 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN
: {
799 const base::string16
& profile1
= GetResourceProfileName(row1
);
800 const base::string16
& profile2
= GetResourceProfileName(row2
);
801 return profile1
.compare(0, profile1
.length(), profile2
, 0,
805 case IDS_TASK_MANAGER_NET_COLUMN
:
806 return ValueCompare(GetNetworkUsage(GetResource(row1
)),
807 GetNetworkUsage(GetResource(row2
)));
809 case IDS_TASK_MANAGER_CPU_COLUMN
:
810 return ValueCompare(GetCPUUsage(GetResource(row1
)),
811 GetCPUUsage(GetResource(row2
)));
813 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
814 return ValueCompareMember(
815 this, &TaskManagerModel::GetPrivateMemory
, row1
, row2
);
817 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
818 return ValueCompareMember(
819 this, &TaskManagerModel::GetSharedMemory
, row1
, row2
);
821 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
822 return ValueCompareMember(
823 this, &TaskManagerModel::GetPhysicalMemory
, row1
, row2
);
825 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
826 return ValueCompare(GetNaClDebugStubPort(row1
),
827 GetNaClDebugStubPort(row2
));
829 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
830 return ValueCompare(GetProcessId(row1
), GetProcessId(row2
));
832 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
: {
833 size_t current1
, peak1
;
834 size_t current2
, peak2
;
835 GetGDIHandles(row1
, ¤t1
, &peak1
);
836 GetGDIHandles(row2
, ¤t2
, &peak2
);
837 return ValueCompare(current1
, current2
);
840 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN
: {
841 size_t current1
, peak1
;
842 size_t current2
, peak2
;
843 GetUSERHandles(row1
, ¤t1
, &peak1
);
844 GetUSERHandles(row2
, ¤t2
, &peak2
);
845 return ValueCompare(current1
, current2
);
848 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN
:
849 return ValueCompare(GetIdleWakeupsPerSecond(row1
),
850 GetIdleWakeupsPerSecond(row2
));
852 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
853 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
854 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
: {
855 bool row1_stats_valid
= CacheWebCoreStats(row1
);
856 bool row2_stats_valid
= CacheWebCoreStats(row2
);
857 if (row1_stats_valid
&& row2_stats_valid
) {
858 const blink::WebCache::ResourceTypeStats
& stats1(
859 GetPerResourceValues(row1
).webcore_stats
);
860 const blink::WebCache::ResourceTypeStats
& stats2(
861 GetPerResourceValues(row2
).webcore_stats
);
863 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
864 return ValueCompare(stats1
.images
.size
, stats2
.images
.size
);
865 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
866 return ValueCompare(stats1
.scripts
.size
, stats2
.scripts
.size
);
867 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
868 return ValueCompare(stats1
.cssStyleSheets
.size
,
869 stats2
.cssStyleSheets
.size
);
875 return OrderUnavailableValue(row1_stats_valid
, row2_stats_valid
);
878 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
: {
882 bool value1_valid
= GetVideoMemory(row1
, &value1
, &has_duplicates
);
883 bool value2_valid
= GetVideoMemory(row2
, &value2
, &has_duplicates
);
884 return value1_valid
&& value2_valid
? ValueCompare(value1
, value2
) :
885 OrderUnavailableValue(value1_valid
, value2_valid
);
888 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
889 return ValueCompareMember(
890 this, &TaskManagerModel::GetV8Memory
, row1
, row2
);
892 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
893 return ValueCompareMember(
894 this, &TaskManagerModel::GetSqliteMemoryUsedBytes
, row1
, row2
);
903 int TaskManagerModel::GetUniqueChildProcessId(int index
) const {
904 return GetResource(index
)->GetUniqueChildProcessId();
907 Resource::Type
TaskManagerModel::GetResourceType(int index
) const {
908 return GetResource(index
)->GetType();
911 WebContents
* TaskManagerModel::GetResourceWebContents(int index
) const {
912 return GetResource(index
)->GetWebContents();
915 void TaskManagerModel::AddResource(Resource
* resource
) {
916 base::ProcessHandle process
= resource
->GetProcess();
918 GroupMap::iterator group_iter
= group_map_
.find(process
);
919 int new_entry_index
= 0;
920 if (group_iter
== group_map_
.end()) {
921 group_map_
.insert(make_pair(process
, ResourceList(1, resource
)));
923 // Not part of a group, just put at the end of the list.
924 resources_
.push_back(resource
);
925 new_entry_index
= static_cast<int>(resources_
.size() - 1);
927 ResourceList
* group_entries
= &(group_iter
->second
);
928 group_entries
->push_back(resource
);
930 // Insert the new entry right after the last entry of its group.
931 ResourceList::iterator iter
=
932 std::find(resources_
.begin(),
934 (*group_entries
)[group_entries
->size() - 2]);
935 DCHECK(iter
!= resources_
.end());
936 new_entry_index
= static_cast<int>(iter
- resources_
.begin()) + 1;
937 resources_
.insert(++iter
, resource
);
940 // Create the ProcessMetrics for this process if needed (not in map).
941 if (metrics_map_
.find(process
) == metrics_map_
.end()) {
942 base::ProcessMetrics
* pm
=
943 #if !defined(OS_MACOSX)
944 base::ProcessMetrics::CreateProcessMetrics(process
);
946 base::ProcessMetrics::CreateProcessMetrics(
947 process
, content::BrowserChildProcessHost::GetPortProvider());
950 metrics_map_
[process
] = pm
;
953 // Notify the table that the contents have changed for it to redraw.
954 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
955 OnItemsAdded(new_entry_index
, 1));
958 void TaskManagerModel::RemoveResource(Resource
* resource
) {
959 base::ProcessHandle process
= resource
->GetProcess();
961 // Find the associated group.
962 GroupMap::iterator group_iter
= group_map_
.find(process
);
963 DCHECK(group_iter
!= group_map_
.end());
964 if (group_iter
== group_map_
.end())
966 ResourceList
& group_entries
= group_iter
->second
;
968 // Remove the entry from the group map.
969 ResourceList::iterator iter
= std::find(group_entries
.begin(),
972 DCHECK(iter
!= group_entries
.end());
973 if (iter
!= group_entries
.end())
974 group_entries
.erase(iter
);
976 // If there are no more entries for that process, do the clean-up.
977 if (group_entries
.empty()) {
978 group_map_
.erase(group_iter
);
980 // Nobody is using this process, we don't need the process metrics anymore.
981 MetricsMap::iterator pm_iter
= metrics_map_
.find(process
);
982 DCHECK(pm_iter
!= metrics_map_
.end());
983 if (pm_iter
!= metrics_map_
.end()) {
984 delete pm_iter
->second
;
985 metrics_map_
.erase(process
);
989 // Remove the entry from the model list.
990 iter
= std::find(resources_
.begin(), resources_
.end(), resource
);
991 DCHECK(iter
!= resources_
.end());
992 if (iter
!= resources_
.end()) {
993 int index
= static_cast<int>(iter
- resources_
.begin());
994 // Notify the observers that the contents will change.
995 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
996 OnItemsToBeRemoved(index
, 1));
997 // Now actually remove the entry from the model list.
998 resources_
.erase(iter
);
999 // Notify the table that the contents have changed.
1000 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1001 OnItemsRemoved(index
, 1));
1004 // Remove the entry from the network maps.
1005 ResourceValueMap::iterator net_iter
=
1006 current_byte_count_map_
.find(resource
);
1007 if (net_iter
!= current_byte_count_map_
.end())
1008 current_byte_count_map_
.erase(net_iter
);
1011 void TaskManagerModel::StartUpdating() {
1012 // Multiple StartUpdating requests may come in, and we only need to take
1013 // action the first time.
1015 if (update_requests_
> 1)
1017 DCHECK_EQ(1, update_requests_
);
1018 DCHECK_NE(TASK_PENDING
, update_state_
);
1020 // If update_state_ is STOPPING, it means a task is still pending. Setting
1021 // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()).
1022 if (update_state_
== IDLE
) {
1023 base::MessageLoop::current()->PostTask(
1025 base::Bind(&TaskManagerModel::RefreshCallback
, this));
1027 update_state_
= TASK_PENDING
;
1029 // Notify resource providers that we are updating.
1032 if (!resources_
.empty()) {
1033 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1034 OnReadyPeriodicalUpdate());
1037 BrowserThread::PostTask(
1038 BrowserThread::IO
, FROM_HERE
,
1039 base::Bind(&TaskManagerModel::SetUpdatingByteCount
, this, true));
1042 void TaskManagerModel::StopUpdating() {
1043 // Don't actually stop updating until we have heard as many calls as those
1044 // to StartUpdating.
1046 if (update_requests_
> 0)
1048 // Make sure that update_requests_ cannot go negative.
1049 CHECK_EQ(0, update_requests_
);
1050 DCHECK_EQ(TASK_PENDING
, update_state_
);
1051 update_state_
= STOPPING
;
1053 // Notify resource providers that we are done updating.
1056 BrowserThread::PostTask(
1057 BrowserThread::IO
, FROM_HERE
,
1058 base::Bind(&TaskManagerModel::SetUpdatingByteCount
, this, false));
1061 void TaskManagerModel::StartListening() {
1062 // Multiple StartListening requests may come in and we only need to take
1063 // action the first time.
1065 if (listen_requests_
> 1)
1067 DCHECK_EQ(1, listen_requests_
);
1069 // Notify resource providers that we should start listening to events.
1070 for (ResourceProviderList::iterator iter
= providers_
.begin();
1071 iter
!= providers_
.end(); ++iter
) {
1072 (*iter
)->StartUpdating();
1076 void TaskManagerModel::StopListening() {
1077 // Don't actually stop listening until we have heard as many calls as those
1078 // to StartListening.
1080 if (listen_requests_
> 0)
1083 DCHECK_EQ(0, listen_requests_
);
1085 // Notify resource providers that we are done listening.
1086 for (ResourceProviderList::const_iterator iter
= providers_
.begin();
1087 iter
!= providers_
.end(); ++iter
) {
1088 (*iter
)->StopUpdating();
1091 // Must clear the resources before the next attempt to start listening.
1095 void TaskManagerModel::Clear() {
1096 int size
= ResourceCount();
1100 // Clear the groups.
1103 // Clear the process related info.
1104 STLDeleteValues(&metrics_map_
);
1106 // Clear the network maps.
1107 current_byte_count_map_
.clear();
1109 per_resource_cache_
.clear();
1110 per_process_cache_
.clear();
1112 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1113 OnItemsRemoved(0, size
));
1117 void TaskManagerModel::ModelChanged() {
1118 // Notify the table that the contents have changed for it to redraw.
1119 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
, OnModelChanged());
1122 void TaskManagerModel::Refresh() {
1123 per_resource_cache_
.clear();
1124 per_process_cache_
.clear();
1126 #if !defined(DISABLE_NACL)
1127 nacl::NaClBrowser
* nacl_browser
= nacl::NaClBrowser::GetInstance();
1128 #endif // !defined(DISABLE_NACL)
1130 // Compute the CPU usage values and check if NaCl GDB debug stub port is
1132 // Note that we compute the CPU usage for all resources (instead of doing it
1133 // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last
1134 // time it was called, and not calling it everytime would skew the value the
1135 // next time it is retrieved (as it would be for more than 1 cycle).
1136 // The same is true for idle wakeups.
1137 for (ResourceList::iterator iter
= resources_
.begin();
1138 iter
!= resources_
.end(); ++iter
) {
1139 base::ProcessHandle process
= (*iter
)->GetProcess();
1140 PerProcessValues
& values(per_process_cache_
[process
]);
1141 #if !defined(DISABLE_NACL)
1142 // Debug stub port doesn't change once known.
1143 if (!values
.is_nacl_debug_stub_port_valid
) {
1144 values
.nacl_debug_stub_port
= nacl_browser
->GetProcessGdbDebugStubPort(
1145 (*iter
)->GetUniqueChildProcessId());
1146 if (values
.nacl_debug_stub_port
!= nacl::kGdbDebugStubPortUnknown
) {
1147 values
.is_nacl_debug_stub_port_valid
= true;
1150 #endif // !defined(DISABLE_NACL)
1151 if (values
.is_cpu_usage_valid
&& values
.is_idle_wakeups_valid
)
1153 MetricsMap::iterator metrics_iter
= metrics_map_
.find(process
);
1154 DCHECK(metrics_iter
!= metrics_map_
.end());
1155 if (!values
.is_cpu_usage_valid
) {
1156 values
.is_cpu_usage_valid
= true;
1157 values
.cpu_usage
= metrics_iter
->second
->GetCPUUsage();
1159 #if defined(OS_MACOSX) || defined(OS_LINUX)
1160 // TODO(port): Implement GetIdleWakeupsPerSecond() on other platforms,
1162 if (!values
.is_idle_wakeups_valid
) {
1163 values
.is_idle_wakeups_valid
= true;
1164 values
.idle_wakeups
= metrics_iter
->second
->GetIdleWakeupsPerSecond();
1166 #endif // defined(OS_MACOSX) || defined(OS_LINUX)
1169 // Send a request to refresh GPU memory consumption values
1170 RefreshVideoMemoryUsageStats();
1172 // Compute the new network usage values.
1173 base::TimeDelta update_time
=
1174 base::TimeDelta::FromMilliseconds(kUpdateTimeMs
);
1175 for (ResourceValueMap::iterator iter
= current_byte_count_map_
.begin();
1176 iter
!= current_byte_count_map_
.end(); ++iter
) {
1177 PerResourceValues
* values
= &(per_resource_cache_
[iter
->first
]);
1178 if (update_time
> base::TimeDelta::FromSeconds(1))
1179 values
->network_usage
= iter
->second
/ update_time
.InSeconds();
1181 values
->network_usage
= iter
->second
* (1 / update_time
.InSeconds());
1183 // Then we reset the current byte count.
1187 // Let resources update themselves if they need to.
1188 for (ResourceList::iterator iter
= resources_
.begin();
1189 iter
!= resources_
.end(); ++iter
) {
1193 if (!resources_
.empty()) {
1194 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1195 OnItemsChanged(0, ResourceCount()));
1199 void TaskManagerModel::NotifyResourceTypeStats(
1200 base::ProcessId renderer_id
,
1201 const blink::WebCache::ResourceTypeStats
& stats
) {
1202 for (ResourceList::iterator it
= resources_
.begin();
1203 it
!= resources_
.end(); ++it
) {
1204 if (base::GetProcId((*it
)->GetProcess()) == renderer_id
) {
1205 (*it
)->NotifyResourceTypeStats(stats
);
1210 void TaskManagerModel::NotifyVideoMemoryUsageStats(
1211 const content::GPUVideoMemoryUsageStats
& video_memory_usage_stats
) {
1212 DCHECK(pending_video_memory_usage_stats_update_
);
1213 video_memory_usage_stats_
= video_memory_usage_stats
;
1214 pending_video_memory_usage_stats_update_
= false;
1217 void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id
,
1218 size_t v8_memory_allocated
,
1219 size_t v8_memory_used
) {
1220 for (ResourceList::iterator it
= resources_
.begin();
1221 it
!= resources_
.end(); ++it
) {
1222 if (base::GetProcId((*it
)->GetProcess()) == renderer_id
) {
1223 (*it
)->NotifyV8HeapStats(v8_memory_allocated
, v8_memory_used
);
1228 void TaskManagerModel::NotifyBytesRead(const net::URLRequest
& request
,
1230 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1231 if (!is_updating_byte_count_
)
1234 // Only net::URLRequestJob instances created by the ResourceDispatcherHost
1235 // have an associated ResourceRequestInfo and a render frame associated.
1236 // All other jobs will have -1 returned for the render process child and
1237 // routing ids - the jobs may still match a resource based on their origin id,
1238 // otherwise BytesRead() will attribute the activity to the Browser resource.
1239 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(&request
);
1240 int child_id
= -1, route_id
= -1;
1242 info
->GetAssociatedRenderFrame(&child_id
, &route_id
);
1244 // Get the origin PID of the request's originator. This will only be set for
1245 // plugins - for renderer or browser initiated requests it will be zero.
1248 origin_pid
= info
->GetOriginPID();
1250 if (bytes_read_buffer_
.empty()) {
1251 base::MessageLoop::current()->PostDelayedTask(
1253 base::Bind(&TaskManagerModel::NotifyMultipleBytesRead
, this),
1254 base::TimeDelta::FromSeconds(1));
1257 bytes_read_buffer_
.push_back(
1258 BytesReadParam(origin_pid
, child_id
, route_id
, byte_count
));
1261 // This is called on the UI thread.
1262 void TaskManagerModel::NotifyDataReady() {
1263 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1264 for (size_t i
= 0; i
< on_data_ready_callbacks_
.size(); ++i
) {
1265 if (!on_data_ready_callbacks_
[i
].is_null())
1266 on_data_ready_callbacks_
[i
].Run();
1269 on_data_ready_callbacks_
.clear();
1272 void TaskManagerModel::RegisterOnDataReadyCallback(
1273 const base::Closure
& callback
) {
1274 on_data_ready_callbacks_
.push_back(callback
);
1277 TaskManagerModel::~TaskManagerModel() {
1278 on_data_ready_callbacks_
.clear();
1281 void TaskManagerModel::RefreshCallback() {
1282 DCHECK_NE(IDLE
, update_state_
);
1284 if (update_state_
== STOPPING
) {
1285 // We have been asked to stop.
1286 update_state_
= IDLE
;
1292 // Schedule the next update.
1293 base::MessageLoop::current()->PostDelayedTask(
1295 base::Bind(&TaskManagerModel::RefreshCallback
, this),
1296 base::TimeDelta::FromMilliseconds(kUpdateTimeMs
));
1299 void TaskManagerModel::RefreshVideoMemoryUsageStats() {
1300 if (pending_video_memory_usage_stats_update_
)
1303 if (!video_memory_usage_stats_observer_
.get()) {
1304 video_memory_usage_stats_observer_
.reset(
1305 new TaskManagerModelGpuDataManagerObserver());
1307 pending_video_memory_usage_stats_update_
= true;
1308 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate();
1311 int64
TaskManagerModel::GetNetworkUsageForResource(Resource
* resource
) const {
1312 // Returns default of 0 if no network usage.
1313 return per_resource_cache_
[resource
].network_usage
;
1316 void TaskManagerModel::BytesRead(BytesReadParam param
) {
1317 if (update_state_
!= TASK_PENDING
|| listen_requests_
== 0) {
1318 // A notification sneaked in while we were stopping the updating, just
1323 // TODO(jcampan): this should be improved once we have a better way of
1324 // linking a network notification back to the object that initiated it.
1325 Resource
* resource
= NULL
;
1326 for (ResourceProviderList::iterator iter
= providers_
.begin();
1327 iter
!= providers_
.end(); ++iter
) {
1328 resource
= (*iter
)->GetResource(param
.origin_pid
,
1335 if (resource
== NULL
) {
1336 // We can't match a resource to the notification. That might mean the
1337 // tab that started a download was closed, or the request may have had
1338 // no originating resource associated with it in the first place.
1339 // We attribute orphaned/unaccounted activity to the Browser process.
1340 CHECK(param
.origin_pid
|| (param
.child_id
!= -1));
1341 param
.origin_pid
= 0;
1342 param
.child_id
= param
.route_id
= -1;
1347 // We do support network usage, mark the resource as such so it can report 0
1349 if (!resource
->SupportNetworkUsage())
1350 resource
->SetSupportNetworkUsage();
1352 ResourceValueMap::const_iterator iter_res
=
1353 current_byte_count_map_
.find(resource
);
1354 if (iter_res
== current_byte_count_map_
.end())
1355 current_byte_count_map_
[resource
] = param
.byte_count
;
1357 current_byte_count_map_
[resource
] = iter_res
->second
+ param
.byte_count
;
1360 void TaskManagerModel::MultipleBytesRead(
1361 const std::vector
<BytesReadParam
>* params
) {
1362 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1363 for (std::vector
<BytesReadParam
>::const_iterator it
= params
->begin();
1364 it
!= params
->end(); ++it
) {
1369 void TaskManagerModel::NotifyMultipleBytesRead() {
1370 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1371 DCHECK(!bytes_read_buffer_
.empty());
1373 std::vector
<BytesReadParam
>* bytes_read_buffer
=
1374 new std::vector
<BytesReadParam
>;
1375 bytes_read_buffer_
.swap(*bytes_read_buffer
);
1376 BrowserThread::PostTask(
1377 BrowserThread::UI
, FROM_HERE
,
1378 base::Bind(&TaskManagerModel::MultipleBytesRead
, this,
1379 base::Owned(bytes_read_buffer
)));
1382 void TaskManagerModel::SetUpdatingByteCount(bool is_updating
) {
1383 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1384 is_updating_byte_count_
= is_updating
;
1387 int64
TaskManagerModel::GetNetworkUsage(Resource
* resource
) const {
1388 int64 net_usage
= GetNetworkUsageForResource(resource
);
1389 if (net_usage
== 0 && !resource
->SupportNetworkUsage())
1394 double TaskManagerModel::GetCPUUsage(Resource
* resource
) const {
1395 const PerProcessValues
& values(per_process_cache_
[resource
->GetProcess()]);
1396 // Returns 0 if not valid, which is fine.
1397 return values
.cpu_usage
;
1400 int TaskManagerModel::GetIdleWakeupsPerSecond(Resource
* resource
) const {
1401 const PerProcessValues
& values(per_process_cache_
[resource
->GetProcess()]);
1402 // Returns 0 if not valid, which is fine.
1403 return values
.idle_wakeups
;
1406 base::string16
TaskManagerModel::GetMemCellText(int64 number
) const {
1407 #if !defined(OS_MACOSX)
1408 base::string16 str
= base::FormatNumber(number
/ 1024);
1410 // Adjust number string if necessary.
1411 base::i18n::AdjustStringForLocaleDirection(&str
);
1412 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT
, str
);
1414 // System expectation is to show "100 kB", "200 MB", etc.
1415 // TODO(thakis): Switch to metric units (as opposed to powers of two).
1416 return ui::FormatBytes(number
);
1420 bool TaskManagerModel::CachePrivateAndSharedMemory(
1421 base::ProcessHandle handle
) const {
1422 PerProcessValues
& values(per_process_cache_
[handle
]);
1423 if (values
.is_private_and_shared_valid
)
1426 MetricsMap::const_iterator iter
= metrics_map_
.find(handle
);
1427 if (iter
== metrics_map_
.end() ||
1428 !iter
->second
->GetMemoryBytes(&values
.private_bytes
,
1429 &values
.shared_bytes
)) {
1433 values
.is_private_and_shared_valid
= true;
1437 bool TaskManagerModel::CacheWebCoreStats(int index
) const {
1438 PerResourceValues
& values(GetPerResourceValues(index
));
1439 if (!values
.is_webcore_stats_valid
) {
1440 if (!GetResource(index
)->ReportsCacheStats())
1442 values
.is_webcore_stats_valid
= true;
1443 values
.webcore_stats
= GetResource(index
)->GetWebCoreCacheStats();
1448 bool TaskManagerModel::CacheV8Memory(int index
) const {
1449 PerResourceValues
& values(GetPerResourceValues(index
));
1450 if (!values
.is_v8_memory_valid
) {
1451 if (!GetResource(index
)->ReportsV8MemoryStats())
1453 values
.is_v8_memory_valid
= true;
1454 values
.v8_memory_allocated
= GetResource(index
)->GetV8MemoryAllocated();
1455 values
.v8_memory_used
= GetResource(index
)->GetV8MemoryUsed();
1460 void TaskManagerModel::AddResourceProvider(ResourceProvider
* provider
) {
1462 providers_
.push_back(provider
);
1465 TaskManagerModel::PerResourceValues
& TaskManagerModel::GetPerResourceValues(
1467 return per_resource_cache_
[GetResource(index
)];
1470 Resource
* TaskManagerModel::GetResource(int index
) const {
1472 CHECK_LT(index
, static_cast<int>(resources_
.size()));
1473 return resources_
[index
];
1476 ////////////////////////////////////////////////////////////////////////////////
1477 // TaskManager class
1478 ////////////////////////////////////////////////////////////////////////////////
1480 void TaskManager::RegisterPrefs(PrefRegistrySimple
* registry
) {
1481 registry
->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement
);
1484 bool TaskManager::IsBrowserProcess(int index
) const {
1485 // If some of the selection is out of bounds, ignore. This may happen when
1486 // killing a process that manages several pages.
1487 return index
< model_
->ResourceCount() &&
1488 model_
->GetProcess(index
) == base::GetCurrentProcessHandle();
1491 void TaskManager::KillProcess(int index
) {
1492 base::ProcessHandle process
= model_
->GetProcess(index
);
1494 if (process
!= base::GetCurrentProcessHandle())
1495 base::KillProcess(process
, content::RESULT_CODE_KILLED
, false);
1498 void TaskManager::ActivateProcess(int index
) {
1499 // GetResourceWebContents returns a pointer to the relevant web contents for
1500 // the resource. If the index doesn't correspond to any web contents
1501 // (i.e. refers to the Browser process or a plugin), GetWebContents will
1503 WebContents
* chosen_web_contents
= model_
->GetResourceWebContents(index
);
1504 if (chosen_web_contents
&& chosen_web_contents
->GetDelegate())
1505 chosen_web_contents
->GetDelegate()->ActivateContents(chosen_web_contents
);
1508 void TaskManager::AddResource(Resource
* resource
) {
1509 model_
->AddResource(resource
);
1512 void TaskManager::RemoveResource(Resource
* resource
) {
1513 model_
->RemoveResource(resource
);
1516 void TaskManager::OnWindowClosed() {
1517 model_
->StopUpdating();
1520 void TaskManager::ModelChanged() {
1521 model_
->ModelChanged();
1525 TaskManager
* TaskManager::GetInstance() {
1526 return Singleton
<TaskManager
>::get();
1529 void TaskManager::OpenAboutMemory(chrome::HostDesktopType desktop_type
) {
1530 chrome::NavigateParams
params(
1531 ProfileManager::GetLastUsedProfileAllowedByPolicy(),
1532 GURL(chrome::kChromeUIMemoryURL
),
1533 ui::PAGE_TRANSITION_LINK
);
1534 params
.disposition
= NEW_FOREGROUND_TAB
;
1535 params
.host_desktop_type
= desktop_type
;
1536 chrome::Navigate(¶ms
);
1539 TaskManager::TaskManager()
1540 : model_(new TaskManagerModel(this)) {
1543 TaskManager::~TaskManager() {