// Copyright (c) 2012 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 "content/browser/profiler_controller_impl.h"
#include "base/bind.h"
#include "base/process/process_handle.h"
#include "base/tracked_objects.h"
#include "content/common/child_process_messages.h"
#include "content/public/browser/browser_child_process_host_iterator.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/profiler_subscriber.h"
#include "content/public/browser/render_process_host.h"
namespace content {
ProfilerController* ProfilerController::GetInstance() {
return ProfilerControllerImpl::GetInstance();
}
ProfilerControllerImpl* ProfilerControllerImpl::GetInstance() {
return Singleton<ProfilerControllerImpl>::get();
}
ProfilerControllerImpl::ProfilerControllerImpl() : subscriber_(NULL) {
}
ProfilerControllerImpl::~ProfilerControllerImpl() {
}
void ProfilerControllerImpl::OnPendingProcesses(int sequence_number,
int pending_processes,
bool end) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (subscriber_)
subscriber_->OnPendingProcesses(sequence_number, pending_processes, end);
}
void ProfilerControllerImpl::OnProfilerDataCollected(
int sequence_number,
const tracked_objects::ProcessDataSnapshot& profiler_data,
int process_type) {
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
BrowserThread::PostTask(
BrowserThread::UI, FROM_HERE,
base::Bind(&ProfilerControllerImpl::OnProfilerDataCollected,
base::Unretained(this),
sequence_number,
profiler_data,
process_type));
return;
}
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
if (subscriber_) {
subscriber_->OnProfilerDataCollected(sequence_number, profiler_data,
process_type);
}
}
void ProfilerControllerImpl::Register(ProfilerSubscriber* subscriber) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DCHECK(!subscriber_);
subscriber_ = subscriber;
}
void ProfilerControllerImpl::Unregister(const ProfilerSubscriber* subscriber) {
DCHECK_EQ(subscriber_, subscriber);
subscriber_ = NULL;
}
void ProfilerControllerImpl::GetProfilerDataFromChildProcesses(
int sequence_number) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
int pending_processes = 0;
for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
// In some cases, there may be no child process of the given type (for
// example, the GPU process may not exist and there may instead just be a
// GPU thread in the browser process). If that's the case, then the process
// handle will be base::kNullProcessHandle and we shouldn't ask it for data.
if (iter.GetData().handle == base::kNullProcessHandle)
continue;
++pending_processes;
if (!iter.Send(new ChildProcessMsg_GetChildProfilerData(sequence_number)))
--pending_processes;
}
BrowserThread::PostTask(
BrowserThread::UI,
FROM_HERE,
base::Bind(
&ProfilerControllerImpl::OnPendingProcesses,
base::Unretained(this),
sequence_number,
pending_processes,
true));
}
void ProfilerControllerImpl::GetProfilerData(int sequence_number) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
int pending_processes = 0;
for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
!it.IsAtEnd(); it.Advance()) {
++pending_processes;
if (!it.GetCurrentValue()->Send(
new ChildProcessMsg_GetChildProfilerData(sequence_number))) {
--pending_processes;
}
}
OnPendingProcesses(sequence_number, pending_processes, false);
BrowserThread::PostTask(
BrowserThread::IO,
FROM_HERE,
base::Bind(&ProfilerControllerImpl::GetProfilerDataFromChildProcesses,
base::Unretained(this),
sequence_number));
}
} // namespace content