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.
4
5#include "content/browser/profiler_controller_impl.h"
6
7#include "base/bind.h"
8#include "base/process/process_handle.h"
9#include "base/tracked_objects.h"
10#include "content/common/child_process_messages.h"
11#include "content/public/browser/browser_child_process_host_iterator.h"
12#include "content/public/browser/browser_thread.h"
13#include "content/public/browser/child_process_data.h"
14#include "content/public/browser/profiler_subscriber.h"
15#include "content/public/browser/render_process_host.h"
16
17namespace content {
18
19ProfilerController* ProfilerController::GetInstance() {
20  return ProfilerControllerImpl::GetInstance();
21}
22
23ProfilerControllerImpl* ProfilerControllerImpl::GetInstance() {
24  return Singleton<ProfilerControllerImpl>::get();
25}
26
27ProfilerControllerImpl::ProfilerControllerImpl() : subscriber_(NULL) {
28}
29
30ProfilerControllerImpl::~ProfilerControllerImpl() {
31}
32
33void ProfilerControllerImpl::OnPendingProcesses(int sequence_number,
34                                                int pending_processes,
35                                                bool end) {
36  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
37  if (subscriber_)
38    subscriber_->OnPendingProcesses(sequence_number, pending_processes, end);
39}
40
41void ProfilerControllerImpl::OnProfilerDataCollected(
42    int sequence_number,
43    const tracked_objects::ProcessDataSnapshot& profiler_data,
44    int process_type) {
45  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
46    BrowserThread::PostTask(
47        BrowserThread::UI, FROM_HERE,
48        base::Bind(&ProfilerControllerImpl::OnProfilerDataCollected,
49                   base::Unretained(this),
50                   sequence_number,
51                   profiler_data,
52                   process_type));
53    return;
54  }
55
56  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
57  if (subscriber_) {
58    subscriber_->OnProfilerDataCollected(sequence_number, profiler_data,
59                                         process_type);
60  }
61}
62
63void ProfilerControllerImpl::Register(ProfilerSubscriber* subscriber) {
64  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
65  DCHECK(!subscriber_);
66  subscriber_ = subscriber;
67}
68
69void ProfilerControllerImpl::Unregister(const ProfilerSubscriber* subscriber) {
70  DCHECK_EQ(subscriber_, subscriber);
71  subscriber_ = NULL;
72}
73
74void ProfilerControllerImpl::GetProfilerDataFromChildProcesses(
75    int sequence_number) {
76  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
77
78  int pending_processes = 0;
79  for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
80    // In some cases, there may be no child process of the given type (for
81    // example, the GPU process may not exist and there may instead just be a
82    // GPU thread in the browser process). If that's the case, then the process
83    // handle will be base::kNullProcessHandle and we shouldn't ask it for data.
84    if (iter.GetData().handle == base::kNullProcessHandle)
85      continue;
86
87    ++pending_processes;
88    if (!iter.Send(new ChildProcessMsg_GetChildProfilerData(sequence_number)))
89      --pending_processes;
90  }
91
92  BrowserThread::PostTask(
93      BrowserThread::UI,
94      FROM_HERE,
95      base::Bind(
96          &ProfilerControllerImpl::OnPendingProcesses,
97          base::Unretained(this),
98          sequence_number,
99          pending_processes,
100          true));
101}
102
103void ProfilerControllerImpl::GetProfilerData(int sequence_number) {
104  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
105
106  int pending_processes = 0;
107  for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
108       !it.IsAtEnd(); it.Advance()) {
109    ++pending_processes;
110    if (!it.GetCurrentValue()->Send(
111            new ChildProcessMsg_GetChildProfilerData(sequence_number))) {
112      --pending_processes;
113    }
114  }
115  OnPendingProcesses(sequence_number, pending_processes, false);
116
117  BrowserThread::PostTask(
118      BrowserThread::IO,
119      FROM_HERE,
120      base::Bind(&ProfilerControllerImpl::GetProfilerDataFromChildProcesses,
121                 base::Unretained(this),
122                 sequence_number));
123}
124
125}  // namespace content
126