NaCl: Update revision in DEPS, r12770 -> r12773
[chromium-blink-merge.git] / chrome / browser / task_manager / task_manager.cc
blob7969f36bad14627d3491ce42ef0f71e6db8ef24d
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"
7 #include "base/bind.h"
8 #include "base/i18n/number_formatting.h"
9 #include "base/i18n/rtl.h"
10 #include "base/prefs/pref_registry_simple.h"
11 #include "base/process/process_metrics.h"
12 #include "base/rand_util.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/task_manager/background_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"
50 #endif
52 #if defined(OS_MACOSX)
53 #include "content/public/browser/browser_child_process_host.h"
54 #endif
56 using content::BrowserThread;
57 using content::ResourceRequestInfo;
58 using content::WebContents;
59 using task_manager::Resource;
60 using task_manager::ResourceProvider;
62 class Profile;
64 namespace {
66 template <class T>
67 int ValueCompare(T value1, T value2) {
68 if (value1 < value2)
69 return -1;
70 if (value1 == value2)
71 return 0;
72 return 1;
75 // Used when one or both of the results to compare are unavailable.
76 int OrderUnavailableValue(bool v1, bool v2) {
77 if (!v1 && !v2)
78 return 0;
79 return v1 ? 1 : -1;
82 // Used by TaskManagerModel::CompareValues(). See it for details of return
83 // value.
84 template <class T>
85 int ValueCompareMember(const TaskManagerModel* model,
86 bool (TaskManagerModel::*f)(int, T*) const,
87 int row1,
88 int row2) {
89 T value1;
90 T value2;
91 bool value1_valid = (model->*f)(row1, &value1);
92 bool value2_valid = (model->*f)(row2, &value2);
93 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
94 OrderUnavailableValue(value1_valid, value2_valid);
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) {
105 switch (col_id) {
106 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
107 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
108 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
109 case IDS_TASK_MANAGER_CPU_COLUMN:
110 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
111 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
112 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
113 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
114 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
115 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
116 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
117 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
118 return true;
119 default:
120 return false;
124 #if defined(OS_WIN)
125 void GetWinGDIHandles(base::ProcessHandle process,
126 size_t* current,
127 size_t* peak) {
128 *current = 0;
129 *peak = 0;
130 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
131 HANDLE current_process = GetCurrentProcess();
132 HANDLE process_with_query_rights;
133 if (DuplicateHandle(current_process, process, current_process,
134 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
135 false, 0)) {
136 *current = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS);
137 *peak = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS_PEAK);
138 CloseHandle(process_with_query_rights);
142 void GetWinUSERHandles(base::ProcessHandle process,
143 size_t* current,
144 size_t* peak) {
145 *current = 0;
146 *peak = 0;
147 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
148 HANDLE current_process = GetCurrentProcess();
149 HANDLE process_with_query_rights;
150 if (DuplicateHandle(current_process, process, current_process,
151 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
152 false, 0)) {
153 *current = GetGuiResources(process_with_query_rights, GR_USEROBJECTS);
154 *peak = GetGuiResources(process_with_query_rights, GR_USEROBJECTS_PEAK);
155 CloseHandle(process_with_query_rights);
158 #endif
160 } // namespace
162 class TaskManagerModelGpuDataManagerObserver
163 : public content::GpuDataManagerObserver {
164 public:
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)
181 OVERRIDE {
182 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
183 NotifyVideoMemoryUsageStats(video_memory_usage_stats);
184 } else {
185 BrowserThread::PostTask(
186 BrowserThread::UI, FROM_HERE, base::Bind(
187 &TaskManagerModelGpuDataManagerObserver::
188 NotifyVideoMemoryUsageStats,
189 video_memory_usage_stats));
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),
199 network_usage(0),
200 is_process_id_valid(false),
201 process_id(0),
202 is_goats_teleported_valid(false),
203 goats_teleported(0),
204 is_webcore_stats_valid(false),
205 is_fps_valid(false),
206 fps(0),
207 is_sqlite_memory_bytes_valid(false),
208 sqlite_memory_bytes(0),
209 is_v8_memory_valid(false),
210 v8_memory_allocated(0),
211 v8_memory_used(0) {}
213 TaskManagerModel::PerResourceValues::~PerResourceValues() {}
215 TaskManagerModel::PerProcessValues::PerProcessValues()
216 : is_cpu_usage_valid(false),
217 cpu_usage(0),
218 is_idle_wakeups_valid(false),
219 idle_wakeups(0),
220 is_private_and_shared_valid(false),
221 private_bytes(0),
222 shared_bytes(0),
223 is_physical_memory_valid(false),
224 physical_memory(0),
225 is_video_memory_valid(false),
226 video_memory(0),
227 video_memory_has_duplicates(false),
228 is_gdi_handles_valid(false),
229 gdi_handles(0),
230 gdi_handles_peak(0),
231 is_user_handles_valid(0),
232 user_handles(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),
243 update_requests_(0),
244 listen_requests_(0),
245 update_state_(IDLE),
246 goat_salt_(base::RandUint64()),
247 last_unique_id_(0) {
248 AddResourceProvider(
249 new task_manager::BrowserProcessResourceProvider(task_manager));
250 AddResourceProvider(
251 new task_manager::BackgroundContentsResourceProvider(task_manager));
252 AddResourceProvider(
253 new task_manager::TabContentsResourceProvider(task_manager));
254 AddResourceProvider(new task_manager::PanelResourceProvider(task_manager));
255 AddResourceProvider(
256 new task_manager::ChildProcessResourceProvider(task_manager));
257 AddResourceProvider(
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);
264 if (provider)
265 AddResourceProvider(provider);
266 #endif
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();
327 ++resource_index) {
328 if (GetResourceUniqueId(resource_index) == unique_id)
329 return resource_index;
331 return -1;
334 base::string16 TaskManagerModel::GetResourceById(int index, int col_id) const {
335 if (IsSharedByGroup(col_id) && !IsResourceFirstInGroup(index))
336 return base::string16();
338 switch (col_id) {
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);
399 default:
400 NOTREACHED();
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();
411 return values.title;
414 const base::string16& TaskManagerModel::GetResourceProfileName(
415 int index) const {
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);
426 if (port == 0) {
427 return base::ASCIIToUTF16("N/A");
428 } else {
429 return base::IntToString16(port);
433 base::string16 TaskManagerModel::GetResourceNetworkUsage(int index) const {
434 int64 net_usage = GetNetworkUsage(index);
435 if (net_usage == -1)
436 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
437 if (net_usage == 0)
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.
449 "%.1f",
450 #else
451 "%.0f",
452 #endif
453 GetCPUUsage(GetResource(index))));
456 base::string16 TaskManagerModel::GetResourcePrivateMemory(int index) const {
457 size_t private_mem;
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 {
464 size_t shared_mem;
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 {
471 size_t phys_mem;
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, &current, &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, &current, &peak);
490 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
491 base::IntToString16(current), base::IntToString16(peak));
494 base::string16 TaskManagerModel::GetResourceWebCoreImageCacheSize(
495 int index) const {
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(
502 int index) const {
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(
509 int index) const {
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 {
517 size_t video_memory;
518 bool has_duplicates;
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(
528 int index) const {
529 float fps = 0;
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 {
536 size_t bytes = 0;
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)
543 const {
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(
553 int index) const {
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,
561 false),
562 ui::FormatBytesWithUnits(memory_used,
563 ui::DATA_UNITS_KIBIBYTE,
564 false));
567 bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const {
568 *result = 0;
569 base::ProcessHandle handle = GetResource(index)->GetProcess();
570 if (!CachePrivateAndSharedMemory(handle))
571 return false;
572 *result = per_process_cache_[handle].private_bytes;
573 return true;
576 bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const {
577 *result = 0;
578 base::ProcessHandle handle = GetResource(index)->GetProcess();
579 if (!CachePrivateAndSharedMemory(handle))
580 return false;
581 *result = per_process_cache_[handle].shared_bytes;
582 return true;
585 bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const {
586 *result = 0;
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))
596 return false;
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;
602 #else
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;
607 #endif
609 *result = values.physical_memory;
610 return true;
613 void TaskManagerModel::GetGDIHandles(int index,
614 size_t* current,
615 size_t* peak) const {
616 *current = 0;
617 *peak = 0;
618 #if defined(OS_WIN)
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(),
624 &values.gdi_handles,
625 &values.gdi_handles_peak);
626 values.is_gdi_handles_valid = true;
628 *current = values.gdi_handles;
629 *peak = values.gdi_handles_peak;
630 #endif
633 void TaskManagerModel::GetUSERHandles(int index,
634 size_t* current,
635 size_t* peak) const {
636 *current = 0;
637 *peak = 0;
638 #if defined(OS_WIN)
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;
650 #endif
653 bool TaskManagerModel::GetWebCoreCacheStats(
654 int index,
655 blink::WebCache::ResourceTypeStats* result) const {
656 if (!CacheWebCoreStats(index))
657 return false;
658 *result = GetPerResourceValues(index).webcore_stats;
659 return true;
662 bool TaskManagerModel::GetVideoMemory(int index,
663 size_t* video_memory,
664 bool* has_duplicates) const {
665 *video_memory = 0;
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())
675 return false;
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;
682 return true;
685 bool TaskManagerModel::GetFPS(int index, float* result) const {
686 *result = 0;
687 PerResourceValues& values(GetPerResourceValues(index));
688 if (!values.is_fps_valid) {
689 if (!GetResource(index)->ReportsFPS())
690 return false;
691 values.is_fps_valid = true;
692 values.fps = GetResource(index)->GetFPS();
694 *result = values.fps;
695 return true;
698 bool TaskManagerModel::GetSqliteMemoryUsedBytes(
699 int index,
700 size_t* result) const {
701 *result = 0;
702 PerResourceValues& values(GetPerResourceValues(index));
703 if (!values.is_sqlite_memory_bytes_valid) {
704 if (!GetResource(index)->ReportsSqliteMemoryUsed())
705 return false;
706 values.is_sqlite_memory_bytes_valid = true;
707 values.sqlite_memory_bytes = GetResource(index)->SqliteMemoryUsedBytes();
709 *result = values.sqlite_memory_bytes;
710 return true;
713 bool TaskManagerModel::GetV8Memory(int index, size_t* result) const {
714 *result = 0;
715 if (!CacheV8Memory(index))
716 return false;
717 *result = GetPerResourceValues(index).v8_memory_allocated;
718 return true;
721 bool TaskManagerModel::GetV8MemoryUsed(int index, size_t* result) const {
722 *result = 0;
723 if (!CacheV8Memory(index))
724 return false;
725 *result = GetPerResourceValues(index).v8_memory_used;
726 return true;
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();
775 if (!icon.isNull())
776 return icon;
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;
790 DCHECK(group);
791 if (group->size() == 1) {
792 return std::make_pair(index, 1);
793 } else {
794 for (int i = index; i >= 0; --i) {
795 if (GetResource(i) == (*group)[0])
796 return std::make_pair(i, group->size());
798 NOTREACHED();
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))
807 group_index++;
810 DCHECK_NE(group_index, -1);
811 return group_index;
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))
820 group_count++;
822 if (group_count == group_index) {
823 count_in_group++;
824 if (count_in_group == index_in_group)
825 return i;
826 } else if (group_count > group_index) {
827 break;
831 NOTREACHED();
832 return -1;
835 int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const {
836 CHECK(row1 < ResourceCount() && row2 < ResourceCount());
837 switch (col_id) {
838 case IDS_TASK_MANAGER_TASK_COLUMN: {
839 static icu::Collator* collator = NULL;
840 if (!collator) {
841 UErrorCode create_status = U_ZERO_ERROR;
842 collator = icu::Collator::createInstance(create_status);
843 if (!U_SUCCESS(create_status)) {
844 collator = NULL;
845 NOTREACHED();
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()),
856 compare_status);
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,
865 profile2.length());
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, &current1, &peak1);
899 GetGDIHandles(row2, &current2, &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, &current1, &peak1);
907 GetUSERHandles(row2, &current2, &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);
921 switch (col_id) {
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);
929 default:
930 NOTREACHED();
931 return 0;
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: {
942 size_t value1;
943 size_t value2;
944 bool has_duplicates;
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);
962 default:
963 NOTREACHED();
964 break;
966 return 0;
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(
982 int index) const {
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);
1002 } else {
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(),
1009 resources_.end(),
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);
1021 #else
1022 base::ProcessMetrics::CreateProcessMetrics(
1023 process, content::BrowserChildProcessHost::GetPortProvider());
1024 #endif
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(),
1045 resource);
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.
1089 update_requests_++;
1090 if (update_requests_ > 1)
1091 return;
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(
1099 FROM_HERE,
1100 base::Bind(&TaskManagerModel::RefreshCallback, this));
1102 update_state_ = TASK_PENDING;
1104 // Notify resource providers that we are updating.
1105 StartListening();
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.
1116 update_requests_--;
1117 if (update_requests_ > 0)
1118 return;
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.
1125 StopListening();
1128 void TaskManagerModel::StartListening() {
1129 // Multiple StartListening requests may come in and we only need to take
1130 // action the first time.
1131 listen_requests_++;
1132 if (listen_requests_ > 1)
1133 return;
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.
1146 listen_requests_--;
1147 if (listen_requests_ > 0)
1148 return;
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.
1159 Clear();
1162 void TaskManagerModel::Clear() {
1163 int size = ResourceCount();
1164 if (size > 0) {
1165 resources_.clear();
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)
1207 continue;
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,
1216 // crbug.com/120488
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();
1235 else
1236 values->network_usage = iter->second * (1 / update_time.InSeconds());
1238 // Then we reset the current byte count.
1239 iter->second = 0;
1242 // Let resources update themselves if they need to.
1243 for (ResourceList::iterator iter = resources_.begin();
1244 iter != resources_.end(); ++iter) {
1245 (*iter)->Refresh();
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,
1266 int routing_id,
1267 float fps) {
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,
1296 int byte_count) {
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;
1306 if (info)
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.
1311 int origin_pid = 0;
1312 if (info)
1313 origin_pid = info->GetOriginPID();
1315 if (bytes_read_buffer_.empty()) {
1316 base::MessageLoop::current()->PostDelayedTask(
1317 FROM_HERE,
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;
1352 return;
1355 Refresh();
1357 // Schedule the next update.
1358 base::MessageLoop::current()->PostDelayedTask(
1359 FROM_HERE,
1360 base::Bind(&TaskManagerModel::RefreshCallback, this),
1361 base::TimeDelta::FromMilliseconds(kUpdateTimeMs));
1364 void TaskManagerModel::RefreshVideoMemoryUsageStats() {
1365 if (pending_video_memory_usage_stats_update_)
1366 return;
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
1384 // ignore it.
1385 return;
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,
1394 param.child_id,
1395 param.route_id);
1396 if (resource)
1397 break;
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;
1408 BytesRead(param);
1409 return;
1412 // We do support network usage, mark the resource as such so it can report 0
1413 // instead of N/A.
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;
1421 else
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) {
1430 BytesRead(*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())
1450 return -1;
1451 return net_usage;
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);
1473 #else
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);
1477 #endif
1480 bool TaskManagerModel::CachePrivateAndSharedMemory(
1481 base::ProcessHandle handle) const {
1482 PerProcessValues& values(per_process_cache_[handle]);
1483 if (values.is_private_and_shared_valid)
1484 return true;
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)) {
1490 return false;
1493 values.is_private_and_shared_valid = true;
1494 return 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())
1501 return false;
1502 values.is_webcore_stats_valid = true;
1503 values.webcore_stats = GetResource(index)->GetWebCoreCacheStats();
1505 return true;
1508 bool TaskManagerModel::CacheV8Memory(int index) const {
1509 PerResourceValues& values(GetPerResourceValues(index));
1510 if (!values.is_v8_memory_valid) {
1511 if (!GetResource(index)->ReportsV8MemoryStats())
1512 return false;
1513 values.is_v8_memory_valid = true;
1514 values.v8_memory_allocated = GetResource(index)->GetV8MemoryAllocated();
1515 values.v8_memory_used = GetResource(index)->GetV8MemoryUsed();
1517 return true;
1520 void TaskManagerModel::AddResourceProvider(ResourceProvider* provider) {
1521 DCHECK(provider);
1522 providers_.push_back(provider);
1525 TaskManagerModel::PerResourceValues& TaskManagerModel::GetPerResourceValues(
1526 int index) const {
1527 return per_resource_cache_[GetResource(index)];
1530 Resource* TaskManagerModel::GetResource(int index) const {
1531 CHECK_GE(index, 0);
1532 CHECK_LT(index, static_cast<int>(resources_.size()));
1533 return resources_[index];
1536 ////////////////////////////////////////////////////////////////////////////////
1537 // TaskManager class
1538 ////////////////////////////////////////////////////////////////////////////////
1539 // static
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);
1553 DCHECK(process);
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
1562 // return NULL.
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();
1584 // static
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(&params);
1599 TaskManager::TaskManager()
1600 : model_(new TaskManagerModel(this)) {
1603 TaskManager::~TaskManager() {