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

Unified 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 side-by-side diff with in-line comments
Download patch
Index: services/resource_coordinator/tracing/coordinator_impl.cc
diff --git a/services/resource_coordinator/tracing/coordinator_impl.cc b/services/resource_coordinator/tracing/coordinator_impl.cc
new file mode 100644
index 0000000000000000000000000000000000000000..caf526cbb9f76826b2553f99d7efa073208c0be1
--- /dev/null
+++ b/services/resource_coordinator/tracing/coordinator_impl.cc
@@ -0,0 +1,249 @@
+// Copyright 2017 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 "services/resource_coordinator/tracing/coordinator_impl.h"
+
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_forward.h"
+#include "base/memory/ptr_util.h"
+#include "base/task_scheduler/post_task.h"
+#include "base/task_scheduler/task_traits.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "base/trace_event/trace_config.h"
+#include "mojo/common/data_pipe_utils.h"
+#include "services/resource_coordinator/public/cpp/tracing/chrome_agent.h"
+#include "services/resource_coordinator/tracing/agent_set_impl.h"
+#include "services/resource_coordinator/tracing/recorder_impl.h"
+#include "services/service_manager/public/cpp/bind_source_info.h"
+
+namespace {
+
+resource_coordinator::tracing::CoordinatorImpl* g_coordinator_impl;
+
+} // namespace
+
+namespace resource_coordinator {
+namespace tracing {
+
+const char CoordinatorImpl::kRequestBufferUsageType[] = "RequestBufferUsage";
+
+// static
+CoordinatorImpl* CoordinatorImpl::GetInstance() {
+ return g_coordinator_impl;
+}
+
+CoordinatorImpl::CoordinatorImpl()
+ : binding_(this), task_runner_(base::ThreadTaskRunnerHandle::Get()) {
+ DCHECK(!g_coordinator_impl);
+ g_coordinator_impl = this;
+ background_task_runner_ = base::CreateSequencedTaskRunnerWithTraits(
+ base::TaskTraits().MayBlock().WithBaseSyncPrimitives().WithPriority(
+ base::TaskPriority::BACKGROUND));
+ agent_set_ = base::MakeUnique<AgentSetImpl>();
+ mojom::AgentSetPtr agent_set_interface_ptr;
+ agent_set_->BindAgentSetRequest(service_manager::BindSourceInfo(),
+ mojo::MakeRequest(&agent_set_interface_ptr));
+ resource_coordinator::tracing::ChromeAgent::InitializeIfNeeded(
+ std::move(agent_set_interface_ptr));
+}
+
+CoordinatorImpl::~CoordinatorImpl() {
+ g_coordinator_impl = nullptr;
+}
+
+void CoordinatorImpl::BindCoordinatorRequest(
+ mojom::CoordinatorRequest request) {
+ binding_.Bind(std::move(request));
+}
+
+void CoordinatorImpl::StartTracing(mojo::ScopedDataPipeProducerHandle stream,
+ const std::string& config) {
+ DCHECK(!stream_.is_valid());
+ config_ = config;
+ stream_ = std::move(stream);
+ first_recorder_update_ = true;
+ recording_label_.clear();
+ agent_set_->SetAgentProcessingCallback(base::Bind(
+ &CoordinatorImpl::SendStartTracingToAgent, base::Unretained(this)));
+}
+
+void CoordinatorImpl::StopAndFlush() {
+ DCHECK(IsTracing());
+ agent_set_->ResetAgentProcessingCallback();
+ agent_set_->ForAllAgents(
+ [](AgentSetImpl::Entry* entry) { entry->agent()->StopAndFlush(); });
+ if (recorders_.size() == 0)
+ OnFlushDone();
+}
+
+void CoordinatorImpl::IsTracing(const IsTracingCallback& callback) {
+ callback.Run(IsTracing());
+}
+
+bool CoordinatorImpl::IsTracing() {
+ return stream_.is_valid() || !get_categories_callback_.is_null();
+}
+
+void CoordinatorImpl::RequestBufferUsage(
+ const RequestBufferUsageCallback& callback) {
+ if (!request_buffer_usage_callback_.is_null()) {
+ callback.Run(false, 0, 0);
+ return;
+ }
+
+ maximum_trace_buffer_usage_ = 0;
+ approximate_event_count_ = 0;
+ request_buffer_usage_callback_ = callback;
+ pending_request_buffer_status_count_ = 0;
+ agent_set_->ForAllAgents([this](AgentSetImpl::Entry* entry) {
+ entry->AddDisconnectClosure(
+ kRequestBufferUsageType,
+ base::BindOnce(&CoordinatorImpl::OnRequestBufferStatusResponse,
+ base::Unretained(this), entry, 0, 0));
+ entry->agent()->RequestBufferStatus(
+ base::BindRepeating(&CoordinatorImpl::OnRequestBufferStatusResponse,
+ base::Unretained(this), entry));
+ pending_request_buffer_status_count_++;
+ });
+}
+
+void CoordinatorImpl::OnRequestBufferStatusResponse(AgentSetImpl::Entry* entry,
+ uint32_t capacity,
+ uint32_t count) {
+ if (!entry->RemoveDisconnectClosure(kRequestBufferUsageType))
+ return;
+
+ DCHECK(pending_request_buffer_status_count_);
+ if (capacity > 0) {
+ float percent_full =
+ static_cast<float>(static_cast<double>(count) / capacity);
+ maximum_trace_buffer_usage_ =
+ std::max(maximum_trace_buffer_usage_, percent_full);
+ approximate_event_count_ += count;
+ }
+
+ if (--pending_request_buffer_status_count_ == 0) {
+ request_buffer_usage_callback_.Run(true, maximum_trace_buffer_usage_,
+ approximate_event_count_);
+ request_buffer_usage_callback_.Reset();
+ }
+}
+
+void CoordinatorImpl::SendStartTracingToAgent(AgentSetImpl::Entry* entry) {
+ bool is_array = entry->type() == mojom::TraceDataType::ARRAY;
+ mojom::RecorderPtr ptr;
+ recorders_[entry->label()].insert(base::MakeUnique<RecorderImpl>(
+ MakeRequest(&ptr), is_array,
+ base::BindRepeating(&CoordinatorImpl::OnRecorderUpdated,
+ base::Unretained(this), entry->label()),
+ background_task_runner_));
+ DCHECK(is_array || recorders_[entry->label()].size() == 1);
+ entry->agent()->StartTracing(config_, std::move(ptr),
+ !get_categories_callback_.is_null(),
+ base::Closure());
+}
+
+void CoordinatorImpl::OnFlushDone() {
+ if (!get_categories_callback_.is_null()) {
+ std::set<std::string> category_set;
+ for (const auto& key_value : recorders_) {
+ for (const auto& recorder : key_value.second) {
+ const auto& recorder_categories = recorder->category_set();
+ category_set.insert(recorder_categories.begin(),
+ recorder_categories.end());
+ }
+ }
+
+ std::string categories_str;
+ bool first = true;
+ for (const auto& category : category_set) {
+ if (!first)
+ categories_str += ",";
+ first = false;
+ categories_str += category;
+ }
+ get_categories_callback_.Run(categories_str);
+ get_categories_callback_.Reset();
+ }
+
+ recorders_.clear();
+ stream_.reset();
+}
+
+void CoordinatorImpl::OnRecorderUpdated(const std::string& label) {
+ DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
+ if (!recording_label_.empty() && recording_label_ != label)
+ return;
+ while (true) {
+ if (!recording_label_.empty() && ReadFromRecorders())
+ return;
+ recording_label_.clear();
+ bool all_finished = true;
+ for (const auto& key_value : recorders_) {
+ for (const auto& recorder : key_value.second) {
+ all_finished &= !recorder->is_recording();
+ if (recorder->data().size() > 0) {
+ recording_label_ = key_value.first;
+ write_label_ = true;
+ break;
+ }
+ }
+ if (recording_label_.size() != 0)
+ break;
+ }
+ if (recording_label_.size() == 0) {
+ // No recorder has any data for us, right now.
+ if (all_finished) {
+ if (!first_recorder_update_)
+ mojo::common::BlockingCopyFromString("}", stream_);
+ // Recorder connections should be closed on their binding thread.
+ task_runner_->PostTask(
+ FROM_HERE,
+ base::Bind(&CoordinatorImpl::OnFlushDone, base::Unretained(this)));
+ }
+ return;
+ }
+ }
+}
+
+bool CoordinatorImpl::ReadFromRecorders() {
+ DCHECK(background_task_runner_->RunsTasksOnCurrentThread());
+ bool all_finished = true;
+ bool is_array = (*recorders_[recording_label_].begin())->is_array();
+ for (const auto& recorder : recorders_[recording_label_]) {
+ all_finished &= !recorder->is_recording();
+ if (recorder->data().size() == 0)
+ continue;
+ DCHECK(stream_.is_valid());
+ if (write_label_) {
+ std::string prefix = first_recorder_update_ ? "{\"" : "\"";
+ prefix += recording_label_ + "\":" + (is_array ? "[" : "\"");
+ mojo::common::BlockingCopyFromString(prefix, stream_);
+ write_label_ = false;
+ first_recorder_update_ = false;
+ } else {
+ if (recorder->is_array())
+ mojo::common::BlockingCopyFromString(",", stream_);
+ }
+ mojo::common::BlockingCopyFromString(recorder->data(), stream_);
+ recorder->clear_data();
+ }
+ if (all_finished) {
+ if (!write_label_)
+ mojo::common::BlockingCopyFromString(is_array ? "]" : "\"", stream_);
+ return false;
+ }
+ return true;
+}
+
+void CoordinatorImpl::GetCategories(const GetCategoriesCallback& callback) {
+ get_categories_callback_ = callback;
+ StartTracing(mojo::ScopedDataPipeProducerHandle(),
+ base::trace_event::TraceConfig("*", "").ToString());
+ StopAndFlush();
+}
+
+} // namespace tracing
+} // namespace resource_coordinator
« 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