OSDN Git Service

ANRdaemon: move trace result from /sdcard to /data am: d93aa41807
[android-x86/system-extras.git] / simpleperf / cpu_hotplug_test.cpp
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <gtest/gtest.h>
18
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #if defined(__BIONIC__)
22 #include <sys/system_properties.h>
23 #endif
24
25 #include <atomic>
26 #include <chrono>
27 #include <condition_variable>
28 #include <thread>
29 #include <unordered_map>
30
31 #include <android-base/file.h>
32 #include <android-base/logging.h>
33 #include <android-base/stringprintf.h>
34
35 #include "command.h"
36 #include "event_attr.h"
37 #include "event_fd.h"
38 #include "event_type.h"
39
40 static std::unique_ptr<Command> RecordCmd() {
41   return CreateCommandInstance("record");
42 }
43
44 #if defined(__BIONIC__)
45 class ScopedMpdecisionKiller {
46  public:
47   ScopedMpdecisionKiller() {
48     have_mpdecision_ = IsMpdecisionRunning();
49     if (have_mpdecision_) {
50       DisableMpdecision();
51     }
52   }
53
54   ~ScopedMpdecisionKiller() {
55     if (have_mpdecision_) {
56       EnableMpdecision();
57     }
58   }
59
60  private:
61   bool IsMpdecisionRunning() {
62     char value[PROP_VALUE_MAX];
63     int len = __system_property_get("init.svc.mpdecision", value);
64     if (len == 0 || (len > 0 && strstr(value, "stopped") != nullptr)) {
65       return false;
66     }
67     return true;
68   }
69
70   void DisableMpdecision() {
71     int ret = __system_property_set("ctl.stop", "mpdecision");
72     CHECK_EQ(0, ret);
73     // Need to wait until mpdecision is actually stopped.
74     usleep(500000);
75     CHECK(!IsMpdecisionRunning());
76   }
77
78   void EnableMpdecision() {
79     int ret = __system_property_set("ctl.start", "mpdecision");
80     CHECK_EQ(0, ret);
81     usleep(500000);
82     CHECK(IsMpdecisionRunning());
83   }
84
85   bool have_mpdecision_;
86 };
87 #else
88 class ScopedMpdecisionKiller {
89  public:
90   ScopedMpdecisionKiller() {
91   }
92 };
93 #endif
94
95 static bool IsCpuOnline(int cpu) {
96   std::string filename = android::base::StringPrintf("/sys/devices/system/cpu/cpu%d/online", cpu);
97   std::string content;
98   CHECK(android::base::ReadFileToString(filename, &content)) << "failed to read file " << filename;
99   return (content.find('1') != std::string::npos);
100 }
101
102 static void SetCpuOnline(int cpu, bool online) {
103   if (IsCpuOnline(cpu) == online) {
104     return;
105   }
106   std::string filename = android::base::StringPrintf("/sys/devices/system/cpu/cpu%d/online", cpu);
107   std::string content = online ? "1" : "0";
108   CHECK(android::base::WriteStringToFile(content, filename)) << "Write " << content << " to "
109                                                              << filename << " failed";
110   CHECK_EQ(online, IsCpuOnline(cpu)) << "set cpu " << cpu << (online ? " online" : " offline")
111                                      << " failed";
112 }
113
114 static int GetCpuCount() {
115   return static_cast<int>(sysconf(_SC_NPROCESSORS_CONF));
116 }
117
118 class CpuOnlineRestorer {
119  public:
120   CpuOnlineRestorer() {
121     for (int cpu = 1; cpu < GetCpuCount(); ++cpu) {
122       online_map_[cpu] = IsCpuOnline(cpu);
123     }
124   }
125
126   ~CpuOnlineRestorer() {
127     for (const auto& pair : online_map_) {
128       SetCpuOnline(pair.first, pair.second);
129     }
130   }
131
132  private:
133   std::unordered_map<int, bool> online_map_;
134 };
135
136 struct CpuToggleThreadArg {
137   int toggle_cpu;
138   std::atomic<bool> end_flag;
139 };
140
141 static void CpuToggleThread(CpuToggleThreadArg* arg) {
142   while (!arg->end_flag) {
143     SetCpuOnline(arg->toggle_cpu, true);
144     sleep(1);
145     SetCpuOnline(arg->toggle_cpu, false);
146     sleep(1);
147   }
148 }
149
150 static bool RecordInChildProcess(int record_cpu, int record_duration_in_second) {
151   pid_t pid = fork();
152   CHECK(pid != -1);
153   if (pid == 0) {
154     std::string cpu_str = android::base::StringPrintf("%d", record_cpu);
155     std::string record_duration_str = android::base::StringPrintf("%d", record_duration_in_second);
156     bool ret = RecordCmd()->Run({"-a", "--cpu", cpu_str, "sleep", record_duration_str});
157     extern bool system_wide_perf_event_open_failed;
158     // It is not an error if perf_event_open failed because of cpu-hotplug.
159     if (!ret && !system_wide_perf_event_open_failed) {
160       exit(1);
161     }
162     exit(0);
163   }
164   int timeout = record_duration_in_second + 10;
165   auto end_time = std::chrono::steady_clock::now() + std::chrono::seconds(timeout);
166   bool child_success = false;
167   while (std::chrono::steady_clock::now() < end_time) {
168     int exit_state;
169     pid_t ret = waitpid(pid, &exit_state, WNOHANG);
170     if (ret == pid) {
171       if (WIFSIGNALED(exit_state) || (WIFEXITED(exit_state) && WEXITSTATUS(exit_state) != 0)) {
172         child_success = false;
173       } else {
174         child_success = true;
175       }
176       break;
177     } else if (ret == -1) {
178       child_success = false;
179       break;
180     }
181     sleep(1);
182   }
183   return child_success;
184 }
185
186 // http://b/25193162.
187 TEST(cpu_offline, offline_while_recording) {
188   ScopedMpdecisionKiller scoped_mpdecision_killer;
189   CpuOnlineRestorer cpuonline_restorer;
190
191   if (GetCpuCount() == 1) {
192     GTEST_LOG_(INFO) << "This test does nothing, because there is only one cpu in the system.";
193     return;
194   }
195   for (int i = 1; i < GetCpuCount(); ++i) {
196     if (!IsCpuOnline(i)) {
197       SetCpuOnline(i, true);
198     }
199   }
200   // Start cpu hotplugger.
201   int test_cpu = GetCpuCount() - 1;
202   CpuToggleThreadArg cpu_toggle_arg;
203   cpu_toggle_arg.toggle_cpu = test_cpu;
204   cpu_toggle_arg.end_flag = false;
205   std::thread cpu_toggle_thread(CpuToggleThread, &cpu_toggle_arg);
206
207   const std::chrono::hours test_duration(10);  // Test for 10 hours.
208   const double RECORD_DURATION_IN_SEC = 2.9;
209   const double SLEEP_DURATION_IN_SEC = 1.3;
210
211   auto end_time = std::chrono::steady_clock::now() + test_duration;
212   size_t iterations = 0;
213   while (std::chrono::steady_clock::now() < end_time) {
214     iterations++;
215     GTEST_LOG_(INFO) << "Test for " << iterations << " times.";
216     ASSERT_TRUE(RecordInChildProcess(test_cpu, RECORD_DURATION_IN_SEC));
217     usleep(static_cast<useconds_t>(SLEEP_DURATION_IN_SEC * 1e6));
218   }
219   cpu_toggle_arg.end_flag = true;
220   cpu_toggle_thread.join();
221 }
222
223 static std::unique_ptr<EventFd> OpenHardwareEventOnCpu(int cpu) {
224   std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles");
225   if (event_type_modifier == nullptr) {
226     return nullptr;
227   }
228   perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
229   return EventFd::OpenEventFile(attr, getpid(), cpu);
230 }
231
232 // http://b/19863147.
233 TEST(cpu_offline, offline_while_recording_on_another_cpu) {
234   ScopedMpdecisionKiller scoped_mpdecision_killer;
235   CpuOnlineRestorer cpuonline_restorer;
236
237   if (GetCpuCount() == 1) {
238     GTEST_LOG_(INFO) << "This test does nothing, because there is only one cpu in the system.";
239     return;
240   }
241
242   const size_t TEST_ITERATION_COUNT = 10u;
243   for (size_t i = 0; i < TEST_ITERATION_COUNT; ++i) {
244     int record_cpu = 0;
245     int toggle_cpu = GetCpuCount() - 1;
246     SetCpuOnline(toggle_cpu, true);
247     std::unique_ptr<EventFd> event_fd = OpenHardwareEventOnCpu(record_cpu);
248     ASSERT_TRUE(event_fd != nullptr);
249     SetCpuOnline(toggle_cpu, false);
250     event_fd = nullptr;
251     event_fd = OpenHardwareEventOnCpu(record_cpu);
252     ASSERT_TRUE(event_fd != nullptr);
253   }
254 }
255
256 int main(int argc, char** argv) {
257   InitLogging(argv, android::base::StderrLogger);
258   testing::InitGoogleTest(&argc, argv);
259   return RUN_ALL_TESTS();
260 }