1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/task_manager/task_manager.h"
8 #include "base/i18n/number_formatting.h"
9 #include "base/i18n/rtl.h"
10 #include "base/prefs/pref_registry_simple.h"
11 #include "base/process/process_metrics.h"
12 #include "base/rand_util.h"
13 #include "base/stl_util.h"
14 #include "base/strings/string16.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h"
18 #include "chrome/browser/browser_process.h"
19 #include "chrome/browser/profiles/profile_manager.h"
20 #include "chrome/browser/task_manager/background_information.h"
21 #include "chrome/browser/task_manager/browser_process_resource_provider.h"
22 #include "chrome/browser/task_manager/child_process_resource_provider.h"
23 #include "chrome/browser/task_manager/extension_information.h"
24 #include "chrome/browser/task_manager/guest_information.h"
25 #include "chrome/browser/task_manager/panel_information.h"
26 #include "chrome/browser/task_manager/printing_information.h"
27 #include "chrome/browser/task_manager/resource_provider.h"
28 #include "chrome/browser/task_manager/tab_contents_information.h"
29 #include "chrome/browser/task_manager/web_contents_resource_provider.h"
30 #include "chrome/browser/ui/browser_navigator.h"
31 #include "chrome/common/pref_names.h"
32 #include "chrome/common/url_constants.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 "grit/generated_resources.h"
44 #include "grit/ui_resources.h"
45 #include "third_party/icu/source/i18n/unicode/coll.h"
46 #include "ui/base/l10n/l10n_util.h"
47 #include "ui/base/resource/resource_bundle.h"
48 #include "ui/base/text/bytes_formatting.h"
49 #include "ui/gfx/image/image_skia.h"
51 #if defined(OS_MACOSX)
52 #include "content/public/browser/browser_child_process_host.h"
55 using content::BrowserThread;
56 using content::ResourceRequestInfo;
57 using content::WebContents;
58 using task_manager::Resource;
59 using task_manager::ResourceProvider;
60 using task_manager::WebContentsInformation;
67 int ValueCompare(T value1, T value2) {
75 // Used when one or both of the results to compare are unavailable.
76 int OrderUnavailableValue(bool v1, bool v2) {
82 // Used by TaskManagerModel::CompareValues(). See it for details of return
85 int ValueCompareMember(const TaskManagerModel* model,
86 bool (TaskManagerModel::*f)(int, T*) const,
91 bool value1_valid = (model->*f)(row1, &value1);
92 bool value2_valid = (model->*f)(row2, &value2);
93 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
94 OrderUnavailableValue(value1_valid, value2_valid);
97 base::string16 FormatStatsSize(const blink::WebCache::ResourceTypeStat& stat) {
98 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
99 ui::FormatBytesWithUnits(stat.size, ui::DATA_UNITS_KIBIBYTE, false),
100 ui::FormatBytesWithUnits(stat.liveSize, ui::DATA_UNITS_KIBIBYTE, false));
103 // Returns true if the specified id should use the first value in the group.
104 bool IsSharedByGroup(int col_id) {
106 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
107 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
108 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
109 case IDS_TASK_MANAGER_CPU_COLUMN:
110 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
111 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
112 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
113 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
114 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
115 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
116 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
117 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
125 void GetWinGDIHandles(base::ProcessHandle process,
130 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
131 HANDLE current_process = GetCurrentProcess();
132 HANDLE process_with_query_rights;
133 if (DuplicateHandle(current_process, process, current_process,
134 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
136 *current = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS);
137 *peak = GetGuiResources(process_with_query_rights, GR_GDIOBJECTS_PEAK);
138 CloseHandle(process_with_query_rights);
142 void GetWinUSERHandles(base::ProcessHandle process,
147 // Get a handle to |process| that has PROCESS_QUERY_INFORMATION rights.
148 HANDLE current_process = GetCurrentProcess();
149 HANDLE process_with_query_rights;
150 if (DuplicateHandle(current_process, process, current_process,
151 &process_with_query_rights, PROCESS_QUERY_INFORMATION,
153 *current = GetGuiResources(process_with_query_rights, GR_USEROBJECTS);
154 *peak = GetGuiResources(process_with_query_rights, GR_USEROBJECTS_PEAK);
155 CloseHandle(process_with_query_rights);
162 class TaskManagerModelGpuDataManagerObserver
163 : public content::GpuDataManagerObserver {
165 TaskManagerModelGpuDataManagerObserver() {
166 content::GpuDataManager::GetInstance()->AddObserver(this);
169 virtual ~TaskManagerModelGpuDataManagerObserver() {
170 content::GpuDataManager::GetInstance()->RemoveObserver(this);
173 static void NotifyVideoMemoryUsageStats(
174 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
175 TaskManager::GetInstance()->model()->NotifyVideoMemoryUsageStats(
176 video_memory_usage_stats);
179 virtual void OnVideoMemoryUsageStatsUpdate(
180 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats)
182 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
183 NotifyVideoMemoryUsageStats(video_memory_usage_stats);
185 BrowserThread::PostTask(
186 BrowserThread::UI, FROM_HERE, base::Bind(
187 &TaskManagerModelGpuDataManagerObserver::
188 NotifyVideoMemoryUsageStats,
189 video_memory_usage_stats));
194 TaskManagerModel::PerResourceValues::PerResourceValues()
195 : is_title_valid(false),
196 is_profile_name_valid(false),
198 is_process_id_valid(false),
200 is_goats_teleported_valid(false),
202 is_webcore_stats_valid(false),
203 is_sqlite_memory_bytes_valid(false),
204 sqlite_memory_bytes(0),
205 is_v8_memory_valid(false),
206 v8_memory_allocated(0),
209 TaskManagerModel::PerResourceValues::~PerResourceValues() {}
211 TaskManagerModel::PerProcessValues::PerProcessValues()
212 : is_cpu_usage_valid(false),
214 is_idle_wakeups_valid(false),
216 is_private_and_shared_valid(false),
219 is_physical_memory_valid(false),
221 is_video_memory_valid(false),
223 video_memory_has_duplicates(false),
224 is_gdi_handles_valid(false),
227 is_user_handles_valid(0),
229 user_handles_peak(0),
230 is_nacl_debug_stub_port_valid(false),
231 nacl_debug_stub_port(0) {}
233 TaskManagerModel::PerProcessValues::~PerProcessValues() {}
235 ////////////////////////////////////////////////////////////////////////////////
236 // TaskManagerModel class
237 ////////////////////////////////////////////////////////////////////////////////
239 TaskManagerModel::TaskManagerModel(TaskManager* task_manager)
240 : pending_video_memory_usage_stats_update_(false),
244 goat_salt_(base::RandUint64()) {
246 new task_manager::BrowserProcessResourceProvider(task_manager));
247 AddResourceProvider(new task_manager::WebContentsResourceProvider(
249 scoped_ptr<WebContentsInformation>(
250 new task_manager::BackgroundInformation())));
251 AddResourceProvider(new task_manager::WebContentsResourceProvider(
253 scoped_ptr<WebContentsInformation>(
254 new task_manager::TabContentsInformation())));
255 AddResourceProvider(new task_manager::WebContentsResourceProvider(
257 scoped_ptr<WebContentsInformation>(
258 new task_manager::PrintingInformation())));
259 AddResourceProvider(new task_manager::WebContentsResourceProvider(
261 scoped_ptr<WebContentsInformation>(
262 new task_manager::PanelInformation())));
264 new task_manager::ChildProcessResourceProvider(task_manager));
265 AddResourceProvider(new task_manager::WebContentsResourceProvider(
267 scoped_ptr<WebContentsInformation>(
268 new task_manager::ExtensionInformation())));
269 AddResourceProvider(new task_manager::WebContentsResourceProvider(
271 scoped_ptr<WebContentsInformation>(
272 new task_manager::GuestInformation())));
275 void TaskManagerModel::AddObserver(TaskManagerModelObserver* observer) {
276 observer_list_.AddObserver(observer);
279 void TaskManagerModel::RemoveObserver(TaskManagerModelObserver* observer) {
280 observer_list_.RemoveObserver(observer);
283 int TaskManagerModel::ResourceCount() const {
284 return resources_.size();
287 int TaskManagerModel::GroupCount() const {
288 return group_map_.size();
291 int TaskManagerModel::GetNaClDebugStubPort(int index) const {
292 base::ProcessHandle handle = GetResource(index)->GetProcess();
293 PerProcessValues& values(per_process_cache_[handle]);
294 if (!values.is_nacl_debug_stub_port_valid) {
295 return nacl::kGdbDebugStubPortUnknown;
297 return values.nacl_debug_stub_port;
300 int64 TaskManagerModel::GetNetworkUsage(int index) const {
301 return GetNetworkUsage(GetResource(index));
304 double TaskManagerModel::GetCPUUsage(int index) const {
305 return GetCPUUsage(GetResource(index));
308 int TaskManagerModel::GetIdleWakeupsPerSecond(int index) const {
309 return GetIdleWakeupsPerSecond(GetResource(index));
312 base::ProcessId TaskManagerModel::GetProcessId(int index) const {
313 PerResourceValues& values(GetPerResourceValues(index));
314 if (!values.is_process_id_valid) {
315 values.is_process_id_valid = true;
316 values.process_id = base::GetProcId(GetResource(index)->GetProcess());
318 return values.process_id;
321 base::ProcessHandle TaskManagerModel::GetProcess(int index) const {
322 return GetResource(index)->GetProcess();
325 base::string16 TaskManagerModel::GetResourceById(int index, int col_id) const {
326 if (IsSharedByGroup(col_id) && !IsResourceFirstInGroup(index))
327 return base::string16();
330 case IDS_TASK_MANAGER_TASK_COLUMN:
331 return GetResourceTitle(index);
333 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN:
334 return GetResourceProfileName(index);
336 case IDS_TASK_MANAGER_NET_COLUMN:
337 return GetResourceNetworkUsage(index);
339 case IDS_TASK_MANAGER_CPU_COLUMN:
340 return GetResourceCPUUsage(index);
342 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
343 return GetResourcePrivateMemory(index);
345 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
346 return GetResourceSharedMemory(index);
348 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
349 return GetResourcePhysicalMemory(index);
351 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
352 return GetResourceProcessId(index);
354 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN:
355 return GetResourceGDIHandles(index);
357 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN:
358 return GetResourceUSERHandles(index);
360 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN:
361 return GetResourceIdleWakeupsPerSecond(index);
363 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN:
364 return GetResourceGoatsTeleported(index);
366 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
367 return GetResourceWebCoreImageCacheSize(index);
369 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
370 return GetResourceWebCoreScriptsCacheSize(index);
372 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
373 return GetResourceWebCoreCSSCacheSize(index);
375 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN:
376 return GetResourceVideoMemory(index);
378 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
379 return GetResourceSqliteMemoryUsed(index);
381 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
382 return GetResourceV8MemoryAllocatedSize(index);
384 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
385 return GetResourceNaClDebugStubPort(index);
389 return base::string16();
393 const base::string16& TaskManagerModel::GetResourceTitle(int index) const {
394 PerResourceValues& values = GetPerResourceValues(index);
395 if (!values.is_title_valid) {
396 values.is_title_valid = true;
397 values.title = GetResource(index)->GetTitle();
402 const base::string16& TaskManagerModel::GetResourceProfileName(
404 PerResourceValues& values(GetPerResourceValues(index));
405 if (!values.is_profile_name_valid) {
406 values.is_profile_name_valid = true;
407 values.profile_name = GetResource(index)->GetProfileName();
409 return values.profile_name;
412 base::string16 TaskManagerModel::GetResourceNaClDebugStubPort(int index) const {
413 int port = GetNaClDebugStubPort(index);
414 if (port == nacl::kGdbDebugStubPortUnknown) {
415 return base::ASCIIToUTF16("Unknown");
416 } else if (port == nacl::kGdbDebugStubPortUnused) {
417 return base::ASCIIToUTF16("N/A");
419 return base::IntToString16(port);
423 base::string16 TaskManagerModel::GetResourceNetworkUsage(int index) const {
424 int64 net_usage = GetNetworkUsage(index);
426 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
428 return base::ASCIIToUTF16("0");
429 base::string16 net_byte = ui::FormatSpeed(net_usage);
430 // Force number string to have LTR directionality.
431 return base::i18n::GetDisplayStringInLTRDirectionality(net_byte);
434 base::string16 TaskManagerModel::GetResourceCPUUsage(int index) const {
435 return base::UTF8ToUTF16(base::StringPrintf(
436 #if defined(OS_MACOSX)
437 // Activity Monitor shows %cpu with one decimal digit -- be
438 // consistent with that.
443 GetCPUUsage(GetResource(index))));
446 base::string16 TaskManagerModel::GetResourcePrivateMemory(int index) const {
448 if (!GetPrivateMemory(index, &private_mem))
449 return base::ASCIIToUTF16("N/A");
450 return GetMemCellText(private_mem);
453 base::string16 TaskManagerModel::GetResourceSharedMemory(int index) const {
455 if (!GetSharedMemory(index, &shared_mem))
456 return base::ASCIIToUTF16("N/A");
457 return GetMemCellText(shared_mem);
460 base::string16 TaskManagerModel::GetResourcePhysicalMemory(int index) const {
462 GetPhysicalMemory(index, &phys_mem);
463 return GetMemCellText(phys_mem);
466 base::string16 TaskManagerModel::GetResourceProcessId(int index) const {
467 return base::IntToString16(GetProcessId(index));
470 base::string16 TaskManagerModel::GetResourceGDIHandles(int index) const {
471 size_t current, peak;
472 GetGDIHandles(index, ¤t, &peak);
473 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
474 base::IntToString16(current), base::IntToString16(peak));
477 base::string16 TaskManagerModel::GetResourceUSERHandles(int index) const {
478 size_t current, peak;
479 GetUSERHandles(index, ¤t, &peak);
480 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_HANDLES_CELL_TEXT,
481 base::IntToString16(current), base::IntToString16(peak));
484 base::string16 TaskManagerModel::GetResourceWebCoreImageCacheSize(
486 if (!CacheWebCoreStats(index))
487 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
488 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.images);
491 base::string16 TaskManagerModel::GetResourceWebCoreScriptsCacheSize(
493 if (!CacheWebCoreStats(index))
494 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
495 return FormatStatsSize(GetPerResourceValues(index).webcore_stats.scripts);
498 base::string16 TaskManagerModel::GetResourceWebCoreCSSCacheSize(
500 if (!CacheWebCoreStats(index))
501 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
502 return FormatStatsSize(
503 GetPerResourceValues(index).webcore_stats.cssStyleSheets);
506 base::string16 TaskManagerModel::GetResourceVideoMemory(int index) const {
509 if (!GetVideoMemory(index, &video_memory, &has_duplicates) || !video_memory)
510 return base::ASCIIToUTF16("N/A");
511 if (has_duplicates) {
512 return GetMemCellText(video_memory) + base::ASCIIToUTF16("*");
514 return GetMemCellText(video_memory);
517 base::string16 TaskManagerModel::GetResourceSqliteMemoryUsed(int index) const {
519 if (!GetSqliteMemoryUsedBytes(index, &bytes))
520 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
521 return GetMemCellText(bytes);
524 base::string16 TaskManagerModel::GetResourceIdleWakeupsPerSecond(int index)
526 return base::FormatNumber(GetIdleWakeupsPerSecond(GetResource(index)));
529 base::string16 TaskManagerModel::GetResourceGoatsTeleported(int index) const {
530 CHECK_LT(index, ResourceCount());
531 return base::FormatNumber(GetGoatsTeleported(index));
534 base::string16 TaskManagerModel::GetResourceV8MemoryAllocatedSize(
536 size_t memory_allocated = 0, memory_used = 0;
537 if (!GetV8MemoryUsed(index, &memory_used) ||
538 !GetV8Memory(index, &memory_allocated))
539 return l10n_util::GetStringUTF16(IDS_TASK_MANAGER_NA_CELL_TEXT);
540 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_CACHE_SIZE_CELL_TEXT,
541 ui::FormatBytesWithUnits(memory_allocated,
542 ui::DATA_UNITS_KIBIBYTE,
544 ui::FormatBytesWithUnits(memory_used,
545 ui::DATA_UNITS_KIBIBYTE,
549 bool TaskManagerModel::GetPrivateMemory(int index, size_t* result) const {
551 base::ProcessHandle handle = GetResource(index)->GetProcess();
552 if (!CachePrivateAndSharedMemory(handle))
554 *result = per_process_cache_[handle].private_bytes;
558 bool TaskManagerModel::GetSharedMemory(int index, size_t* result) const {
560 base::ProcessHandle handle = GetResource(index)->GetProcess();
561 if (!CachePrivateAndSharedMemory(handle))
563 *result = per_process_cache_[handle].shared_bytes;
567 bool TaskManagerModel::GetPhysicalMemory(int index, size_t* result) const {
570 base::ProcessHandle handle = GetResource(index)->GetProcess();
571 PerProcessValues& values(per_process_cache_[handle]);
573 if (!values.is_physical_memory_valid) {
574 base::WorkingSetKBytes ws_usage;
575 MetricsMap::const_iterator iter = metrics_map_.find(handle);
576 if (iter == metrics_map_.end() ||
577 !iter->second->GetWorkingSetKBytes(&ws_usage))
580 values.is_physical_memory_valid = true;
581 #if defined(OS_LINUX)
582 // On Linux private memory is also resident. Just use it.
583 values.physical_memory = ws_usage.priv * 1024;
585 // Memory = working_set.private + working_set.shareable.
586 // We exclude the shared memory.
587 values.physical_memory = iter->second->GetWorkingSetSize();
588 values.physical_memory -= ws_usage.shared * 1024;
591 *result = values.physical_memory;
595 void TaskManagerModel::GetGDIHandles(int index,
597 size_t* peak) const {
601 base::ProcessHandle handle = GetResource(index)->GetProcess();
602 PerProcessValues& values(per_process_cache_[handle]);
604 if (!values.is_gdi_handles_valid) {
605 GetWinGDIHandles(GetResource(index)->GetProcess(),
607 &values.gdi_handles_peak);
608 values.is_gdi_handles_valid = true;
610 *current = values.gdi_handles;
611 *peak = values.gdi_handles_peak;
615 void TaskManagerModel::GetUSERHandles(int index,
617 size_t* peak) const {
621 base::ProcessHandle handle = GetResource(index)->GetProcess();
622 PerProcessValues& values(per_process_cache_[handle]);
624 if (!values.is_user_handles_valid) {
625 GetWinUSERHandles(GetResource(index)->GetProcess(),
626 &values.user_handles,
627 &values.user_handles_peak);
628 values.is_user_handles_valid = true;
630 *current = values.user_handles;
631 *peak = values.user_handles_peak;
635 bool TaskManagerModel::GetWebCoreCacheStats(
637 blink::WebCache::ResourceTypeStats* result) const {
638 if (!CacheWebCoreStats(index))
640 *result = GetPerResourceValues(index).webcore_stats;
644 bool TaskManagerModel::GetVideoMemory(int index,
645 size_t* video_memory,
646 bool* has_duplicates) const {
648 *has_duplicates = false;
650 base::ProcessId pid = GetProcessId(index);
651 PerProcessValues& values(
652 per_process_cache_[GetResource(index)->GetProcess()]);
653 if (!values.is_video_memory_valid) {
654 content::GPUVideoMemoryUsageStats::ProcessMap::const_iterator i =
655 video_memory_usage_stats_.process_map.find(pid);
656 if (i == video_memory_usage_stats_.process_map.end())
658 values.is_video_memory_valid = true;
659 values.video_memory = i->second.video_memory;
660 values.video_memory_has_duplicates = i->second.has_duplicates;
662 *video_memory = values.video_memory;
663 *has_duplicates = values.video_memory_has_duplicates;
667 bool TaskManagerModel::GetSqliteMemoryUsedBytes(
669 size_t* result) const {
671 PerResourceValues& values(GetPerResourceValues(index));
672 if (!values.is_sqlite_memory_bytes_valid) {
673 if (!GetResource(index)->ReportsSqliteMemoryUsed())
675 values.is_sqlite_memory_bytes_valid = true;
676 values.sqlite_memory_bytes = GetResource(index)->SqliteMemoryUsedBytes();
678 *result = values.sqlite_memory_bytes;
682 bool TaskManagerModel::GetV8Memory(int index, size_t* result) const {
684 if (!CacheV8Memory(index))
686 *result = GetPerResourceValues(index).v8_memory_allocated;
690 bool TaskManagerModel::GetV8MemoryUsed(int index, size_t* result) const {
692 if (!CacheV8Memory(index))
694 *result = GetPerResourceValues(index).v8_memory_used;
698 bool TaskManagerModel::CanActivate(int index) const {
699 CHECK_LT(index, ResourceCount());
700 return GetResourceWebContents(index) != NULL;
703 int TaskManagerModel::GetGoatsTeleported(int index) const {
704 PerResourceValues& values(GetPerResourceValues(index));
705 if (!values.is_goats_teleported_valid) {
706 values.is_goats_teleported_valid = true;
707 values.goats_teleported = goat_salt_ * (index + 1);
708 values.goats_teleported = (values.goats_teleported >> 16) & 255;
710 return values.goats_teleported;
713 bool TaskManagerModel::IsResourceFirstInGroup(int index) const {
714 Resource* resource = GetResource(index);
715 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
716 DCHECK(iter != group_map_.end());
717 const ResourceList& group = iter->second;
718 return (group[0] == resource);
721 bool TaskManagerModel::IsResourceLastInGroup(int index) const {
722 Resource* resource = GetResource(index);
723 GroupMap::const_iterator iter = group_map_.find(resource->GetProcess());
724 DCHECK(iter != group_map_.end());
725 const ResourceList& group = iter->second;
726 return (group.back() == resource);
729 gfx::ImageSkia TaskManagerModel::GetResourceIcon(int index) const {
730 gfx::ImageSkia icon = GetResource(index)->GetIcon();
734 static const gfx::ImageSkia* default_icon =
735 ResourceBundle::GetSharedInstance().
736 GetNativeImageNamed(IDR_DEFAULT_FAVICON).ToImageSkia();
737 return *default_icon;
740 TaskManagerModel::GroupRange
741 TaskManagerModel::GetGroupRangeForResource(int index) const {
742 Resource* resource = GetResource(index);
743 GroupMap::const_iterator group_iter =
744 group_map_.find(resource->GetProcess());
745 DCHECK(group_iter != group_map_.end());
746 const ResourceList& group = group_iter->second;
747 if (group.size() == 1) {
748 return std::make_pair(index, 1);
750 for (int i = index; i >= 0; --i) {
751 if (GetResource(i) == group[0])
752 return std::make_pair(i, group.size());
755 return std::make_pair(-1, -1);
759 int TaskManagerModel::GetGroupIndexForResource(int index) const {
760 int group_index = -1;
761 for (int i = 0; i <= index; ++i) {
762 if (IsResourceFirstInGroup(i))
766 DCHECK_NE(group_index, -1);
770 int TaskManagerModel::GetResourceIndexForGroup(int group_index,
771 int index_in_group) const {
772 int group_count = -1;
773 int count_in_group = -1;
774 for (int i = 0; i < ResourceCount(); ++i) {
775 if (IsResourceFirstInGroup(i))
778 if (group_count == group_index) {
780 if (count_in_group == index_in_group)
782 } else if (group_count > group_index) {
791 int TaskManagerModel::CompareValues(int row1, int row2, int col_id) const {
792 CHECK(row1 < ResourceCount() && row2 < ResourceCount());
794 case IDS_TASK_MANAGER_TASK_COLUMN: {
795 static icu::Collator* collator = NULL;
797 UErrorCode create_status = U_ZERO_ERROR;
798 collator = icu::Collator::createInstance(create_status);
799 if (!U_SUCCESS(create_status)) {
804 const base::string16& title1 = GetResourceTitle(row1);
805 const base::string16& title2 = GetResourceTitle(row2);
806 UErrorCode compare_status = U_ZERO_ERROR;
807 UCollationResult compare_result = collator->compare(
808 static_cast<const UChar*>(title1.c_str()),
809 static_cast<int>(title1.length()),
810 static_cast<const UChar*>(title2.c_str()),
811 static_cast<int>(title2.length()),
813 DCHECK(U_SUCCESS(compare_status));
814 return compare_result;
817 case IDS_TASK_MANAGER_PROFILE_NAME_COLUMN: {
818 const base::string16& profile1 = GetResourceProfileName(row1);
819 const base::string16& profile2 = GetResourceProfileName(row2);
820 return profile1.compare(0, profile1.length(), profile2, 0,
824 case IDS_TASK_MANAGER_NET_COLUMN:
825 return ValueCompare(GetNetworkUsage(GetResource(row1)),
826 GetNetworkUsage(GetResource(row2)));
828 case IDS_TASK_MANAGER_CPU_COLUMN:
829 return ValueCompare(GetCPUUsage(GetResource(row1)),
830 GetCPUUsage(GetResource(row2)));
832 case IDS_TASK_MANAGER_PRIVATE_MEM_COLUMN:
833 return ValueCompareMember(
834 this, &TaskManagerModel::GetPrivateMemory, row1, row2);
836 case IDS_TASK_MANAGER_SHARED_MEM_COLUMN:
837 return ValueCompareMember(
838 this, &TaskManagerModel::GetSharedMemory, row1, row2);
840 case IDS_TASK_MANAGER_PHYSICAL_MEM_COLUMN:
841 return ValueCompareMember(
842 this, &TaskManagerModel::GetPhysicalMemory, row1, row2);
844 case IDS_TASK_MANAGER_NACL_DEBUG_STUB_PORT_COLUMN:
845 return ValueCompare(GetNaClDebugStubPort(row1),
846 GetNaClDebugStubPort(row2));
848 case IDS_TASK_MANAGER_PROCESS_ID_COLUMN:
849 return ValueCompare(GetProcessId(row1), GetProcessId(row2));
851 case IDS_TASK_MANAGER_GDI_HANDLES_COLUMN: {
852 size_t current1, peak1;
853 size_t current2, peak2;
854 GetGDIHandles(row1, ¤t1, &peak1);
855 GetGDIHandles(row2, ¤t2, &peak2);
856 return ValueCompare(current1, current2);
859 case IDS_TASK_MANAGER_USER_HANDLES_COLUMN: {
860 size_t current1, peak1;
861 size_t current2, peak2;
862 GetUSERHandles(row1, ¤t1, &peak1);
863 GetUSERHandles(row2, ¤t2, &peak2);
864 return ValueCompare(current1, current2);
867 case IDS_TASK_MANAGER_IDLE_WAKEUPS_COLUMN:
868 return ValueCompare(GetIdleWakeupsPerSecond(row1),
869 GetIdleWakeupsPerSecond(row2));
871 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
872 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
873 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN: {
874 bool row1_stats_valid = CacheWebCoreStats(row1);
875 bool row2_stats_valid = CacheWebCoreStats(row2);
876 if (row1_stats_valid && row2_stats_valid) {
877 const blink::WebCache::ResourceTypeStats& stats1(
878 GetPerResourceValues(row1).webcore_stats);
879 const blink::WebCache::ResourceTypeStats& stats2(
880 GetPerResourceValues(row2).webcore_stats);
882 case IDS_TASK_MANAGER_WEBCORE_IMAGE_CACHE_COLUMN:
883 return ValueCompare(stats1.images.size, stats2.images.size);
884 case IDS_TASK_MANAGER_WEBCORE_SCRIPTS_CACHE_COLUMN:
885 return ValueCompare(stats1.scripts.size, stats2.scripts.size);
886 case IDS_TASK_MANAGER_WEBCORE_CSS_CACHE_COLUMN:
887 return ValueCompare(stats1.cssStyleSheets.size,
888 stats2.cssStyleSheets.size);
894 return OrderUnavailableValue(row1_stats_valid, row2_stats_valid);
897 case IDS_TASK_MANAGER_VIDEO_MEMORY_COLUMN: {
901 bool value1_valid = GetVideoMemory(row1, &value1, &has_duplicates);
902 bool value2_valid = GetVideoMemory(row2, &value2, &has_duplicates);
903 return value1_valid && value2_valid ? ValueCompare(value1, value2) :
904 OrderUnavailableValue(value1_valid, value2_valid);
907 case IDS_TASK_MANAGER_GOATS_TELEPORTED_COLUMN:
908 return ValueCompare(GetGoatsTeleported(row1), GetGoatsTeleported(row2));
910 case IDS_TASK_MANAGER_JAVASCRIPT_MEMORY_ALLOCATED_COLUMN:
911 return ValueCompareMember(
912 this, &TaskManagerModel::GetV8Memory, row1, row2);
914 case IDS_TASK_MANAGER_SQLITE_MEMORY_USED_COLUMN:
915 return ValueCompareMember(
916 this, &TaskManagerModel::GetSqliteMemoryUsedBytes, row1, row2);
925 int TaskManagerModel::GetUniqueChildProcessId(int index) const {
926 return GetResource(index)->GetUniqueChildProcessId();
929 Resource::Type TaskManagerModel::GetResourceType(int index) const {
930 return GetResource(index)->GetType();
933 WebContents* TaskManagerModel::GetResourceWebContents(int index) const {
934 return GetResource(index)->GetWebContents();
937 void TaskManagerModel::AddResource(Resource* resource) {
938 base::ProcessHandle process = resource->GetProcess();
940 GroupMap::iterator group_iter = group_map_.find(process);
941 int new_entry_index = 0;
942 if (group_iter == group_map_.end()) {
943 group_map_.insert(make_pair(process, ResourceList(1, resource)));
945 // Not part of a group, just put at the end of the list.
946 resources_.push_back(resource);
947 new_entry_index = static_cast<int>(resources_.size() - 1);
949 ResourceList* group_entries = &(group_iter->second);
950 group_entries->push_back(resource);
952 // Insert the new entry right after the last entry of its group.
953 ResourceList::iterator iter =
954 std::find(resources_.begin(),
956 (*group_entries)[group_entries->size() - 2]);
957 DCHECK(iter != resources_.end());
958 new_entry_index = static_cast<int>(iter - resources_.begin()) + 1;
959 resources_.insert(++iter, resource);
962 // Create the ProcessMetrics for this process if needed (not in map).
963 if (metrics_map_.find(process) == metrics_map_.end()) {
964 base::ProcessMetrics* pm =
965 #if !defined(OS_MACOSX)
966 base::ProcessMetrics::CreateProcessMetrics(process);
968 base::ProcessMetrics::CreateProcessMetrics(
969 process, content::BrowserChildProcessHost::GetPortProvider());
972 metrics_map_[process] = pm;
975 // Notify the table that the contents have changed for it to redraw.
976 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
977 OnItemsAdded(new_entry_index, 1));
980 void TaskManagerModel::RemoveResource(Resource* resource) {
981 base::ProcessHandle process = resource->GetProcess();
983 // Find the associated group.
984 GroupMap::iterator group_iter = group_map_.find(process);
985 DCHECK(group_iter != group_map_.end());
986 if (group_iter == group_map_.end())
988 ResourceList& group_entries = group_iter->second;
990 // Remove the entry from the group map.
991 ResourceList::iterator iter = std::find(group_entries.begin(),
994 DCHECK(iter != group_entries.end());
995 if (iter != group_entries.end())
996 group_entries.erase(iter);
998 // If there are no more entries for that process, do the clean-up.
999 if (group_entries.empty()) {
1000 group_map_.erase(group_iter);
1002 // Nobody is using this process, we don't need the process metrics anymore.
1003 MetricsMap::iterator pm_iter = metrics_map_.find(process);
1004 DCHECK(pm_iter != metrics_map_.end());
1005 if (pm_iter != metrics_map_.end()) {
1006 delete pm_iter->second;
1007 metrics_map_.erase(process);
1011 // Remove the entry from the model list.
1012 iter = std::find(resources_.begin(), resources_.end(), resource);
1013 DCHECK(iter != resources_.end());
1014 if (iter != resources_.end()) {
1015 int index = static_cast<int>(iter - resources_.begin());
1016 // Notify the observers that the contents will change.
1017 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1018 OnItemsToBeRemoved(index, 1));
1019 // Now actually remove the entry from the model list.
1020 resources_.erase(iter);
1021 // Notify the table that the contents have changed.
1022 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1023 OnItemsRemoved(index, 1));
1026 // Remove the entry from the network maps.
1027 ResourceValueMap::iterator net_iter =
1028 current_byte_count_map_.find(resource);
1029 if (net_iter != current_byte_count_map_.end())
1030 current_byte_count_map_.erase(net_iter);
1033 void TaskManagerModel::StartUpdating() {
1034 // Multiple StartUpdating requests may come in, and we only need to take
1035 // action the first time.
1037 if (update_requests_ > 1)
1039 DCHECK_EQ(1, update_requests_);
1040 DCHECK_NE(TASK_PENDING, update_state_);
1042 // If update_state_ is STOPPING, it means a task is still pending. Setting
1043 // it to TASK_PENDING ensures the tasks keep being posted (by Refresh()).
1044 if (update_state_ == IDLE) {
1045 base::MessageLoop::current()->PostTask(
1047 base::Bind(&TaskManagerModel::RefreshCallback, this));
1049 update_state_ = TASK_PENDING;
1051 // Notify resource providers that we are updating.
1054 if (!resources_.empty()) {
1055 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1056 OnReadyPeriodicalUpdate());
1060 void TaskManagerModel::StopUpdating() {
1061 // Don't actually stop updating until we have heard as many calls as those
1062 // to StartUpdating.
1064 if (update_requests_ > 0)
1066 // Make sure that update_requests_ cannot go negative.
1067 CHECK_EQ(0, update_requests_);
1068 DCHECK_EQ(TASK_PENDING, update_state_);
1069 update_state_ = STOPPING;
1071 // Notify resource providers that we are done updating.
1075 void TaskManagerModel::StartListening() {
1076 // Multiple StartListening requests may come in and we only need to take
1077 // action the first time.
1079 if (listen_requests_ > 1)
1081 DCHECK_EQ(1, listen_requests_);
1083 // Notify resource providers that we should start listening to events.
1084 for (ResourceProviderList::iterator iter = providers_.begin();
1085 iter != providers_.end(); ++iter) {
1086 (*iter)->StartUpdating();
1090 void TaskManagerModel::StopListening() {
1091 // Don't actually stop listening until we have heard as many calls as those
1092 // to StartListening.
1094 if (listen_requests_ > 0)
1097 DCHECK_EQ(0, listen_requests_);
1099 // Notify resource providers that we are done listening.
1100 for (ResourceProviderList::const_iterator iter = providers_.begin();
1101 iter != providers_.end(); ++iter) {
1102 (*iter)->StopUpdating();
1105 // Must clear the resources before the next attempt to start listening.
1109 void TaskManagerModel::Clear() {
1110 int size = ResourceCount();
1114 // Clear the groups.
1117 // Clear the process related info.
1118 STLDeleteValues(&metrics_map_);
1120 // Clear the network maps.
1121 current_byte_count_map_.clear();
1123 per_resource_cache_.clear();
1124 per_process_cache_.clear();
1126 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1127 OnItemsRemoved(0, size));
1131 void TaskManagerModel::ModelChanged() {
1132 // Notify the table that the contents have changed for it to redraw.
1133 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_, OnModelChanged());
1136 void TaskManagerModel::Refresh() {
1137 goat_salt_ = base::RandUint64();
1139 per_resource_cache_.clear();
1140 per_process_cache_.clear();
1142 #if !defined(DISABLE_NACL)
1143 nacl::NaClBrowser* nacl_browser = nacl::NaClBrowser::GetInstance();
1144 #endif // !defined(DISABLE_NACL)
1146 // Compute the CPU usage values and check if NaCl GDB debug stub port is
1148 // Note that we compute the CPU usage for all resources (instead of doing it
1149 // lazily) as process_util::GetCPUUsage() returns the CPU usage since the last
1150 // time it was called, and not calling it everytime would skew the value the
1151 // next time it is retrieved (as it would be for more than 1 cycle).
1152 // The same is true for idle wakeups.
1153 for (ResourceList::iterator iter = resources_.begin();
1154 iter != resources_.end(); ++iter) {
1155 base::ProcessHandle process = (*iter)->GetProcess();
1156 PerProcessValues& values(per_process_cache_[process]);
1157 #if !defined(DISABLE_NACL)
1158 // Debug stub port doesn't change once known.
1159 if (!values.is_nacl_debug_stub_port_valid) {
1160 values.nacl_debug_stub_port = nacl_browser->GetProcessGdbDebugStubPort(
1161 (*iter)->GetUniqueChildProcessId());
1162 if (values.nacl_debug_stub_port != nacl::kGdbDebugStubPortUnknown) {
1163 values.is_nacl_debug_stub_port_valid = true;
1166 #endif // !defined(DISABLE_NACL)
1167 if (values.is_cpu_usage_valid && values.is_idle_wakeups_valid)
1169 MetricsMap::iterator metrics_iter = metrics_map_.find(process);
1170 DCHECK(metrics_iter != metrics_map_.end());
1171 if (!values.is_cpu_usage_valid) {
1172 values.is_cpu_usage_valid = true;
1173 values.cpu_usage = metrics_iter->second->GetCPUUsage();
1175 #if defined(OS_MACOSX)
1176 // TODO: Implement GetIdleWakeupsPerSecond() on other platforms,
1178 if (!values.is_idle_wakeups_valid) {
1179 values.is_idle_wakeups_valid = true;
1180 values.idle_wakeups = metrics_iter->second->GetIdleWakeupsPerSecond();
1182 #endif // defined(OS_MACOSX)
1185 // Send a request to refresh GPU memory consumption values
1186 RefreshVideoMemoryUsageStats();
1188 // Compute the new network usage values.
1189 base::TimeDelta update_time =
1190 base::TimeDelta::FromMilliseconds(kUpdateTimeMs);
1191 for (ResourceValueMap::iterator iter = current_byte_count_map_.begin();
1192 iter != current_byte_count_map_.end(); ++iter) {
1193 PerResourceValues* values = &(per_resource_cache_[iter->first]);
1194 if (update_time > base::TimeDelta::FromSeconds(1))
1195 values->network_usage = iter->second / update_time.InSeconds();
1197 values->network_usage = iter->second * (1 / update_time.InSeconds());
1199 // Then we reset the current byte count.
1203 // Let resources update themselves if they need to.
1204 for (ResourceList::iterator iter = resources_.begin();
1205 iter != resources_.end(); ++iter) {
1209 if (!resources_.empty()) {
1210 FOR_EACH_OBSERVER(TaskManagerModelObserver, observer_list_,
1211 OnItemsChanged(0, ResourceCount()));
1215 void TaskManagerModel::NotifyResourceTypeStats(
1216 base::ProcessId renderer_id,
1217 const blink::WebCache::ResourceTypeStats& stats) {
1218 for (ResourceList::iterator it = resources_.begin();
1219 it != resources_.end(); ++it) {
1220 if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
1221 (*it)->NotifyResourceTypeStats(stats);
1226 void TaskManagerModel::NotifyVideoMemoryUsageStats(
1227 const content::GPUVideoMemoryUsageStats& video_memory_usage_stats) {
1228 DCHECK(pending_video_memory_usage_stats_update_);
1229 video_memory_usage_stats_ = video_memory_usage_stats;
1230 pending_video_memory_usage_stats_update_ = false;
1233 void TaskManagerModel::NotifyV8HeapStats(base::ProcessId renderer_id,
1234 size_t v8_memory_allocated,
1235 size_t v8_memory_used) {
1236 for (ResourceList::iterator it = resources_.begin();
1237 it != resources_.end(); ++it) {
1238 if (base::GetProcId((*it)->GetProcess()) == renderer_id) {
1239 (*it)->NotifyV8HeapStats(v8_memory_allocated, v8_memory_used);
1244 void TaskManagerModel::NotifyBytesRead(const net::URLRequest& request,
1246 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1248 // Only net::URLRequestJob instances created by the ResourceDispatcherHost
1249 // have an associated ResourceRequestInfo and a render frame associated.
1250 // All other jobs will have -1 returned for the render process child and
1251 // routing ids - the jobs may still match a resource based on their origin id,
1252 // otherwise BytesRead() will attribute the activity to the Browser resource.
1253 const ResourceRequestInfo* info = ResourceRequestInfo::ForRequest(&request);
1254 int child_id = -1, route_id = -1;
1256 info->GetAssociatedRenderFrame(&child_id, &route_id);
1258 // Get the origin PID of the request's originator. This will only be set for
1259 // plugins - for renderer or browser initiated requests it will be zero.
1262 origin_pid = info->GetOriginPID();
1264 if (bytes_read_buffer_.empty()) {
1265 base::MessageLoop::current()->PostDelayedTask(
1267 base::Bind(&TaskManagerModel::NotifyMultipleBytesRead, this),
1268 base::TimeDelta::FromSeconds(1));
1271 bytes_read_buffer_.push_back(
1272 BytesReadParam(origin_pid, child_id, route_id, byte_count));
1275 // This is called on the UI thread.
1276 void TaskManagerModel::NotifyDataReady() {
1277 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1278 for (size_t i = 0; i < on_data_ready_callbacks_.size(); ++i) {
1279 if (!on_data_ready_callbacks_[i].is_null())
1280 on_data_ready_callbacks_[i].Run();
1283 on_data_ready_callbacks_.clear();
1286 void TaskManagerModel::RegisterOnDataReadyCallback(
1287 const base::Closure& callback) {
1288 on_data_ready_callbacks_.push_back(callback);
1291 TaskManagerModel::~TaskManagerModel() {
1292 on_data_ready_callbacks_.clear();
1295 void TaskManagerModel::RefreshCallback() {
1296 DCHECK_NE(IDLE, update_state_);
1298 if (update_state_ == STOPPING) {
1299 // We have been asked to stop.
1300 update_state_ = IDLE;
1306 // Schedule the next update.
1307 base::MessageLoop::current()->PostDelayedTask(
1309 base::Bind(&TaskManagerModel::RefreshCallback, this),
1310 base::TimeDelta::FromMilliseconds(kUpdateTimeMs));
1313 void TaskManagerModel::RefreshVideoMemoryUsageStats() {
1314 if (pending_video_memory_usage_stats_update_)
1317 if (!video_memory_usage_stats_observer_.get()) {
1318 video_memory_usage_stats_observer_.reset(
1319 new TaskManagerModelGpuDataManagerObserver());
1321 pending_video_memory_usage_stats_update_ = true;
1322 content::GpuDataManager::GetInstance()->RequestVideoMemoryUsageStatsUpdate();
1325 int64 TaskManagerModel::GetNetworkUsageForResource(Resource* resource) const {
1326 // Returns default of 0 if no network usage.
1327 return per_resource_cache_[resource].network_usage;
1330 void TaskManagerModel::BytesRead(BytesReadParam param) {
1331 if (update_state_ != TASK_PENDING || listen_requests_ == 0) {
1332 // A notification sneaked in while we were stopping the updating, just
1337 // TODO(jcampan): this should be improved once we have a better way of
1338 // linking a network notification back to the object that initiated it.
1339 Resource* resource = NULL;
1340 for (ResourceProviderList::iterator iter = providers_.begin();
1341 iter != providers_.end(); ++iter) {
1342 resource = (*iter)->GetResource(param.origin_pid,
1349 if (resource == NULL) {
1350 // We can't match a resource to the notification. That might mean the
1351 // tab that started a download was closed, or the request may have had
1352 // no originating resource associated with it in the first place.
1353 // We attribute orphaned/unaccounted activity to the Browser process.
1354 CHECK(param.origin_pid || (param.child_id != -1));
1355 param.origin_pid = 0;
1356 param.child_id = param.route_id = -1;
1361 // We do support network usage, mark the resource as such so it can report 0
1363 if (!resource->SupportNetworkUsage())
1364 resource->SetSupportNetworkUsage();
1366 ResourceValueMap::const_iterator iter_res =
1367 current_byte_count_map_.find(resource);
1368 if (iter_res == current_byte_count_map_.end())
1369 current_byte_count_map_[resource] = param.byte_count;
1371 current_byte_count_map_[resource] = iter_res->second + param.byte_count;
1374 void TaskManagerModel::MultipleBytesRead(
1375 const std::vector<BytesReadParam>* params) {
1376 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
1377 for (std::vector<BytesReadParam>::const_iterator it = params->begin();
1378 it != params->end(); ++it) {
1383 void TaskManagerModel::NotifyMultipleBytesRead() {
1384 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
1385 DCHECK(!bytes_read_buffer_.empty());
1387 std::vector<BytesReadParam>* bytes_read_buffer =
1388 new std::vector<BytesReadParam>;
1389 bytes_read_buffer_.swap(*bytes_read_buffer);
1390 BrowserThread::PostTask(
1391 BrowserThread::UI, FROM_HERE,
1392 base::Bind(&TaskManagerModel::MultipleBytesRead, this,
1393 base::Owned(bytes_read_buffer)));
1396 int64 TaskManagerModel::GetNetworkUsage(Resource* resource) const {
1397 int64 net_usage = GetNetworkUsageForResource(resource);
1398 if (net_usage == 0 && !resource->SupportNetworkUsage())
1403 double TaskManagerModel::GetCPUUsage(Resource* resource) const {
1404 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]);
1405 // Returns 0 if not valid, which is fine.
1406 return values.cpu_usage;
1409 int TaskManagerModel::GetIdleWakeupsPerSecond(Resource* resource) const {
1410 const PerProcessValues& values(per_process_cache_[resource->GetProcess()]);
1411 // Returns 0 if not valid, which is fine.
1412 return values.idle_wakeups;
1415 base::string16 TaskManagerModel::GetMemCellText(int64 number) const {
1416 #if !defined(OS_MACOSX)
1417 base::string16 str = base::FormatNumber(number / 1024);
1419 // Adjust number string if necessary.
1420 base::i18n::AdjustStringForLocaleDirection(&str);
1421 return l10n_util::GetStringFUTF16(IDS_TASK_MANAGER_MEM_CELL_TEXT, str);
1423 // System expectation is to show "100 kB", "200 MB", etc.
1424 // TODO(thakis): Switch to metric units (as opposed to powers of two).
1425 return ui::FormatBytes(number);
1429 bool TaskManagerModel::CachePrivateAndSharedMemory(
1430 base::ProcessHandle handle) const {
1431 PerProcessValues& values(per_process_cache_[handle]);
1432 if (values.is_private_and_shared_valid)
1435 MetricsMap::const_iterator iter = metrics_map_.find(handle);
1436 if (iter == metrics_map_.end() ||
1437 !iter->second->GetMemoryBytes(&values.private_bytes,
1438 &values.shared_bytes)) {
1442 values.is_private_and_shared_valid = true;
1446 bool TaskManagerModel::CacheWebCoreStats(int index) const {
1447 PerResourceValues& values(GetPerResourceValues(index));
1448 if (!values.is_webcore_stats_valid) {
1449 if (!GetResource(index)->ReportsCacheStats())
1451 values.is_webcore_stats_valid = true;
1452 values.webcore_stats = GetResource(index)->GetWebCoreCacheStats();
1457 bool TaskManagerModel::CacheV8Memory(int index) const {
1458 PerResourceValues& values(GetPerResourceValues(index));
1459 if (!values.is_v8_memory_valid) {
1460 if (!GetResource(index)->ReportsV8MemoryStats())
1462 values.is_v8_memory_valid = true;
1463 values.v8_memory_allocated = GetResource(index)->GetV8MemoryAllocated();
1464 values.v8_memory_used = GetResource(index)->GetV8MemoryUsed();
1469 void TaskManagerModel::AddResourceProvider(ResourceProvider* provider) {
1471 providers_.push_back(provider);
1474 TaskManagerModel::PerResourceValues& TaskManagerModel::GetPerResourceValues(
1476 return per_resource_cache_[GetResource(index)];
1479 Resource* TaskManagerModel::GetResource(int index) const {
1481 CHECK_LT(index, static_cast<int>(resources_.size()));
1482 return resources_[index];
1485 ////////////////////////////////////////////////////////////////////////////////
1486 // TaskManager class
1487 ////////////////////////////////////////////////////////////////////////////////
1489 void TaskManager::RegisterPrefs(PrefRegistrySimple* registry) {
1490 registry->RegisterDictionaryPref(prefs::kTaskManagerWindowPlacement);
1493 bool TaskManager::IsBrowserProcess(int index) const {
1494 // If some of the selection is out of bounds, ignore. This may happen when
1495 // killing a process that manages several pages.
1496 return index < model_->ResourceCount() &&
1497 model_->GetProcess(index) == base::GetCurrentProcessHandle();
1500 void TaskManager::KillProcess(int index) {
1501 base::ProcessHandle process = model_->GetProcess(index);
1503 if (process != base::GetCurrentProcessHandle())
1504 base::KillProcess(process, content::RESULT_CODE_KILLED, false);
1507 void TaskManager::ActivateProcess(int index) {
1508 // GetResourceWebContents returns a pointer to the relevant web contents for
1509 // the resource. If the index doesn't correspond to any web contents
1510 // (i.e. refers to the Browser process or a plugin), GetWebContents will
1512 WebContents* chosen_web_contents = model_->GetResourceWebContents(index);
1513 if (chosen_web_contents && chosen_web_contents->GetDelegate())
1514 chosen_web_contents->GetDelegate()->ActivateContents(chosen_web_contents);
1517 void TaskManager::AddResource(Resource* resource) {
1518 model_->AddResource(resource);
1521 void TaskManager::RemoveResource(Resource* resource) {
1522 model_->RemoveResource(resource);
1525 void TaskManager::OnWindowClosed() {
1526 model_->StopUpdating();
1529 void TaskManager::ModelChanged() {
1530 model_->ModelChanged();
1534 TaskManager* TaskManager::GetInstance() {
1535 return Singleton<TaskManager>::get();
1538 void TaskManager::OpenAboutMemory(chrome::HostDesktopType desktop_type) {
1539 chrome::NavigateParams params(
1540 ProfileManager::GetLastUsedProfileAllowedByPolicy(),
1541 GURL(chrome::kChromeUIMemoryURL),
1542 content::PAGE_TRANSITION_LINK);
1543 params.disposition = NEW_FOREGROUND_TAB;
1544 params.host_desktop_type = desktop_type;
1545 chrome::Navigate(¶ms);
1548 TaskManager::TaskManager()
1549 : model_(new TaskManagerModel(this)) {
1552 TaskManager::~TaskManager() {