Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(125)

Side by Side Diff: services/resource_coordinator/tracing/coordinator_impl.cc

Issue 2833873003: WIP: The tracing service prototype
Patch Set: sync Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2017 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 "services/resource_coordinator/tracing/coordinator_impl.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/callback_forward.h"
10 #include "base/memory/ptr_util.h"
11 #include "base/task_scheduler/post_task.h"
12 #include "base/task_scheduler/task_traits.h"
13 #include "base/threading/thread_task_runner_handle.h"
14 #include "base/trace_event/trace_config.h"
15 #include "mojo/common/data_pipe_utils.h"
16 #include "services/resource_coordinator/public/cpp/tracing/chrome_agent.h"
17 #include "services/resource_coordinator/tracing/agent_set_impl.h"
18 #include "services/resource_coordinator/tracing/recorder_impl.h"
19 #include "services/service_manager/public/cpp/bind_source_info.h"
20
21 namespace {
22
23 resource_coordinator::tracing::CoordinatorImpl* g_coordinator_impl;
24
25 } // namespace
26
27 namespace resource_coordinator {
28 namespace tracing {
29
30 const char CoordinatorImpl::kRequestBufferUsageType[] = "RequestBufferUsage";
31
32 // static
33 CoordinatorImpl* CoordinatorImpl::GetInstance() {
34 return g_coordinator_impl;
35 }
36
37 CoordinatorImpl::CoordinatorImpl()
38 : binding_(this), task_runner_(base::ThreadTaskRunnerHandle::Get()) {
39 DCHECK(!g_coordinator_impl);
40 g_coordinator_impl = this;
41 background_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
42 base::TaskTraits().MayBlock().WithBaseSyncPrimitives().WithPriority(
43 base::TaskPriority::BACKGROUND));
44 agent_set_ = base::MakeUnique<AgentSetImpl>();
45 mojom::AgentSetPtr agent_set_interface_ptr;
46 agent_set_->BindAgentSetRequest(service_manager::BindSourceInfo(),
47 mojo::MakeRequest(&agent_set_interface_ptr));
48 resource_coordinator::tracing::ChromeAgent::InitializeIfNeeded(
49 std::move(agent_set_interface_ptr));
50 }
51
52 CoordinatorImpl::~CoordinatorImpl() {
53 g_coordinator_impl = nullptr;
54 }
55
56 void CoordinatorImpl::BindCoordinatorRequest(
57 mojom::CoordinatorRequest request) {
58 binding_.Bind(std::move(request));
59 }
60
61 void CoordinatorImpl::StartTracing(mojo::ScopedDataPipeProducerHandle stream,
62 const std::string& config) {
63 DCHECK(!stream_.is_valid());
64 config_ = config;
65 stream_ = std::move(stream);
66 first_recorder_update_ = true;
67 recording_label_.clear();
68 agent_set_->SetAgentProcessingCallback(base::Bind(
69 &CoordinatorImpl::SendStartTracingToAgent, base::Unretained(this)));
70 }
71
72 void CoordinatorImpl::StopAndFlush() {
73 DCHECK(IsTracing());
74 agent_set_->ResetAgentProcessingCallback();
75 agent_set_->ForAllAgents(
76 [](AgentSetImpl::Entry* entry) { entry->agent()->StopAndFlush(); });
77 if (recorders_.size() == 0)
78 OnFlushDone();
79 }
80
81 void CoordinatorImpl::IsTracing(const IsTracingCallback& callback) {
82 callback.Run(IsTracing());
83 }
84
85 bool CoordinatorImpl::IsTracing() {
86 return stream_.is_valid() || !get_categories_callback_.is_null();
87 }
88
89 void CoordinatorImpl::RequestBufferUsage(
90 const RequestBufferUsageCallback& callback) {
91 if (!request_buffer_usage_callback_.is_null()) {
92 callback.Run(false, 0, 0);
93 return;
94 }
95
96 maximum_trace_buffer_usage_ = 0;
97 approximate_event_count_ = 0;
98 request_buffer_usage_callback_ = callback;
99 pending_request_buffer_status_count_ = 0;
100 agent_set_->ForAllAgents([this](AgentSetImpl::Entry* entry) {
101 entry->AddDisconnectClosure(
102 kRequestBufferUsageType,
103 base::BindOnce(&CoordinatorImpl::OnRequestBufferStatusResponse,
104 base::Unretained(this), entry, 0, 0));
105 entry->agent()->RequestBufferStatus(
106 base::BindRepeating(&CoordinatorImpl::OnRequestBufferStatusResponse,
107 base::Unretained(this), entry));
108 pending_request_buffer_status_count_++;
109 });
110 }
111
112 void CoordinatorImpl::OnRequestBufferStatusResponse(AgentSetImpl::Entry* entry,
113 uint32_t capacity,
114 uint32_t count) {
115 if (!entry->RemoveDisconnectClosure(kRequestBufferUsageType))
116 return;
117
118 DCHECK(pending_request_buffer_status_count_);
119 if (capacity > 0) {
120 float percent_full =
121 static_cast<float>(static_cast<double>(count) / capacity);
122 maximum_trace_buffer_usage_ =
123 std::max(maximum_trace_buffer_usage_, percent_full);
124 approximate_event_count_ += count;
125 }
126
127 if (--pending_request_buffer_status_count_ == 0) {
128 request_buffer_usage_callback_.Run(true, maximum_trace_buffer_usage_,
129 approximate_event_count_);
130 request_buffer_usage_callback_.Reset();
131 }
132 }
133
134 void CoordinatorImpl::SendStartTracingToAgent(AgentSetImpl::Entry* entry) {
135 bool is_array = entry->type() == mojom::TraceDataType::ARRAY;
136 mojom::RecorderPtr ptr;
137 recorders_[entry->label()].insert(base::MakeUnique<RecorderImpl>(
138 MakeRequest(&ptr), is_array,
139 base::BindRepeating(&CoordinatorImpl::OnRecorderUpdated,
140 base::Unretained(this), entry->label()),
141 background_task_runner_));
142 DCHECK(is_array || recorders_[entry->label()].size() == 1);
143 entry->agent()->StartTracing(config_, std::move(ptr),
144 !get_categories_callback_.is_null(),
145 base::Closure());
146 }
147
148 void CoordinatorImpl::OnFlushDone() {
149 if (!get_categories_callback_.is_null()) {
150 std::set<std::string> category_set;
151 for (const auto& key_value : recorders_) {
152 for (const auto& recorder : key_value.second) {
153 const auto& recorder_categories = recorder->category_set();
154 category_set.insert(recorder_categories.begin(),
155 recorder_categories.end());
156 }
157 }
158
159 std::string categories_str;
160 bool first = true;
161 for (const auto& category : category_set) {
162 if (!first)
163 categories_str += ",";
164 first = false;
165 categories_str += category;
166 }
167 get_categories_callback_.Run(categories_str);
168 get_categories_callback_.Reset();
169 }
170
171 recorders_.clear();
172 stream_.reset();
173 }
174
175 void CoordinatorImpl::OnRecorderUpdated(const std::string& label) {
176 DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
177 if (!recording_label_.empty() && recording_label_ != label)
178 return;
179 while (true) {
180 if (!recording_label_.empty() && ReadFromRecorders())
181 return;
182 recording_label_.clear();
183 bool all_finished = true;
184 for (const auto& key_value : recorders_) {
185 for (const auto& recorder : key_value.second) {
186 all_finished &= !recorder->is_recording();
187 if (recorder->data().size() > 0) {
188 recording_label_ = key_value.first;
189 write_label_ = true;
190 break;
191 }
192 }
193 if (recording_label_.size() != 0)
194 break;
195 }
196 if (recording_label_.size() == 0) {
197 // No recorder has any data for us, right now.
198 if (all_finished) {
199 if (!first_recorder_update_)
200 mojo::common::BlockingCopyFromString("}", stream_);
201 // Recorder connections should be closed on their binding thread.
202 task_runner_->PostTask(
203 FROM_HERE,
204 base::Bind(&CoordinatorImpl::OnFlushDone, base::Unretained(this)));
205 }
206 return;
207 }
208 }
209 }
210
211 bool CoordinatorImpl::ReadFromRecorders() {
212 DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
213 bool all_finished = true;
214 bool is_array = (*recorders_[recording_label_].begin())->is_array();
215 for (const auto& recorder : recorders_[recording_label_]) {
216 all_finished &= !recorder->is_recording();
217 if (recorder->data().size() == 0)
218 continue;
219 DCHECK(stream_.is_valid());
220 if (write_label_) {
221 std::string prefix = first_recorder_update_ ? "{\"" : "\"";
222 prefix += recording_label_ + "\":" + (is_array ? "[" : "\"");
223 mojo::common::BlockingCopyFromString(prefix, stream_);
224 write_label_ = false;
225 first_recorder_update_ = false;
226 } else {
227 if (recorder->is_array())
228 mojo::common::BlockingCopyFromString(",", stream_);
229 }
230 mojo::common::BlockingCopyFromString(recorder->data(), stream_);
231 recorder->clear_data();
232 }
233 if (all_finished) {
234 if (!write_label_)
235 mojo::common::BlockingCopyFromString(is_array ? "]" : "\"", stream_);
236 return false;
237 }
238 return true;
239 }
240
241 void CoordinatorImpl::GetCategories(const GetCategoriesCallback& callback) {
242 get_categories_callback_ = callback;
243 StartTracing(mojo::ScopedDataPipeProducerHandle(),
244 base::trace_event::TraceConfig("*", "").ToString());
245 StopAndFlush();
246 }
247
248 } // namespace tracing
249 } // namespace resource_coordinator
OLDNEW
« no previous file with comments | « services/resource_coordinator/tracing/coordinator_impl.h ('k') | services/resource_coordinator/tracing/main.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698