cpufreq_monitor_android_unittest.cc 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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 <list>
  6. #include <fcntl.h>
  7. #include "base/files/file_util.h"
  8. #include "base/files/scoped_file.h"
  9. #include "base/files/scoped_temp_dir.h"
  10. #include "base/memory/raw_ptr.h"
  11. #include "base/strings/stringprintf.h"
  12. #include "base/time/time.h"
  13. #include "testing/gtest/include/gtest/gtest.h"
  14. namespace base {
  15. namespace trace_event {
  16. class TestTaskRunner final : public SingleThreadTaskRunner {
  17. public:
  18. bool PostDelayedTask(const Location& from_here,
  19. OnceClosure task,
  20. base::TimeDelta delay) override {
  21. delayed_tasks_.push_back(std::make_pair(std::move(delay), std::move(task)));
  22. return true;
  23. }
  24. bool PostNonNestableDelayedTask(const Location& from_here,
  25. OnceClosure task,
  26. base::TimeDelta delay) override {
  27. NOTREACHED();
  28. return false;
  29. }
  30. bool RunsTasksInCurrentSequence() const override { return true; }
  31. // Returns the delay in ms for this task if there was a task to be run,
  32. // and -1 if there are no tasks in the queue.
  33. int64_t RunNextTask() {
  34. if (delayed_tasks_.size() == 0)
  35. return -1;
  36. auto time_delta = delayed_tasks_.front().first;
  37. std::move(delayed_tasks_.front().second).Run();
  38. delayed_tasks_.pop_front();
  39. return time_delta.InMilliseconds();
  40. }
  41. private:
  42. ~TestTaskRunner() override {}
  43. std::list<std::pair<base::TimeDelta, OnceClosure>> delayed_tasks_;
  44. };
  45. class TestDelegate : public CPUFreqMonitorDelegate {
  46. public:
  47. TestDelegate(const std::string& temp_dir_path)
  48. : temp_dir_path_(temp_dir_path) {}
  49. void set_trace_category_enabled(bool enabled) {
  50. trace_category_enabled_ = enabled;
  51. }
  52. void set_cpu_ids(const std::vector<unsigned int>& cpu_ids) {
  53. cpu_ids_ = cpu_ids;
  54. }
  55. void set_kernel_max_cpu(unsigned int kernel_max_cpu) {
  56. kernel_max_cpu_ = kernel_max_cpu;
  57. }
  58. const std::vector<std::pair<unsigned int, unsigned int>>& recorded_freqs() {
  59. return recorded_freqs_;
  60. }
  61. // CPUFreqMonitorDelegate implementation:
  62. void GetCPUIds(std::vector<unsigned int>* ids) const override {
  63. // Use the test values if available.
  64. if (cpu_ids_.size() > 0) {
  65. *ids = cpu_ids_;
  66. return;
  67. }
  68. // Otherwise fall back to the original function.
  69. CPUFreqMonitorDelegate::GetCPUIds(ids);
  70. }
  71. void RecordFrequency(unsigned int cpu_id, unsigned int freq) override {
  72. recorded_freqs_.emplace_back(
  73. std::pair<unsigned int, unsigned int>(cpu_id, freq));
  74. }
  75. bool IsTraceCategoryEnabled() const override {
  76. return trace_category_enabled_;
  77. }
  78. std::string GetScalingCurFreqPathString(unsigned int cpu_id) const override {
  79. return base::StringPrintf("%s/scaling_cur_freq%d", temp_dir_path_.c_str(),
  80. cpu_id);
  81. }
  82. std::string GetRelatedCPUsPathString(unsigned int cpu_id) const override {
  83. return base::StringPrintf("%s/related_cpus%d", temp_dir_path_.c_str(),
  84. cpu_id);
  85. }
  86. unsigned int GetKernelMaxCPUs() const override { return kernel_max_cpu_; }
  87. protected:
  88. scoped_refptr<SingleThreadTaskRunner> CreateTaskRunner() override {
  89. return base::WrapRefCounted(new TestTaskRunner());
  90. }
  91. private:
  92. // Maps CPU ID to frequency.
  93. std::vector<std::pair<unsigned int, unsigned int>> recorded_freqs_;
  94. std::vector<unsigned int> cpu_ids_;
  95. bool trace_category_enabled_ = true;
  96. std::string temp_dir_path_;
  97. unsigned int kernel_max_cpu_ = 0;
  98. };
  99. class CPUFreqMonitorTest : public testing::Test {
  100. public:
  101. CPUFreqMonitorTest() : testing::Test() {}
  102. void SetUp() override {
  103. temp_dir_ = std::make_unique<ScopedTempDir>();
  104. ASSERT_TRUE(temp_dir_->CreateUniqueTempDir());
  105. std::string base_path = temp_dir_->GetPath().value();
  106. auto delegate = std::make_unique<TestDelegate>(base_path);
  107. // Retain a pointer to the delegate since we're passing ownership to the
  108. // monitor but we need to be able to modify it.
  109. delegate_ = delegate.get();
  110. // Can't use make_unique because it's a private constructor.
  111. CPUFreqMonitor* monitor = new CPUFreqMonitor(std::move(delegate));
  112. monitor_.reset(monitor);
  113. }
  114. void TearDown() override {
  115. monitor_.reset();
  116. temp_dir_.reset();
  117. }
  118. void CreateDefaultScalingCurFreqFiles(
  119. const std::vector<std::pair<unsigned int, unsigned int>>& frequencies) {
  120. for (auto& pair : frequencies) {
  121. std::string file_path =
  122. delegate_->GetScalingCurFreqPathString(pair.first);
  123. std::string str_freq = base::StringPrintf("%d\n", pair.second);
  124. base::WriteFile(base::FilePath(file_path), str_freq);
  125. }
  126. }
  127. void CreateRelatedCPUFiles(const std::vector<unsigned int>& clusters,
  128. const std::vector<std::string>& related_cpus) {
  129. for (unsigned int i = 0; i < clusters.size(); i++) {
  130. base::WriteFile(base::FilePath(delegate_->GetRelatedCPUsPathString(i)),
  131. related_cpus[clusters[i]]);
  132. }
  133. }
  134. void InitBasicCPUInfo() {
  135. std::vector<std::pair<unsigned int, unsigned int>> frequencies = {
  136. {0, 500}, {2, 1000}, {4, 800}, {6, 750},
  137. };
  138. std::vector<unsigned int> cpu_ids;
  139. for (auto& pair : frequencies) {
  140. cpu_ids.push_back(pair.first);
  141. }
  142. delegate()->set_cpu_ids(cpu_ids);
  143. CreateDefaultScalingCurFreqFiles(frequencies);
  144. }
  145. TestTaskRunner* GetOrCreateTaskRunner() {
  146. return static_cast<TestTaskRunner*>(
  147. monitor_->GetOrCreateTaskRunner().get());
  148. }
  149. CPUFreqMonitor* monitor() { return monitor_.get(); }
  150. ScopedTempDir* temp_dir() { return temp_dir_.get(); }
  151. TestDelegate* delegate() { return delegate_; }
  152. private:
  153. scoped_refptr<TestTaskRunner> task_runner_;
  154. std::unique_ptr<ScopedTempDir> temp_dir_;
  155. std::unique_ptr<CPUFreqMonitor> monitor_;
  156. raw_ptr<TestDelegate> delegate_;
  157. };
  158. TEST_F(CPUFreqMonitorTest, TestStart) {
  159. InitBasicCPUInfo();
  160. monitor()->Start();
  161. ASSERT_TRUE(monitor()->IsEnabledForTesting());
  162. }
  163. TEST_F(CPUFreqMonitorTest, TestSample) {
  164. // Vector of CPU ID to frequency.
  165. std::vector<std::pair<unsigned int, unsigned int>> frequencies = {{0, 500},
  166. {4, 1000}};
  167. std::vector<unsigned int> cpu_ids;
  168. for (auto& pair : frequencies) {
  169. cpu_ids.push_back(pair.first);
  170. }
  171. delegate()->set_cpu_ids(cpu_ids);
  172. // Build some files with CPU frequency info in it to sample.
  173. std::vector<std::pair<unsigned int, base::ScopedFD>> fds;
  174. for (auto& pair : frequencies) {
  175. std::string file_path = base::StringPrintf(
  176. "%s/temp%d", temp_dir()->GetPath().value().c_str(), pair.first);
  177. // Uses raw file descriptors so we can build our ScopedFDs in the same loop.
  178. int fd = open(file_path.c_str(), O_RDWR | O_CREAT | O_SYNC,
  179. S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
  180. ASSERT_FALSE(fd == -1);
  181. std::string str_freq = base::StringPrintf("%d\n", pair.second);
  182. write(fd, str_freq.c_str(), str_freq.length());
  183. fds.emplace_back(std::make_pair(pair.first, base::ScopedFD(fd)));
  184. }
  185. // This ensures we set it to enabled before sampling, otherwise the call to
  186. // Sample() will end early.
  187. CreateDefaultScalingCurFreqFiles(frequencies);
  188. monitor()->Start();
  189. ASSERT_TRUE(monitor()->IsEnabledForTesting());
  190. // Ensure that we run our undelayed posted task for Sample.
  191. ASSERT_EQ(GetOrCreateTaskRunner()->RunNextTask(), 0);
  192. // Run the new delayed task so we sample again.
  193. ASSERT_TRUE(GetOrCreateTaskRunner()->RunNextTask() ==
  194. CPUFreqMonitor::kDefaultCPUFreqSampleIntervalMs);
  195. // Ensure that the values that we recorded agree with the frequencies above.
  196. auto recorded_freqs = delegate()->recorded_freqs();
  197. ASSERT_EQ(recorded_freqs.size(), frequencies.size() * 2);
  198. for (unsigned int i = 0; i < frequencies.size(); i++) {
  199. auto freq_pair = frequencies[i];
  200. // We sampled twice, so the recording pairs should be equal.
  201. auto recorded_pair_1 = recorded_freqs[i];
  202. auto recorded_pair_2 = recorded_freqs[i + 2];
  203. ASSERT_EQ(freq_pair.first, recorded_pair_1.first);
  204. ASSERT_EQ(freq_pair.second, recorded_pair_1.second);
  205. ASSERT_EQ(freq_pair.first, recorded_pair_2.first);
  206. ASSERT_EQ(freq_pair.second, recorded_pair_2.second);
  207. }
  208. // Test that calling Stop works, we shouldn't post any more tasks if Sample
  209. // is called.
  210. monitor()->Stop();
  211. // Clear out the first Sample task that's on deck, then try again to make sure
  212. // no new task was posted.
  213. ASSERT_TRUE(GetOrCreateTaskRunner()->RunNextTask() ==
  214. CPUFreqMonitor::kDefaultCPUFreqSampleIntervalMs);
  215. ASSERT_EQ(GetOrCreateTaskRunner()->RunNextTask(), -1);
  216. }
  217. TEST_F(CPUFreqMonitorTest, TestStartFail_TraceCategoryDisabled) {
  218. delegate()->set_trace_category_enabled(false);
  219. CreateDefaultScalingCurFreqFiles({{0, 1000}});
  220. monitor()->Start();
  221. ASSERT_FALSE(monitor()->IsEnabledForTesting());
  222. }
  223. TEST_F(CPUFreqMonitorTest, TestStartFail_NoScalingCurFreqFiles) {
  224. monitor()->Start();
  225. ASSERT_FALSE(monitor()->IsEnabledForTesting());
  226. }
  227. TEST_F(CPUFreqMonitorTest, TestDelegate_GetCPUIds) {
  228. delegate()->set_kernel_max_cpu(8);
  229. std::vector<std::string> related_cpus = {"0 1 2 3\n", "4 5 6 7\n"};
  230. std::vector<unsigned int> clusters = {0, 0, 0, 0, 1, 1, 1, 1};
  231. CreateRelatedCPUFiles(clusters, related_cpus);
  232. std::vector<unsigned int> cpu_ids;
  233. delegate()->GetCPUIds(&cpu_ids);
  234. EXPECT_EQ(cpu_ids.size(), 2U);
  235. EXPECT_EQ(cpu_ids[0], 0U);
  236. EXPECT_EQ(cpu_ids[1], 4U);
  237. }
  238. TEST_F(CPUFreqMonitorTest, TestDelegate_GetCPUIds_FailReadingFallback) {
  239. delegate()->set_kernel_max_cpu(8);
  240. std::vector<unsigned int> cpu_ids;
  241. delegate()->GetCPUIds(&cpu_ids);
  242. EXPECT_EQ(cpu_ids.size(), 1U);
  243. EXPECT_EQ(cpu_ids[0], 0U);
  244. }
  245. TEST_F(CPUFreqMonitorTest, TestMultipleStartStop) {
  246. InitBasicCPUInfo();
  247. monitor()->Start();
  248. ASSERT_TRUE(monitor()->IsEnabledForTesting());
  249. monitor()->Stop();
  250. ASSERT_FALSE(monitor()->IsEnabledForTesting());
  251. monitor()->Start();
  252. ASSERT_TRUE(monitor()->IsEnabledForTesting());
  253. monitor()->Stop();
  254. ASSERT_FALSE(monitor()->IsEnabledForTesting());
  255. }
  256. TEST_F(CPUFreqMonitorTest, TestTraceLogEnableDisable) {
  257. InitBasicCPUInfo();
  258. monitor()->OnTraceLogEnabled();
  259. // OnTraceLogEnabled posts a task for Start.
  260. GetOrCreateTaskRunner()->RunNextTask();
  261. ASSERT_TRUE(monitor()->IsEnabledForTesting());
  262. monitor()->OnTraceLogDisabled();
  263. ASSERT_FALSE(monitor()->IsEnabledForTesting());
  264. // We also need to clear out the task for Sample from the Start call.
  265. GetOrCreateTaskRunner()->RunNextTask();
  266. monitor()->OnTraceLogEnabled();
  267. GetOrCreateTaskRunner()->RunNextTask();
  268. ASSERT_TRUE(monitor()->IsEnabledForTesting());
  269. monitor()->OnTraceLogDisabled();
  270. ASSERT_FALSE(monitor()->IsEnabledForTesting());
  271. }
  272. } // namespace trace_event
  273. } // namespace base