/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef SRC_PROFILING_PERF_PERF_PRODUCER_H_ #define SRC_PROFILING_PERF_PERF_PRODUCER_H_ #include #include #include #include #include #include #include "perfetto/base/task_runner.h" #include "perfetto/ext/base/optional.h" #include "perfetto/ext/base/scoped_file.h" #include "perfetto/ext/base/unix_socket.h" #include "perfetto/ext/base/weak_ptr.h" #include "perfetto/ext/tracing/core/basic_types.h" #include "perfetto/ext/tracing/core/producer.h" #include "perfetto/ext/tracing/core/trace_writer.h" #include "perfetto/ext/tracing/core/tracing_service.h" #include "src/profiling/common/callstack_trie.h" #include "src/profiling/common/interning_output.h" #include "src/profiling/common/unwind_support.h" #include "src/profiling/perf/common_types.h" #include "src/profiling/perf/event_config.h" #include "src/profiling/perf/event_reader.h" #include "src/profiling/perf/proc_descriptors.h" #include "src/profiling/perf/unwinding.h" #include "src/tracing/core/metatrace_writer.h" // TODO(rsavitski): move to e.g. src/tracefs/. #include "src/traced/probes/ftrace/ftrace_procfs.h" namespace perfetto { namespace profiling { // TODO(rsavitski): describe the high-level architecture and threading. Rough // summary in the mean time: three stages: (1) kernel buffer reader that parses // the samples -> (2) callstack unwinder -> (3) interning and serialization of // samples. This class handles stages (1) and (3) on the main thread. Unwinding // is done by |Unwinder| on a dedicated thread. class PerfProducer : public Producer, public ProcDescriptorDelegate, public Unwinder::Delegate { public: PerfProducer(ProcDescriptorGetter* proc_fd_getter, base::TaskRunner* task_runner); ~PerfProducer() override = default; PerfProducer(const PerfProducer&) = delete; PerfProducer& operator=(const PerfProducer&) = delete; PerfProducer(PerfProducer&&) = delete; PerfProducer& operator=(PerfProducer&&) = delete; void ConnectWithRetries(const char* socket_name); // Producer impl: void OnConnect() override; void OnDisconnect() override; void OnTracingSetup() override {} void SetupDataSource(DataSourceInstanceID, const DataSourceConfig&) override; void StartDataSource(DataSourceInstanceID instance_id, const DataSourceConfig& config) override; void StopDataSource(DataSourceInstanceID instance_id) override; void Flush(FlushRequestID flush_id, const DataSourceInstanceID* data_source_ids, size_t num_data_sources) override; void ClearIncrementalState(const DataSourceInstanceID* data_source_ids, size_t num_data_sources) override; // ProcDescriptorDelegate impl: void OnProcDescriptors(pid_t pid, uid_t uid, base::ScopedFile maps_fd, base::ScopedFile mem_fd) override; // Unwinder::Delegate impl (callbacks from unwinder): void PostEmitSample(DataSourceInstanceID ds_id, CompletedSample sample) override; void PostEmitUnwinderSkippedSample(DataSourceInstanceID ds_id, ParsedSample sample) override; void PostFinishDataSourceStop(DataSourceInstanceID ds_id) override; private: // State of the producer's connection to tracing service (traced). enum State { kNotStarted = 0, kNotConnected, kConnecting, kConnected, }; // Represents the data source scoped view of a process. Specifically: // * whether the process is in scope of the tracing session (if the latter // specifies a target filter). // * the state of the (possibly asynchronous) lookup of /proc//{maps,mem} // file descriptors, which are necessary for callstack unwinding of samples. enum class ProcessTrackingStatus { kInitial, kResolving, // waiting on proc-fd lookup kResolved, // proc-fds obtained, and process considered relevant kExpired, // proc-fd lookup timed out kRejected // process not considered relevant for the data source }; struct DataSourceState { enum class Status { kActive, kShuttingDown }; DataSourceState(EventConfig _event_config, std::unique_ptr _trace_writer, std::vector _per_cpu_readers) : event_config(std::move(_event_config)), trace_writer(std::move(_trace_writer)), per_cpu_readers(std::move(_per_cpu_readers)) {} Status status = Status::kActive; const EventConfig event_config; std::unique_ptr trace_writer; // Indexed by cpu, vector never resized. std::vector per_cpu_readers; // Tracks the incremental state for interned entries. InterningOutputTracker interning_output; // Producer thread's view of sampled processes. This is the primary tracking // structure, but a subset of updates are replicated to a similar structure // in the |Unwinder|, which needs to track whether the necessary unwinding // inputs for a given process' samples are ready. std::map process_states; // Command lines we have decided to unwind, up to a total of // additional_cmdline_count values. base::FlatSet additional_cmdlines; }; // For |EmitSkippedSample|. enum class SampleSkipReason { kReadStage = 0, // discarded at read stage kUnwindEnqueue, // discarded due to unwinder queue being full kUnwindStage, // discarded at unwind stage }; void ConnectService(); void Restart(); void ResetConnectionBackoff(); void IncreaseConnectionBackoff(); // Periodic read task which reads a batch of samples from all kernel ring // buffers associated with the given data source. void TickDataSourceRead(DataSourceInstanceID ds_id); // Returns *false* if the reader has caught up with the writer position, true // otherwise. Return value is only useful if the underlying perf_event has // been paused (to identify when the buffer is empty). |max_samples| is a cap // on the amount of samples that will be parsed, which might be more than the // number of underlying records (as there might be non-sample records). bool ReadAndParsePerCpuBuffer(EventReader* reader, uint64_t max_samples, DataSourceInstanceID ds_id, DataSourceState* ds); void InitiateDescriptorLookup(DataSourceInstanceID ds_id, pid_t pid, uint32_t timeout_ms); // Do not call directly, use |InitiateDescriptorLookup|. void StartDescriptorLookup(DataSourceInstanceID ds_id, pid_t pid, uint32_t timeout_ms); void EvaluateDescriptorLookupTimeout(DataSourceInstanceID ds_id, pid_t pid); void EmitSample(DataSourceInstanceID ds_id, CompletedSample sample); void EmitRingBufferLoss(DataSourceInstanceID ds_id, size_t cpu, uint64_t records_lost); void PostEmitSkippedSample(DataSourceInstanceID ds_id, ParsedSample sample, SampleSkipReason reason); // Emit a packet indicating that a sample was relevant, but skipped as it was // considered to be not unwindable (e.g. the process no longer exists). void EmitSkippedSample(DataSourceInstanceID ds_id, ParsedSample sample, SampleSkipReason reason); // Starts the shutdown of the given data source instance, starting with // pausing the reader frontend. Once the reader reaches the point where all // kernel buffers have been fully consumed, it will notify the |Unwinder| to // proceed with the shutdown sequence. The unwinder in turn will call back to // this producer once there are no more outstanding samples for the data // source at the unwinding stage. void InitiateReaderStop(DataSourceState* ds); // Destroys the state belonging to this instance, and acks the stop to the // tracing service. void FinishDataSourceStop(DataSourceInstanceID ds_id); // Immediately destroys the data source state, and instructs the unwinder to // do the same. This is used for abrupt stops. void PurgeDataSource(DataSourceInstanceID ds_id); // Immediately stops the data source if this daemon's overall memory footprint // is above the given threshold. This periodic task is started only for data // sources that specify a limit. void CheckMemoryFootprintPeriodic(DataSourceInstanceID ds_id, uint32_t max_daemon_memory_kb); void StartMetatraceSource(DataSourceInstanceID ds_id, BufferID target_buffer); // Task runner owned by the main thread. base::TaskRunner* const task_runner_; State state_ = kNotStarted; const char* producer_socket_name_ = nullptr; uint32_t connection_backoff_ms_ = 0; // Valid and stable for the lifetime of this class. ProcDescriptorGetter* const proc_fd_getter_; // Owns shared memory, must outlive trace writing. std::unique_ptr endpoint_; // If multiple metatrace sources are enabled concurrently, // only the first one becomes active. std::map metatrace_writers_; // Interns callstacks across all data sources. // TODO(rsavitski): for long profiling sessions, consider purging trie when it // grows too large (at the moment purged only when no sources are active). // TODO(rsavitski): interning sequences are monotonic for the lifetime of the // daemon. Consider resetting them at safe points - possible when no sources // are active, and tricky otherwise. In the latter case, it'll require // emitting incremental sequence invalidation packets on all relevant // sequences. GlobalCallstackTrie callstack_trie_; // State associated with perf-sampling data sources. std::map data_sources_; // Unwinding stage, running on a dedicated thread. UnwinderHandle unwinding_worker_; // Used for tracepoint name -> id lookups. Initialized lazily, and in general // best effort - can be null if tracefs isn't accessible. std::unique_ptr tracefs_; base::WeakPtrFactory weak_factory_; // keep last }; } // namespace profiling } // namespace perfetto #endif // SRC_PROFILING_PERF_PERF_PRODUCER_H_