blob: 5709ac2f0e5c5495941232e8602c35a4162c981f [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef SRC_PERFORMANCE_PERFETTO_BRIDGE_CONSUMER_ADAPTER_H_
#define SRC_PERFORMANCE_PERFETTO_BRIDGE_CONSUMER_ADAPTER_H_
#include <lib/trace-engine/instrumentation.h>
#include <lib/trace-provider/provider.h>
#include <lib/trace/observer.h>
#include <memory>
#include <mutex>
#include <perfetto/base/task_runner.h>
#include <perfetto/ext/tracing/core/consumer.h>
#include <perfetto/ext/tracing/core/tracing_service.h>
#include "lib/fit/function.h"
#include "lib/fpromise/promise.h"
#include "lib/trace-engine/types.h"
#include "src/lib/fxl/synchronization/thread_annotations.h"
#include "src/tracing/core/tracing_service_impl.h"
// Encapsulation of the Fuchsia trace observer and provider protocols,
// for testing.
// TODO(https://fxbug.dev/42067571): Use a testable C++ API from trace engine if one becomes
// available.
class FuchsiaTracing {
public:
FuchsiaTracing() = default;
virtual ~FuchsiaTracing() = default;
virtual void StartObserving(fit::function<void(trace_state_t)>) = 0;
virtual void AcquireProlongedContext() = 0;
virtual void ReleaseProlongedContext() = 0;
virtual void AcquireWriteContext() = 0;
virtual bool HasWriteContext() = 0;
virtual void WriteBlob(const char* data, size_t size) = 0;
virtual void ReleaseWriteContext() = 0;
virtual trace::ProviderConfig GetProviderConfig() = 0;
virtual void SetGetKnownCategoriesCallback(trace::GetKnownCategoriesCallback callback) = 0;
};
// Adapts the Fuchsia Tracing protocol to the Perfetto Consumer protocol.
// Perfetto events are handled via the perfetto::Consumer method implementations.
// Commands are sent to Perfetto via |consumer_endpoint_|.
class ConsumerAdapter : public perfetto::Consumer {
public:
using ConnectConsumerCallback =
std::function<std::unique_ptr<perfetto::ConsumerEndpoint>(perfetto::Consumer*)>;
// Sets the amount of buffer usage that will cause the buffer to be read mid-trace.
static constexpr float kConsumerUtilizationReadThreshold = 0.6f;
ConsumerAdapter(perfetto::TracingService* tracing_service, trace::TraceProvider* trace_provider,
perfetto::base::TaskRunner* perfetto_task_runner);
// Public for testing.
ConsumerAdapter(ConnectConsumerCallback connect_callback,
std::unique_ptr<FuchsiaTracing> fuchsia_tracing,
perfetto::base::TaskRunner* perfetto_task_runner);
~ConsumerAdapter() override;
ConsumerAdapter(const ConsumerAdapter& other) = delete;
void operator=(const ConsumerAdapter& other) = delete;
private:
class ScopedProlongedTraceContext;
// Finite state machine states.
// State transition rules are applied in ChangeState().
enum class State {
INACTIVE, // Tracing inactive.
// Active tracing states.
ACTIVE, // Tracing active; scheduled stats-checking task pending.
STATS, // Periodic buffer utilization check before READING.
// Changes to ACTIVE if there is sufficient space in the buffer.
READING, // Reading consumer buffer once STATS threshold is hit.
// Changes to ACTIVE on read completion.
// Shutdown states, run in-order in response to the Fuchsia TRACE_STOPPING event.
READING_PENDING_SHUTDOWN, // If shutdown is called mid-read, defers shutdown until reading
// has finished. Changes to SHUTDOWN_FLUSH on read completion.
SHUTDOWN_FLUSH, // Flush() called on shutdown.
SHUTDOWN_DISABLED, // DisableTracing() called after flush completion.
SHUTDOWN_READING, // ReadBuffers() called after tracing has stopped.
SHUTDOWN_STATS, // GetTraceStats() called for end-of-session diagnostics logging.
// Changes to INACTIVE when complete.
};
void ChangeState(State new_state);
State GetState();
// Handles fuchsia.tracing events.
void OnTraceStateUpdate(trace_state_t new_state);
// Called in response to the Fuchsia TRACE_STARTED event.
void OnStartTracing();
// Called in response to the Fuchsia TRACE_STOPPING event.
void CallPerfettoDisableTracing();
void ShutdownTracing();
void SchedulePerfettoGetStats();
void CallPerfettoReadBuffers(bool on_shutdown);
void OnPerfettoReadBuffersComplete();
void CallPerfettoFlush();
void CallPerfettoGetTraceStats(bool on_shutdown);
fpromise::promise<std::vector<trace::KnownCategory>> GetKnownCategories();
// perfetto::Consumer implementation.
void OnConnect() override;
void OnDisconnect() override;
void OnTracingDisabled(const std::string& error) override;
void OnTraceData(std::vector<perfetto::TracePacket> packets, bool has_more) override;
void OnDetach(bool success) override;
void OnAttach(bool success, const perfetto::TraceConfig&) override;
void OnTraceStats(bool success, const perfetto::TraceStats&) override;
void OnObservableEvents(const perfetto::ObservableEvents&) override;
// Interactions with `perfetto_service_` and `consumer_endpoint_` must take place on
// `perfetto_task_runner_`. `consumer_endpoint_` lives for the duration of a tracing session.
perfetto::base::TaskRunner* perfetto_task_runner_;
ConnectConsumerCallback connect_callback_;
std::unique_ptr<perfetto::ConsumerEndpoint> consumer_endpoint_;
std::unique_ptr<FuchsiaTracing> fuchsia_tracing_;
std::atomic<State> state_ FXL_GUARDED_BY(state_mutex_) = State::INACTIVE;
std::mutex state_mutex_;
};
#endif // SRC_PERFORMANCE_PERFETTO_BRIDGE_CONSUMER_ADAPTER_H_