Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / task_manager / task_manager.cc
blob56e5e26525c2e734def7dabaf17328b099d16c9c
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/extensions/extension_system.h"
20 #include "chrome/browser/profiles/profile_manager.h"
21 #include "chrome/browser/task_manager/background_resource_provider.h"
22 #include "chrome/browser/task_manager/browser_process_resource_provider.h"
23 #include "chrome/browser/task_manager/child_process_resource_provider.h"
24 #include "chrome/browser/task_manager/extension_process_resource_provider.h"
25 #include "chrome/browser/task_manager/guest_resource_provider.h"
26 #include "chrome/browser/task_manager/notification_resource_provider.h"
27 #include "chrome/browser/task_manager/panel_resource_provider.h"
28 #include "chrome/browser/task_manager/resource_provider.h"
29 #include "chrome/browser/task_manager/tab_contents_resource_provider.h"
30 #include "chrome/browser/task_manager/worker_resource_provider.h"
31 #include "chrome/browser/ui/browser_navigator.h"
32 #include "chrome/common/pref_names.h"
33 #include "chrome/common/url_constants.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/gpu_data_manager.h"
36 #include "content/public/browser/gpu_data_manager_observer.h"
37 #include "content/public/browser/resource_request_info.h"
38 #include "content/public/browser/web_contents.h"
39 #include "content/public/browser/web_contents_delegate.h"
40 #include "content/public/common/result_codes.h"
41 #include "grit/generated_resources.h"
42 #include "grit/ui_resources.h"
43 #include "third_party/icu/source/i18n/unicode/coll.h"
44 #include "ui/base/l10n/l10n_util.h"
45 #include "ui/base/resource/resource_bundle.h"
46 #include "ui/base/text/bytes_formatting.h"
47 #include "ui/gfx/image/image_skia.h"
49 #if defined(OS_MACOSX)
50 #include "content/public/browser/browser_child_process_host.h"
51 #endif
53 using content::BrowserThread;
54 using content::ResourceRequestInfo;
55 using content::WebContents;
56 using task_manager::Resource;
57 using task_manager::ResourceProvider;
59 class Profile;
61 namespace {
63 template <class T>
64 int ValueCompare(T value1, T value2) {
65 if (value1 < value2)
66 return -1;
67 if (value1 == value2)
68 return 0;
69 return 1;
72 // Used when one or both of the results to compare are unavailable.
73 int OrderUnavailableValue(bool v1, bool v2) {
74 if (!v1 && !v2)
75 return 0;
76 return v1 ? 1 : -1;
79 // Used by TaskManagerModel::CompareValues(). See it for details of return
80 // value.
81 template <class T>
82 int ValueCompareMember(const TaskManagerModel* model,
83 bool (TaskManagerModel::*f)(int, T*) const,
84 int row1,
85 int row2) {
86 T value1;
87 T value2;
88 bool value1_valid = (model->*f)(row1, &value1);
89 bool value2_valid = (model->*f)(row2, &value2);
90 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
91 OrderUnavailableValue(value1_valid, value2_valid);
94 base::string16 FormatStatsSize(const blink::WebCache::ResourceTypeStat& stat) {
95 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
96 ui::FormatBytesWithUnits(stat.size, ui::DATA_UNITS_KIBIBYTE, false),
97 ui::FormatBytesWithUnits(stat.liveSize, ui::DATA_UNITS_KIBIBYTE, false));
100 // Returns true if the specified id should use the first value in the group.
101 bool IsSharedByGroup(int col_id) {
102 switch (col_id) {
103 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
104 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
105 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
106 case IDS_TASK_MANAGER_CPU_COLUMN:
107 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
108 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
109 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
110 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
111 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
112 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
113 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
114 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
115 return true;
116 default:
117 return false;
121 #if defined(OS_WIN)
122 void GetWinGDIHandles(base::ProcessHandle process,
123 size_t* current,
124 size_t* peak) {
125 *current = 0;
126 *peak = 0;
127 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
128 HANDLE current_process = GetCurrentProcess();
129 HANDLE process_with_query_rights;
130 if (DuplicateHandle(current_process, process, current_process,
131 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
132 false, 0)) {
133 *current = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS);
134 *peak = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS_PEAK);
135 CloseHandle(process_with_query_rights);
139 void GetWinUSERHandles(base::ProcessHandle process,
140 size_t* current,
141 size_t* peak) {
142 *current = 0;
143 *peak = 0;
144 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
145 HANDLE current_process = GetCurrentProcess();
146 HANDLE process_with_query_rights;
147 if (DuplicateHandle(current_process, process, current_process,
148 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
149 false, 0)) {
150 *current = GetGuiResources(process_with_query_rights, GR_USEROBJECTS);
151 *peak = GetGuiResources(process_with_query_rights, GR_USEROBJECTS_PEAK);
152 CloseHandle(process_with_query_rights);
155 #endif
157 } // namespace
159 class TaskManagerModelGpuDataManagerObserver
160 : public content::GpuDataManagerObserver {
161 public:
162 TaskManagerModelGpuDataManagerObserver() {
163 content::GpuDataManager::GetInstance()->AddObserver(this);
166 virtual ~TaskManagerModelGpuDataManagerObserver() {
167 content::GpuDataManager::GetInstance()->RemoveObserver(this);
170 static void NotifyVideoMemoryUsageStats(
171 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
172 TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats(
173 video_memory_usage_stats);
176 virtual void OnVideoMemoryUsageStatsUpdate(
177 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats)
178 OVERRIDE {
179 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
180 NotifyVideoMemoryUsageStats(video_memory_usage_stats);
181 } else {
182 BrowserThread::PostTask(
183 BrowserThread::UI, FROM_HERE, base::Bind(
184 &TaskManagerModelGpuDataManagerObserver::
185 NotifyVideoMemoryUsageStats,
186 video_memory_usage_stats));
191 TaskManagerModel::PerResourceValues::PerResourceValues()
192 : is_nacl_debug_stub_port_valid(false),
193 nacl_debug_stub_port(0),
194 is_title_valid(false),
195 is_profile_name_valid(false),
196 network_usage(0),
197 is_process_id_valid(false),
198 process_id(0),
199 is_goats_teleported_valid(false),
200 goats_teleported(0),
201 is_webcore_stats_valid(false),
202 is_fps_valid(false),
203 fps(0),
204 is_sqlite_memory_bytes_valid(false),
205 sqlite_memory_bytes(0),
206 is_v8_memory_valid(false),
207 v8_memory_allocated(0),
208 v8_memory_used(0) {}
210 TaskManagerModel::PerResourceValues::~PerResourceValues() {}
212 TaskManagerModel::PerProcessValues::PerProcessValues()
213 : is_cpu_usage_valid(false),
214 cpu_usage(0),
215 is_idle_wakeups_valid(false),
216 idle_wakeups(0),
217 is_private_and_shared_valid(false),
218 private_bytes(0),
219 shared_bytes(0),
220 is_physical_memory_valid(false),
221 physical_memory(0),
222 is_video_memory_valid(false),
223 video_memory(0),
224 video_memory_has_duplicates(false),
225 is_gdi_handles_valid(false),
226 gdi_handles(0),
227 gdi_handles_peak(0),
228 is_user_handles_valid(0),
229 user_handles(0),
230 user_handles_peak(0) {}
232 TaskManagerModel::PerProcessValues::~PerProcessValues() {}
234 ////////////////////////////////////////////////////////////////////////////////
235 // TaskManagerModel class
236 ////////////////////////////////////////////////////////////////////////////////
238 TaskManagerModel::TaskManagerModel(TaskManager* task_manager)
239 : pending_video_memory_usage_stats_update_(false),
240 update_requests_(0),
241 listen_requests_(0),
242 update_state_(IDLE),
243 goat_salt_(base::RandUint64()),
244 last_unique_id_(0) {
245 AddResourceProvider(
246 new task_manager::BrowserProcessResourceProvider(task_manager));
247 AddResourceProvider(
248 new task_manager::BackgroundContentsResourceProvider(task_manager));
249 AddResourceProvider(
250 new task_manager::TabContentsResourceProvider(task_manager));
251 AddResourceProvider(new task_manager::PanelResourceProvider(task_manager));
252 AddResourceProvider(
253 new task_manager::ChildProcessResourceProvider(task_manager));
254 AddResourceProvider(
255 new task_manager::ExtensionProcessResourceProvider(task_manager));
256 AddResourceProvider(new task_manager::GuestResourceProvider(task_manager));
258 #if defined(ENABLE_NOTIFICATIONS)
259 ResourceProvider* provider =
260 task_manager::NotificationResourceProvider::Create(task_manager);
261 if (provider)
262 AddResourceProvider(provider);
263 #endif
265 AddResourceProvider(new task_manager::WorkerResourceProvider(task_manager));
268 void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) {
269 observer_list_.AddObserver(observer);
272 void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) {
273 observer_list_.RemoveObserver(observer);
276 int TaskManagerModel::ResourceCount() const {
277 return resources_.size();
280 int TaskManagerModel::GroupCount() const {
281 return group_map_.size();
284 int TaskManagerModel::GetNaClDebugStubPort(int index) const {
285 PerResourceValues& values(GetPerResourceValues(index));
286 if (!values.is_nacl_debug_stub_port_valid) {
287 values.is_nacl_debug_stub_port_valid = true;
288 values.nacl_debug_stub_port = GetResource(index)->GetNaClDebugStubPort();
290 return values.nacl_debug_stub_port;
293 int64 TaskManagerModel::GetNetworkUsage(int index) const {
294 return GetNetworkUsage(GetResource(index));
297 double TaskManagerModel::GetCPUUsage(int index) const {
298 return GetCPUUsage(GetResource(index));
301 int TaskManagerModel::GetIdleWakeupsPerSecond(int index) const {
302 return GetIdleWakeupsPerSecond(GetResource(index));
305 base::ProcessId TaskManagerModel::GetProcessId(int index) const {
306 PerResourceValues& values(GetPerResourceValues(index));
307 if (!values.is_process_id_valid) {
308 values.is_process_id_valid = true;
309 values.process_id = base::GetProcId(GetResource(index)->GetProcess());
311 return values.process_id;
314 base::ProcessHandle TaskManagerModel::GetProcess(int index) const {
315 return GetResource(index)->GetProcess();
318 int TaskManagerModel::GetResourceUniqueId(int index) const {
319 return GetResource(index)->get_unique_id();
322 int TaskManagerModel::GetResourceIndexByUniqueId(const int unique_id) const {
323 for (int resource_index = 0; resource_index < ResourceCount();
324 ++resource_index) {
325 if (GetResourceUniqueId(resource_index) == unique_id)
326 return resource_index;
328 return -1;
331 base::string16 TaskManagerModel::GetResourceById(int index, int col_id) const {
332 if (IsSharedByGroup(col_id) && !IsResourceFirstInGroup(index))
333 return base::string16();
335 switch (col_id) {
336 case IDS_TASK_MANAGER_TASK_COLUMN:
337 return GetResourceTitle(index);
339 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN:
340 return GetResourceProfileName(index);
342 case IDS_TASK_MANAGER_NET_COLUMN:
343 return GetResourceNetworkUsage(index);
345 case IDS_TASK_MANAGER_CPU_COLUMN:
346 return GetResourceCPUUsage(index);
348 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
349 return GetResourcePrivateMemory(index);
351 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
352 return GetResourceSharedMemory(index);
354 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
355 return GetResourcePhysicalMemory(index);
357 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
358 return GetResourceProcessId(index);
360 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN:
361 return GetResourceGDIHandles(index);
363 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN:
364 return GetResourceUSERHandles(index);
366 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN:
367 return GetResourceIdleWakeupsPerSecond(index);
369 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN:
370 return GetResourceGoatsTeleported(index);
372 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
373 return GetResourceWebCoreImageCacheSize(index);
375 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
376 return GetResourceWebCoreScriptsCacheSize(index);
378 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
379 return GetResourceWebCoreCSSCacheSize(index);
381 case IDS_TASK_MANAGER_FPS_COLUMN:
382 return GetResourceFPS(index);
384 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
385 return GetResourceVideoMemory(index);
387 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
388 return GetResourceSqliteMemoryUsed(index);
390 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
391 return GetResourceV8MemoryAllocatedSize(index);
393 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
394 return GetResourceNaClDebugStubPort(index);
396 default:
397 NOTREACHED();
398 return base::string16();
402 const base::string16& TaskManagerModel::GetResourceTitle(int index) const {
403 PerResourceValues& values = GetPerResourceValues(index);
404 if (!values.is_title_valid) {
405 values.is_title_valid = true;
406 values.title = GetResource(index)->GetTitle();
408 return values.title;
411 const base::string16& TaskManagerModel::GetResourceProfileName(
412 int index) const {
413 PerResourceValues& values(GetPerResourceValues(index));
414 if (!values.is_profile_name_valid) {
415 values.is_profile_name_valid = true;
416 values.profile_name = GetResource(index)->GetProfileName();
418 return values.profile_name;
421 base::string16 TaskManagerModel::GetResourceNaClDebugStubPort(int index) const {
422 int port = GetNaClDebugStubPort(index);
423 if (port == 0) {
424 return base::ASCIIToUTF16("N/A");
425 } else {
426 return base::IntToString16(port);
430 base::string16 TaskManagerModel::GetResourceNetworkUsage(int index) const {
431 int64 net_usage = GetNetworkUsage(index);
432 if (net_usage == -1)
433 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
434 if (net_usage == 0)
435 return base::ASCIIToUTF16("0");
436 base::string16 net_byte = ui::FormatSpeed(net_usage);
437 // Force number string to have LTR directionality.
438 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte);
441 base::string16 TaskManagerModel::GetResourceCPUUsage(int index) const {
442 return base::UTF8ToUTF16(base::StringPrintf(
443 #if defined(OS_MACOSX)
444 // Activity Monitor shows %cpu with one decimal digit -- be
445 // consistent with that.
446 "%.1f",
447 #else
448 "%.0f",
449 #endif
450 GetCPUUsage(GetResource(index))));
453 base::string16 TaskManagerModel::GetResourcePrivateMemory(int index) const {
454 size_t private_mem;
455 if (!GetPrivateMemory(index, &private_mem))
456 return base::ASCIIToUTF16("N/A");
457 return GetMemCellText(private_mem);
460 base::string16 TaskManagerModel::GetResourceSharedMemory(int index) const {
461 size_t shared_mem;
462 if (!GetSharedMemory(index, &shared_mem))
463 return base::ASCIIToUTF16("N/A");
464 return GetMemCellText(shared_mem);
467 base::string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const {
468 size_t phys_mem;
469 GetPhysicalMemory(index, &phys_mem);
470 return GetMemCellText(phys_mem);
473 base::string16 TaskManagerModel::GetResourceProcessId(int index) const {
474 return base::IntToString16(GetProcessId(index));
477 base::string16 TaskManagerModel::GetResourceGDIHandles(int index) const {
478 size_t current, peak;
479 GetGDIHandles(index, &current, &peak);
480 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
481 base::IntToString16(current), base::IntToString16(peak));
484 base::string16 TaskManagerModel::GetResourceUSERHandles(int index) const {
485 size_t current, peak;
486 GetUSERHandles(index, &current, &peak);
487 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
488 base::IntToString16(current), base::IntToString16(peak));
491 base::string16 TaskManagerModel::GetResourceWebCoreImageCacheSize(
492 int index) const {
493 if (!CacheWebCoreStats(index))
494 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
495 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.images);
498 base::string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
499 int index) const {
500 if (!CacheWebCoreStats(index))
501 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
502 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.scripts);
505 base::string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize(
506 int index) const {
507 if (!CacheWebCoreStats(index))
508 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
509 return FormatStatsSize(
510 GetPerResourceValues(index).webcore_stats.cssStyleSheets);
513 base::string16 TaskManagerModel::GetResourceVideoMemory(int index) const {
514 size_t video_memory;
515 bool has_duplicates;
516 if (!GetVideoMemory(index, &video_memory, &has_duplicates) || !video_memory)
517 return base::ASCIIToUTF16("N/A");
518 if (has_duplicates) {
519 return GetMemCellText(video_memory) + base::ASCIIToUTF16("*");
521 return GetMemCellText(video_memory);
524 base::string16 TaskManagerModel::GetResourceFPS(
525 int index) const {
526 float fps = 0;
527 if (!GetFPS(index, &fps))
528 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
529 return base::UTF8ToUTF16(base::StringPrintf("%.0f", fps));
532 base::string16 TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const {
533 size_t bytes = 0;
534 if (!GetSqliteMemoryUsedBytes(index, &bytes))
535 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
536 return GetMemCellText(bytes);
539 base::string16 TaskManagerModel::GetResourceIdleWakeupsPerSecond(int index)
540 const {
541 return base::FormatNumber(GetIdleWakeupsPerSecond(GetResource(index)));
544 base::string16 TaskManagerModel::GetResourceGoatsTeleported(int index) const {
545 CHECK_LT(index, ResourceCount());
546 return base::FormatNumber(GetGoatsTeleported(index));
549 base::string16 TaskManagerModel::GetResourceV8MemoryAllocatedSize(
550 int index) const {
551 size_t memory_allocated = 0, memory_used = 0;
552 if (!GetV8MemoryUsed(index, &memory_used) ||
553 !GetV8Memory(index, &memory_allocated))
554 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
555 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
556 ui::FormatBytesWithUnits(memory_allocated,
557 ui::DATA_UNITS_KIBIBYTE,
558 false),
559 ui::FormatBytesWithUnits(memory_used,
560 ui::DATA_UNITS_KIBIBYTE,
561 false));
564 bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const {
565 *result = 0;
566 base::ProcessHandle handle = GetResource(index)->GetProcess();
567 if (!CachePrivateAndSharedMemory(handle))
568 return false;
569 *result = per_process_cache_[handle].private_bytes;
570 return true;
573 bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const {
574 *result = 0;
575 base::ProcessHandle handle = GetResource(index)->GetProcess();
576 if (!CachePrivateAndSharedMemory(handle))
577 return false;
578 *result = per_process_cache_[handle].shared_bytes;
579 return true;
582 bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const {
583 *result = 0;
585 base::ProcessHandle handle = GetResource(index)->GetProcess();
586 PerProcessValues& values(per_process_cache_[handle]);
588 if (!values.is_physical_memory_valid) {
589 base::WorkingSetKBytes ws_usage;
590 MetricsMap::const_iterator iter = metrics_map_.find(handle);
591 if (iter == metrics_map_.end() ||
592 !iter->second->GetWorkingSetKBytes(&ws_usage))
593 return false;
595 values.is_physical_memory_valid = true;
596 #if defined(OS_LINUX)
597 // On Linux private memory is also resident. Just use it.
598 values.physical_memory = ws_usage.priv * 1024;
599 #else
600 // Memory = working_set.private + working_set.shareable.
601 // We exclude the shared memory.
602 values.physical_memory = iter->second->GetWorkingSetSize();
603 values.physical_memory -= ws_usage.shared * 1024;
604 #endif
606 *result = values.physical_memory;
607 return true;
610 void TaskManagerModel::GetGDIHandles(int index,
611 size_t* current,
612 size_t* peak) const {
613 *current = 0;
614 *peak = 0;
615 #if defined(OS_WIN)
616 base::ProcessHandle handle = GetResource(index)->GetProcess();
617 PerProcessValues& values(per_process_cache_[handle]);
619 if (!values.is_gdi_handles_valid) {
620 GetWinGDIHandles(GetResource(index)->GetProcess(),
621 &values.gdi_handles,
622 &values.gdi_handles_peak);
623 values.is_gdi_handles_valid = true;
625 *current = values.gdi_handles;
626 *peak = values.gdi_handles_peak;
627 #endif
630 void TaskManagerModel::GetUSERHandles(int index,
631 size_t* current,
632 size_t* peak) const {
633 *current = 0;
634 *peak = 0;
635 #if defined(OS_WIN)
636 base::ProcessHandle handle = GetResource(index)->GetProcess();
637 PerProcessValues& values(per_process_cache_[handle]);
639 if (!values.is_user_handles_valid) {
640 GetWinUSERHandles(GetResource(index)->GetProcess(),
641 &values.user_handles,
642 &values.user_handles_peak);
643 values.is_user_handles_valid = true;
645 *current = values.user_handles;
646 *peak = values.user_handles_peak;
647 #endif
650 bool TaskManagerModel::GetWebCoreCacheStats(
651 int index,
652 blink::WebCache::ResourceTypeStats* result) const {
653 if (!CacheWebCoreStats(index))
654 return false;
655 *result = GetPerResourceValues(index).webcore_stats;
656 return true;
659 bool TaskManagerModel::GetVideoMemory(int index,
660 size_t* video_memory,
661 bool* has_duplicates) const {
662 *video_memory = 0;
663 *has_duplicates = false;
665 base::ProcessId pid = GetProcessId(index);
666 PerProcessValues& values(
667 per_process_cache_[GetResource(index)->GetProcess()]);
668 if (!values.is_video_memory_valid) {
669 content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i =
670 video_memory_usage_stats_.process_map.find(pid);
671 if (i == video_memory_usage_stats_.process_map.end())
672 return false;
673 values.is_video_memory_valid = true;
674 values.video_memory = i->second.video_memory;
675 values.video_memory_has_duplicates = i->second.has_duplicates;
677 *video_memory = values.video_memory;
678 *has_duplicates = values.video_memory_has_duplicates;
679 return true;
682 bool TaskManagerModel::GetFPS(int index, float* result) const {
683 *result = 0;
684 PerResourceValues& values(GetPerResourceValues(index));
685 if (!values.is_fps_valid) {
686 if (!GetResource(index)->ReportsFPS())
687 return false;
688 values.is_fps_valid = true;
689 values.fps = GetResource(index)->GetFPS();
691 *result = values.fps;
692 return true;
695 bool TaskManagerModel::GetSqliteMemoryUsedBytes(
696 int index,
697 size_t* result) const {
698 *result = 0;
699 PerResourceValues& values(GetPerResourceValues(index));
700 if (!values.is_sqlite_memory_bytes_valid) {
701 if (!GetResource(index)->ReportsSqliteMemoryUsed())
702 return false;
703 values.is_sqlite_memory_bytes_valid = true;
704 values.sqlite_memory_bytes = GetResource(index)->SqliteMemoryUsedBytes();
706 *result = values.sqlite_memory_bytes;
707 return true;
710 bool TaskManagerModel::GetV8Memory(int index, size_t* result) const {
711 *result = 0;
712 if (!CacheV8Memory(index))
713 return false;
714 *result = GetPerResourceValues(index).v8_memory_allocated;
715 return true;
718 bool TaskManagerModel::GetV8MemoryUsed(int index, size_t* result) const {
719 *result = 0;
720 if (!CacheV8Memory(index))
721 return false;
722 *result = GetPerResourceValues(index).v8_memory_used;
723 return true;
726 bool TaskManagerModel::CanActivate(int index) const {
727 CHECK_LT(index, ResourceCount());
728 return GetResourceWebContents(index) != NULL;
731 bool TaskManagerModel::CanInspect(int index) const {
732 return GetResource(index)->CanInspect();
735 void TaskManagerModel::Inspect(int index) const {
736 CHECK_LT(index, ResourceCount());
737 GetResource(index)->Inspect();
740 int TaskManagerModel::GetGoatsTeleported(int index) const {
741 PerResourceValues& values(GetPerResourceValues(index));
742 if (!values.is_goats_teleported_valid) {
743 values.is_goats_teleported_valid = true;
744 values.goats_teleported = goat_salt_ * (index + 1);
745 values.goats_teleported = (values.goats_teleported >> 16) & 255;
747 return values.goats_teleported;
750 bool TaskManagerModel::IsResourceFirstInGroup(int index) const {
751 Resource* resource = GetResource(index);
752 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
753 DCHECK(iter != group_map_.end());
754 const ResourceList* group = iter->second;
755 return ((*group)[0] == resource);
758 bool TaskManagerModel::IsResourceLastInGroup(int index) const {
759 Resource* resource = GetResource(index);
760 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
761 DCHECK(iter != group_map_.end());
762 const ResourceList* group = iter->second;
763 return (group->back() == resource);
766 bool TaskManagerModel::IsBackgroundResource(int index) const {
767 return GetResource(index)->IsBackground();
770 gfx::ImageSkia TaskManagerModel::GetResourceIcon(int index) const {
771 gfx::ImageSkia icon = GetResource(index)->GetIcon();
772 if (!icon.isNull())
773 return icon;
775 static gfx::ImageSkia* default_icon = ResourceBundle::GetSharedInstance().
776 GetImageSkiaNamed(IDR_DEFAULT_FAVICON);
777 return *default_icon;
780 TaskManagerModel::GroupRange
781 TaskManagerModel::GetGroupRangeForResource(int index) const {
782 Resource* resource = GetResource(index);
783 GroupMap::const_iterator group_iter =
784 group_map_.find(resource->GetProcess());
785 DCHECK(group_iter != group_map_.end());
786 ResourceList* group = group_iter->second;
787 DCHECK(group);
788 if (group->size() == 1) {
789 return std::make_pair(index, 1);
790 } else {
791 for (int i = index; i >= 0; --i) {
792 if (GetResource(i) == (*group)[0])
793 return std::make_pair(i, group->size());
795 NOTREACHED();
796 return std::make_pair(-1, -1);
800 int TaskManagerModel::GetGroupIndexForResource(int index) const {
801 int group_index = -1;
802 for (int i = 0; i <= index; ++i) {
803 if (IsResourceFirstInGroup(i))
804 group_index++;
807 DCHECK_NE(group_index, -1);
808 return group_index;
811 int TaskManagerModel::GetResourceIndexForGroup(int group_index,
812 int index_in_group) const {
813 int group_count = -1;
814 int count_in_group = -1;
815 for (int i = 0; i < ResourceCount(); ++i) {
816 if (IsResourceFirstInGroup(i))
817 group_count++;
819 if (group_count == group_index) {
820 count_in_group++;
821 if (count_in_group == index_in_group)
822 return i;
823 } else if (group_count > group_index) {
824 break;
828 NOTREACHED();
829 return -1;
832 int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const {
833 CHECK(row1 < ResourceCount() && row2 < ResourceCount());
834 switch (col_id) {
835 case IDS_TASK_MANAGER_TASK_COLUMN: {
836 static icu::Collator* collator = NULL;
837 if (!collator) {
838 UErrorCode create_status = U_ZERO_ERROR;
839 collator = icu::Collator::createInstance(create_status);
840 if (!U_SUCCESS(create_status)) {
841 collator = NULL;
842 NOTREACHED();
845 const base::string16& title1 = GetResourceTitle(row1);
846 const base::string16& title2 = GetResourceTitle(row2);
847 UErrorCode compare_status = U_ZERO_ERROR;
848 UCollationResult compare_result = collator->compare(
849 static_cast<const UChar*>(title1.c_str()),
850 static_cast<int>(title1.length()),
851 static_cast<const UChar*>(title2.c_str()),
852 static_cast<int>(title2.length()),
853 compare_status);
854 DCHECK(U_SUCCESS(compare_status));
855 return compare_result;
858 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN: {
859 const base::string16& profile1 = GetResourceProfileName(row1);
860 const base::string16& profile2 = GetResourceProfileName(row2);
861 return profile1.compare(0, profile1.length(), profile2, 0,
862 profile2.length());
865 case IDS_TASK_MANAGER_NET_COLUMN:
866 return ValueCompare(GetNetworkUsage(GetResource(row1)),
867 GetNetworkUsage(GetResource(row2)));
869 case IDS_TASK_MANAGER_CPU_COLUMN:
870 return ValueCompare(GetCPUUsage(GetResource(row1)),
871 GetCPUUsage(GetResource(row2)));
873 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
874 return ValueCompareMember(
875 this, &TaskManagerModel::GetPrivateMemory, row1, row2);
877 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
878 return ValueCompareMember(
879 this, &TaskManagerModel::GetSharedMemory, row1, row2);
881 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
882 return ValueCompareMember(
883 this, &TaskManagerModel::GetPhysicalMemory, row1, row2);
885 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
886 return ValueCompare(GetNaClDebugStubPort(row1),
887 GetNaClDebugStubPort(row2));
889 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
890 return ValueCompare(GetProcessId(row1), GetProcessId(row2));
892 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN: {
893 size_t current1, peak1;
894 size_t current2, peak2;
895 GetGDIHandles(row1, &current1, &peak1);
896 GetGDIHandles(row2, &current2, &peak2);
897 return ValueCompare(current1, current2);
900 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN: {
901 size_t current1, peak1;
902 size_t current2, peak2;
903 GetUSERHandles(row1, &current1, &peak1);
904 GetUSERHandles(row2, &current2, &peak2);
905 return ValueCompare(current1, current2);
908 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
909 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
910 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: {
911 bool row1_stats_valid = CacheWebCoreStats(row1);
912 bool row2_stats_valid = CacheWebCoreStats(row2);
913 if (row1_stats_valid && row2_stats_valid) {
914 const blink::WebCache::ResourceTypeStats& stats1(
915 GetPerResourceValues(row1).webcore_stats);
916 const blink::WebCache::ResourceTypeStats& stats2(
917 GetPerResourceValues(row2).webcore_stats);
918 switch (col_id) {
919 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
920 return ValueCompare(stats1.images.size, stats2.images.size);
921 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
922 return ValueCompare(stats1.scripts.size, stats2.scripts.size);
923 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
924 return ValueCompare(stats1.cssStyleSheets.size,
925 stats2.cssStyleSheets.size);
926 default:
927 NOTREACHED();
928 return 0;
931 return OrderUnavailableValue(row1_stats_valid, row2_stats_valid);
934 case IDS_TASK_MANAGER_FPS_COLUMN:
935 return ValueCompareMember(
936 this, &TaskManagerModel::GetFPS, row1, row2);
938 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN: {
939 size_t value1;
940 size_t value2;
941 bool has_duplicates;
942 bool value1_valid = GetVideoMemory(row1, &value1, &has_duplicates);
943 bool value2_valid = GetVideoMemory(row2, &value2, &has_duplicates);
944 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
945 OrderUnavailableValue(value1_valid, value2_valid);
948 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN:
949 return ValueCompare(GetGoatsTeleported(row1), GetGoatsTeleported(row2));
951 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
952 return ValueCompareMember(
953 this, &TaskManagerModel::GetV8Memory, row1, row2);
955 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
956 return ValueCompareMember(
957 this, &TaskManagerModel::GetSqliteMemoryUsedBytes, row1, row2);
959 default:
960 NOTREACHED();
961 break;
963 return 0;
966 int TaskManagerModel::GetUniqueChildProcessId(int index) const {
967 return GetResource(index)->GetUniqueChildProcessId();
970 Resource::Type TaskManagerModel::GetResourceType(int index) const {
971 return GetResource(index)->GetType();
974 WebContents* TaskManagerModel::GetResourceWebContents(int index) const {
975 return GetResource(index)->GetWebContents();
978 const extensions::Extension* TaskManagerModel::GetResourceExtension(
979 int index) const {
980 return GetResource(index)->GetExtension();
983 void TaskManagerModel::AddResource(Resource* resource) {
984 resource->unique_id_ = ++last_unique_id_;
986 base::ProcessHandle process = resource->GetProcess();
988 ResourceList* group_entries = NULL;
989 GroupMap::const_iterator group_iter = group_map_.find(process);
990 int new_entry_index = 0;
991 if (group_iter == group_map_.end()) {
992 group_entries = new ResourceList();
993 group_map_[process] = group_entries;
994 group_entries->push_back(resource);
996 // Not part of a group, just put at the end of the list.
997 resources_.push_back(resource);
998 new_entry_index = static_cast<int>(resources_.size() - 1);
999 } else {
1000 group_entries = group_iter->second;
1001 group_entries->push_back(resource);
1003 // Insert the new entry right after the last entry of its group.
1004 ResourceList::iterator iter =
1005 std::find(resources_.begin(),
1006 resources_.end(),
1007 (*group_entries)[group_entries->size() - 2]);
1008 DCHECK(iter != resources_.end());
1009 new_entry_index = static_cast<int>(iter - resources_.begin()) + 1;
1010 resources_.insert(++iter, resource);
1013 // Create the ProcessMetrics for this process if needed (not in map).
1014 if (metrics_map_.find(process) == metrics_map_.end()) {
1015 base::ProcessMetrics* pm =
1016 #if !defined(OS_MACOSX)
1017 base::ProcessMetrics::CreateProcessMetrics(process);
1018 #else
1019 base::ProcessMetrics::CreateProcessMetrics(
1020 process, content::BrowserChildProcessHost::GetPortProvider());
1021 #endif
1023 metrics_map_[process] = pm;
1026 // Notify the table that the contents have changed for it to redraw.
1027 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1028 OnItemsAdded(new_entry_index, 1));
1031 void TaskManagerModel::RemoveResource(Resource* resource) {
1032 base::ProcessHandle process = resource->GetProcess();
1034 // Find the associated group.
1035 GroupMap::iterator group_iter = group_map_.find(process);
1036 DCHECK(group_iter != group_map_.end());
1037 ResourceList* group_entries = group_iter->second;
1039 // Remove the entry from the group map.
1040 ResourceList::iterator iter = std::find(group_entries->begin(),
1041 group_entries->end(),
1042 resource);
1043 DCHECK(iter != group_entries->end());
1044 group_entries->erase(iter);
1046 // If there are no more entries for that process, do the clean-up.
1047 if (group_entries->empty()) {
1048 delete group_entries;
1049 group_map_.erase(process);
1051 // Nobody is using this process, we don't need the process metrics anymore.
1052 MetricsMap::iterator pm_iter = metrics_map_.find(process);
1053 DCHECK(pm_iter != metrics_map_.end());
1054 if (pm_iter != metrics_map_.end()) {
1055 delete pm_iter->second;
1056 metrics_map_.erase(process);
1060 // Prepare to remove the entry from the model list.
1061 iter = std::find(resources_.begin(), resources_.end(), resource);
1062 DCHECK(iter != resources_.end());
1063 int index = static_cast<int>(iter - resources_.begin());
1065 // Notify the observers that the contents will change.
1066 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1067 OnItemsToBeRemoved(index, 1));
1069 // Now actually remove the entry from the model list.
1070 resources_.erase(iter);
1072 // Remove the entry from the network maps.
1073 ResourceValueMap::iterator net_iter =
1074 current_byte_count_map_.find(resource);
1075 if (net_iter != current_byte_count_map_.end())
1076 current_byte_count_map_.erase(net_iter);
1078 // Notify the table that the contents have changed.
1079 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1080 OnItemsRemoved(index, 1));
1083 void TaskManagerModel::StartUpdating() {
1084 // Multiple StartUpdating requests may come in, and we only need to take
1085 // action the first time.
1086 update_requests_++;
1087 if (update_requests_ > 1)
1088 return;
1089 DCHECK_EQ(1, update_requests_);
1090 DCHECK_NE(TASK_PENDING, update_state_);
1092 // If update_state_ is STOPPING, it means a task is still pending. Setting
1093 // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()).
1094 if (update_state_ == IDLE) {
1095 base::MessageLoop::current()->PostTask(
1096 FROM_HERE,
1097 base::Bind(&TaskManagerModel::RefreshCallback, this));
1099 update_state_ = TASK_PENDING;
1101 // Notify resource providers that we are updating.
1102 StartListening();
1104 if (!resources_.empty()) {
1105 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1106 OnReadyPeriodicalUpdate());
1110 void TaskManagerModel::StopUpdating() {
1111 // Don't actually stop updating until we have heard as many calls as those
1112 // to StartUpdating.
1113 update_requests_--;
1114 if (update_requests_ > 0)
1115 return;
1116 // Make sure that update_requests_ cannot go negative.
1117 CHECK_EQ(0, update_requests_);
1118 DCHECK_EQ(TASK_PENDING, update_state_);
1119 update_state_ = STOPPING;
1121 // Notify resource providers that we are done updating.
1122 StopListening();
1125 void TaskManagerModel::StartListening() {
1126 // Multiple StartListening requests may come in and we only need to take
1127 // action the first time.
1128 listen_requests_++;
1129 if (listen_requests_ > 1)
1130 return;
1131 DCHECK_EQ(1, listen_requests_);
1133 // Notify resource providers that we should start listening to events.
1134 for (ResourceProviderList::iterator iter = providers_.begin();
1135 iter != providers_.end(); ++iter) {
1136 (*iter)->StartUpdating();
1140 void TaskManagerModel::StopListening() {
1141 // Don't actually stop listening until we have heard as many calls as those
1142 // to StartListening.
1143 listen_requests_--;
1144 if (listen_requests_ > 0)
1145 return;
1147 DCHECK_EQ(0, listen_requests_);
1149 // Notify resource providers that we are done listening.
1150 for (ResourceProviderList::const_iterator iter = providers_.begin();
1151 iter != providers_.end(); ++iter) {
1152 (*iter)->StopUpdating();
1155 // Must clear the resources before the next attempt to start listening.
1156 Clear();
1159 void TaskManagerModel::Clear() {
1160 int size = ResourceCount();
1161 if (size > 0) {
1162 resources_.clear();
1164 // Clear the groups.
1165 STLDeleteValues(&group_map_);
1167 // Clear the process related info.
1168 STLDeleteValues(&metrics_map_);
1170 // Clear the network maps.
1171 current_byte_count_map_.clear();
1173 per_resource_cache_.clear();
1174 per_process_cache_.clear();
1176 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1177 OnItemsRemoved(0, size));
1179 last_unique_id_ = 0;
1182 void TaskManagerModel::ModelChanged() {
1183 // Notify the table that the contents have changed for it to redraw.
1184 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, OnModelChanged());
1187 void TaskManagerModel::Refresh() {
1188 goat_salt_ = base::RandUint64();
1190 per_resource_cache_.clear();
1191 per_process_cache_.clear();
1193 // Compute the CPU usage values.
1194 // Note that we compute the CPU usage for all resources (instead of doing it
1195 // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last
1196 // time it was called, and not calling it everytime would skew the value the
1197 // next time it is retrieved (as it would be for more than 1 cycle).
1198 // The same is true for idle wakeups.
1199 for (ResourceList::iterator iter = resources_.begin();
1200 iter != resources_.end(); ++iter) {
1201 base::ProcessHandle process = (*iter)->GetProcess();
1202 PerProcessValues& values(per_process_cache_[process]);
1203 if (values.is_cpu_usage_valid && values.is_idle_wakeups_valid)
1204 continue;
1205 MetricsMap::iterator metrics_iter = metrics_map_.find(process);
1206 DCHECK(metrics_iter != metrics_map_.end());
1207 if (!values.is_cpu_usage_valid) {
1208 values.is_cpu_usage_valid = true;
1209 values.cpu_usage = metrics_iter->second->GetCPUUsage();
1211 if (!values.is_idle_wakeups_valid) {
1212 values.is_idle_wakeups_valid = true;
1213 values.idle_wakeups = metrics_iter->second->GetIdleWakeupsPerSecond();
1217 // Send a request to refresh GPU memory consumption values
1218 RefreshVideoMemoryUsageStats();
1220 // Compute the new network usage values.
1221 base::TimeDelta update_time =
1222 base::TimeDelta::FromMilliseconds(kUpdateTimeMs);
1223 for (ResourceValueMap::iterator iter = current_byte_count_map_.begin();
1224 iter != current_byte_count_map_.end(); ++iter) {
1225 PerResourceValues* values = &(per_resource_cache_[iter->first]);
1226 if (update_time > base::TimeDelta::FromSeconds(1))
1227 values->network_usage = iter->second / update_time.InSeconds();
1228 else
1229 values->network_usage = iter->second * (1 / update_time.InSeconds());
1231 // Then we reset the current byte count.
1232 iter->second = 0;
1235 // Let resources update themselves if they need to.
1236 for (ResourceList::iterator iter = resources_.begin();
1237 iter != resources_.end(); ++iter) {
1238 (*iter)->Refresh();
1241 if (!resources_.empty()) {
1242 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1243 OnItemsChanged(0, ResourceCount()));
1247 void TaskManagerModel::NotifyResourceTypeStats(
1248 base::ProcessId renderer_id,
1249 const blink::WebCache::ResourceTypeStats& stats) {
1250 for (ResourceList::iterator it = resources_.begin();
1251 it != resources_.end(); ++it) {
1252 if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
1253 (*it)->NotifyResourceTypeStats(stats);
1258 void TaskManagerModel::NotifyFPS(base::ProcessId renderer_id,
1259 int routing_id,
1260 float fps) {
1261 for (ResourceList::iterator it = resources_.begin();
1262 it != resources_.end(); ++it) {
1263 if (base::GetProcId((*it)->GetProcess()) == renderer_id &&
1264 (*it)->GetRoutingID() == routing_id) {
1265 (*it)->NotifyFPS(fps);
1270 void TaskManagerModel::NotifyVideoMemoryUsageStats(
1271 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
1272 DCHECK(pending_video_memory_usage_stats_update_);
1273 video_memory_usage_stats_ = video_memory_usage_stats;
1274 pending_video_memory_usage_stats_update_ = false;
1277 void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id,
1278 size_t v8_memory_allocated,
1279 size_t v8_memory_used) {
1280 for (ResourceList::iterator it = resources_.begin();
1281 it != resources_.end(); ++it) {
1282 if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
1283 (*it)->NotifyV8HeapStats(v8_memory_allocated, v8_memory_used);
1288 void TaskManagerModel::NotifyBytesRead(const net::URLRequest& request,
1289 int byte_count) {
1290 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1292 // Only net::URLRequestJob instances created by the ResourceDispatcherHost
1293 // have an associated ResourceRequestInfo and a render frame associated.
1294 // All other jobs will have -1 returned for the render process child and
1295 // routing ids - the jobs may still match a resource based on their origin id,
1296 // otherwise BytesRead() will attribute the activity to the Browser resource.
1297 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request);
1298 int child_id = -1, route_id = -1;
1299 if (info)
1300 info->GetAssociatedRenderFrame(&child_id, &route_id);
1302 // Get the origin PID of the request's originator. This will only be set for
1303 // plugins - for renderer or browser initiated requests it will be zero.
1304 int origin_pid = 0;
1305 if (info)
1306 origin_pid = info->GetOriginPID();
1308 if (bytes_read_buffer_.empty()) {
1309 base::MessageLoop::current()->PostDelayedTask(
1310 FROM_HERE,
1311 base::Bind(&TaskManagerModel::NotifyMultipleBytesRead, this),
1312 base::TimeDelta::FromSeconds(1));
1315 bytes_read_buffer_.push_back(
1316 BytesReadParam(origin_pid, child_id, route_id, byte_count));
1319 // This is called on the UI thread.
1320 void TaskManagerModel::NotifyDataReady() {
1321 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1322 for (size_t i = 0; i < on_data_ready_callbacks_.size(); ++i) {
1323 if (!on_data_ready_callbacks_[i].is_null())
1324 on_data_ready_callbacks_[i].Run();
1327 on_data_ready_callbacks_.clear();
1330 void TaskManagerModel::RegisterOnDataReadyCallback(
1331 const base::Closure& callback) {
1332 on_data_ready_callbacks_.push_back(callback);
1335 TaskManagerModel::~TaskManagerModel() {
1336 on_data_ready_callbacks_.clear();
1339 void TaskManagerModel::RefreshCallback() {
1340 DCHECK_NE(IDLE, update_state_);
1342 if (update_state_ == STOPPING) {
1343 // We have been asked to stop.
1344 update_state_ = IDLE;
1345 return;
1348 Refresh();
1350 // Schedule the next update.
1351 base::MessageLoop::current()->PostDelayedTask(
1352 FROM_HERE,
1353 base::Bind(&TaskManagerModel::RefreshCallback, this),
1354 base::TimeDelta::FromMilliseconds(kUpdateTimeMs));
1357 void TaskManagerModel::RefreshVideoMemoryUsageStats() {
1358 if (pending_video_memory_usage_stats_update_)
1359 return;
1361 if (!video_memory_usage_stats_observer_.get()) {
1362 video_memory_usage_stats_observer_.reset(
1363 new TaskManagerModelGpuDataManagerObserver());
1365 pending_video_memory_usage_stats_update_ = true;
1366 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate();
1369 int64 TaskManagerModel::GetNetworkUsageForResource(Resource* resource) const {
1370 // Returns default of 0 if no network usage.
1371 return per_resource_cache_[resource].network_usage;
1374 void TaskManagerModel::BytesRead(BytesReadParam param) {
1375 if (update_state_ != TASK_PENDING || listen_requests_ == 0) {
1376 // A notification sneaked in while we were stopping the updating, just
1377 // ignore it.
1378 return;
1381 // TODO(jcampan): this should be improved once we have a better way of
1382 // linking a network notification back to the object that initiated it.
1383 Resource* resource = NULL;
1384 for (ResourceProviderList::iterator iter = providers_.begin();
1385 iter != providers_.end(); ++iter) {
1386 resource = (*iter)->GetResource(param.origin_pid,
1387 param.child_id,
1388 param.route_id);
1389 if (resource)
1390 break;
1393 if (resource == NULL) {
1394 // We can't match a resource to the notification. That might mean the
1395 // tab that started a download was closed, or the request may have had
1396 // no originating resource associated with it in the first place.
1397 // We attribute orphaned/unaccounted activity to the Browser process.
1398 CHECK(param.origin_pid || (param.child_id != -1));
1399 param.origin_pid = 0;
1400 param.child_id = param.route_id = -1;
1401 BytesRead(param);
1402 return;
1405 // We do support network usage, mark the resource as such so it can report 0
1406 // instead of N/A.
1407 if (!resource->SupportNetworkUsage())
1408 resource->SetSupportNetworkUsage();
1410 ResourceValueMap::const_iterator iter_res =
1411 current_byte_count_map_.find(resource);
1412 if (iter_res == current_byte_count_map_.end())
1413 current_byte_count_map_[resource] = param.byte_count;
1414 else
1415 current_byte_count_map_[resource] = iter_res->second + param.byte_count;
1418 void TaskManagerModel::MultipleBytesRead(
1419 const std::vector<BytesReadParam>* params) {
1420 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1421 for (std::vector<BytesReadParam>::const_iterator it = params->begin();
1422 it != params->end(); ++it) {
1423 BytesRead(*it);
1427 void TaskManagerModel::NotifyMultipleBytesRead() {
1428 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1429 DCHECK(!bytes_read_buffer_.empty());
1431 std::vector<BytesReadParam>* bytes_read_buffer =
1432 new std::vector<BytesReadParam>;
1433 bytes_read_buffer_.swap(*bytes_read_buffer);
1434 BrowserThread::PostTask(
1435 BrowserThread::UI, FROM_HERE,
1436 base::Bind(&TaskManagerModel::MultipleBytesRead, this,
1437 base::Owned(bytes_read_buffer)));
1440 int64 TaskManagerModel::GetNetworkUsage(Resource* resource) const {
1441 int64 net_usage = GetNetworkUsageForResource(resource);
1442 if (net_usage == 0 && !resource->SupportNetworkUsage())
1443 return -1;
1444 return net_usage;
1447 double TaskManagerModel::GetCPUUsage(Resource* resource) const {
1448 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]);
1449 // Returns 0 if not valid, which is fine.
1450 return values.cpu_usage;
1453 int TaskManagerModel::GetIdleWakeupsPerSecond(Resource* resource) const {
1454 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]);
1455 // Returns 0 if not valid, which is fine.
1456 return values.idle_wakeups;
1459 base::string16 TaskManagerModel::GetMemCellText(int64 number) const {
1460 #if !defined(OS_MACOSX)
1461 base::string16 str = base::FormatNumber(number / 1024);
1463 // Adjust number string if necessary.
1464 base::i18n::AdjustStringForLocaleDirection(&str);
1465 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT, str);
1466 #else
1467 // System expectation is to show "100 kB", "200 MB", etc.
1468 // TODO(thakis): Switch to metric units (as opposed to powers of two).
1469 return ui::FormatBytes(number);
1470 #endif
1473 bool TaskManagerModel::CachePrivateAndSharedMemory(
1474 base::ProcessHandle handle) const {
1475 PerProcessValues& values(per_process_cache_[handle]);
1476 if (values.is_private_and_shared_valid)
1477 return true;
1479 MetricsMap::const_iterator iter = metrics_map_.find(handle);
1480 if (iter == metrics_map_.end() ||
1481 !iter->second->GetMemoryBytes(&values.private_bytes,
1482 &values.shared_bytes)) {
1483 return false;
1486 values.is_private_and_shared_valid = true;
1487 return true;
1490 bool TaskManagerModel::CacheWebCoreStats(int index) const {
1491 PerResourceValues& values(GetPerResourceValues(index));
1492 if (!values.is_webcore_stats_valid) {
1493 if (!GetResource(index)->ReportsCacheStats())
1494 return false;
1495 values.is_webcore_stats_valid = true;
1496 values.webcore_stats = GetResource(index)->GetWebCoreCacheStats();
1498 return true;
1501 bool TaskManagerModel::CacheV8Memory(int index) const {
1502 PerResourceValues& values(GetPerResourceValues(index));
1503 if (!values.is_v8_memory_valid) {
1504 if (!GetResource(index)->ReportsV8MemoryStats())
1505 return false;
1506 values.is_v8_memory_valid = true;
1507 values.v8_memory_allocated = GetResource(index)->GetV8MemoryAllocated();
1508 values.v8_memory_used = GetResource(index)->GetV8MemoryUsed();
1510 return true;
1513 void TaskManagerModel::AddResourceProvider(ResourceProvider* provider) {
1514 DCHECK(provider);
1515 providers_.push_back(provider);
1518 TaskManagerModel::PerResourceValues& TaskManagerModel::GetPerResourceValues(
1519 int index) const {
1520 return per_resource_cache_[GetResource(index)];
1523 Resource* TaskManagerModel::GetResource(int index) const {
1524 CHECK_GE(index, 0);
1525 CHECK_LT(index, static_cast<int>(resources_.size()));
1526 return resources_[index];
1529 ////////////////////////////////////////////////////////////////////////////////
1530 // TaskManager class
1531 ////////////////////////////////////////////////////////////////////////////////
1532 // static
1533 void TaskManager::RegisterPrefs(PrefRegistrySimple* registry) {
1534 registry->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement);
1537 bool TaskManager::IsBrowserProcess(int index) const {
1538 // If some of the selection is out of bounds, ignore. This may happen when
1539 // killing a process that manages several pages.
1540 return index < model_->ResourceCount() &&
1541 model_->GetProcess(index) == base::GetCurrentProcessHandle();
1544 void TaskManager::KillProcess(int index) {
1545 base::ProcessHandle process = model_->GetProcess(index);
1546 DCHECK(process);
1547 if (process != base::GetCurrentProcessHandle())
1548 base::KillProcess(process, content::RESULT_CODE_KILLED, false);
1551 void TaskManager::ActivateProcess(int index) {
1552 // GetResourceWebContents returns a pointer to the relevant web contents for
1553 // the resource. If the index doesn't correspond to any web contents
1554 // (i.e. refers to the Browser process or a plugin), GetWebContents will
1555 // return NULL.
1556 WebContents* chosen_web_contents = model_->GetResourceWebContents(index);
1557 if (chosen_web_contents && chosen_web_contents->GetDelegate())
1558 chosen_web_contents->GetDelegate()->ActivateContents(chosen_web_contents);
1561 void TaskManager::AddResource(Resource* resource) {
1562 model_->AddResource(resource);
1565 void TaskManager::RemoveResource(Resource* resource) {
1566 model_->RemoveResource(resource);
1569 void TaskManager::OnWindowClosed() {
1570 model_->StopUpdating();
1573 void TaskManager::ModelChanged() {
1574 model_->ModelChanged();
1577 // static
1578 TaskManager* TaskManager::GetInstance() {
1579 return Singleton<TaskManager>::get();
1582 void TaskManager::OpenAboutMemory(chrome::HostDesktopType desktop_type) {
1583 chrome::NavigateParams params(
1584 ProfileManager::GetLastUsedProfileAllowedByPolicy(),
1585 GURL(chrome::kChromeUIMemoryURL),
1586 content::PAGE_TRANSITION_LINK);
1587 params.disposition = NEW_FOREGROUND_TAB;
1588 params.host_desktop_type = desktop_type;
1589 chrome::Navigate(&params);
1592 TaskManager::TaskManager()
1593 : model_(new TaskManagerModel(this)) {
1596 TaskManager::~TaskManager() {