Show buffer overruns in ProfileProto.
Test: profile inputmethod.latin at inverval 1, observe overflow
Change-Id: I5553502de233f6f661edaf01c46416ca5422d0e0
Bug: 129054982
diff --git a/protos/perfetto/trace/perfetto_trace.proto b/protos/perfetto/trace/perfetto_trace.proto
index ed13053..67e1098 100644
--- a/protos/perfetto/trace/perfetto_trace.proto
+++ b/protos/perfetto/trace/perfetto_trace.proto
@@ -2513,6 +2513,10 @@
// If false, the process outlived the profiling session.
optional bool disconnected = 6;
+ // If disconnected, this disconnect was caused by the client overrunning
+ // the buffer.
+ optional bool buffer_overran = 7;
+
optional ProcessStats stats = 5;
repeated HeapSample samples = 2;
diff --git a/protos/perfetto/trace/profiling/profile_packet.proto b/protos/perfetto/trace/profiling/profile_packet.proto
index 4be89b1..1228057 100644
--- a/protos/perfetto/trace/profiling/profile_packet.proto
+++ b/protos/perfetto/trace/profiling/profile_packet.proto
@@ -105,6 +105,10 @@
// If false, the process outlived the profiling session.
optional bool disconnected = 6;
+ // If disconnected, this disconnect was caused by the client overrunning
+ // the buffer.
+ optional bool buffer_overran = 7;
+
optional ProcessStats stats = 5;
repeated HeapSample samples = 2;
diff --git a/src/profiling/memory/heapprofd_producer.cc b/src/profiling/memory/heapprofd_producer.cc
index 19eb2f9..b62f0a9 100644
--- a/src/profiling/memory/heapprofd_producer.cc
+++ b/src/profiling/memory/heapprofd_producer.cc
@@ -403,6 +403,7 @@
proto->set_pid(static_cast<uint64_t>(pid));
proto->set_from_startup(from_startup);
proto->set_disconnected(process_state.disconnected);
+ proto->set_buffer_overran(process_state.buffer_overran);
auto* stats = proto->set_stats();
stats->set_unwinding_errors(process_state.unwinding_errors);
stats->set_heap_samples(process_state.heap_samples);
@@ -739,11 +740,12 @@
}
void HeapprofdProducer::PostSocketDisconnected(DataSourceInstanceID ds_id,
- pid_t pid) {
+ pid_t pid,
+ SharedRingBuffer::Stats stats) {
auto weak_this = weak_factory_.GetWeakPtr();
- task_runner_->PostTask([weak_this, ds_id, pid] {
+ task_runner_->PostTask([weak_this, ds_id, pid, stats] {
if (weak_this)
- weak_this->HandleSocketDisconnected(ds_id, pid);
+ weak_this->HandleSocketDisconnected(ds_id, pid, stats);
});
}
@@ -821,8 +823,10 @@
}
}
-void HeapprofdProducer::HandleSocketDisconnected(DataSourceInstanceID id,
- pid_t pid) {
+void HeapprofdProducer::HandleSocketDisconnected(
+ DataSourceInstanceID id,
+ pid_t pid,
+ SharedRingBuffer::Stats stats) {
auto it = data_sources_.find(id);
if (it == data_sources_.end())
return;
@@ -833,6 +837,7 @@
return;
ProcessState& process_state = process_state_it->second;
process_state.disconnected = true;
+ process_state.buffer_overran = stats.num_writes_overflow > 0;
// TODO(fmayer): Dump on process disconnect rather than data source
// destruction. This prevents us needing to hold onto the bookkeeping data
diff --git a/src/profiling/memory/heapprofd_producer.h b/src/profiling/memory/heapprofd_producer.h
index 148d71b..ae4a5fc 100644
--- a/src/profiling/memory/heapprofd_producer.h
+++ b/src/profiling/memory/heapprofd_producer.h
@@ -105,11 +105,15 @@
// UnwindingWorker::Delegate impl:
void PostAllocRecord(AllocRecord) override;
void PostFreeRecord(FreeRecord) override;
- void PostSocketDisconnected(DataSourceInstanceID, pid_t) override;
+ void PostSocketDisconnected(DataSourceInstanceID,
+ pid_t,
+ SharedRingBuffer::Stats) override;
void HandleAllocRecord(AllocRecord);
void HandleFreeRecord(FreeRecord);
- void HandleSocketDisconnected(DataSourceInstanceID, pid_t);
+ void HandleSocketDisconnected(DataSourceInstanceID,
+ pid_t,
+ SharedRingBuffer::Stats);
// Valid only if mode_ == kChild.
void SetTargetProcess(pid_t target_pid,
@@ -163,6 +167,8 @@
struct ProcessState {
ProcessState(GlobalCallstackTrie* callsites) : heap_tracker(callsites) {}
bool disconnected = false;
+ bool buffer_overran = false;
+
uint64_t heap_samples = 0;
uint64_t map_reparses = 0;
uint64_t unwinding_errors = 0;
diff --git a/src/profiling/memory/unwinding.cc b/src/profiling/memory/unwinding.cc
index 53304c8..b05ff64 100644
--- a/src/profiling/memory/unwinding.cc
+++ b/src/profiling/memory/unwinding.cc
@@ -246,12 +246,32 @@
return;
}
ClientData& client_data = it->second;
+ SharedRingBuffer& shmem = client_data.shmem;
+
+ // Currently, these stats are used to determine whether the application
+ // disconnected due to an error condition (i.e. buffer overflow) or
+ // volutarily. Because a buffer overflow leads to an immediate disconnect, we
+ // do not need these stats when heapprofd tears down the tracing session.
+ //
+ // TODO(fmayer): We should make it that normal disconnects also go through
+ // this code path, so we can write other stats to the result. This will also
+ // allow us to free the bookkeeping data earlier for processes that exit
+ // during the session. See TODO in
+ // HeapprofdProducer::HandleSocketDisconnected.
+ SharedRingBuffer::Stats stats = {};
+ {
+ auto lock = shmem.AcquireLock(ScopedSpinlock::Mode::Try);
+ if (lock.locked())
+ stats = shmem.GetStats(lock);
+ else
+ PERFETTO_ELOG("Failed to log shmem to get stats.");
+ }
DataSourceInstanceID ds_id = client_data.data_source_instance_id;
pid_t peer_pid = self->peer_pid();
client_data_.erase(it);
// The erase invalidates the self pointer.
self = nullptr;
- delegate_->PostSocketDisconnected(ds_id, peer_pid);
+ delegate_->PostSocketDisconnected(ds_id, peer_pid, stats);
}
void UnwindingWorker::OnDataAvailable(base::UnixSocket* self) {
diff --git a/src/profiling/memory/unwinding.h b/src/profiling/memory/unwinding.h
index af238db..374e49c 100644
--- a/src/profiling/memory/unwinding.h
+++ b/src/profiling/memory/unwinding.h
@@ -136,7 +136,9 @@
public:
virtual void PostAllocRecord(AllocRecord) = 0;
virtual void PostFreeRecord(FreeRecord) = 0;
- virtual void PostSocketDisconnected(DataSourceInstanceID, pid_t pid) = 0;
+ virtual void PostSocketDisconnected(DataSourceInstanceID,
+ pid_t pid,
+ SharedRingBuffer::Stats stats) = 0;
virtual ~Delegate();
};
diff --git a/tools/trace_to_text/trace_to_profile.cc b/tools/trace_to_text/trace_to_profile.cc
index cfc6781..b1f82bb 100644
--- a/tools/trace_to_text/trace_to_profile.cc
+++ b/tools/trace_to_text/trace_to_profile.cc
@@ -227,6 +227,11 @@
GProfile cur_profile = profile;
uint64_t pid = p.first;
for (const ProfilePacket::ProcessHeapSamples* samples : p.second) {
+ if (samples->buffer_overran()) {
+ PERFETTO_ELOG("WARNING: The profile for %" PRIu64
+ " ended early due to a buffer overrun.",
+ pid);
+ }
for (const ProfilePacket::HeapSample& sample : samples->samples()) {
GSample* gsample = cur_profile.add_sample();
auto it = callstack_lookup.find(sample.callstack_id());