aboutsummaryrefslogtreecommitdiff
path: root/src/profiling/memory/heapprofd_producer.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/profiling/memory/heapprofd_producer.h')
-rw-r--r--src/profiling/memory/heapprofd_producer.h132
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.
};