traced_probes: Add kmem_activity trigger
kmem_activity gets triggered when there is detected kernel memory
activity -- kswapd, direct reclaim, compaction. This is used a hueristic
for memory pressure, which allows for signaling perfetto to capture
system memory state during periods of memory pressure.
Bug: 155928119
Test: adb root
adb push test/configs/mm_events.cfg /data/local/tmp/
adb shell 'cat /data/local/tmp/mm_events.cfg | perfetto --txt -c - -o /data/misc/perfetto-traces/trace'
[In another shell] Synthesize memory pressure (e.g adb shell /data/local/tmp/lmkd_unit_test)
adb pull /data/misc/perfetto-traces/trace
Change-Id: Id0a5dad2f6e557606801bad0a58ea180123f54fd
diff --git a/Android.bp b/Android.bp
index 1567a65..42cd999 100644
--- a/Android.bp
+++ b/Android.bp
@@ -8153,6 +8153,7 @@
filegroup {
name: "perfetto_src_traced_probes_probes_src",
srcs: [
+ "src/traced/probes/kmem_activity_trigger.cc",
"src/traced/probes/probes_producer.cc",
],
}
diff --git a/BUILD b/BUILD
index 7695658..34851ea 100644
--- a/BUILD
+++ b/BUILD
@@ -1465,6 +1465,8 @@
filegroup(
name = "src_traced_probes_probes_src",
srcs = [
+ "src/traced/probes/kmem_activity_trigger.cc",
+ "src/traced/probes/kmem_activity_trigger.h",
"src/traced/probes/probes_producer.cc",
"src/traced/probes/probes_producer.h",
],
diff --git a/src/traced/probes/BUILD.gn b/src/traced/probes/BUILD.gn
index 9e09790..7fcdf42 100644
--- a/src/traced/probes/BUILD.gn
+++ b/src/traced/probes/BUILD.gn
@@ -67,6 +67,8 @@
sources = [
"probes_producer.cc",
"probes_producer.h",
+ "kmem_activity_trigger.cc",
+ "kmem_activity_trigger.h",
]
}
diff --git a/src/traced/probes/ftrace/ftrace_procfs.cc b/src/traced/probes/ftrace/ftrace_procfs.cc
index 5628cb7..7e10bc4 100644
--- a/src/traced/probes/ftrace/ftrace_procfs.cc
+++ b/src/traced/probes/ftrace/ftrace_procfs.cc
@@ -157,11 +157,15 @@
// on Android. The permissions to these files are configured in
// platform/framework/native/cmds/atrace/atrace.rc.
for (size_t cpu = 0; cpu < NumberOfCpus(); cpu++) {
- if (!ClearFile(root_ + "per_cpu/cpu" + std::to_string(cpu) + "/trace"))
- PERFETTO_ELOG("Failed to clear buffer for CPU %zd", cpu);
+ ClearPerCpuTrace(cpu);
}
}
+void FtraceProcfs::ClearPerCpuTrace(size_t cpu) {
+ if (!ClearFile(root_ + "per_cpu/cpu" + std::to_string(cpu) + "/trace"))
+ PERFETTO_ELOG("Failed to clear buffer for CPU %zd", cpu);
+}
+
bool FtraceProcfs::WriteTraceMarker(const std::string& str) {
std::string path = root_ + "trace_marker";
return WriteToFile(path, str);
diff --git a/src/traced/probes/ftrace/ftrace_procfs.h b/src/traced/probes/ftrace/ftrace_procfs.h
index f2ea712..e8b292f 100644
--- a/src/traced/probes/ftrace/ftrace_procfs.h
+++ b/src/traced/probes/ftrace/ftrace_procfs.h
@@ -68,6 +68,9 @@
// Clears the trace buffers for all CPUs. Blocks until this is done.
void ClearTrace();
+ // Clears the trace buffer for cpu. Blocks until this is done.
+ void ClearPerCpuTrace(size_t cpu);
+
// Writes the string |str| as an event into the trace buffer.
bool WriteTraceMarker(const std::string& str);
diff --git a/src/traced/probes/kmem_activity_trigger.cc b/src/traced/probes/kmem_activity_trigger.cc
new file mode 100644
index 0000000..7b55313
--- /dev/null
+++ b/src/traced/probes/kmem_activity_trigger.cc
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2021 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.
+ */
+
+#include "src/traced/probes/kmem_activity_trigger.h"
+
+#include <unistd.h>
+
+#include "src/traced/probes/ftrace/ftrace_procfs.h"
+#include "src/traced/probes/probes_producer.h"
+
+namespace perfetto {
+
+namespace {
+constexpr base::TimeSeconds kTriggerInterval{60}; // 1 min
+constexpr size_t kPerCpuTraceBufferSizeInPages = 1;
+constexpr char kTriggerName[] = "kmem_activity";
+} // namespace
+
+void KmemActivityTriggerThread::InitializeOnThread() {
+ // Create kmem activity FtraceProcfs
+ size_t index = 0;
+ while (!ftrace_procfs_ && FtraceController::kTracingPaths[index]) {
+ std::string root = FtraceController::kTracingPaths[index++] +
+ std::string("instances/mm_events/");
+ ftrace_procfs_ = FtraceProcfs::Create(root);
+ }
+ if (!ftrace_procfs_) {
+#if PERFETTO_BUILDFLAG(PERFETTO_ANDROID_BUILD)
+ PERFETTO_LOG(
+ "mm_events ftrace instance not found. Triggering of traces on memory "
+ "pressure will not be available on this device.");
+#endif
+ return;
+ }
+
+ ftrace_procfs_->SetCpuBufferSizeInPages(kPerCpuTraceBufferSizeInPages);
+
+ // Enable mm trace events
+ ftrace_procfs_->EnableEvent("vmscan", "mm_vmscan_kswapd_wake");
+ ftrace_procfs_->EnableEvent("vmscan", "mm_vmscan_direct_reclaim_begin");
+ ftrace_procfs_->EnableEvent("compaction", "mm_compaction_begin");
+
+ ftrace_procfs_->EnableTracing();
+
+ size_t num_cpus = ftrace_procfs_->NumberOfCpus();
+ for (size_t cpu = 0; cpu < num_cpus; cpu++) {
+ trace_pipe_fds_.emplace_back(ftrace_procfs_->OpenPipeForCpu(cpu));
+
+ if (!trace_pipe_fds_.back()) {
+ PERFETTO_PLOG("Failed to open trace_pipe_raw for cpu %zu", cpu);
+ trace_pipe_fds_.pop_back();
+ continue;
+ }
+
+ int watch_fd = trace_pipe_fds_.back().get();
+ thread_.AddFileDescriptorWatch(watch_fd, [this, cpu]() {
+ base::TimeSeconds now = base::GetBootTimeS();
+ base::TimeSeconds elapsed = std::chrono::duration_cast<base::TimeSeconds>(
+ now - last_trigger_time_);
+ ProbesProducer* probes_producer = ProbesProducer::GetInstance();
+ if (probes_producer &&
+ (elapsed > kTriggerInterval || last_trigger_time_.count() == 0)) {
+ probes_producer->ActivateTrigger(kTriggerName);
+ last_trigger_time_ = now;
+ }
+ ftrace_procfs_->ClearPerCpuTrace(cpu);
+ });
+ }
+}
+
+KmemActivityTriggerThread::KmemActivityTriggerThread()
+ : thread_(base::ThreadTaskRunner::CreateAndStart()) {
+ thread_.PostTask([this]() { InitializeOnThread(); });
+}
+
+KmemActivityTriggerThread::~KmemActivityTriggerThread() {
+ thread_.PostTask([this]() {
+ ftrace_procfs_->DisableTracing();
+ ftrace_procfs_->ClearTrace();
+
+ for (const base::ScopedFile& fd : trace_pipe_fds_) {
+ thread_.RemoveFileDescriptorWatch(fd.get());
+ }
+
+ trace_pipe_fds_.clear();
+
+ thread_.get()->Quit();
+ });
+}
+
+} // namespace perfetto
diff --git a/src/traced/probes/kmem_activity_trigger.h b/src/traced/probes/kmem_activity_trigger.h
new file mode 100644
index 0000000..b15d347
--- /dev/null
+++ b/src/traced/probes/kmem_activity_trigger.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2021 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_TRACED_PROBES_KMEM_ACTIVITY_TRIGGER_H_
+#define SRC_TRACED_PROBES_KMEM_ACTIVITY_TRIGGER_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "perfetto/base/time.h"
+#include "perfetto/ext/base/scoped_file.h"
+#include "perfetto/ext/base/thread_task_runner.h"
+
+namespace perfetto {
+
+class FtraceProcfs;
+
+class KmemActivityTriggerThread {
+ public:
+ KmemActivityTriggerThread();
+ ~KmemActivityTriggerThread();
+
+ private:
+ void InitializeOnThread();
+
+ base::ThreadTaskRunner thread_;
+ std::unique_ptr<FtraceProcfs> ftrace_procfs_;
+ std::vector<base::ScopedFile> trace_pipe_fds_;
+ base::TimeSeconds last_trigger_time_{0};
+};
+
+} // namespace perfetto
+
+#endif // SRC_TRACED_PROBES_KMEM_ACTIVITY_TRIGGER_H_
diff --git a/src/traced/probes/probes.cc b/src/traced/probes/probes.cc
index 9d83f45..39f6be8 100644
--- a/src/traced/probes/probes.cc
+++ b/src/traced/probes/probes.cc
@@ -27,6 +27,7 @@
#include "perfetto/ext/tracing/ipc/default_socket.h"
#include "src/traced/probes/ftrace/ftrace_procfs.h"
+#include "src/traced/probes/kmem_activity_trigger.h"
#include "src/traced/probes/probes_producer.h"
namespace perfetto {
@@ -85,6 +86,10 @@
base::UnixTaskRunner task_runner;
ProbesProducer producer;
producer.ConnectWithRetries(GetProducerSocket(), &task_runner);
+
+ // Start the thread that polls mm_event instance and triggers
+ KmemActivityTriggerThread kmem_activity_trigger;
+
task_runner.Run();
return 0;
}
diff --git a/src/traced/probes/probes_producer.cc b/src/traced/probes/probes_producer.cc
index 58389b8..cfa893d 100644
--- a/src/traced/probes/probes_producer.cc
+++ b/src/traced/probes/probes_producer.cc
@@ -86,8 +86,19 @@
// +--------------+
//
-ProbesProducer::ProbesProducer() : weak_factory_(this) {}
+ProbesProducer* ProbesProducer::instance_ = nullptr;
+
+ProbesProducer* ProbesProducer::GetInstance() {
+ return instance_;
+}
+
+ProbesProducer::ProbesProducer() : weak_factory_(this) {
+ PERFETTO_CHECK(instance_ == nullptr);
+ instance_ = this;
+}
+
ProbesProducer::~ProbesProducer() {
+ instance_ = nullptr;
// The ftrace data sources must be deleted before the ftrace controller.
data_sources_.clear();
ftrace_.reset();
@@ -493,7 +504,7 @@
if (ps->on_demand_dumps_enabled())
ps_data_source = ps;
}
- } // for (session_data_sources_)
+ } // for (session_data_sources_)
}
void ProbesProducer::ConnectWithRetries(const char* socket_name,
@@ -526,4 +537,11 @@
connection_backoff_ms_ = kInitialConnectionBackoffMs;
}
+void ProbesProducer::ActivateTrigger(std::string trigger) {
+ task_runner_->PostTask([this, trigger]() {
+ if (endpoint_)
+ endpoint_->ActivateTriggers({trigger});
+ });
+}
+
} // namespace perfetto
diff --git a/src/traced/probes/probes_producer.h b/src/traced/probes/probes_producer.h
index 39d6425..b879a01 100644
--- a/src/traced/probes/probes_producer.h
+++ b/src/traced/probes/probes_producer.h
@@ -44,6 +44,8 @@
ProbesProducer();
~ProbesProducer() override;
+ static ProbesProducer* GetInstance();
+
// Producer Impl:
void OnConnect() override;
void OnDisconnect() override;
@@ -93,8 +95,11 @@
std::unique_ptr<ProbesDataSource> CreateInitialDisplayStateDataSource(
TracingSessionID session_id,
const DataSourceConfig& config);
+ void ActivateTrigger(std::string trigger);
private:
+ static ProbesProducer* instance_;
+
enum State {
kNotStarted = 0,
kNotConnected,