| /* |
| * 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() { |
| ftrace_procfs_ = |
| FtraceProcfs::CreateGuessingMountPoint("instances/mm_events/"); |
| 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 |