| /* | 
 |  * Copyright (C) 2020 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/profiling/common/profiler_guardrails.h" | 
 |  | 
 | #include <unistd.h> | 
 |  | 
 | #include <algorithm> | 
 | #include "perfetto/ext/base/file_utils.h" | 
 | #include "perfetto/ext/base/optional.h" | 
 | #include "perfetto/ext/base/scoped_file.h" | 
 | #include "perfetto/ext/base/watchdog_posix.h" | 
 |  | 
 | namespace perfetto { | 
 | namespace profiling { | 
 |  | 
 | base::Optional<uint64_t> GetCputimeSecForCurrentProcess() { | 
 |   return GetCputimeSecForCurrentProcess( | 
 |       base::OpenFile("/proc/self/stat", O_RDONLY)); | 
 | } | 
 |  | 
 | base::Optional<uint64_t> GetCputimeSecForCurrentProcess( | 
 |     base::ScopedFile stat_fd) { | 
 |   if (!stat_fd) | 
 |     return base::nullopt; | 
 |   base::ProcStat stat; | 
 |   if (!ReadProcStat(stat_fd.get(), &stat)) { | 
 |     PERFETTO_ELOG("Failed to read stat file to enforce guardrails."); | 
 |     return base::nullopt; | 
 |   } | 
 |   return (stat.utime + stat.stime) / | 
 |          static_cast<unsigned long>(sysconf(_SC_CLK_TCK)); | 
 | } | 
 |  | 
 | ProfilerMemoryGuardrails::ProfilerMemoryGuardrails() | 
 |     : ProfilerMemoryGuardrails(base::OpenFile("/proc/self/status", O_RDONLY)) {} | 
 |  | 
 | ProfilerMemoryGuardrails::ProfilerMemoryGuardrails(base::ScopedFile status_fd) { | 
 |   std::string status; | 
 |   if (base::ReadFileDescriptor(*status_fd, &status)) | 
 |     anon_and_swap_ = GetRssAnonAndSwap(status); | 
 |  | 
 |   if (!anon_and_swap_) { | 
 |     PERFETTO_ELOG("Failed to read memory usage."); | 
 |     return; | 
 |   } | 
 | } | 
 |  | 
 | bool ProfilerMemoryGuardrails::IsOverMemoryThreshold( | 
 |     const GuardrailConfig& ds) { | 
 |   uint32_t ds_max_mem = ds.memory_guardrail_kb; | 
 |   if (!ds_max_mem || !anon_and_swap_) | 
 |     return false; | 
 |  | 
 |   if (ds_max_mem > 0 && *anon_and_swap_ > ds_max_mem) { | 
 |     PERFETTO_ELOG("Exceeded data-source memory guardrail (%" PRIu32 | 
 |                   " > %" PRIu32 "). Shutting down.", | 
 |                   *anon_and_swap_, ds_max_mem); | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | ProfilerCpuGuardrails::ProfilerCpuGuardrails() { | 
 |   opt_cputime_sec_ = GetCputimeSecForCurrentProcess(); | 
 |   if (!opt_cputime_sec_) { | 
 |     PERFETTO_ELOG("Failed to get CPU time."); | 
 |   } | 
 | } | 
 |  | 
 | // For testing. | 
 | ProfilerCpuGuardrails::ProfilerCpuGuardrails(base::ScopedFile stat_fd) { | 
 |   opt_cputime_sec_ = GetCputimeSecForCurrentProcess(std::move(stat_fd)); | 
 |   if (!opt_cputime_sec_) { | 
 |     PERFETTO_ELOG("Failed to get CPU time."); | 
 |   } | 
 | } | 
 |  | 
 | bool ProfilerCpuGuardrails::IsOverCpuThreshold(const GuardrailConfig& ds) { | 
 |   uint64_t ds_max_cpu = ds.cpu_guardrail_sec; | 
 |   if (!ds_max_cpu || !opt_cputime_sec_) | 
 |     return false; | 
 |   uint64_t cputime_sec = *opt_cputime_sec_; | 
 |  | 
 |   auto start_cputime_sec = ds.cpu_start_secs; | 
 |   // We reject data-sources with CPU guardrails if we cannot read the | 
 |   // initial value, which means we get a non-nullopt value here. | 
 |   PERFETTO_CHECK(start_cputime_sec); | 
 |   uint64_t cpu_diff = cputime_sec - *start_cputime_sec; | 
 |   if (cputime_sec > *start_cputime_sec && cpu_diff > ds_max_cpu) { | 
 |     PERFETTO_ELOG("Exceeded data-source CPU guardrail (%" PRIu64 " > %" PRIu64 | 
 |                   "). Shutting down.", | 
 |                   cpu_diff, ds_max_cpu); | 
 |     return true; | 
 |   } | 
 |   return false; | 
 | } | 
 |  | 
 | }  // namespace profiling | 
 | }  // namespace perfetto |