diff options
Diffstat (limited to 'src/profiling/memory/heapprofd_producer.h')
-rw-r--r-- | src/profiling/memory/heapprofd_producer.h | 132 |
1 files changed, 51 insertions, 81 deletions
diff --git a/src/profiling/memory/heapprofd_producer.h b/src/profiling/memory/heapprofd_producer.h index b8e9c53af..7cf33670e 100644 --- a/src/profiling/memory/heapprofd_producer.h +++ b/src/profiling/memory/heapprofd_producer.h @@ -22,8 +22,6 @@ #include <map> #include <vector> -#include <inttypes.h> - #include "perfetto/base/task_runner.h" #include "perfetto/ext/base/optional.h" #include "perfetto/ext/base/unix_socket.h" @@ -35,17 +33,13 @@ #include "perfetto/ext/tracing/core/tracing_service.h" #include "perfetto/tracing/core/data_source_config.h" -#include "perfetto/tracing/core/forward_decls.h" #include "src/profiling/common/interning_output.h" #include "src/profiling/common/proc_utils.h" -#include "src/profiling/common/profiler_guardrails.h" #include "src/profiling/memory/bookkeeping.h" #include "src/profiling/memory/bookkeeping_dump.h" -#include "src/profiling/memory/log_histogram.h" -#include "src/profiling/memory/shared_ring_buffer.h" +#include "src/profiling/memory/page_idle_checker.h" #include "src/profiling/memory/system_property.h" #include "src/profiling/memory/unwinding.h" -#include "src/profiling/memory/unwound_messages.h" #include "protos/perfetto/config/profiling/heapprofd_config.gen.h" @@ -59,15 +53,25 @@ struct Process { std::string cmdline; }; +class LogHistogram { + public: + static const uint64_t kMaxBucket; + static constexpr size_t kBuckets = 20; + + void Add(uint64_t value) { values_[GetBucket(value)]++; } + std::vector<std::pair<uint64_t, uint64_t>> GetData(); + + private: + size_t GetBucket(uint64_t value); + + std::array<uint64_t, kBuckets> values_ = {}; +}; + // TODO(rsavitski): central daemon can do less work if it knows that the global // operating mode is fork-based, as it then will not be interacting with the // clients. This can be implemented as an additional mode here. enum class HeapprofdMode { kCentral, kChild }; -bool HeapprofdConfigToClientConfiguration( - const HeapprofdConfig& heapprofd_config, - ClientConfiguration* cli_config); - // Heap profiling producer. Can be instantiated in two modes, central and // child (also referred to as fork mode). // @@ -95,8 +99,7 @@ class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { // Alternatively, find a better name for this. class SocketDelegate : public base::UnixSocket::EventListener { public: - explicit SocketDelegate(HeapprofdProducer* producer) - : producer_(producer) {} + SocketDelegate(HeapprofdProducer* producer) : producer_(producer) {} void OnDisconnect(base::UnixSocket* self) override; void OnNewIncomingConnection( @@ -108,9 +111,7 @@ class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { HeapprofdProducer* producer_; }; - HeapprofdProducer(HeapprofdMode mode, - base::TaskRunner* task_runner, - bool exit_when_done); + HeapprofdProducer(HeapprofdMode mode, base::TaskRunner* task_runner); ~HeapprofdProducer() override; // Producer Impl: @@ -131,24 +132,27 @@ class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { void DumpAll(); // UnwindingWorker::Delegate impl: - void PostAllocRecord(UnwindingWorker*, std::unique_ptr<AllocRecord>) override; - void PostFreeRecord(UnwindingWorker*, std::vector<FreeRecord>) override; - void PostHeapNameRecord(UnwindingWorker*, HeapNameRecord) override; - void PostSocketDisconnected(UnwindingWorker*, - DataSourceInstanceID, + void PostAllocRecord(AllocRecord) override; + void PostFreeRecord(FreeRecord) override; + void PostSocketDisconnected(DataSourceInstanceID, pid_t, SharedRingBuffer::Stats) override; - void HandleAllocRecord(AllocRecord*); + void HandleAllocRecord(AllocRecord); void HandleFreeRecord(FreeRecord); - void HandleHeapNameRecord(HeapNameRecord); void HandleSocketDisconnected(DataSourceInstanceID, pid_t, SharedRingBuffer::Stats); // Valid only if mode_ == kChild. - void SetTargetProcess(pid_t target_pid, std::string target_cmdline); - void SetDataSourceCallback(std::function<void()> fn); + void SetTargetProcess(pid_t target_pid, + std::string target_cmdline, + base::ScopedFile inherited_socket); + // Valid only if mode_ == kChild. Kicks off a periodic check that the child + // heapprofd is actively working on a data source (which should correspond to + // the target process). The first check is delayed to let the freshly spawned + // producer get the data sources from the tracing service (i.e. traced). + void ScheduleActiveDataSourceWatchdog(); // Exposed for testing. void SetProducerEndpoint( @@ -158,13 +162,6 @@ class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { return socket_delegate_; } - // Adopts the (connected) sockets inherited from the target process, invoking - // the on-connection callback. - // Specific to mode_ == kChild - void AdoptSocket(base::ScopedFile fd); - - void TerminateWhenDone(); - private: // State of the connection to tracing service (traced). enum State { @@ -175,19 +172,10 @@ class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { }; struct ProcessState { - struct HeapInfo { - HeapInfo(GlobalCallstackTrie* cs, bool dam) : heap_tracker(cs, dam) {} - - HeapTracker heap_tracker; - std::string heap_name; - uint64_t sampling_interval = 0u; - uint64_t orig_sampling_interval = 0u; - }; - ProcessState(GlobalCallstackTrie* c, bool d) - : callsites(c), dump_at_max_mode(d) {} + ProcessState(GlobalCallstackTrie* callsites, bool dump_at_max_mode) + : heap_tracker(callsites, dump_at_max_mode) {} bool disconnected = false; - SharedRingBuffer::ErrorState error_state = - SharedRingBuffer::ErrorState::kNoError; + bool buffer_overran = false; bool buffer_corrupted = false; uint64_t heap_samples = 0; @@ -195,37 +183,17 @@ class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { uint64_t unwinding_errors = 0; uint64_t total_unwinding_time_us = 0; - uint64_t client_spinlock_blocked_us = 0; - GlobalCallstackTrie* callsites; - bool dump_at_max_mode; LogHistogram unwinding_time_us; - std::map<uint32_t, HeapInfo> heap_infos; - - HeapInfo& GetHeapInfo(uint32_t heap_id) { - auto it = heap_infos.find(heap_id); - if (it == heap_infos.end()) { - std::tie(it, std::ignore) = heap_infos.emplace( - std::piecewise_construct, std::forward_as_tuple(heap_id), - std::forward_as_tuple(callsites, dump_at_max_mode)); - } - return it->second; - } - - HeapTracker& GetHeapTracker(uint32_t heap_id) { - return GetHeapInfo(heap_id).heap_tracker; - } + HeapTracker heap_tracker; + + base::Optional<PageIdleChecker> page_idle_checker; }; struct DataSource { - explicit DataSource(std::unique_ptr<TraceWriter> tw) - : trace_writer(std::move(tw)) { - // Make MSAN happy. - memset(&client_configuration, 0, sizeof(client_configuration)); - } + DataSource(std::unique_ptr<TraceWriter> tw) : trace_writer(std::move(tw)) {} DataSourceInstanceID id; std::unique_ptr<TraceWriter> trace_writer; - DataSourceConfig ds_config; HeapprofdConfig config; ClientConfiguration client_configuration; std::vector<SystemProperties::Handle> properties; @@ -239,7 +207,7 @@ class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { bool hit_guardrail = false; bool was_stopped = false; uint32_t stop_timeout_ms; - GuardrailConfig guardrail_config; + base::Optional<uint64_t> start_cputime_sec; }; struct PendingProcess { @@ -256,14 +224,14 @@ class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { void ResetConnectionBackoff(); void IncreaseConnectionBackoff(); - void CheckDataSourceMemoryTask(); - void CheckDataSourceCpuTask(); + base::Optional<uint64_t> GetCputimeSec(); + + void CheckDataSourceMemory(); + void CheckDataSourceCpu(); void FinishDataSourceFlush(FlushRequestID flush_id); - void DumpProcessesInDataSource(DataSource* ds); + bool DumpProcessesInDataSource(DataSourceInstanceID id); void DumpProcessState(DataSource* ds, pid_t pid, ProcessState* process); - static void SetStats(protos::pbzero::ProfilePacket::ProcessStats* stats, - const ProcessState& process_state); void DoContinuousDump(DataSourceInstanceID id, uint32_t dump_interval); @@ -279,21 +247,19 @@ class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { void TerminateProcess(int exit_status); // Specific to mode_ == kChild void ActiveDataSourceWatchdogCheck(); + // Adopts the (connected) sockets inherited from the target process, invoking + // the on-connection callback. + // Specific to mode_ == kChild + void AdoptTargetProcessSocket(); void ShutdownDataSource(DataSource* ds); bool MaybeFinishDataSource(DataSource* ds); - void WriteRejectedConcurrentSession(BufferID buffer_id, pid_t pid); - // Class state: // Task runner is owned by the main thread. base::TaskRunner* const task_runner_; const HeapprofdMode mode_; - // TODO(fmayer): Refactor to make this boolean unnecessary. - // Whether to terminate this producer after the first data-source has - // finished. - bool exit_when_done_; // State of connection to the tracing service. State state_ = kNotStarted; @@ -322,9 +288,13 @@ class HeapprofdProducer : public Producer, public UnwindingWorker::Delegate { // Specific to mode_ == kChild Process target_process_{base::kInvalidPid, ""}; - base::Optional<std::function<void()>> data_source_callback_; + // This is a valid FD only between SetTargetProcess and + // AdoptTargetProcessSocket. + // Specific to mode_ == kChild + base::ScopedFile inherited_fd_; SocketDelegate socket_delegate_; + base::ScopedFile stat_fd_; base::WeakPtrFactory<HeapprofdProducer> weak_factory_; // Keep last. }; |