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