perfetto: set memory and CPU guardrails on traced and traced_probes
Bug: 73051936
Bug: 73052380
Change-Id: I0db375ea5b7ac4e26b52d74e860d96cdf7fbbd5d
diff --git a/src/traced/probes/probes.cc b/src/traced/probes/probes.cc
index 6281744..78ccea6 100644
--- a/src/traced/probes/probes.cc
+++ b/src/traced/probes/probes.cc
@@ -40,6 +40,13 @@
}
}
+ // Set the watchdog to kill the process if we average more than 32MB of
+ // memory or 75% CPU over a 30 second window.
+ base::Watchdog* watchdog = base::Watchdog::GetInstance();
+ watchdog->SetCpuLimit(75, 30 * 1000);
+ watchdog->SetMemoryLimit(32 * 1024 * 1024, 30 * 1000);
+ watchdog->Start();
+
PERFETTO_LOG("Starting %s service", argv[0]);
base::UnixTaskRunner task_runner;
ProbesProducer producer;
diff --git a/src/traced/service/service.cc b/src/traced/service/service.cc
index 8107312..b3f7812 100644
--- a/src/traced/service/service.cc
+++ b/src/traced/service/service.cc
@@ -15,6 +15,7 @@
*/
#include "perfetto/base/unix_task_runner.h"
+#include "perfetto/base/watchdog.h"
#include "perfetto/traced/traced.h"
#include "perfetto/tracing/ipc/service_ipc_host.h"
@@ -41,6 +42,13 @@
svc->Start(PERFETTO_PRODUCER_SOCK_NAME, PERFETTO_CONSUMER_SOCK_NAME);
}
+ // Set the CPU limit and start the watchdog running. The memory limit will
+ // be set inside the service code as it relies on the size of buffers.
+ // The CPU limit is 75% over a 30 second interval.
+ base::Watchdog* watchdog = base::Watchdog::GetInstance();
+ watchdog->SetCpuLimit(75, 30 * 1000);
+ watchdog->Start();
+
PERFETTO_ILOG("Started traced, listening on %s %s",
PERFETTO_PRODUCER_SOCK_NAME, PERFETTO_CONSUMER_SOCK_NAME);
task_runner.Run();
diff --git a/src/tracing/core/service_impl.cc b/src/tracing/core/service_impl.cc
index 5f30a87..7da32f7 100644
--- a/src/tracing/core/service_impl.cc
+++ b/src/tracing/core/service_impl.cc
@@ -105,6 +105,8 @@
auto it_and_inserted = producers_.emplace(id, endpoint.get());
PERFETTO_DCHECK(it_and_inserted.second);
task_runner_->PostTask(std::bind(&Producer::OnConnect, endpoint->producer_));
+
+ UpdateMemoryGuardrail();
return std::move(endpoint);
}
@@ -122,6 +124,7 @@
}
producers_.erase(id);
+ UpdateMemoryGuardrail();
}
ServiceImpl::ProducerEndpointImpl* ServiceImpl::GetProducer(
@@ -238,6 +241,7 @@
break;
}
}
+ UpdateMemoryGuardrail();
// This can happen if either:
// - All the kMaxTraceBufferID slots are taken.
@@ -433,6 +437,8 @@
buffers_.erase(buffer_id);
}
tracing_sessions_.erase(tsid);
+ UpdateMemoryGuardrail();
+
PERFETTO_LOG("Tracing session %" PRIu64 " ended, total sessions:%zu", tsid,
tracing_sessions_.size());
}
@@ -595,6 +601,27 @@
return last_producer_id_;
}
+void ServiceImpl::UpdateMemoryGuardrail() {
+#if !PERFETTO_BUILDFLAG(PERFETTO_CHROMIUM_BUILD)
+ uint64_t total_buffer_bytes = 0;
+
+ // Sum up all the shared memory buffers.
+ for (const auto& id_to_producer : producers_) {
+ total_buffer_bytes += id_to_producer.second->shared_memory()->size();
+ }
+
+ // Sum up all the trace buffers.
+ for (const auto& id_to_buffer : buffers_) {
+ total_buffer_bytes += id_to_buffer.second.size;
+ }
+
+ // Set the guard rail to 32MB + the sum of all the buffers over a 30 second
+ // interval.
+ uint64_t guardrail = 32 * 1024 * 1024 + total_buffer_bytes;
+ base::Watchdog::GetInstance()->SetMemoryLimit(guardrail, 30 * 1000);
+#endif
+}
+
////////////////////////////////////////////////////////////////////////////////
// ServiceImpl::ConsumerEndpointImpl implementation
////////////////////////////////////////////////////////////////////////////////
diff --git a/src/tracing/core/service_impl.h b/src/tracing/core/service_impl.h
index 7725c12..2717d2d 100644
--- a/src/tracing/core/service_impl.h
+++ b/src/tracing/core/service_impl.h
@@ -238,6 +238,10 @@
// session doesn't exists.
TracingSession* GetTracingSession(TracingSessionID);
+ // Update the memory guard rail by using the latest information from the
+ // shared memory and trace buffers.
+ void UpdateMemoryGuardrail();
+
base::TaskRunner* const task_runner_;
std::unique_ptr<SharedMemory::Factory> shm_factory_;
ProducerID last_producer_id_ = 0;