Roll src/third_party/WebKit bf18a82:a9cee16 (svn 185297:185304)
[chromium-blink-merge.git] / chrome / browser / task_manager / task_manager.cc
blob3d7b02c3f20f40d3ad1ba17de88aa5da1a7b9900
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/prefs/pref_service.h"
12 #include "base/process/process_metrics.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/profiles/profile_window.h"
21 #include "chrome/browser/task_manager/background_information.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_information.h"
25 #include "chrome/browser/task_manager/guest_information.h"
26 #include "chrome/browser/task_manager/panel_information.h"
27 #include "chrome/browser/task_manager/printing_information.h"
28 #include "chrome/browser/task_manager/resource_provider.h"
29 #include "chrome/browser/task_manager/tab_contents_information.h"
30 #include "chrome/browser/task_manager/web_contents_resource_provider.h"
31 #include "chrome/browser/ui/browser_navigator.h"
32 #include "chrome/browser/ui/user_manager.h"
33 #include "chrome/common/pref_names.h"
34 #include "chrome/common/url_constants.h"
35 #include "chrome/grit/generated_resources.h"
36 #include "components/nacl/browser/nacl_browser.h"
37 #include "content/public/browser/browser_thread.h"
38 #include "content/public/browser/gpu_data_manager.h"
39 #include "content/public/browser/gpu_data_manager_observer.h"
40 #include "content/public/browser/resource_request_info.h"
41 #include "content/public/browser/web_contents.h"
42 #include "content/public/browser/web_contents_delegate.h"
43 #include "content/public/browser/worker_service.h"
44 #include "content/public/common/result_codes.h"
45 #include "extensions/browser/extension_system.h"
46 #include "third_party/icu/source/i18n/unicode/coll.h"
47 #include "ui/base/l10n/l10n_util.h"
48 #include "ui/base/resource/resource_bundle.h"
49 #include "ui/base/text/bytes_formatting.h"
50 #include "ui/gfx/image/image_skia.h"
51 #include "ui/resources/grit/ui_resources.h"
53 #if defined(OS_MACOSX)
54 #include "content/public/browser/browser_child_process_host.h"
55 #endif
57 using content::BrowserThread;
58 using content::ResourceRequestInfo;
59 using content::WebContents;
60 using task_manager::Resource;
61 using task_manager::ResourceProvider;
62 using task_manager::WebContentsInformation;
64 class Profile;
66 namespace {
68 template <class T>
69 int ValueCompare(T value1, T value2) {
70 if (value1 < value2)
71 return -1;
72 if (value1 == value2)
73 return 0;
74 return 1;
77 // Used when one or both of the results to compare are unavailable.
78 int OrderUnavailableValue(bool v1, bool v2) {
79 if (!v1 && !v2)
80 return 0;
81 return v1 ? 1 : -1;
84 // Used by TaskManagerModel::CompareValues(). See it for details of return
85 // value.
86 template <class T>
87 int ValueCompareMember(const TaskManagerModel* model,
88 bool (TaskManagerModel::*f)(int, T*) const,
89 int row1,
90 int row2) {
91 T value1;
92 T value2;
93 bool value1_valid = (model->*f)(row1, &value1);
94 bool value2_valid = (model->*f)(row2, &value2);
95 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
96 OrderUnavailableValue(value1_valid, value2_valid);
99 base::string16 FormatStatsSize(const blink::WebCache::ResourceTypeStat& stat) {
100 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
101 ui::FormatBytesWithUnits(stat.size, ui::DATA_UNITS_KIBIBYTE, false),
102 ui::FormatBytesWithUnits(stat.liveSize, ui::DATA_UNITS_KIBIBYTE, false));
105 // Returns true if the specified id should use the first value in the group.
106 bool IsSharedByGroup(int col_id) {
107 switch (col_id) {
108 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
109 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
110 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
111 case IDS_TASK_MANAGER_CPU_COLUMN:
112 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
113 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
114 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
115 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
116 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
117 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
118 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
119 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
120 return true;
121 default:
122 return false;
126 #if defined(OS_WIN)
127 void GetWinGDIHandles(base::ProcessHandle process,
128 size_t* current,
129 size_t* peak) {
130 *current = 0;
131 *peak = 0;
132 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
133 HANDLE current_process = GetCurrentProcess();
134 HANDLE process_with_query_rights;
135 if (DuplicateHandle(current_process, process, current_process,
136 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
137 false, 0)) {
138 *current = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS);
139 *peak = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS_PEAK);
140 CloseHandle(process_with_query_rights);
144 void GetWinUSERHandles(base::ProcessHandle process,
145 size_t* current,
146 size_t* peak) {
147 *current = 0;
148 *peak = 0;
149 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
150 HANDLE current_process = GetCurrentProcess();
151 HANDLE process_with_query_rights;
152 if (DuplicateHandle(current_process, process, current_process,
153 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
154 false, 0)) {
155 *current = GetGuiResources(process_with_query_rights, GR_USEROBJECTS);
156 *peak = GetGuiResources(process_with_query_rights, GR_USEROBJECTS_PEAK);
157 CloseHandle(process_with_query_rights);
160 #endif
162 } // namespace
164 class TaskManagerModelGpuDataManagerObserver
165 : public content::GpuDataManagerObserver {
166 public:
167 TaskManagerModelGpuDataManagerObserver() {
168 content::GpuDataManager::GetInstance()->AddObserver(this);
171 ~TaskManagerModelGpuDataManagerObserver() override {
172 content::GpuDataManager::GetInstance()->RemoveObserver(this);
175 static void NotifyVideoMemoryUsageStats(
176 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
177 TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats(
178 video_memory_usage_stats);
181 void OnVideoMemoryUsageStatsUpdate(const content::GPUVideoMemoryUsageStats&
182 video_memory_usage_stats) override {
183 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
184 NotifyVideoMemoryUsageStats(video_memory_usage_stats);
185 } else {
186 BrowserThread::PostTask(
187 BrowserThread::UI, FROM_HERE, base::Bind(
188 &TaskManagerModelGpuDataManagerObserver::
189 NotifyVideoMemoryUsageStats,
190 video_memory_usage_stats));
195 TaskManagerModel::PerResourceValues::PerResourceValues()
196 : is_title_valid(false),
197 is_profile_name_valid(false),
198 network_usage(0),
199 is_process_id_valid(false),
200 process_id(0),
201 is_webcore_stats_valid(false),
202 is_sqlite_memory_bytes_valid(false),
203 sqlite_memory_bytes(0),
204 is_v8_memory_valid(false),
205 v8_memory_allocated(0),
206 v8_memory_used(0) {}
208 TaskManagerModel::PerResourceValues::~PerResourceValues() {}
210 TaskManagerModel::PerProcessValues::PerProcessValues()
211 : is_cpu_usage_valid(false),
212 cpu_usage(0),
213 is_idle_wakeups_valid(false),
214 idle_wakeups(0),
215 is_private_and_shared_valid(false),
216 private_bytes(0),
217 shared_bytes(0),
218 is_physical_memory_valid(false),
219 physical_memory(0),
220 is_video_memory_valid(false),
221 video_memory(0),
222 video_memory_has_duplicates(false),
223 is_gdi_handles_valid(false),
224 gdi_handles(0),
225 gdi_handles_peak(0),
226 is_user_handles_valid(0),
227 user_handles(0),
228 user_handles_peak(0),
229 is_nacl_debug_stub_port_valid(false),
230 nacl_debug_stub_port(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 is_updating_byte_count_(false) {
244 AddResourceProvider(
245 new task_manager::BrowserProcessResourceProvider(task_manager));
246 AddResourceProvider(new task_manager::WebContentsResourceProvider(
247 task_manager,
248 scoped_ptr<WebContentsInformation>(
249 new task_manager::BackgroundInformation())));
250 AddResourceProvider(new task_manager::WebContentsResourceProvider(
251 task_manager,
252 scoped_ptr<WebContentsInformation>(
253 new task_manager::TabContentsInformation())));
254 #if defined(ENABLE_PRINT_PREVIEW)
255 AddResourceProvider(new task_manager::WebContentsResourceProvider(
256 task_manager,
257 scoped_ptr<WebContentsInformation>(
258 new task_manager::PrintingInformation())));
259 #endif // ENABLE_PRINT_PREVIEW
260 AddResourceProvider(new task_manager::WebContentsResourceProvider(
261 task_manager,
262 scoped_ptr<WebContentsInformation>(
263 new task_manager::PanelInformation())));
264 AddResourceProvider(
265 new task_manager::ChildProcessResourceProvider(task_manager));
266 AddResourceProvider(new task_manager::WebContentsResourceProvider(
267 task_manager,
268 scoped_ptr<WebContentsInformation>(
269 new task_manager::ExtensionInformation())));
270 AddResourceProvider(new task_manager::WebContentsResourceProvider(
271 task_manager,
272 scoped_ptr<WebContentsInformation>(
273 new task_manager::GuestInformation())));
276 void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) {
277 observer_list_.AddObserver(observer);
280 void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) {
281 observer_list_.RemoveObserver(observer);
284 int TaskManagerModel::ResourceCount() const {
285 return resources_.size();
288 int TaskManagerModel::GroupCount() const {
289 return group_map_.size();
292 int TaskManagerModel::GetNaClDebugStubPort(int index) const {
293 base::ProcessHandle handle = GetResource(index)->GetProcess();
294 PerProcessValues& values(per_process_cache_[handle]);
295 if (!values.is_nacl_debug_stub_port_valid) {
296 return nacl::kGdbDebugStubPortUnknown;
298 return values.nacl_debug_stub_port;
301 int64 TaskManagerModel::GetNetworkUsage(int index) const {
302 return GetNetworkUsage(GetResource(index));
305 double TaskManagerModel::GetCPUUsage(int index) const {
306 return GetCPUUsage(GetResource(index));
309 int TaskManagerModel::GetIdleWakeupsPerSecond(int index) const {
310 return GetIdleWakeupsPerSecond(GetResource(index));
313 base::ProcessId TaskManagerModel::GetProcessId(int index) const {
314 PerResourceValues& values(GetPerResourceValues(index));
315 if (!values.is_process_id_valid) {
316 values.is_process_id_valid = true;
317 values.process_id = base::GetProcId(GetResource(index)->GetProcess());
319 return values.process_id;
322 base::ProcessHandle TaskManagerModel::GetProcess(int index) const {
323 return GetResource(index)->GetProcess();
326 base::string16 TaskManagerModel::GetResourceById(int index, int col_id) const {
327 if (IsSharedByGroup(col_id) && !IsResourceFirstInGroup(index))
328 return base::string16();
330 switch (col_id) {
331 case IDS_TASK_MANAGER_TASK_COLUMN:
332 return GetResourceTitle(index);
334 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN:
335 return GetResourceProfileName(index);
337 case IDS_TASK_MANAGER_NET_COLUMN:
338 return GetResourceNetworkUsage(index);
340 case IDS_TASK_MANAGER_CPU_COLUMN:
341 return GetResourceCPUUsage(index);
343 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
344 return GetResourcePrivateMemory(index);
346 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
347 return GetResourceSharedMemory(index);
349 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
350 return GetResourcePhysicalMemory(index);
352 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
353 return GetResourceProcessId(index);
355 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN:
356 return GetResourceGDIHandles(index);
358 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN:
359 return GetResourceUSERHandles(index);
361 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN:
362 return GetResourceIdleWakeupsPerSecond(index);
364 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
365 return GetResourceWebCoreImageCacheSize(index);
367 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
368 return GetResourceWebCoreScriptsCacheSize(index);
370 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
371 return GetResourceWebCoreCSSCacheSize(index);
373 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
374 return GetResourceVideoMemory(index);
376 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
377 return GetResourceSqliteMemoryUsed(index);
379 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
380 return GetResourceV8MemoryAllocatedSize(index);
382 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
383 return GetResourceNaClDebugStubPort(index);
385 default:
386 NOTREACHED();
387 return base::string16();
391 const base::string16& TaskManagerModel::GetResourceTitle(int index) const {
392 PerResourceValues& values = GetPerResourceValues(index);
393 if (!values.is_title_valid) {
394 values.is_title_valid = true;
395 values.title = GetResource(index)->GetTitle();
397 return values.title;
400 const base::string16& TaskManagerModel::GetResourceProfileName(
401 int index) const {
402 PerResourceValues& values(GetPerResourceValues(index));
403 if (!values.is_profile_name_valid) {
404 values.is_profile_name_valid = true;
405 values.profile_name = GetResource(index)->GetProfileName();
407 return values.profile_name;
410 base::string16 TaskManagerModel::GetResourceNaClDebugStubPort(int index) const {
411 int port = GetNaClDebugStubPort(index);
412 if (port == nacl::kGdbDebugStubPortUnknown) {
413 return base::ASCIIToUTF16("Unknown");
414 } else if (port == nacl::kGdbDebugStubPortUnused) {
415 return base::ASCIIToUTF16("N/A");
416 } else {
417 return base::IntToString16(port);
421 base::string16 TaskManagerModel::GetResourceNetworkUsage(int index) const {
422 int64 net_usage = GetNetworkUsage(index);
423 if (net_usage == -1)
424 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
425 if (net_usage == 0)
426 return base::ASCIIToUTF16("0");
427 base::string16 net_byte = ui::FormatSpeed(net_usage);
428 // Force number string to have LTR directionality.
429 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte);
432 base::string16 TaskManagerModel::GetResourceCPUUsage(int index) const {
433 return base::UTF8ToUTF16(base::StringPrintf(
434 #if defined(OS_MACOSX)
435 // Activity Monitor shows %cpu with one decimal digit -- be
436 // consistent with that.
437 "%.1f",
438 #else
439 "%.0f",
440 #endif
441 GetCPUUsage(GetResource(index))));
444 base::string16 TaskManagerModel::GetResourcePrivateMemory(int index) const {
445 size_t private_mem;
446 if (!GetPrivateMemory(index, &private_mem))
447 return base::ASCIIToUTF16("N/A");
448 return GetMemCellText(private_mem);
451 base::string16 TaskManagerModel::GetResourceSharedMemory(int index) const {
452 size_t shared_mem;
453 if (!GetSharedMemory(index, &shared_mem))
454 return base::ASCIIToUTF16("N/A");
455 return GetMemCellText(shared_mem);
458 base::string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const {
459 size_t phys_mem;
460 GetPhysicalMemory(index, &phys_mem);
461 return GetMemCellText(phys_mem);
464 base::string16 TaskManagerModel::GetResourceProcessId(int index) const {
465 return base::IntToString16(GetProcessId(index));
468 base::string16 TaskManagerModel::GetResourceGDIHandles(int index) const {
469 size_t current, peak;
470 GetGDIHandles(index, &current, &peak);
471 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
472 base::IntToString16(current), base::IntToString16(peak));
475 base::string16 TaskManagerModel::GetResourceUSERHandles(int index) const {
476 size_t current, peak;
477 GetUSERHandles(index, &current, &peak);
478 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
479 base::IntToString16(current), base::IntToString16(peak));
482 base::string16 TaskManagerModel::GetResourceWebCoreImageCacheSize(
483 int index) const {
484 if (!CacheWebCoreStats(index))
485 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
486 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.images);
489 base::string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
490 int index) const {
491 if (!CacheWebCoreStats(index))
492 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
493 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.scripts);
496 base::string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize(
497 int index) const {
498 if (!CacheWebCoreStats(index))
499 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
500 return FormatStatsSize(
501 GetPerResourceValues(index).webcore_stats.cssStyleSheets);
504 base::string16 TaskManagerModel::GetResourceVideoMemory(int index) const {
505 size_t video_memory;
506 bool has_duplicates;
507 if (!GetVideoMemory(index, &video_memory, &has_duplicates) || !video_memory)
508 return base::ASCIIToUTF16("N/A");
509 if (has_duplicates) {
510 return GetMemCellText(video_memory) + base::ASCIIToUTF16("*");
512 return GetMemCellText(video_memory);
515 base::string16 TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const {
516 size_t bytes = 0;
517 if (!GetSqliteMemoryUsedBytes(index, &bytes))
518 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
519 return GetMemCellText(bytes);
522 base::string16 TaskManagerModel::GetResourceIdleWakeupsPerSecond(int index)
523 const {
524 return base::FormatNumber(GetIdleWakeupsPerSecond(GetResource(index)));
527 base::string16 TaskManagerModel::GetResourceV8MemoryAllocatedSize(
528 int index) const {
529 size_t memory_allocated = 0, memory_used = 0;
530 if (!GetV8MemoryUsed(index, &memory_used) ||
531 !GetV8Memory(index, &memory_allocated))
532 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
533 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
534 ui::FormatBytesWithUnits(memory_allocated,
535 ui::DATA_UNITS_KIBIBYTE,
536 false),
537 ui::FormatBytesWithUnits(memory_used,
538 ui::DATA_UNITS_KIBIBYTE,
539 false));
542 bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const {
543 *result = 0;
544 base::ProcessHandle handle = GetResource(index)->GetProcess();
545 if (!CachePrivateAndSharedMemory(handle))
546 return false;
547 *result = per_process_cache_[handle].private_bytes;
548 return true;
551 bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const {
552 *result = 0;
553 base::ProcessHandle handle = GetResource(index)->GetProcess();
554 if (!CachePrivateAndSharedMemory(handle))
555 return false;
556 *result = per_process_cache_[handle].shared_bytes;
557 return true;
560 bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const {
561 *result = 0;
563 base::ProcessHandle handle = GetResource(index)->GetProcess();
564 PerProcessValues& values(per_process_cache_[handle]);
566 if (!values.is_physical_memory_valid) {
567 base::WorkingSetKBytes ws_usage;
568 MetricsMap::const_iterator iter = metrics_map_.find(handle);
569 if (iter == metrics_map_.end() ||
570 !iter->second->GetWorkingSetKBytes(&ws_usage))
571 return false;
573 values.is_physical_memory_valid = true;
574 #if defined(OS_LINUX)
575 // On Linux private memory is also resident. Just use it.
576 values.physical_memory = ws_usage.priv * 1024;
577 #else
578 // Memory = working_set.private + working_set.shareable.
579 // We exclude the shared memory.
580 values.physical_memory = iter->second->GetWorkingSetSize();
581 values.physical_memory -= ws_usage.shared * 1024;
582 #endif
584 *result = values.physical_memory;
585 return true;
588 void TaskManagerModel::GetGDIHandles(int index,
589 size_t* current,
590 size_t* peak) const {
591 *current = 0;
592 *peak = 0;
593 #if defined(OS_WIN)
594 base::ProcessHandle handle = GetResource(index)->GetProcess();
595 PerProcessValues& values(per_process_cache_[handle]);
597 if (!values.is_gdi_handles_valid) {
598 GetWinGDIHandles(GetResource(index)->GetProcess(),
599 &values.gdi_handles,
600 &values.gdi_handles_peak);
601 values.is_gdi_handles_valid = true;
603 *current = values.gdi_handles;
604 *peak = values.gdi_handles_peak;
605 #endif
608 void TaskManagerModel::GetUSERHandles(int index,
609 size_t* current,
610 size_t* peak) const {
611 *current = 0;
612 *peak = 0;
613 #if defined(OS_WIN)
614 base::ProcessHandle handle = GetResource(index)->GetProcess();
615 PerProcessValues& values(per_process_cache_[handle]);
617 if (!values.is_user_handles_valid) {
618 GetWinUSERHandles(GetResource(index)->GetProcess(),
619 &values.user_handles,
620 &values.user_handles_peak);
621 values.is_user_handles_valid = true;
623 *current = values.user_handles;
624 *peak = values.user_handles_peak;
625 #endif
628 bool TaskManagerModel::GetWebCoreCacheStats(
629 int index,
630 blink::WebCache::ResourceTypeStats* result) const {
631 if (!CacheWebCoreStats(index))
632 return false;
633 *result = GetPerResourceValues(index).webcore_stats;
634 return true;
637 bool TaskManagerModel::GetVideoMemory(int index,
638 size_t* video_memory,
639 bool* has_duplicates) const {
640 *video_memory = 0;
641 *has_duplicates = false;
643 base::ProcessId pid = GetProcessId(index);
644 PerProcessValues& values(
645 per_process_cache_[GetResource(index)->GetProcess()]);
646 if (!values.is_video_memory_valid) {
647 content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i =
648 video_memory_usage_stats_.process_map.find(pid);
649 if (i == video_memory_usage_stats_.process_map.end())
650 return false;
651 values.is_video_memory_valid = true;
652 values.video_memory = i->second.video_memory;
653 values.video_memory_has_duplicates = i->second.has_duplicates;
655 *video_memory = values.video_memory;
656 *has_duplicates = values.video_memory_has_duplicates;
657 return true;
660 bool TaskManagerModel::GetSqliteMemoryUsedBytes(
661 int index,
662 size_t* result) const {
663 *result = 0;
664 PerResourceValues& values(GetPerResourceValues(index));
665 if (!values.is_sqlite_memory_bytes_valid) {
666 if (!GetResource(index)->ReportsSqliteMemoryUsed())
667 return false;
668 values.is_sqlite_memory_bytes_valid = true;
669 values.sqlite_memory_bytes = GetResource(index)->SqliteMemoryUsedBytes();
671 *result = values.sqlite_memory_bytes;
672 return true;
675 bool TaskManagerModel::GetV8Memory(int index, size_t* result) const {
676 *result = 0;
677 if (!CacheV8Memory(index))
678 return false;
679 *result = GetPerResourceValues(index).v8_memory_allocated;
680 return true;
683 bool TaskManagerModel::GetV8MemoryUsed(int index, size_t* result) const {
684 *result = 0;
685 if (!CacheV8Memory(index))
686 return false;
687 *result = GetPerResourceValues(index).v8_memory_used;
688 return true;
691 bool TaskManagerModel::CanActivate(int index) const {
692 CHECK_LT(index, ResourceCount());
693 return GetResourceWebContents(index) != NULL;
696 bool TaskManagerModel::IsResourceFirstInGroup(int index) const {
697 Resource* resource = GetResource(index);
698 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
699 DCHECK(iter != group_map_.end());
700 const ResourceList& group = iter->second;
701 return (group[0] == resource);
704 bool TaskManagerModel::IsResourceLastInGroup(int index) const {
705 Resource* resource = GetResource(index);
706 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
707 DCHECK(iter != group_map_.end());
708 const ResourceList& group = iter->second;
709 return (group.back() == resource);
712 gfx::ImageSkia TaskManagerModel::GetResourceIcon(int index) const {
713 gfx::ImageSkia icon = GetResource(index)->GetIcon();
714 if (!icon.isNull())
715 return icon;
717 static const gfx::ImageSkia* default_icon =
718 ResourceBundle::GetSharedInstance().
719 GetNativeImageNamed(IDR_DEFAULT_FAVICON).ToImageSkia();
720 return *default_icon;
723 TaskManagerModel::GroupRange
724 TaskManagerModel::GetGroupRangeForResource(int index) const {
725 Resource* resource = GetResource(index);
726 GroupMap::const_iterator group_iter =
727 group_map_.find(resource->GetProcess());
728 DCHECK(group_iter != group_map_.end());
729 const ResourceList& group = group_iter->second;
730 if (group.size() == 1) {
731 return std::make_pair(index, 1);
732 } else {
733 for (int i = index; i >= 0; --i) {
734 if (GetResource(i) == group[0])
735 return std::make_pair(i, group.size());
737 NOTREACHED();
738 return std::make_pair(-1, -1);
742 int TaskManagerModel::GetGroupIndexForResource(int index) const {
743 int group_index = -1;
744 for (int i = 0; i <= index; ++i) {
745 if (IsResourceFirstInGroup(i))
746 group_index++;
749 DCHECK_NE(group_index, -1);
750 return group_index;
753 int TaskManagerModel::GetResourceIndexForGroup(int group_index,
754 int index_in_group) const {
755 int group_count = -1;
756 int count_in_group = -1;
757 for (int i = 0; i < ResourceCount(); ++i) {
758 if (IsResourceFirstInGroup(i))
759 group_count++;
761 if (group_count == group_index) {
762 count_in_group++;
763 if (count_in_group == index_in_group)
764 return i;
765 } else if (group_count > group_index) {
766 break;
770 NOTREACHED();
771 return -1;
774 int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const {
775 CHECK(row1 < ResourceCount() && row2 < ResourceCount());
776 switch (col_id) {
777 case IDS_TASK_MANAGER_TASK_COLUMN: {
778 static icu::Collator* collator = NULL;
779 if (!collator) {
780 UErrorCode create_status = U_ZERO_ERROR;
781 collator = icu::Collator::createInstance(create_status);
782 if (!U_SUCCESS(create_status)) {
783 collator = NULL;
784 NOTREACHED();
787 const base::string16& title1 = GetResourceTitle(row1);
788 const base::string16& title2 = GetResourceTitle(row2);
789 UErrorCode compare_status = U_ZERO_ERROR;
790 UCollationResult compare_result = collator->compare(
791 static_cast<const UChar*>(title1.c_str()),
792 static_cast<int>(title1.length()),
793 static_cast<const UChar*>(title2.c_str()),
794 static_cast<int>(title2.length()),
795 compare_status);
796 DCHECK(U_SUCCESS(compare_status));
797 return compare_result;
800 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN: {
801 const base::string16& profile1 = GetResourceProfileName(row1);
802 const base::string16& profile2 = GetResourceProfileName(row2);
803 return profile1.compare(0, profile1.length(), profile2, 0,
804 profile2.length());
807 case IDS_TASK_MANAGER_NET_COLUMN:
808 return ValueCompare(GetNetworkUsage(GetResource(row1)),
809 GetNetworkUsage(GetResource(row2)));
811 case IDS_TASK_MANAGER_CPU_COLUMN:
812 return ValueCompare(GetCPUUsage(GetResource(row1)),
813 GetCPUUsage(GetResource(row2)));
815 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
816 return ValueCompareMember(
817 this, &TaskManagerModel::GetPrivateMemory, row1, row2);
819 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
820 return ValueCompareMember(
821 this, &TaskManagerModel::GetSharedMemory, row1, row2);
823 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
824 return ValueCompareMember(
825 this, &TaskManagerModel::GetPhysicalMemory, row1, row2);
827 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
828 return ValueCompare(GetNaClDebugStubPort(row1),
829 GetNaClDebugStubPort(row2));
831 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
832 return ValueCompare(GetProcessId(row1), GetProcessId(row2));
834 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN: {
835 size_t current1, peak1;
836 size_t current2, peak2;
837 GetGDIHandles(row1, &current1, &peak1);
838 GetGDIHandles(row2, &current2, &peak2);
839 return ValueCompare(current1, current2);
842 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN: {
843 size_t current1, peak1;
844 size_t current2, peak2;
845 GetUSERHandles(row1, &current1, &peak1);
846 GetUSERHandles(row2, &current2, &peak2);
847 return ValueCompare(current1, current2);
850 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN:
851 return ValueCompare(GetIdleWakeupsPerSecond(row1),
852 GetIdleWakeupsPerSecond(row2));
854 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
855 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
856 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: {
857 bool row1_stats_valid = CacheWebCoreStats(row1);
858 bool row2_stats_valid = CacheWebCoreStats(row2);
859 if (row1_stats_valid && row2_stats_valid) {
860 const blink::WebCache::ResourceTypeStats& stats1(
861 GetPerResourceValues(row1).webcore_stats);
862 const blink::WebCache::ResourceTypeStats& stats2(
863 GetPerResourceValues(row2).webcore_stats);
864 switch (col_id) {
865 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
866 return ValueCompare(stats1.images.size, stats2.images.size);
867 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
868 return ValueCompare(stats1.scripts.size, stats2.scripts.size);
869 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
870 return ValueCompare(stats1.cssStyleSheets.size,
871 stats2.cssStyleSheets.size);
872 default:
873 NOTREACHED();
874 return 0;
877 return OrderUnavailableValue(row1_stats_valid, row2_stats_valid);
880 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN: {
881 size_t value1;
882 size_t value2;
883 bool has_duplicates;
884 bool value1_valid = GetVideoMemory(row1, &value1, &has_duplicates);
885 bool value2_valid = GetVideoMemory(row2, &value2, &has_duplicates);
886 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
887 OrderUnavailableValue(value1_valid, value2_valid);
890 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
891 return ValueCompareMember(
892 this, &TaskManagerModel::GetV8Memory, row1, row2);
894 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
895 return ValueCompareMember(
896 this, &TaskManagerModel::GetSqliteMemoryUsedBytes, row1, row2);
898 default:
899 NOTREACHED();
900 break;
902 return 0;
905 int TaskManagerModel::GetUniqueChildProcessId(int index) const {
906 return GetResource(index)->GetUniqueChildProcessId();
909 Resource::Type TaskManagerModel::GetResourceType(int index) const {
910 return GetResource(index)->GetType();
913 WebContents* TaskManagerModel::GetResourceWebContents(int index) const {
914 return GetResource(index)->GetWebContents();
917 void TaskManagerModel::AddResource(Resource* resource) {
918 base::ProcessHandle process = resource->GetProcess();
920 GroupMap::iterator group_iter = group_map_.find(process);
921 int new_entry_index = 0;
922 if (group_iter == group_map_.end()) {
923 group_map_.insert(make_pair(process, ResourceList(1, resource)));
925 // Not part of a group, just put at the end of the list.
926 resources_.push_back(resource);
927 new_entry_index = static_cast<int>(resources_.size() - 1);
928 } else {
929 ResourceList* group_entries = &(group_iter->second);
930 group_entries->push_back(resource);
932 // Insert the new entry right after the last entry of its group.
933 ResourceList::iterator iter =
934 std::find(resources_.begin(),
935 resources_.end(),
936 (*group_entries)[group_entries->size() - 2]);
937 DCHECK(iter != resources_.end());
938 new_entry_index = static_cast<int>(iter - resources_.begin()) + 1;
939 resources_.insert(++iter, resource);
942 // Create the ProcessMetrics for this process if needed (not in map).
943 if (metrics_map_.find(process) == metrics_map_.end()) {
944 base::ProcessMetrics* pm =
945 #if !defined(OS_MACOSX)
946 base::ProcessMetrics::CreateProcessMetrics(process);
947 #else
948 base::ProcessMetrics::CreateProcessMetrics(
949 process, content::BrowserChildProcessHost::GetPortProvider());
950 #endif
952 metrics_map_[process] = pm;
955 // Notify the table that the contents have changed for it to redraw.
956 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
957 OnItemsAdded(new_entry_index, 1));
960 void TaskManagerModel::RemoveResource(Resource* resource) {
961 base::ProcessHandle process = resource->GetProcess();
963 // Find the associated group.
964 GroupMap::iterator group_iter = group_map_.find(process);
965 DCHECK(group_iter != group_map_.end());
966 if (group_iter == group_map_.end())
967 return;
968 ResourceList& group_entries = group_iter->second;
970 // Remove the entry from the group map.
971 ResourceList::iterator iter = std::find(group_entries.begin(),
972 group_entries.end(),
973 resource);
974 DCHECK(iter != group_entries.end());
975 if (iter != group_entries.end())
976 group_entries.erase(iter);
978 // If there are no more entries for that process, do the clean-up.
979 if (group_entries.empty()) {
980 group_map_.erase(group_iter);
982 // Nobody is using this process, we don't need the process metrics anymore.
983 MetricsMap::iterator pm_iter = metrics_map_.find(process);
984 DCHECK(pm_iter != metrics_map_.end());
985 if (pm_iter != metrics_map_.end()) {
986 delete pm_iter->second;
987 metrics_map_.erase(process);
991 // Remove the entry from the model list.
992 iter = std::find(resources_.begin(), resources_.end(), resource);
993 DCHECK(iter != resources_.end());
994 if (iter != resources_.end()) {
995 int index = static_cast<int>(iter - resources_.begin());
996 // Notify the observers that the contents will change.
997 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
998 OnItemsToBeRemoved(index, 1));
999 // Now actually remove the entry from the model list.
1000 resources_.erase(iter);
1001 // Notify the table that the contents have changed.
1002 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1003 OnItemsRemoved(index, 1));
1006 // Remove the entry from the network maps.
1007 ResourceValueMap::iterator net_iter =
1008 current_byte_count_map_.find(resource);
1009 if (net_iter != current_byte_count_map_.end())
1010 current_byte_count_map_.erase(net_iter);
1013 void TaskManagerModel::StartUpdating() {
1014 // Multiple StartUpdating requests may come in, and we only need to take
1015 // action the first time.
1016 update_requests_++;
1017 if (update_requests_ > 1)
1018 return;
1019 DCHECK_EQ(1, update_requests_);
1020 DCHECK_NE(TASK_PENDING, update_state_);
1022 // If update_state_ is STOPPING, it means a task is still pending. Setting
1023 // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()).
1024 if (update_state_ == IDLE) {
1025 base::MessageLoop::current()->PostTask(
1026 FROM_HERE,
1027 base::Bind(&TaskManagerModel::RefreshCallback, this));
1029 update_state_ = TASK_PENDING;
1031 // Notify resource providers that we are updating.
1032 StartListening();
1034 if (!resources_.empty()) {
1035 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1036 OnReadyPeriodicalUpdate());
1039 BrowserThread::PostTask(
1040 BrowserThread::IO, FROM_HERE,
1041 base::Bind(&TaskManagerModel::SetUpdatingByteCount, this, true));
1044 void TaskManagerModel::StopUpdating() {
1045 // Don't actually stop updating until we have heard as many calls as those
1046 // to StartUpdating.
1047 update_requests_--;
1048 if (update_requests_ > 0)
1049 return;
1050 // Make sure that update_requests_ cannot go negative.
1051 CHECK_EQ(0, update_requests_);
1052 DCHECK_EQ(TASK_PENDING, update_state_);
1053 update_state_ = STOPPING;
1055 // Notify resource providers that we are done updating.
1056 StopListening();
1058 BrowserThread::PostTask(
1059 BrowserThread::IO, FROM_HERE,
1060 base::Bind(&TaskManagerModel::SetUpdatingByteCount, this, false));
1063 void TaskManagerModel::StartListening() {
1064 // Multiple StartListening requests may come in and we only need to take
1065 // action the first time.
1066 listen_requests_++;
1067 if (listen_requests_ > 1)
1068 return;
1069 DCHECK_EQ(1, listen_requests_);
1071 // Notify resource providers that we should start listening to events.
1072 for (ResourceProviderList::iterator iter = providers_.begin();
1073 iter != providers_.end(); ++iter) {
1074 (*iter)->StartUpdating();
1078 void TaskManagerModel::StopListening() {
1079 // Don't actually stop listening until we have heard as many calls as those
1080 // to StartListening.
1081 listen_requests_--;
1082 if (listen_requests_ > 0)
1083 return;
1085 DCHECK_EQ(0, listen_requests_);
1087 // Notify resource providers that we are done listening.
1088 for (ResourceProviderList::const_iterator iter = providers_.begin();
1089 iter != providers_.end(); ++iter) {
1090 (*iter)->StopUpdating();
1093 // Must clear the resources before the next attempt to start listening.
1094 Clear();
1097 void TaskManagerModel::Clear() {
1098 int size = ResourceCount();
1099 if (size > 0) {
1100 resources_.clear();
1102 // Clear the groups.
1103 group_map_.clear();
1105 // Clear the process related info.
1106 STLDeleteValues(&metrics_map_);
1108 // Clear the network maps.
1109 current_byte_count_map_.clear();
1111 per_resource_cache_.clear();
1112 per_process_cache_.clear();
1114 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1115 OnItemsRemoved(0, size));
1119 void TaskManagerModel::ModelChanged() {
1120 // Notify the table that the contents have changed for it to redraw.
1121 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, OnModelChanged());
1124 void TaskManagerModel::Refresh() {
1125 per_resource_cache_.clear();
1126 per_process_cache_.clear();
1128 #if !defined(DISABLE_NACL)
1129 nacl::NaClBrowser* nacl_browser = nacl::NaClBrowser::GetInstance();
1130 #endif // !defined(DISABLE_NACL)
1132 // Compute the CPU usage values and check if NaCl GDB debug stub port is
1133 // known.
1134 // Note that we compute the CPU usage for all resources (instead of doing it
1135 // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last
1136 // time it was called, and not calling it everytime would skew the value the
1137 // next time it is retrieved (as it would be for more than 1 cycle).
1138 // The same is true for idle wakeups.
1139 for (ResourceList::iterator iter = resources_.begin();
1140 iter != resources_.end(); ++iter) {
1141 base::ProcessHandle process = (*iter)->GetProcess();
1142 PerProcessValues& values(per_process_cache_[process]);
1143 #if !defined(DISABLE_NACL)
1144 // Debug stub port doesn't change once known.
1145 if (!values.is_nacl_debug_stub_port_valid) {
1146 values.nacl_debug_stub_port = nacl_browser->GetProcessGdbDebugStubPort(
1147 (*iter)->GetUniqueChildProcessId());
1148 if (values.nacl_debug_stub_port != nacl::kGdbDebugStubPortUnknown) {
1149 values.is_nacl_debug_stub_port_valid = true;
1152 #endif // !defined(DISABLE_NACL)
1153 if (values.is_cpu_usage_valid && values.is_idle_wakeups_valid)
1154 continue;
1155 MetricsMap::iterator metrics_iter = metrics_map_.find(process);
1156 DCHECK(metrics_iter != metrics_map_.end());
1157 if (!values.is_cpu_usage_valid) {
1158 values.is_cpu_usage_valid = true;
1159 values.cpu_usage = metrics_iter->second->GetCPUUsage();
1161 #if defined(OS_MACOSX) || defined(OS_LINUX)
1162 // TODO(port): Implement GetIdleWakeupsPerSecond() on other platforms,
1163 // crbug.com/120488
1164 if (!values.is_idle_wakeups_valid) {
1165 values.is_idle_wakeups_valid = true;
1166 values.idle_wakeups = metrics_iter->second->GetIdleWakeupsPerSecond();
1168 #endif // defined(OS_MACOSX) || defined(OS_LINUX)
1171 // Send a request to refresh GPU memory consumption values
1172 RefreshVideoMemoryUsageStats();
1174 // Compute the new network usage values.
1175 base::TimeDelta update_time =
1176 base::TimeDelta::FromMilliseconds(kUpdateTimeMs);
1177 for (ResourceValueMap::iterator iter = current_byte_count_map_.begin();
1178 iter != current_byte_count_map_.end(); ++iter) {
1179 PerResourceValues* values = &(per_resource_cache_[iter->first]);
1180 if (update_time > base::TimeDelta::FromSeconds(1))
1181 values->network_usage = iter->second / update_time.InSeconds();
1182 else
1183 values->network_usage = iter->second * (1 / update_time.InSeconds());
1185 // Then we reset the current byte count.
1186 iter->second = 0;
1189 // Let resources update themselves if they need to.
1190 for (ResourceList::iterator iter = resources_.begin();
1191 iter != resources_.end(); ++iter) {
1192 (*iter)->Refresh();
1195 if (!resources_.empty()) {
1196 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1197 OnItemsChanged(0, ResourceCount()));
1201 void TaskManagerModel::NotifyResourceTypeStats(
1202 base::ProcessId renderer_id,
1203 const blink::WebCache::ResourceTypeStats& stats) {
1204 for (ResourceList::iterator it = resources_.begin();
1205 it != resources_.end(); ++it) {
1206 if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
1207 (*it)->NotifyResourceTypeStats(stats);
1212 void TaskManagerModel::NotifyVideoMemoryUsageStats(
1213 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
1214 DCHECK(pending_video_memory_usage_stats_update_);
1215 video_memory_usage_stats_ = video_memory_usage_stats;
1216 pending_video_memory_usage_stats_update_ = false;
1219 void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id,
1220 size_t v8_memory_allocated,
1221 size_t v8_memory_used) {
1222 for (ResourceList::iterator it = resources_.begin();
1223 it != resources_.end(); ++it) {
1224 if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
1225 (*it)->NotifyV8HeapStats(v8_memory_allocated, v8_memory_used);
1230 void TaskManagerModel::NotifyBytesRead(const net::URLRequest& request,
1231 int byte_count) {
1232 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1233 if (!is_updating_byte_count_)
1234 return;
1236 // Only net::URLRequestJob instances created by the ResourceDispatcherHost
1237 // have an associated ResourceRequestInfo and a render frame associated.
1238 // All other jobs will have -1 returned for the render process child and
1239 // routing ids - the jobs may still match a resource based on their origin id,
1240 // otherwise BytesRead() will attribute the activity to the Browser resource.
1241 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request);
1242 int child_id = -1, route_id = -1;
1243 if (info)
1244 info->GetAssociatedRenderFrame(&child_id, &route_id);
1246 // Get the origin PID of the request's originator. This will only be set for
1247 // plugins - for renderer or browser initiated requests it will be zero.
1248 int origin_pid = 0;
1249 if (info)
1250 origin_pid = info->GetOriginPID();
1252 if (bytes_read_buffer_.empty()) {
1253 base::MessageLoop::current()->PostDelayedTask(
1254 FROM_HERE,
1255 base::Bind(&TaskManagerModel::NotifyMultipleBytesRead, this),
1256 base::TimeDelta::FromSeconds(1));
1259 bytes_read_buffer_.push_back(
1260 BytesReadParam(origin_pid, child_id, route_id, byte_count));
1263 // This is called on the UI thread.
1264 void TaskManagerModel::NotifyDataReady() {
1265 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1266 for (size_t i = 0; i < on_data_ready_callbacks_.size(); ++i) {
1267 if (!on_data_ready_callbacks_[i].is_null())
1268 on_data_ready_callbacks_[i].Run();
1271 on_data_ready_callbacks_.clear();
1274 void TaskManagerModel::RegisterOnDataReadyCallback(
1275 const base::Closure& callback) {
1276 on_data_ready_callbacks_.push_back(callback);
1279 TaskManagerModel::~TaskManagerModel() {
1280 on_data_ready_callbacks_.clear();
1283 void TaskManagerModel::RefreshCallback() {
1284 DCHECK_NE(IDLE, update_state_);
1286 if (update_state_ == STOPPING) {
1287 // We have been asked to stop.
1288 update_state_ = IDLE;
1289 return;
1292 Refresh();
1294 // Schedule the next update.
1295 base::MessageLoop::current()->PostDelayedTask(
1296 FROM_HERE,
1297 base::Bind(&TaskManagerModel::RefreshCallback, this),
1298 base::TimeDelta::FromMilliseconds(kUpdateTimeMs));
1301 void TaskManagerModel::RefreshVideoMemoryUsageStats() {
1302 if (pending_video_memory_usage_stats_update_)
1303 return;
1305 if (!video_memory_usage_stats_observer_.get()) {
1306 video_memory_usage_stats_observer_.reset(
1307 new TaskManagerModelGpuDataManagerObserver());
1309 pending_video_memory_usage_stats_update_ = true;
1310 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate();
1313 int64 TaskManagerModel::GetNetworkUsageForResource(Resource* resource) const {
1314 // Returns default of 0 if no network usage.
1315 return per_resource_cache_[resource].network_usage;
1318 void TaskManagerModel::BytesRead(BytesReadParam param) {
1319 if (update_state_ != TASK_PENDING || listen_requests_ == 0) {
1320 // A notification sneaked in while we were stopping the updating, just
1321 // ignore it.
1322 return;
1325 // TODO(jcampan): this should be improved once we have a better way of
1326 // linking a network notification back to the object that initiated it.
1327 Resource* resource = NULL;
1328 for (ResourceProviderList::iterator iter = providers_.begin();
1329 iter != providers_.end(); ++iter) {
1330 resource = (*iter)->GetResource(param.origin_pid,
1331 param.child_id,
1332 param.route_id);
1333 if (resource)
1334 break;
1337 if (resource == NULL) {
1338 // We can't match a resource to the notification. That might mean the
1339 // tab that started a download was closed, or the request may have had
1340 // no originating resource associated with it in the first place.
1341 // We attribute orphaned/unaccounted activity to the Browser process.
1342 CHECK(param.origin_pid || (param.child_id != -1));
1343 param.origin_pid = 0;
1344 param.child_id = param.route_id = -1;
1345 BytesRead(param);
1346 return;
1349 // We do support network usage, mark the resource as such so it can report 0
1350 // instead of N/A.
1351 if (!resource->SupportNetworkUsage())
1352 resource->SetSupportNetworkUsage();
1354 ResourceValueMap::const_iterator iter_res =
1355 current_byte_count_map_.find(resource);
1356 if (iter_res == current_byte_count_map_.end())
1357 current_byte_count_map_[resource] = param.byte_count;
1358 else
1359 current_byte_count_map_[resource] = iter_res->second + param.byte_count;
1362 void TaskManagerModel::MultipleBytesRead(
1363 const std::vector<BytesReadParam>* params) {
1364 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1365 for (std::vector<BytesReadParam>::const_iterator it = params->begin();
1366 it != params->end(); ++it) {
1367 BytesRead(*it);
1371 void TaskManagerModel::NotifyMultipleBytesRead() {
1372 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1373 DCHECK(!bytes_read_buffer_.empty());
1375 std::vector<BytesReadParam>* bytes_read_buffer =
1376 new std::vector<BytesReadParam>;
1377 bytes_read_buffer_.swap(*bytes_read_buffer);
1378 BrowserThread::PostTask(
1379 BrowserThread::UI, FROM_HERE,
1380 base::Bind(&TaskManagerModel::MultipleBytesRead, this,
1381 base::Owned(bytes_read_buffer)));
1384 void TaskManagerModel::SetUpdatingByteCount(bool is_updating) {
1385 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1386 is_updating_byte_count_ = is_updating;
1389 int64 TaskManagerModel::GetNetworkUsage(Resource* resource) const {
1390 int64 net_usage = GetNetworkUsageForResource(resource);
1391 if (net_usage == 0 && !resource->SupportNetworkUsage())
1392 return -1;
1393 return net_usage;
1396 double TaskManagerModel::GetCPUUsage(Resource* resource) const {
1397 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]);
1398 // Returns 0 if not valid, which is fine.
1399 return values.cpu_usage;
1402 int TaskManagerModel::GetIdleWakeupsPerSecond(Resource* resource) const {
1403 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]);
1404 // Returns 0 if not valid, which is fine.
1405 return values.idle_wakeups;
1408 base::string16 TaskManagerModel::GetMemCellText(int64 number) const {
1409 #if !defined(OS_MACOSX)
1410 base::string16 str = base::FormatNumber(number / 1024);
1412 // Adjust number string if necessary.
1413 base::i18n::AdjustStringForLocaleDirection(&str);
1414 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT, str);
1415 #else
1416 // System expectation is to show "100 kB", "200 MB", etc.
1417 // TODO(thakis): Switch to metric units (as opposed to powers of two).
1418 return ui::FormatBytes(number);
1419 #endif
1422 bool TaskManagerModel::CachePrivateAndSharedMemory(
1423 base::ProcessHandle handle) const {
1424 PerProcessValues& values(per_process_cache_[handle]);
1425 if (values.is_private_and_shared_valid)
1426 return true;
1428 MetricsMap::const_iterator iter = metrics_map_.find(handle);
1429 if (iter == metrics_map_.end() ||
1430 !iter->second->GetMemoryBytes(&values.private_bytes,
1431 &values.shared_bytes)) {
1432 return false;
1435 values.is_private_and_shared_valid = true;
1436 return true;
1439 bool TaskManagerModel::CacheWebCoreStats(int index) const {
1440 PerResourceValues& values(GetPerResourceValues(index));
1441 if (!values.is_webcore_stats_valid) {
1442 if (!GetResource(index)->ReportsCacheStats())
1443 return false;
1444 values.is_webcore_stats_valid = true;
1445 values.webcore_stats = GetResource(index)->GetWebCoreCacheStats();
1447 return true;
1450 bool TaskManagerModel::CacheV8Memory(int index) const {
1451 PerResourceValues& values(GetPerResourceValues(index));
1452 if (!values.is_v8_memory_valid) {
1453 if (!GetResource(index)->ReportsV8MemoryStats())
1454 return false;
1455 values.is_v8_memory_valid = true;
1456 values.v8_memory_allocated = GetResource(index)->GetV8MemoryAllocated();
1457 values.v8_memory_used = GetResource(index)->GetV8MemoryUsed();
1459 return true;
1462 void TaskManagerModel::AddResourceProvider(ResourceProvider* provider) {
1463 DCHECK(provider);
1464 providers_.push_back(provider);
1467 TaskManagerModel::PerResourceValues& TaskManagerModel::GetPerResourceValues(
1468 int index) const {
1469 return per_resource_cache_[GetResource(index)];
1472 Resource* TaskManagerModel::GetResource(int index) const {
1473 CHECK_GE(index, 0);
1474 CHECK_LT(index, static_cast<int>(resources_.size()));
1475 return resources_[index];
1478 ////////////////////////////////////////////////////////////////////////////////
1479 // TaskManager class
1480 ////////////////////////////////////////////////////////////////////////////////
1481 // static
1482 void TaskManager::RegisterPrefs(PrefRegistrySimple* registry) {
1483 registry->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement);
1486 bool TaskManager::IsBrowserProcess(int index) const {
1487 // If some of the selection is out of bounds, ignore. This may happen when
1488 // killing a process that manages several pages.
1489 return index < model_->ResourceCount() &&
1490 model_->GetProcess(index) == base::GetCurrentProcessHandle();
1493 void TaskManager::KillProcess(int index) {
1494 base::ProcessHandle process = model_->GetProcess(index);
1495 DCHECK(process);
1496 if (process != base::GetCurrentProcessHandle())
1497 base::KillProcess(process, content::RESULT_CODE_KILLED, false);
1500 void TaskManager::ActivateProcess(int index) {
1501 // GetResourceWebContents returns a pointer to the relevant web contents for
1502 // the resource. If the index doesn't correspond to any web contents
1503 // (i.e. refers to the Browser process or a plugin), GetWebContents will
1504 // return NULL.
1505 WebContents* chosen_web_contents = model_->GetResourceWebContents(index);
1506 if (chosen_web_contents && chosen_web_contents->GetDelegate())
1507 chosen_web_contents->GetDelegate()->ActivateContents(chosen_web_contents);
1510 void TaskManager::AddResource(Resource* resource) {
1511 model_->AddResource(resource);
1514 void TaskManager::RemoveResource(Resource* resource) {
1515 model_->RemoveResource(resource);
1518 void TaskManager::OnWindowClosed() {
1519 model_->StopUpdating();
1522 void TaskManager::ModelChanged() {
1523 model_->ModelChanged();
1526 // static
1527 TaskManager* TaskManager::GetInstance() {
1528 return Singleton<TaskManager>::get();
1531 void TaskManager::OpenAboutMemory(chrome::HostDesktopType desktop_type) {
1532 Profile* profile = ProfileManager::GetLastUsedProfileAllowedByPolicy();
1533 if (profile->IsGuestSession() && !g_browser_process->local_state()->
1534 GetBoolean(prefs::kBrowserGuestModeEnabled)) {
1535 UserManager::Show(base::FilePath(),
1536 profiles::USER_MANAGER_NO_TUTORIAL,
1537 profiles::USER_MANAGER_SELECT_PROFILE_CHROME_MEMORY);
1538 return;
1541 chrome::NavigateParams params(
1542 profile, GURL(chrome::kChromeUIMemoryURL), ui::PAGE_TRANSITION_LINK);
1543 params.disposition = NEW_FOREGROUND_TAB;
1544 params.host_desktop_type = desktop_type;
1545 chrome::Navigate(&params);
1548 TaskManager::TaskManager()
1549 : model_(new TaskManagerModel(this)) {
1552 TaskManager::~TaskManager() {