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/rand_util.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/task_manager/background_resource_provider.h"
21 #include "chrome/browser/task_manager/browser_process_resource_provider.h"
22 #include "chrome/browser/task_manager/child_process_resource_provider.h"
23 #include "chrome/browser/task_manager/extension_process_resource_provider.h"
24 #include "chrome/browser/task_manager/guest_resource_provider.h"
25 #include "chrome/browser/task_manager/panel_resource_provider.h"
26 #include "chrome/browser/task_manager/resource_provider.h"
27 #include "chrome/browser/task_manager/tab_contents_resource_provider.h"
28 #include "chrome/browser/task_manager/worker_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 "content/public/browser/browser_thread.h"
33 #include "content/public/browser/gpu_data_manager.h"
34 #include "content/public/browser/gpu_data_manager_observer.h"
35 #include "content/public/browser/resource_request_info.h"
36 #include "content/public/browser/web_contents.h"
37 #include "content/public/browser/web_contents_delegate.h"
38 #include "content/public/common/result_codes.h"
39 #include "extensions/browser/extension_system.h"
40 #include "grit/generated_resources.h"
41 #include "grit/ui_resources.h"
42 #include "third_party/icu/source/i18n/unicode/coll.h"
43 #include "ui/base/l10n/l10n_util.h"
44 #include "ui/base/resource/resource_bundle.h"
45 #include "ui/base/text/bytes_formatting.h"
46 #include "ui/gfx/image/image_skia.h"
48 #if !defined(OS_CHROMEOS)
49 #include "chrome/browser/task_manager/notification_resource_provider.h"
52 #if defined(OS_MACOSX)
53 #include "content/public/browser/browser_child_process_host.h"
56 using content::BrowserThread
;
57 using content::ResourceRequestInfo
;
58 using content::WebContents
;
59 using task_manager::Resource
;
60 using task_manager::ResourceProvider
;
67 int ValueCompare(T value1
, T value2
) {
75 // Used when one or both of the results to compare are unavailable.
76 int OrderUnavailableValue(bool v1
, bool v2
) {
82 // Used by TaskManagerModel::CompareValues(). See it for details of return
85 int ValueCompareMember(const TaskManagerModel
* model
,
86 bool (TaskManagerModel::*f
)(int, T
*) const,
91 bool value1_valid
= (model
->*f
)(row1
, &value1
);
92 bool value2_valid
= (model
->*f
)(row2
, &value2
);
93 return value1_valid
&& value2_valid
? ValueCompare(value1
, value2
) :
94 OrderUnavailableValue(value1_valid
, value2_valid
);
97 base::string16
FormatStatsSize(const blink::WebCache::ResourceTypeStat
& stat
) {
98 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT
,
99 ui::FormatBytesWithUnits(stat
.size
, ui::DATA_UNITS_KIBIBYTE
, false),
100 ui::FormatBytesWithUnits(stat
.liveSize
, ui::DATA_UNITS_KIBIBYTE
, false));
103 // Returns true if the specified id should use the first value in the group.
104 bool IsSharedByGroup(int col_id
) {
106 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
107 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
108 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
109 case IDS_TASK_MANAGER_CPU_COLUMN
:
110 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
111 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
112 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
:
113 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
114 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
115 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
116 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
117 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
125 void GetWinGDIHandles(base::ProcessHandle process
,
130 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
131 HANDLE current_process
= GetCurrentProcess();
132 HANDLE process_with_query_rights
;
133 if (DuplicateHandle(current_process
, process
, current_process
,
134 &process_with_query_rights
, PROCESS_QUERY_INFORMATION
,
136 *current
= GetGuiResources(process_with_query_rights
, GR_GDIOBJECTS
);
137 *peak
= GetGuiResources(process_with_query_rights
, GR_GDIOBJECTS_PEAK
);
138 CloseHandle(process_with_query_rights
);
142 void GetWinUSERHandles(base::ProcessHandle process
,
147 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
148 HANDLE current_process
= GetCurrentProcess();
149 HANDLE process_with_query_rights
;
150 if (DuplicateHandle(current_process
, process
, current_process
,
151 &process_with_query_rights
, PROCESS_QUERY_INFORMATION
,
153 *current
= GetGuiResources(process_with_query_rights
, GR_USEROBJECTS
);
154 *peak
= GetGuiResources(process_with_query_rights
, GR_USEROBJECTS_PEAK
);
155 CloseHandle(process_with_query_rights
);
162 class TaskManagerModelGpuDataManagerObserver
163 : public content::GpuDataManagerObserver
{
165 TaskManagerModelGpuDataManagerObserver() {
166 content::GpuDataManager::GetInstance()->AddObserver(this);
169 virtual ~TaskManagerModelGpuDataManagerObserver() {
170 content::GpuDataManager::GetInstance()->RemoveObserver(this);
173 static void NotifyVideoMemoryUsageStats(
174 const content::GPUVideoMemoryUsageStats
& video_memory_usage_stats
) {
175 TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats(
176 video_memory_usage_stats
);
179 virtual void OnVideoMemoryUsageStatsUpdate(
180 const content::GPUVideoMemoryUsageStats
& video_memory_usage_stats
)
182 if (BrowserThread::CurrentlyOn(BrowserThread::UI
)) {
183 NotifyVideoMemoryUsageStats(video_memory_usage_stats
);
185 BrowserThread::PostTask(
186 BrowserThread::UI
, FROM_HERE
, base::Bind(
187 &TaskManagerModelGpuDataManagerObserver::
188 NotifyVideoMemoryUsageStats
,
189 video_memory_usage_stats
));
194 TaskManagerModel::PerResourceValues::PerResourceValues()
195 : is_nacl_debug_stub_port_valid(false),
196 nacl_debug_stub_port(0),
197 is_title_valid(false),
198 is_profile_name_valid(false),
200 is_process_id_valid(false),
202 is_goats_teleported_valid(false),
204 is_webcore_stats_valid(false),
207 is_sqlite_memory_bytes_valid(false),
208 sqlite_memory_bytes(0),
209 is_v8_memory_valid(false),
210 v8_memory_allocated(0),
213 TaskManagerModel::PerResourceValues::~PerResourceValues() {}
215 TaskManagerModel::PerProcessValues::PerProcessValues()
216 : is_cpu_usage_valid(false),
218 is_idle_wakeups_valid(false),
220 is_private_and_shared_valid(false),
223 is_physical_memory_valid(false),
225 is_video_memory_valid(false),
227 video_memory_has_duplicates(false),
228 is_gdi_handles_valid(false),
231 is_user_handles_valid(0),
233 user_handles_peak(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 goat_salt_(base::RandUint64()),
249 new task_manager::BrowserProcessResourceProvider(task_manager
));
251 new task_manager::BackgroundContentsResourceProvider(task_manager
));
253 new task_manager::TabContentsResourceProvider(task_manager
));
254 AddResourceProvider(new task_manager::PanelResourceProvider(task_manager
));
256 new task_manager::ChildProcessResourceProvider(task_manager
));
258 new task_manager::ExtensionProcessResourceProvider(task_manager
));
259 AddResourceProvider(new task_manager::GuestResourceProvider(task_manager
));
261 #if !defined(OS_CHROMEOS) && defined(ENABLE_NOTIFICATIONS)
262 ResourceProvider
* provider
=
263 task_manager::NotificationResourceProvider::Create(task_manager
);
265 AddResourceProvider(provider
);
268 AddResourceProvider(new task_manager::WorkerResourceProvider(task_manager
));
271 void TaskManagerModel::AddObserver(TaskManagerModelObserver
* observer
) {
272 observer_list_
.AddObserver(observer
);
275 void TaskManagerModel::RemoveObserver(TaskManagerModelObserver
* observer
) {
276 observer_list_
.RemoveObserver(observer
);
279 int TaskManagerModel::ResourceCount() const {
280 return resources_
.size();
283 int TaskManagerModel::GroupCount() const {
284 return group_map_
.size();
287 int TaskManagerModel::GetNaClDebugStubPort(int index
) const {
288 PerResourceValues
& values(GetPerResourceValues(index
));
289 if (!values
.is_nacl_debug_stub_port_valid
) {
290 values
.is_nacl_debug_stub_port_valid
= true;
291 values
.nacl_debug_stub_port
= GetResource(index
)->GetNaClDebugStubPort();
293 return values
.nacl_debug_stub_port
;
296 int64
TaskManagerModel::GetNetworkUsage(int index
) const {
297 return GetNetworkUsage(GetResource(index
));
300 double TaskManagerModel::GetCPUUsage(int index
) const {
301 return GetCPUUsage(GetResource(index
));
304 int TaskManagerModel::GetIdleWakeupsPerSecond(int index
) const {
305 return GetIdleWakeupsPerSecond(GetResource(index
));
308 base::ProcessId
TaskManagerModel::GetProcessId(int index
) const {
309 PerResourceValues
& values(GetPerResourceValues(index
));
310 if (!values
.is_process_id_valid
) {
311 values
.is_process_id_valid
= true;
312 values
.process_id
= base::GetProcId(GetResource(index
)->GetProcess());
314 return values
.process_id
;
317 base::ProcessHandle
TaskManagerModel::GetProcess(int index
) const {
318 return GetResource(index
)->GetProcess();
321 int TaskManagerModel::GetResourceUniqueId(int index
) const {
322 return GetResource(index
)->get_unique_id();
325 int TaskManagerModel::GetResourceIndexByUniqueId(const int unique_id
) const {
326 for (int resource_index
= 0; resource_index
< ResourceCount();
328 if (GetResourceUniqueId(resource_index
) == unique_id
)
329 return resource_index
;
334 base::string16
TaskManagerModel::GetResourceById(int index
, int col_id
) const {
335 if (IsSharedByGroup(col_id
) && !IsResourceFirstInGroup(index
))
336 return base::string16();
339 case IDS_TASK_MANAGER_TASK_COLUMN
:
340 return GetResourceTitle(index
);
342 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN
:
343 return GetResourceProfileName(index
);
345 case IDS_TASK_MANAGER_NET_COLUMN
:
346 return GetResourceNetworkUsage(index
);
348 case IDS_TASK_MANAGER_CPU_COLUMN
:
349 return GetResourceCPUUsage(index
);
351 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
352 return GetResourcePrivateMemory(index
);
354 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
355 return GetResourceSharedMemory(index
);
357 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
358 return GetResourcePhysicalMemory(index
);
360 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
361 return GetResourceProcessId(index
);
363 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
:
364 return GetResourceGDIHandles(index
);
366 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN
:
367 return GetResourceUSERHandles(index
);
369 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN
:
370 return GetResourceIdleWakeupsPerSecond(index
);
372 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN
:
373 return GetResourceGoatsTeleported(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_FPS_COLUMN
:
385 return GetResourceFPS(index
);
387 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
:
388 return GetResourceVideoMemory(index
);
390 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
391 return GetResourceSqliteMemoryUsed(index
);
393 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
394 return GetResourceV8MemoryAllocatedSize(index
);
396 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
397 return GetResourceNaClDebugStubPort(index
);
401 return base::string16();
405 const base::string16
& TaskManagerModel::GetResourceTitle(int index
) const {
406 PerResourceValues
& values
= GetPerResourceValues(index
);
407 if (!values
.is_title_valid
) {
408 values
.is_title_valid
= true;
409 values
.title
= GetResource(index
)->GetTitle();
414 const base::string16
& TaskManagerModel::GetResourceProfileName(
416 PerResourceValues
& values(GetPerResourceValues(index
));
417 if (!values
.is_profile_name_valid
) {
418 values
.is_profile_name_valid
= true;
419 values
.profile_name
= GetResource(index
)->GetProfileName();
421 return values
.profile_name
;
424 base::string16
TaskManagerModel::GetResourceNaClDebugStubPort(int index
) const {
425 int port
= GetNaClDebugStubPort(index
);
427 return base::ASCIIToUTF16("N/A");
429 return base::IntToString16(port
);
433 base::string16
TaskManagerModel::GetResourceNetworkUsage(int index
) const {
434 int64 net_usage
= GetNetworkUsage(index
);
436 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
438 return base::ASCIIToUTF16("0");
439 base::string16 net_byte
= ui::FormatSpeed(net_usage
);
440 // Force number string to have LTR directionality.
441 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte
);
444 base::string16
TaskManagerModel::GetResourceCPUUsage(int index
) const {
445 return base::UTF8ToUTF16(base::StringPrintf(
446 #if defined(OS_MACOSX)
447 // Activity Monitor shows %cpu with one decimal digit -- be
448 // consistent with that.
453 GetCPUUsage(GetResource(index
))));
456 base::string16
TaskManagerModel::GetResourcePrivateMemory(int index
) const {
458 if (!GetPrivateMemory(index
, &private_mem
))
459 return base::ASCIIToUTF16("N/A");
460 return GetMemCellText(private_mem
);
463 base::string16
TaskManagerModel::GetResourceSharedMemory(int index
) const {
465 if (!GetSharedMemory(index
, &shared_mem
))
466 return base::ASCIIToUTF16("N/A");
467 return GetMemCellText(shared_mem
);
470 base::string16
TaskManagerModel::GetResourcePhysicalMemory(int index
) const {
472 GetPhysicalMemory(index
, &phys_mem
);
473 return GetMemCellText(phys_mem
);
476 base::string16
TaskManagerModel::GetResourceProcessId(int index
) const {
477 return base::IntToString16(GetProcessId(index
));
480 base::string16
TaskManagerModel::GetResourceGDIHandles(int index
) const {
481 size_t current
, peak
;
482 GetGDIHandles(index
, ¤t
, &peak
);
483 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT
,
484 base::IntToString16(current
), base::IntToString16(peak
));
487 base::string16
TaskManagerModel::GetResourceUSERHandles(int index
) const {
488 size_t current
, peak
;
489 GetUSERHandles(index
, ¤t
, &peak
);
490 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT
,
491 base::IntToString16(current
), base::IntToString16(peak
));
494 base::string16
TaskManagerModel::GetResourceWebCoreImageCacheSize(
496 if (!CacheWebCoreStats(index
))
497 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
498 return FormatStatsSize(GetPerResourceValues(index
).webcore_stats
.images
);
501 base::string16
TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
503 if (!CacheWebCoreStats(index
))
504 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
505 return FormatStatsSize(GetPerResourceValues(index
).webcore_stats
.scripts
);
508 base::string16
TaskManagerModel::GetResourceWebCoreCSSCacheSize(
510 if (!CacheWebCoreStats(index
))
511 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
512 return FormatStatsSize(
513 GetPerResourceValues(index
).webcore_stats
.cssStyleSheets
);
516 base::string16
TaskManagerModel::GetResourceVideoMemory(int index
) const {
519 if (!GetVideoMemory(index
, &video_memory
, &has_duplicates
) || !video_memory
)
520 return base::ASCIIToUTF16("N/A");
521 if (has_duplicates
) {
522 return GetMemCellText(video_memory
) + base::ASCIIToUTF16("*");
524 return GetMemCellText(video_memory
);
527 base::string16
TaskManagerModel::GetResourceFPS(
530 if (!GetFPS(index
, &fps
))
531 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
532 return base::UTF8ToUTF16(base::StringPrintf("%.0f", fps
));
535 base::string16
TaskManagerModel::GetResourceSqliteMemoryUsed(int index
) const {
537 if (!GetSqliteMemoryUsedBytes(index
, &bytes
))
538 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
539 return GetMemCellText(bytes
);
542 base::string16
TaskManagerModel::GetResourceIdleWakeupsPerSecond(int index
)
544 return base::FormatNumber(GetIdleWakeupsPerSecond(GetResource(index
)));
547 base::string16
TaskManagerModel::GetResourceGoatsTeleported(int index
) const {
548 CHECK_LT(index
, ResourceCount());
549 return base::FormatNumber(GetGoatsTeleported(index
));
552 base::string16
TaskManagerModel::GetResourceV8MemoryAllocatedSize(
554 size_t memory_allocated
= 0, memory_used
= 0;
555 if (!GetV8MemoryUsed(index
, &memory_used
) ||
556 !GetV8Memory(index
, &memory_allocated
))
557 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT
);
558 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT
,
559 ui::FormatBytesWithUnits(memory_allocated
,
560 ui::DATA_UNITS_KIBIBYTE
,
562 ui::FormatBytesWithUnits(memory_used
,
563 ui::DATA_UNITS_KIBIBYTE
,
567 bool TaskManagerModel::GetPrivateMemory(int index
, size_t* result
) const {
569 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
570 if (!CachePrivateAndSharedMemory(handle
))
572 *result
= per_process_cache_
[handle
].private_bytes
;
576 bool TaskManagerModel::GetSharedMemory(int index
, size_t* result
) const {
578 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
579 if (!CachePrivateAndSharedMemory(handle
))
581 *result
= per_process_cache_
[handle
].shared_bytes
;
585 bool TaskManagerModel::GetPhysicalMemory(int index
, size_t* result
) const {
588 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
589 PerProcessValues
& values(per_process_cache_
[handle
]);
591 if (!values
.is_physical_memory_valid
) {
592 base::WorkingSetKBytes ws_usage
;
593 MetricsMap::const_iterator iter
= metrics_map_
.find(handle
);
594 if (iter
== metrics_map_
.end() ||
595 !iter
->second
->GetWorkingSetKBytes(&ws_usage
))
598 values
.is_physical_memory_valid
= true;
599 #if defined(OS_LINUX)
600 // On Linux private memory is also resident. Just use it.
601 values
.physical_memory
= ws_usage
.priv
* 1024;
603 // Memory = working_set.private + working_set.shareable.
604 // We exclude the shared memory.
605 values
.physical_memory
= iter
->second
->GetWorkingSetSize();
606 values
.physical_memory
-= ws_usage
.shared
* 1024;
609 *result
= values
.physical_memory
;
613 void TaskManagerModel::GetGDIHandles(int index
,
615 size_t* peak
) const {
619 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
620 PerProcessValues
& values(per_process_cache_
[handle
]);
622 if (!values
.is_gdi_handles_valid
) {
623 GetWinGDIHandles(GetResource(index
)->GetProcess(),
625 &values
.gdi_handles_peak
);
626 values
.is_gdi_handles_valid
= true;
628 *current
= values
.gdi_handles
;
629 *peak
= values
.gdi_handles_peak
;
633 void TaskManagerModel::GetUSERHandles(int index
,
635 size_t* peak
) const {
639 base::ProcessHandle handle
= GetResource(index
)->GetProcess();
640 PerProcessValues
& values(per_process_cache_
[handle
]);
642 if (!values
.is_user_handles_valid
) {
643 GetWinUSERHandles(GetResource(index
)->GetProcess(),
644 &values
.user_handles
,
645 &values
.user_handles_peak
);
646 values
.is_user_handles_valid
= true;
648 *current
= values
.user_handles
;
649 *peak
= values
.user_handles_peak
;
653 bool TaskManagerModel::GetWebCoreCacheStats(
655 blink::WebCache::ResourceTypeStats
* result
) const {
656 if (!CacheWebCoreStats(index
))
658 *result
= GetPerResourceValues(index
).webcore_stats
;
662 bool TaskManagerModel::GetVideoMemory(int index
,
663 size_t* video_memory
,
664 bool* has_duplicates
) const {
666 *has_duplicates
= false;
668 base::ProcessId pid
= GetProcessId(index
);
669 PerProcessValues
& values(
670 per_process_cache_
[GetResource(index
)->GetProcess()]);
671 if (!values
.is_video_memory_valid
) {
672 content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i
=
673 video_memory_usage_stats_
.process_map
.find(pid
);
674 if (i
== video_memory_usage_stats_
.process_map
.end())
676 values
.is_video_memory_valid
= true;
677 values
.video_memory
= i
->second
.video_memory
;
678 values
.video_memory_has_duplicates
= i
->second
.has_duplicates
;
680 *video_memory
= values
.video_memory
;
681 *has_duplicates
= values
.video_memory_has_duplicates
;
685 bool TaskManagerModel::GetFPS(int index
, float* result
) const {
687 PerResourceValues
& values(GetPerResourceValues(index
));
688 if (!values
.is_fps_valid
) {
689 if (!GetResource(index
)->ReportsFPS())
691 values
.is_fps_valid
= true;
692 values
.fps
= GetResource(index
)->GetFPS();
694 *result
= values
.fps
;
698 bool TaskManagerModel::GetSqliteMemoryUsedBytes(
700 size_t* result
) const {
702 PerResourceValues
& values(GetPerResourceValues(index
));
703 if (!values
.is_sqlite_memory_bytes_valid
) {
704 if (!GetResource(index
)->ReportsSqliteMemoryUsed())
706 values
.is_sqlite_memory_bytes_valid
= true;
707 values
.sqlite_memory_bytes
= GetResource(index
)->SqliteMemoryUsedBytes();
709 *result
= values
.sqlite_memory_bytes
;
713 bool TaskManagerModel::GetV8Memory(int index
, size_t* result
) const {
715 if (!CacheV8Memory(index
))
717 *result
= GetPerResourceValues(index
).v8_memory_allocated
;
721 bool TaskManagerModel::GetV8MemoryUsed(int index
, size_t* result
) const {
723 if (!CacheV8Memory(index
))
725 *result
= GetPerResourceValues(index
).v8_memory_used
;
729 bool TaskManagerModel::CanActivate(int index
) const {
730 CHECK_LT(index
, ResourceCount());
731 return GetResourceWebContents(index
) != NULL
;
734 bool TaskManagerModel::CanInspect(int index
) const {
735 return GetResource(index
)->CanInspect();
738 void TaskManagerModel::Inspect(int index
) const {
739 CHECK_LT(index
, ResourceCount());
740 GetResource(index
)->Inspect();
743 int TaskManagerModel::GetGoatsTeleported(int index
) const {
744 PerResourceValues
& values(GetPerResourceValues(index
));
745 if (!values
.is_goats_teleported_valid
) {
746 values
.is_goats_teleported_valid
= true;
747 values
.goats_teleported
= goat_salt_
* (index
+ 1);
748 values
.goats_teleported
= (values
.goats_teleported
>> 16) & 255;
750 return values
.goats_teleported
;
753 bool TaskManagerModel::IsResourceFirstInGroup(int index
) const {
754 Resource
* resource
= GetResource(index
);
755 GroupMap::const_iterator iter
= group_map_
.find(resource
->GetProcess());
756 DCHECK(iter
!= group_map_
.end());
757 const ResourceList
* group
= iter
->second
;
758 return ((*group
)[0] == resource
);
761 bool TaskManagerModel::IsResourceLastInGroup(int index
) const {
762 Resource
* resource
= GetResource(index
);
763 GroupMap::const_iterator iter
= group_map_
.find(resource
->GetProcess());
764 DCHECK(iter
!= group_map_
.end());
765 const ResourceList
* group
= iter
->second
;
766 return (group
->back() == resource
);
769 bool TaskManagerModel::IsBackgroundResource(int index
) const {
770 return GetResource(index
)->IsBackground();
773 gfx::ImageSkia
TaskManagerModel::GetResourceIcon(int index
) const {
774 gfx::ImageSkia icon
= GetResource(index
)->GetIcon();
778 static gfx::ImageSkia
* default_icon
= ResourceBundle::GetSharedInstance().
779 GetImageSkiaNamed(IDR_DEFAULT_FAVICON
);
780 return *default_icon
;
783 TaskManagerModel::GroupRange
784 TaskManagerModel::GetGroupRangeForResource(int index
) const {
785 Resource
* resource
= GetResource(index
);
786 GroupMap::const_iterator group_iter
=
787 group_map_
.find(resource
->GetProcess());
788 DCHECK(group_iter
!= group_map_
.end());
789 ResourceList
* group
= group_iter
->second
;
791 if (group
->size() == 1) {
792 return std::make_pair(index
, 1);
794 for (int i
= index
; i
>= 0; --i
) {
795 if (GetResource(i
) == (*group
)[0])
796 return std::make_pair(i
, group
->size());
799 return std::make_pair(-1, -1);
803 int TaskManagerModel::GetGroupIndexForResource(int index
) const {
804 int group_index
= -1;
805 for (int i
= 0; i
<= index
; ++i
) {
806 if (IsResourceFirstInGroup(i
))
810 DCHECK_NE(group_index
, -1);
814 int TaskManagerModel::GetResourceIndexForGroup(int group_index
,
815 int index_in_group
) const {
816 int group_count
= -1;
817 int count_in_group
= -1;
818 for (int i
= 0; i
< ResourceCount(); ++i
) {
819 if (IsResourceFirstInGroup(i
))
822 if (group_count
== group_index
) {
824 if (count_in_group
== index_in_group
)
826 } else if (group_count
> group_index
) {
835 int TaskManagerModel::CompareValues(int row1
, int row2
, int col_id
) const {
836 CHECK(row1
< ResourceCount() && row2
< ResourceCount());
838 case IDS_TASK_MANAGER_TASK_COLUMN
: {
839 static icu::Collator
* collator
= NULL
;
841 UErrorCode create_status
= U_ZERO_ERROR
;
842 collator
= icu::Collator::createInstance(create_status
);
843 if (!U_SUCCESS(create_status
)) {
848 const base::string16
& title1
= GetResourceTitle(row1
);
849 const base::string16
& title2
= GetResourceTitle(row2
);
850 UErrorCode compare_status
= U_ZERO_ERROR
;
851 UCollationResult compare_result
= collator
->compare(
852 static_cast<const UChar
*>(title1
.c_str()),
853 static_cast<int>(title1
.length()),
854 static_cast<const UChar
*>(title2
.c_str()),
855 static_cast<int>(title2
.length()),
857 DCHECK(U_SUCCESS(compare_status
));
858 return compare_result
;
861 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN
: {
862 const base::string16
& profile1
= GetResourceProfileName(row1
);
863 const base::string16
& profile2
= GetResourceProfileName(row2
);
864 return profile1
.compare(0, profile1
.length(), profile2
, 0,
868 case IDS_TASK_MANAGER_NET_COLUMN
:
869 return ValueCompare(GetNetworkUsage(GetResource(row1
)),
870 GetNetworkUsage(GetResource(row2
)));
872 case IDS_TASK_MANAGER_CPU_COLUMN
:
873 return ValueCompare(GetCPUUsage(GetResource(row1
)),
874 GetCPUUsage(GetResource(row2
)));
876 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN
:
877 return ValueCompareMember(
878 this, &TaskManagerModel::GetPrivateMemory
, row1
, row2
);
880 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN
:
881 return ValueCompareMember(
882 this, &TaskManagerModel::GetSharedMemory
, row1
, row2
);
884 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN
:
885 return ValueCompareMember(
886 this, &TaskManagerModel::GetPhysicalMemory
, row1
, row2
);
888 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN
:
889 return ValueCompare(GetNaClDebugStubPort(row1
),
890 GetNaClDebugStubPort(row2
));
892 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN
:
893 return ValueCompare(GetProcessId(row1
), GetProcessId(row2
));
895 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN
: {
896 size_t current1
, peak1
;
897 size_t current2
, peak2
;
898 GetGDIHandles(row1
, ¤t1
, &peak1
);
899 GetGDIHandles(row2
, ¤t2
, &peak2
);
900 return ValueCompare(current1
, current2
);
903 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN
: {
904 size_t current1
, peak1
;
905 size_t current2
, peak2
;
906 GetUSERHandles(row1
, ¤t1
, &peak1
);
907 GetUSERHandles(row2
, ¤t2
, &peak2
);
908 return ValueCompare(current1
, current2
);
911 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
912 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
913 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
: {
914 bool row1_stats_valid
= CacheWebCoreStats(row1
);
915 bool row2_stats_valid
= CacheWebCoreStats(row2
);
916 if (row1_stats_valid
&& row2_stats_valid
) {
917 const blink::WebCache::ResourceTypeStats
& stats1(
918 GetPerResourceValues(row1
).webcore_stats
);
919 const blink::WebCache::ResourceTypeStats
& stats2(
920 GetPerResourceValues(row2
).webcore_stats
);
922 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN
:
923 return ValueCompare(stats1
.images
.size
, stats2
.images
.size
);
924 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN
:
925 return ValueCompare(stats1
.scripts
.size
, stats2
.scripts
.size
);
926 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN
:
927 return ValueCompare(stats1
.cssStyleSheets
.size
,
928 stats2
.cssStyleSheets
.size
);
934 return OrderUnavailableValue(row1_stats_valid
, row2_stats_valid
);
937 case IDS_TASK_MANAGER_FPS_COLUMN
:
938 return ValueCompareMember(
939 this, &TaskManagerModel::GetFPS
, row1
, row2
);
941 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN
: {
945 bool value1_valid
= GetVideoMemory(row1
, &value1
, &has_duplicates
);
946 bool value2_valid
= GetVideoMemory(row2
, &value2
, &has_duplicates
);
947 return value1_valid
&& value2_valid
? ValueCompare(value1
, value2
) :
948 OrderUnavailableValue(value1_valid
, value2_valid
);
951 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN
:
952 return ValueCompare(GetGoatsTeleported(row1
), GetGoatsTeleported(row2
));
954 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN
:
955 return ValueCompareMember(
956 this, &TaskManagerModel::GetV8Memory
, row1
, row2
);
958 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN
:
959 return ValueCompareMember(
960 this, &TaskManagerModel::GetSqliteMemoryUsedBytes
, row1
, row2
);
969 int TaskManagerModel::GetUniqueChildProcessId(int index
) const {
970 return GetResource(index
)->GetUniqueChildProcessId();
973 Resource::Type
TaskManagerModel::GetResourceType(int index
) const {
974 return GetResource(index
)->GetType();
977 WebContents
* TaskManagerModel::GetResourceWebContents(int index
) const {
978 return GetResource(index
)->GetWebContents();
981 const extensions::Extension
* TaskManagerModel::GetResourceExtension(
983 return GetResource(index
)->GetExtension();
986 void TaskManagerModel::AddResource(Resource
* resource
) {
987 resource
->unique_id_
= ++last_unique_id_
;
989 base::ProcessHandle process
= resource
->GetProcess();
991 ResourceList
* group_entries
= NULL
;
992 GroupMap::const_iterator group_iter
= group_map_
.find(process
);
993 int new_entry_index
= 0;
994 if (group_iter
== group_map_
.end()) {
995 group_entries
= new ResourceList();
996 group_map_
[process
] = group_entries
;
997 group_entries
->push_back(resource
);
999 // Not part of a group, just put at the end of the list.
1000 resources_
.push_back(resource
);
1001 new_entry_index
= static_cast<int>(resources_
.size() - 1);
1003 group_entries
= group_iter
->second
;
1004 group_entries
->push_back(resource
);
1006 // Insert the new entry right after the last entry of its group.
1007 ResourceList::iterator iter
=
1008 std::find(resources_
.begin(),
1010 (*group_entries
)[group_entries
->size() - 2]);
1011 DCHECK(iter
!= resources_
.end());
1012 new_entry_index
= static_cast<int>(iter
- resources_
.begin()) + 1;
1013 resources_
.insert(++iter
, resource
);
1016 // Create the ProcessMetrics for this process if needed (not in map).
1017 if (metrics_map_
.find(process
) == metrics_map_
.end()) {
1018 base::ProcessMetrics
* pm
=
1019 #if !defined(OS_MACOSX)
1020 base::ProcessMetrics::CreateProcessMetrics(process
);
1022 base::ProcessMetrics::CreateProcessMetrics(
1023 process
, content::BrowserChildProcessHost::GetPortProvider());
1026 metrics_map_
[process
] = pm
;
1029 // Notify the table that the contents have changed for it to redraw.
1030 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1031 OnItemsAdded(new_entry_index
, 1));
1034 void TaskManagerModel::RemoveResource(Resource
* resource
) {
1035 base::ProcessHandle process
= resource
->GetProcess();
1037 // Find the associated group.
1038 GroupMap::iterator group_iter
= group_map_
.find(process
);
1039 DCHECK(group_iter
!= group_map_
.end());
1040 ResourceList
* group_entries
= group_iter
->second
;
1042 // Remove the entry from the group map.
1043 ResourceList::iterator iter
= std::find(group_entries
->begin(),
1044 group_entries
->end(),
1046 DCHECK(iter
!= group_entries
->end());
1047 group_entries
->erase(iter
);
1049 // If there are no more entries for that process, do the clean-up.
1050 if (group_entries
->empty()) {
1051 delete group_entries
;
1052 group_map_
.erase(process
);
1054 // Nobody is using this process, we don't need the process metrics anymore.
1055 MetricsMap::iterator pm_iter
= metrics_map_
.find(process
);
1056 DCHECK(pm_iter
!= metrics_map_
.end());
1057 if (pm_iter
!= metrics_map_
.end()) {
1058 delete pm_iter
->second
;
1059 metrics_map_
.erase(process
);
1063 // Prepare to remove the entry from the model list.
1064 iter
= std::find(resources_
.begin(), resources_
.end(), resource
);
1065 DCHECK(iter
!= resources_
.end());
1066 int index
= static_cast<int>(iter
- resources_
.begin());
1068 // Notify the observers that the contents will change.
1069 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1070 OnItemsToBeRemoved(index
, 1));
1072 // Now actually remove the entry from the model list.
1073 resources_
.erase(iter
);
1075 // Remove the entry from the network maps.
1076 ResourceValueMap::iterator net_iter
=
1077 current_byte_count_map_
.find(resource
);
1078 if (net_iter
!= current_byte_count_map_
.end())
1079 current_byte_count_map_
.erase(net_iter
);
1081 // Notify the table that the contents have changed.
1082 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1083 OnItemsRemoved(index
, 1));
1086 void TaskManagerModel::StartUpdating() {
1087 // Multiple StartUpdating requests may come in, and we only need to take
1088 // action the first time.
1090 if (update_requests_
> 1)
1092 DCHECK_EQ(1, update_requests_
);
1093 DCHECK_NE(TASK_PENDING
, update_state_
);
1095 // If update_state_ is STOPPING, it means a task is still pending. Setting
1096 // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()).
1097 if (update_state_
== IDLE
) {
1098 base::MessageLoop::current()->PostTask(
1100 base::Bind(&TaskManagerModel::RefreshCallback
, this));
1102 update_state_
= TASK_PENDING
;
1104 // Notify resource providers that we are updating.
1107 if (!resources_
.empty()) {
1108 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1109 OnReadyPeriodicalUpdate());
1113 void TaskManagerModel::StopUpdating() {
1114 // Don't actually stop updating until we have heard as many calls as those
1115 // to StartUpdating.
1117 if (update_requests_
> 0)
1119 // Make sure that update_requests_ cannot go negative.
1120 CHECK_EQ(0, update_requests_
);
1121 DCHECK_EQ(TASK_PENDING
, update_state_
);
1122 update_state_
= STOPPING
;
1124 // Notify resource providers that we are done updating.
1128 void TaskManagerModel::StartListening() {
1129 // Multiple StartListening requests may come in and we only need to take
1130 // action the first time.
1132 if (listen_requests_
> 1)
1134 DCHECK_EQ(1, listen_requests_
);
1136 // Notify resource providers that we should start listening to events.
1137 for (ResourceProviderList::iterator iter
= providers_
.begin();
1138 iter
!= providers_
.end(); ++iter
) {
1139 (*iter
)->StartUpdating();
1143 void TaskManagerModel::StopListening() {
1144 // Don't actually stop listening until we have heard as many calls as those
1145 // to StartListening.
1147 if (listen_requests_
> 0)
1150 DCHECK_EQ(0, listen_requests_
);
1152 // Notify resource providers that we are done listening.
1153 for (ResourceProviderList::const_iterator iter
= providers_
.begin();
1154 iter
!= providers_
.end(); ++iter
) {
1155 (*iter
)->StopUpdating();
1158 // Must clear the resources before the next attempt to start listening.
1162 void TaskManagerModel::Clear() {
1163 int size
= ResourceCount();
1167 // Clear the groups.
1168 STLDeleteValues(&group_map_
);
1170 // Clear the process related info.
1171 STLDeleteValues(&metrics_map_
);
1173 // Clear the network maps.
1174 current_byte_count_map_
.clear();
1176 per_resource_cache_
.clear();
1177 per_process_cache_
.clear();
1179 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1180 OnItemsRemoved(0, size
));
1182 last_unique_id_
= 0;
1185 void TaskManagerModel::ModelChanged() {
1186 // Notify the table that the contents have changed for it to redraw.
1187 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
, OnModelChanged());
1190 void TaskManagerModel::Refresh() {
1191 goat_salt_
= base::RandUint64();
1193 per_resource_cache_
.clear();
1194 per_process_cache_
.clear();
1196 // Compute the CPU usage values.
1197 // Note that we compute the CPU usage for all resources (instead of doing it
1198 // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last
1199 // time it was called, and not calling it everytime would skew the value the
1200 // next time it is retrieved (as it would be for more than 1 cycle).
1201 // The same is true for idle wakeups.
1202 for (ResourceList::iterator iter
= resources_
.begin();
1203 iter
!= resources_
.end(); ++iter
) {
1204 base::ProcessHandle process
= (*iter
)->GetProcess();
1205 PerProcessValues
& values(per_process_cache_
[process
]);
1206 if (values
.is_cpu_usage_valid
&& values
.is_idle_wakeups_valid
)
1208 MetricsMap::iterator metrics_iter
= metrics_map_
.find(process
);
1209 DCHECK(metrics_iter
!= metrics_map_
.end());
1210 if (!values
.is_cpu_usage_valid
) {
1211 values
.is_cpu_usage_valid
= true;
1212 values
.cpu_usage
= metrics_iter
->second
->GetCPUUsage();
1214 #if defined(OS_MACOSX)
1215 // TODO: Implement GetIdleWakeupsPerSecond() on other platforms,
1217 if (!values
.is_idle_wakeups_valid
) {
1218 values
.is_idle_wakeups_valid
= true;
1219 values
.idle_wakeups
= metrics_iter
->second
->GetIdleWakeupsPerSecond();
1221 #endif // defined(OS_MACOSX)
1224 // Send a request to refresh GPU memory consumption values
1225 RefreshVideoMemoryUsageStats();
1227 // Compute the new network usage values.
1228 base::TimeDelta update_time
=
1229 base::TimeDelta::FromMilliseconds(kUpdateTimeMs
);
1230 for (ResourceValueMap::iterator iter
= current_byte_count_map_
.begin();
1231 iter
!= current_byte_count_map_
.end(); ++iter
) {
1232 PerResourceValues
* values
= &(per_resource_cache_
[iter
->first
]);
1233 if (update_time
> base::TimeDelta::FromSeconds(1))
1234 values
->network_usage
= iter
->second
/ update_time
.InSeconds();
1236 values
->network_usage
= iter
->second
* (1 / update_time
.InSeconds());
1238 // Then we reset the current byte count.
1242 // Let resources update themselves if they need to.
1243 for (ResourceList::iterator iter
= resources_
.begin();
1244 iter
!= resources_
.end(); ++iter
) {
1248 if (!resources_
.empty()) {
1249 FOR_EACH_OBSERVER(TaskManagerModelObserver
, observer_list_
,
1250 OnItemsChanged(0, ResourceCount()));
1254 void TaskManagerModel::NotifyResourceTypeStats(
1255 base::ProcessId renderer_id
,
1256 const blink::WebCache::ResourceTypeStats
& stats
) {
1257 for (ResourceList::iterator it
= resources_
.begin();
1258 it
!= resources_
.end(); ++it
) {
1259 if (base::GetProcId((*it
)->GetProcess()) == renderer_id
) {
1260 (*it
)->NotifyResourceTypeStats(stats
);
1265 void TaskManagerModel::NotifyFPS(base::ProcessId renderer_id
,
1268 for (ResourceList::iterator it
= resources_
.begin();
1269 it
!= resources_
.end(); ++it
) {
1270 if (base::GetProcId((*it
)->GetProcess()) == renderer_id
&&
1271 (*it
)->GetRoutingID() == routing_id
) {
1272 (*it
)->NotifyFPS(fps
);
1277 void TaskManagerModel::NotifyVideoMemoryUsageStats(
1278 const content::GPUVideoMemoryUsageStats
& video_memory_usage_stats
) {
1279 DCHECK(pending_video_memory_usage_stats_update_
);
1280 video_memory_usage_stats_
= video_memory_usage_stats
;
1281 pending_video_memory_usage_stats_update_
= false;
1284 void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id
,
1285 size_t v8_memory_allocated
,
1286 size_t v8_memory_used
) {
1287 for (ResourceList::iterator it
= resources_
.begin();
1288 it
!= resources_
.end(); ++it
) {
1289 if (base::GetProcId((*it
)->GetProcess()) == renderer_id
) {
1290 (*it
)->NotifyV8HeapStats(v8_memory_allocated
, v8_memory_used
);
1295 void TaskManagerModel::NotifyBytesRead(const net::URLRequest
& request
,
1297 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1299 // Only net::URLRequestJob instances created by the ResourceDispatcherHost
1300 // have an associated ResourceRequestInfo and a render frame associated.
1301 // All other jobs will have -1 returned for the render process child and
1302 // routing ids - the jobs may still match a resource based on their origin id,
1303 // otherwise BytesRead() will attribute the activity to the Browser resource.
1304 const ResourceRequestInfo
* info
= ResourceRequestInfo::ForRequest(&request
);
1305 int child_id
= -1, route_id
= -1;
1307 info
->GetAssociatedRenderFrame(&child_id
, &route_id
);
1309 // Get the origin PID of the request's originator. This will only be set for
1310 // plugins - for renderer or browser initiated requests it will be zero.
1313 origin_pid
= info
->GetOriginPID();
1315 if (bytes_read_buffer_
.empty()) {
1316 base::MessageLoop::current()->PostDelayedTask(
1318 base::Bind(&TaskManagerModel::NotifyMultipleBytesRead
, this),
1319 base::TimeDelta::FromSeconds(1));
1322 bytes_read_buffer_
.push_back(
1323 BytesReadParam(origin_pid
, child_id
, route_id
, byte_count
));
1326 // This is called on the UI thread.
1327 void TaskManagerModel::NotifyDataReady() {
1328 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1329 for (size_t i
= 0; i
< on_data_ready_callbacks_
.size(); ++i
) {
1330 if (!on_data_ready_callbacks_
[i
].is_null())
1331 on_data_ready_callbacks_
[i
].Run();
1334 on_data_ready_callbacks_
.clear();
1337 void TaskManagerModel::RegisterOnDataReadyCallback(
1338 const base::Closure
& callback
) {
1339 on_data_ready_callbacks_
.push_back(callback
);
1342 TaskManagerModel::~TaskManagerModel() {
1343 on_data_ready_callbacks_
.clear();
1346 void TaskManagerModel::RefreshCallback() {
1347 DCHECK_NE(IDLE
, update_state_
);
1349 if (update_state_
== STOPPING
) {
1350 // We have been asked to stop.
1351 update_state_
= IDLE
;
1357 // Schedule the next update.
1358 base::MessageLoop::current()->PostDelayedTask(
1360 base::Bind(&TaskManagerModel::RefreshCallback
, this),
1361 base::TimeDelta::FromMilliseconds(kUpdateTimeMs
));
1364 void TaskManagerModel::RefreshVideoMemoryUsageStats() {
1365 if (pending_video_memory_usage_stats_update_
)
1368 if (!video_memory_usage_stats_observer_
.get()) {
1369 video_memory_usage_stats_observer_
.reset(
1370 new TaskManagerModelGpuDataManagerObserver());
1372 pending_video_memory_usage_stats_update_
= true;
1373 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate();
1376 int64
TaskManagerModel::GetNetworkUsageForResource(Resource
* resource
) const {
1377 // Returns default of 0 if no network usage.
1378 return per_resource_cache_
[resource
].network_usage
;
1381 void TaskManagerModel::BytesRead(BytesReadParam param
) {
1382 if (update_state_
!= TASK_PENDING
|| listen_requests_
== 0) {
1383 // A notification sneaked in while we were stopping the updating, just
1388 // TODO(jcampan): this should be improved once we have a better way of
1389 // linking a network notification back to the object that initiated it.
1390 Resource
* resource
= NULL
;
1391 for (ResourceProviderList::iterator iter
= providers_
.begin();
1392 iter
!= providers_
.end(); ++iter
) {
1393 resource
= (*iter
)->GetResource(param
.origin_pid
,
1400 if (resource
== NULL
) {
1401 // We can't match a resource to the notification. That might mean the
1402 // tab that started a download was closed, or the request may have had
1403 // no originating resource associated with it in the first place.
1404 // We attribute orphaned/unaccounted activity to the Browser process.
1405 CHECK(param
.origin_pid
|| (param
.child_id
!= -1));
1406 param
.origin_pid
= 0;
1407 param
.child_id
= param
.route_id
= -1;
1412 // We do support network usage, mark the resource as such so it can report 0
1414 if (!resource
->SupportNetworkUsage())
1415 resource
->SetSupportNetworkUsage();
1417 ResourceValueMap::const_iterator iter_res
=
1418 current_byte_count_map_
.find(resource
);
1419 if (iter_res
== current_byte_count_map_
.end())
1420 current_byte_count_map_
[resource
] = param
.byte_count
;
1422 current_byte_count_map_
[resource
] = iter_res
->second
+ param
.byte_count
;
1425 void TaskManagerModel::MultipleBytesRead(
1426 const std::vector
<BytesReadParam
>* params
) {
1427 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
1428 for (std::vector
<BytesReadParam
>::const_iterator it
= params
->begin();
1429 it
!= params
->end(); ++it
) {
1434 void TaskManagerModel::NotifyMultipleBytesRead() {
1435 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO
));
1436 DCHECK(!bytes_read_buffer_
.empty());
1438 std::vector
<BytesReadParam
>* bytes_read_buffer
=
1439 new std::vector
<BytesReadParam
>;
1440 bytes_read_buffer_
.swap(*bytes_read_buffer
);
1441 BrowserThread::PostTask(
1442 BrowserThread::UI
, FROM_HERE
,
1443 base::Bind(&TaskManagerModel::MultipleBytesRead
, this,
1444 base::Owned(bytes_read_buffer
)));
1447 int64
TaskManagerModel::GetNetworkUsage(Resource
* resource
) const {
1448 int64 net_usage
= GetNetworkUsageForResource(resource
);
1449 if (net_usage
== 0 && !resource
->SupportNetworkUsage())
1454 double TaskManagerModel::GetCPUUsage(Resource
* resource
) const {
1455 const PerProcessValues
& values(per_process_cache_
[resource
->GetProcess()]);
1456 // Returns 0 if not valid, which is fine.
1457 return values
.cpu_usage
;
1460 int TaskManagerModel::GetIdleWakeupsPerSecond(Resource
* resource
) const {
1461 const PerProcessValues
& values(per_process_cache_
[resource
->GetProcess()]);
1462 // Returns 0 if not valid, which is fine.
1463 return values
.idle_wakeups
;
1466 base::string16
TaskManagerModel::GetMemCellText(int64 number
) const {
1467 #if !defined(OS_MACOSX)
1468 base::string16 str
= base::FormatNumber(number
/ 1024);
1470 // Adjust number string if necessary.
1471 base::i18n::AdjustStringForLocaleDirection(&str
);
1472 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT
, str
);
1474 // System expectation is to show "100 kB", "200 MB", etc.
1475 // TODO(thakis): Switch to metric units (as opposed to powers of two).
1476 return ui::FormatBytes(number
);
1480 bool TaskManagerModel::CachePrivateAndSharedMemory(
1481 base::ProcessHandle handle
) const {
1482 PerProcessValues
& values(per_process_cache_
[handle
]);
1483 if (values
.is_private_and_shared_valid
)
1486 MetricsMap::const_iterator iter
= metrics_map_
.find(handle
);
1487 if (iter
== metrics_map_
.end() ||
1488 !iter
->second
->GetMemoryBytes(&values
.private_bytes
,
1489 &values
.shared_bytes
)) {
1493 values
.is_private_and_shared_valid
= true;
1497 bool TaskManagerModel::CacheWebCoreStats(int index
) const {
1498 PerResourceValues
& values(GetPerResourceValues(index
));
1499 if (!values
.is_webcore_stats_valid
) {
1500 if (!GetResource(index
)->ReportsCacheStats())
1502 values
.is_webcore_stats_valid
= true;
1503 values
.webcore_stats
= GetResource(index
)->GetWebCoreCacheStats();
1508 bool TaskManagerModel::CacheV8Memory(int index
) const {
1509 PerResourceValues
& values(GetPerResourceValues(index
));
1510 if (!values
.is_v8_memory_valid
) {
1511 if (!GetResource(index
)->ReportsV8MemoryStats())
1513 values
.is_v8_memory_valid
= true;
1514 values
.v8_memory_allocated
= GetResource(index
)->GetV8MemoryAllocated();
1515 values
.v8_memory_used
= GetResource(index
)->GetV8MemoryUsed();
1520 void TaskManagerModel::AddResourceProvider(ResourceProvider
* provider
) {
1522 providers_
.push_back(provider
);
1525 TaskManagerModel::PerResourceValues
& TaskManagerModel::GetPerResourceValues(
1527 return per_resource_cache_
[GetResource(index
)];
1530 Resource
* TaskManagerModel::GetResource(int index
) const {
1532 CHECK_LT(index
, static_cast<int>(resources_
.size()));
1533 return resources_
[index
];
1536 ////////////////////////////////////////////////////////////////////////////////
1537 // TaskManager class
1538 ////////////////////////////////////////////////////////////////////////////////
1540 void TaskManager::RegisterPrefs(PrefRegistrySimple
* registry
) {
1541 registry
->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement
);
1544 bool TaskManager::IsBrowserProcess(int index
) const {
1545 // If some of the selection is out of bounds, ignore. This may happen when
1546 // killing a process that manages several pages.
1547 return index
< model_
->ResourceCount() &&
1548 model_
->GetProcess(index
) == base::GetCurrentProcessHandle();
1551 void TaskManager::KillProcess(int index
) {
1552 base::ProcessHandle process
= model_
->GetProcess(index
);
1554 if (process
!= base::GetCurrentProcessHandle())
1555 base::KillProcess(process
, content::RESULT_CODE_KILLED
, false);
1558 void TaskManager::ActivateProcess(int index
) {
1559 // GetResourceWebContents returns a pointer to the relevant web contents for
1560 // the resource. If the index doesn't correspond to any web contents
1561 // (i.e. refers to the Browser process or a plugin), GetWebContents will
1563 WebContents
* chosen_web_contents
= model_
->GetResourceWebContents(index
);
1564 if (chosen_web_contents
&& chosen_web_contents
->GetDelegate())
1565 chosen_web_contents
->GetDelegate()->ActivateContents(chosen_web_contents
);
1568 void TaskManager::AddResource(Resource
* resource
) {
1569 model_
->AddResource(resource
);
1572 void TaskManager::RemoveResource(Resource
* resource
) {
1573 model_
->RemoveResource(resource
);
1576 void TaskManager::OnWindowClosed() {
1577 model_
->StopUpdating();
1580 void TaskManager::ModelChanged() {
1581 model_
->ModelChanged();
1585 TaskManager
* TaskManager::GetInstance() {
1586 return Singleton
<TaskManager
>::get();
1589 void TaskManager::OpenAboutMemory(chrome::HostDesktopType desktop_type
) {
1590 chrome::NavigateParams
params(
1591 ProfileManager::GetLastUsedProfileAllowedByPolicy(),
1592 GURL(chrome::kChromeUIMemoryURL
),
1593 content::PAGE_TRANSITION_LINK
);
1594 params
.disposition
= NEW_FOREGROUND_TAB
;
1595 params
.host_desktop_type
= desktop_type
;
1596 chrome::Navigate(¶ms
);
1599 TaskManager::TaskManager()
1600 : model_(new TaskManagerModel(this)) {
1603 TaskManager::~TaskManager() {