cpufreq_monitor_android.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/trace_event/cpufreq_monitor_android.h"
  5. #include <fcntl.h>
  6. #include "base/bind.h"
  7. #include "base/files/file_util.h"
  8. #include "base/files/scoped_file.h"
  9. #include "base/memory/scoped_refptr.h"
  10. #include "base/no_destructor.h"
  11. #include "base/strings/string_number_conversions.h"
  12. #include "base/strings/string_split.h"
  13. #include "base/strings/stringprintf.h"
  14. #include "base/task/task_traits.h"
  15. #include "base/task/thread_pool.h"
  16. #include "base/trace_event/trace_event.h"
  17. namespace base {
  18. namespace trace_event {
  19. namespace {
  20. const size_t kNumBytesToReadForSampling = 32;
  21. constexpr const char kTraceCategory[] = TRACE_DISABLED_BY_DEFAULT("power");
  22. const char kEventTitle[] = "CPU Frequency";
  23. } // namespace
  24. CPUFreqMonitorDelegate::CPUFreqMonitorDelegate() {}
  25. std::string CPUFreqMonitorDelegate::GetScalingCurFreqPathString(
  26. unsigned int cpu_id) const {
  27. return base::StringPrintf(
  28. "/sys/devices/system/cpu/cpu%d/cpufreq/scaling_cur_freq", cpu_id);
  29. }
  30. bool CPUFreqMonitorDelegate::IsTraceCategoryEnabled() const {
  31. bool enabled;
  32. TRACE_EVENT_CATEGORY_GROUP_ENABLED(kTraceCategory, &enabled);
  33. return enabled;
  34. }
  35. unsigned int CPUFreqMonitorDelegate::GetKernelMaxCPUs() const {
  36. std::string str;
  37. if (!base::ReadFileToString(
  38. base::FilePath("/sys/devices/system/cpu/kernel_max"), &str)) {
  39. // If we fail to read the kernel_max file, we just assume that CPU0 exists.
  40. return 0;
  41. }
  42. unsigned int kernel_max_cpu = 0;
  43. base::StringToUint(str, &kernel_max_cpu);
  44. return kernel_max_cpu;
  45. }
  46. std::string CPUFreqMonitorDelegate::GetRelatedCPUsPathString(
  47. unsigned int cpu_id) const {
  48. return base::StringPrintf(
  49. "/sys/devices/system/cpu/cpu%d/cpufreq/related_cpus", cpu_id);
  50. }
  51. void CPUFreqMonitorDelegate::GetCPUIds(std::vector<unsigned int>* ids) const {
  52. ids->clear();
  53. unsigned int kernel_max_cpu = GetKernelMaxCPUs();
  54. // CPUs related to one that's already marked for monitoring get set to "false"
  55. // so we don't needlessly monitor CPUs with redundant frequency information.
  56. char cpus_to_monitor[kernel_max_cpu + 1];
  57. std::memset(cpus_to_monitor, 1, kernel_max_cpu + 1);
  58. // Rule out the related CPUs for each one so we only end up with the CPUs
  59. // that are representative of the cluster.
  60. for (unsigned int i = 0; i <= kernel_max_cpu; i++) {
  61. if (!cpus_to_monitor[i])
  62. continue;
  63. std::string filename = GetRelatedCPUsPathString(i);
  64. std::string line;
  65. if (!base::ReadFileToString(base::FilePath(filename), &line))
  66. continue;
  67. // When reading the related_cpus file, we expected the format to be
  68. // something like "0 1 2 3" for CPU0-3 if they're all in one cluster.
  69. for (auto& str_piece :
  70. base::SplitString(line, " ", base::WhitespaceHandling::TRIM_WHITESPACE,
  71. base::SplitResult::SPLIT_WANT_NONEMPTY)) {
  72. unsigned int cpu_id;
  73. if (base::StringToUint(str_piece, &cpu_id)) {
  74. if (cpu_id != i && cpu_id <= kernel_max_cpu)
  75. cpus_to_monitor[cpu_id] = 0;
  76. }
  77. }
  78. ids->push_back(i);
  79. }
  80. // If none of the files were readable, we assume CPU0 exists and fall back to
  81. // using that.
  82. if (ids->size() == 0)
  83. ids->push_back(0);
  84. }
  85. void CPUFreqMonitorDelegate::RecordFrequency(unsigned int cpu_id,
  86. unsigned int freq) {
  87. TRACE_COUNTER_ID1(kTraceCategory, kEventTitle, cpu_id, freq);
  88. }
  89. scoped_refptr<SingleThreadTaskRunner>
  90. CPUFreqMonitorDelegate::CreateTaskRunner() {
  91. return base::ThreadPool::CreateSingleThreadTaskRunner(
  92. {base::MayBlock(), base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN,
  93. base::TaskPriority::BEST_EFFORT},
  94. base::SingleThreadTaskRunnerThreadMode::SHARED);
  95. }
  96. CPUFreqMonitor::CPUFreqMonitor()
  97. : CPUFreqMonitor(std::make_unique<CPUFreqMonitorDelegate>()) {}
  98. CPUFreqMonitor::CPUFreqMonitor(std::unique_ptr<CPUFreqMonitorDelegate> delegate)
  99. : delegate_(std::move(delegate)) {}
  100. CPUFreqMonitor::~CPUFreqMonitor() {
  101. Stop();
  102. }
  103. // static
  104. CPUFreqMonitor* CPUFreqMonitor::GetInstance() {
  105. static base::NoDestructor<CPUFreqMonitor> instance;
  106. return instance.get();
  107. }
  108. void CPUFreqMonitor::OnTraceLogEnabled() {
  109. GetOrCreateTaskRunner()->PostTask(
  110. FROM_HERE,
  111. base::BindOnce(&CPUFreqMonitor::Start, weak_ptr_factory_.GetWeakPtr()));
  112. }
  113. void CPUFreqMonitor::OnTraceLogDisabled() {
  114. Stop();
  115. }
  116. void CPUFreqMonitor::Start() {
  117. // It's the responsibility of the caller to ensure that Start/Stop are
  118. // synchronized. If Start/Stop are called asynchronously where this value
  119. // may be incorrect, we have bigger problems.
  120. if (is_enabled_.load(std::memory_order_relaxed) ||
  121. !delegate_->IsTraceCategoryEnabled()) {
  122. return;
  123. }
  124. std::vector<unsigned int> cpu_ids;
  125. delegate_->GetCPUIds(&cpu_ids);
  126. std::vector<std::pair<unsigned int, base::ScopedFD>> fds;
  127. for (unsigned int id : cpu_ids) {
  128. std::string fstr = delegate_->GetScalingCurFreqPathString(id);
  129. int fd = open(fstr.c_str(), O_RDONLY);
  130. if (fd == -1)
  131. continue;
  132. fds.emplace_back(std::make_pair(id, base::ScopedFD(fd)));
  133. }
  134. // We failed to read any scaling_cur_freq files, no point sampling nothing.
  135. if (fds.size() == 0)
  136. return;
  137. is_enabled_.store(true, std::memory_order_release);
  138. GetOrCreateTaskRunner()->PostTask(
  139. FROM_HERE,
  140. base::BindOnce(&CPUFreqMonitor::Sample, weak_ptr_factory_.GetWeakPtr(),
  141. std::move(fds)));
  142. }
  143. void CPUFreqMonitor::Stop() {
  144. is_enabled_.store(false, std::memory_order_release);
  145. }
  146. void CPUFreqMonitor::Sample(
  147. std::vector<std::pair<unsigned int, base::ScopedFD>> fds) {
  148. // For the same reason as above we use relaxed ordering, because if this value
  149. // is in transition and we use acquire ordering then we'll never shut down our
  150. // original Sample tasks until the next Stop, so it's still the responsibility
  151. // of callers to sync Start/Stop.
  152. if (!is_enabled_.load(std::memory_order_relaxed))
  153. return;
  154. for (auto& id_fd : fds) {
  155. int fd = id_fd.second.get();
  156. unsigned int freq = 0;
  157. // If we have trouble reading data from the file for any reason we'll end up
  158. // reporting the frequency as nothing.
  159. lseek(fd, 0L, SEEK_SET);
  160. char data[kNumBytesToReadForSampling];
  161. ssize_t bytes_read = read(fd, data, kNumBytesToReadForSampling);
  162. if (bytes_read > 0) {
  163. if (static_cast<size_t>(bytes_read) < kNumBytesToReadForSampling)
  164. data[static_cast<size_t>(bytes_read)] = '\0';
  165. int ret = sscanf(data, "%d", &freq);
  166. if (ret == 0 || ret == std::char_traits<char>::eof())
  167. freq = 0;
  168. }
  169. delegate_->RecordFrequency(id_fd.first, freq);
  170. }
  171. GetOrCreateTaskRunner()->PostDelayedTask(
  172. FROM_HERE,
  173. base::BindOnce(&CPUFreqMonitor::Sample, weak_ptr_factory_.GetWeakPtr(),
  174. std::move(fds)),
  175. base::Milliseconds(kDefaultCPUFreqSampleIntervalMs));
  176. }
  177. bool CPUFreqMonitor::IsEnabledForTesting() {
  178. return is_enabled_.load(std::memory_order_acquire);
  179. }
  180. const scoped_refptr<SingleThreadTaskRunner>&
  181. CPUFreqMonitor::GetOrCreateTaskRunner() {
  182. if (!task_runner_)
  183. task_runner_ = delegate_->CreateTaskRunner();
  184. return task_runner_;
  185. }
  186. } // namespace trace_event
  187. } // namespace base