blob: 97793437bf41e628dbb549152e5c42cc8558abcb [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/task_management/sampling/task_manager_impl.h"
#include "base/stl_util.h"
#include "chrome/browser/task_management/providers/browser_process_task_provider.h"
#include "chrome/browser/task_management/providers/child_process_task_provider.h"
#include "chrome/browser/task_management/providers/web_contents/web_contents_task_provider.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/gpu_data_manager.h"
namespace task_management {
namespace {
inline scoped_refptr<base::SequencedTaskRunner> GetBlockingPoolRunner() {
base::SequencedWorkerPool* blocking_pool =
content::BrowserThread::GetBlockingPool();
base::SequencedWorkerPool::SequenceToken token =
blocking_pool->GetSequenceToken();
DCHECK(token.IsValid());
return blocking_pool->GetSequencedTaskRunner(token);
}
base::LazyInstance<TaskManagerImpl> lazy_task_manager_instance =
LAZY_INSTANCE_INITIALIZER;
} // namespace
TaskManagerImpl::TaskManagerImpl()
: blocking_pool_runner_(GetBlockingPoolRunner()),
is_running_(false) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
task_providers_.push_back(new BrowserProcessTaskProvider());
task_providers_.push_back(new ChildProcessTaskProvider());
task_providers_.push_back(new WebContentsTaskProvider());
content::GpuDataManager::GetInstance()->AddObserver(this);
}
TaskManagerImpl::~TaskManagerImpl() {
content::GpuDataManager::GetInstance()->RemoveObserver(this);
STLDeleteValues(&task_groups_by_proc_id_);
}
// static
TaskManagerImpl* TaskManagerImpl::GetInstance() {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
return lazy_task_manager_instance.Pointer();
}
void TaskManagerImpl::ActivateTask(TaskId task_id) {
GetTaskByTaskId(task_id)->Activate();
}
double TaskManagerImpl::GetCpuUsage(TaskId task_id) const {
return GetTaskGroupByTaskId(task_id)->cpu_usage();
}
int64 TaskManagerImpl::GetPhysicalMemoryUsage(TaskId task_id) const {
return GetTaskGroupByTaskId(task_id)->physical_bytes();
}
int64 TaskManagerImpl::GetPrivateMemoryUsage(TaskId task_id) const {
return GetTaskGroupByTaskId(task_id)->private_bytes();
}
int64 TaskManagerImpl::GetSharedMemoryUsage(TaskId task_id) const {
return GetTaskGroupByTaskId(task_id)->shared_bytes();
}
int64 TaskManagerImpl::GetGpuMemoryUsage(TaskId task_id,
bool* has_duplicates) const {
const TaskGroup* task_group = GetTaskGroupByTaskId(task_id);
if (has_duplicates)
*has_duplicates = task_group->gpu_memory_has_duplicates();
return task_group->gpu_memory();
}
int TaskManagerImpl::GetIdleWakeupsPerSecond(TaskId task_id) const {
return GetTaskGroupByTaskId(task_id)->idle_wakeups_per_second();
}
int TaskManagerImpl::GetNaClDebugStubPort(TaskId task_id) const {
#if !defined(DISABLE_NACL)
return GetTaskGroupByTaskId(task_id)->nacl_debug_stub_port();
#else
return -1;
#endif // !defined(DISABLE_NACL)
}
void TaskManagerImpl::GetGDIHandles(TaskId task_id,
int64* current,
int64* peak) const {
#if defined(OS_WIN)
const TaskGroup* task_group = GetTaskGroupByTaskId(task_id);
*current = task_group->gdi_current_handles();
*peak = task_group->gdi_peak_handles();
#else
*current = -1;
*peak = -1;
#endif // defined(OS_WIN)
}
void TaskManagerImpl::GetUSERHandles(TaskId task_id,
int64* current,
int64* peak) const {
#if defined(OS_WIN)
const TaskGroup* task_group = GetTaskGroupByTaskId(task_id);
*current = task_group->user_current_handles();
*peak = task_group->user_peak_handles();
#else
*current = -1;
*peak = -1;
#endif // defined(OS_WIN)
}
const base::string16& TaskManagerImpl::GetTitle(TaskId task_id) const {
return GetTaskByTaskId(task_id)->title();
}
base::string16 TaskManagerImpl::GetProfileName(TaskId task_id) const {
return GetTaskByTaskId(task_id)->GetProfileName();
}
const gfx::ImageSkia& TaskManagerImpl::GetIcon(TaskId task_id) const {
return GetTaskByTaskId(task_id)->icon();
}
const base::ProcessHandle& TaskManagerImpl::GetProcessHandle(
TaskId task_id) const {
return GetTaskGroupByTaskId(task_id)->process_handle();
}
const base::ProcessId& TaskManagerImpl::GetProcessId(TaskId task_id) const {
return GetTaskGroupByTaskId(task_id)->process_id();
}
Task::Type TaskManagerImpl::GetType(TaskId task_id) const {
return GetTaskByTaskId(task_id)->GetType();
}
int64 TaskManagerImpl::GetNetworkUsage(TaskId task_id) const {
return GetTaskByTaskId(task_id)->network_usage();
}
int64 TaskManagerImpl::GetSqliteMemoryUsed(TaskId task_id) const {
return GetTaskByTaskId(task_id)->GetSqliteMemoryUsed();
}
bool TaskManagerImpl::GetV8Memory(TaskId task_id,
int64* allocated,
int64* used) const {
const Task* task = GetTaskByTaskId(task_id);
if (!task->ReportsV8Memory())
return false;
*allocated = task->GetV8MemoryAllocated();
*used = task->GetV8MemoryUsed();
return true;
}
bool TaskManagerImpl::GetWebCacheStats(
TaskId task_id,
blink::WebCache::ResourceTypeStats* stats) const {
const Task* task = GetTaskByTaskId(task_id);
if (!task->ReportsWebCacheStats())
return false;
*stats = task->GetWebCacheStats();
return true;
}
const TaskIdList& TaskManagerImpl::GetTaskIdsList() const {
DCHECK(is_running_) << "Task manager is not running. You must observe the "
"task manager for it to start running";
if (sorted_task_ids_.empty()) {
sorted_task_ids_.reserve(task_groups_by_task_id_.size());
// Ensure browser process group of task IDs are at the beginning of the
// list.
const TaskGroup* browser_group =
task_groups_by_proc_id_.at(base::GetCurrentProcId());
browser_group->AppendSortedTaskIds(&sorted_task_ids_);
for (const auto& groups_pair : task_groups_by_proc_id_) {
if (groups_pair.second == browser_group)
continue;
groups_pair.second->AppendSortedTaskIds(&sorted_task_ids_);
}
}
return sorted_task_ids_;
}
size_t TaskManagerImpl::GetNumberOfTasksOnSameProcess(TaskId task_id) const {
return GetTaskGroupByTaskId(task_id)->num_tasks();
}
void TaskManagerImpl::TaskAdded(Task* task) {
DCHECK(task);
TaskGroup* task_group = nullptr;
const base::ProcessId proc_id = task->process_id();
const TaskId task_id = task->task_id();
auto itr = task_groups_by_proc_id_.find(proc_id);
if (itr == task_groups_by_proc_id_.end()) {
task_group = new TaskGroup(task->process_handle(),
proc_id,
blocking_pool_runner_);
task_groups_by_proc_id_[proc_id] = task_group;
} else {
task_group = itr->second;
}
task_group->AddTask(task);
task_groups_by_task_id_[task_id] = task_group;
// Invalidate the cached sorted IDs by clearing the list.
sorted_task_ids_.clear();
NotifyObserversOnTaskAdded(task_id);
}
void TaskManagerImpl::TaskRemoved(Task* task) {
DCHECK(task);
const base::ProcessId proc_id = task->process_id();
const TaskId task_id = task->task_id();
DCHECK(ContainsKey(task_groups_by_proc_id_, proc_id));
DCHECK(ContainsKey(task_groups_by_task_id_, task_id));
NotifyObserversOnTaskToBeRemoved(task_id);
TaskGroup* task_group = task_groups_by_proc_id_.at(proc_id);
task_group->RemoveTask(task);
task_groups_by_task_id_.erase(task_id);
// Invalidate the cached sorted IDs by clearing the list.
sorted_task_ids_.clear();
if (task_group->empty()) {
task_groups_by_proc_id_.erase(proc_id);
delete task_group;
}
}
void TaskManagerImpl::OnVideoMemoryUsageStatsUpdate(
const content::GPUVideoMemoryUsageStats& gpu_memory_stats) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
gpu_memory_stats_ = gpu_memory_stats;
}
// static
void TaskManagerImpl::OnMultipleBytesReadUI(
std::vector<BytesReadParam>* params) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
DCHECK(params);
for (BytesReadParam& param : *params) {
if (!GetInstance()->UpdateTasksWithBytesRead(param)) {
// We can't match a task to the notification. That might mean the
// tab that started a download was closed, or the request may have had
// no originating task associated with it in the first place.
// We attribute orphaned/unaccounted activity to the Browser process.
DCHECK(param.origin_pid || (param.child_id != -1));
param.origin_pid = 0;
param.child_id = param.route_id = -1;
GetInstance()->UpdateTasksWithBytesRead(param);
}
}
}
void TaskManagerImpl::Refresh() {
if (IsResourceRefreshEnabled(REFRESH_TYPE_GPU_MEMORY)) {
content::GpuDataManager::GetInstance()->
RequestVideoMemoryUsageStatsUpdate();
}
for (auto& groups_itr : task_groups_by_proc_id_) {
groups_itr.second->Refresh(gpu_memory_stats_,
GetCurrentRefreshTime(),
enabled_resources_flags());
}
NotifyObserversOnRefresh(GetTaskIdsList());
}
void TaskManagerImpl::StartUpdating() {
is_running_ = true;
for (auto& provider : task_providers_)
provider->SetObserver(this);
io_thread_helper_manager_.reset(new IoThreadHelperManager);
}
void TaskManagerImpl::StopUpdating() {
is_running_ = false;
io_thread_helper_manager_.reset();
for (auto& provider : task_providers_)
provider->ClearObserver();
STLDeleteValues(&task_groups_by_proc_id_);
task_groups_by_task_id_.clear();
sorted_task_ids_.clear();
}
bool TaskManagerImpl::UpdateTasksWithBytesRead(const BytesReadParam& param) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
for (auto& task_provider : task_providers_) {
Task* task = task_provider->GetTaskOfUrlRequest(param.origin_pid,
param.child_id,
param.route_id);
if (task) {
task->OnNetworkBytesRead(param.byte_count);
return true;
}
}
// Couldn't match the bytes to any existing task.
return false;
}
TaskGroup* TaskManagerImpl::GetTaskGroupByTaskId(TaskId task_id) const {
DCHECK(ContainsKey(task_groups_by_task_id_, task_id));
return task_groups_by_task_id_.at(task_id);
}
Task* TaskManagerImpl::GetTaskByTaskId(TaskId task_id) const {
return GetTaskGroupByTaskId(task_id)->GetTaskById(task_id);
}
} // namespace task_management