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
RecordCmd()40 static std::unique_ptr<Command> RecordCmd() {
41 return CreateCommandInstance("record");
42 }
43
44 #if defined(__BIONIC__)
45 class ScopedMpdecisionKiller {
46 public:
ScopedMpdecisionKiller()47 ScopedMpdecisionKiller() {
48 have_mpdecision_ = IsMpdecisionRunning();
49 if (have_mpdecision_) {
50 DisableMpdecision();
51 }
52 }
53
~ScopedMpdecisionKiller()54 ~ScopedMpdecisionKiller() {
55 if (have_mpdecision_) {
56 EnableMpdecision();
57 }
58 }
59
60 private:
IsMpdecisionRunning()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
DisableMpdecision()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
EnableMpdecision()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:
ScopedMpdecisionKiller()90 ScopedMpdecisionKiller() {
91 }
92 };
93 #endif
94
IsCpuOnline(int cpu)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
SetCpuOnline(int cpu,bool online)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
GetCpuCount()114 static int GetCpuCount() {
115 return static_cast<int>(sysconf(_SC_NPROCESSORS_CONF));
116 }
117
118 class CpuOnlineRestorer {
119 public:
CpuOnlineRestorer()120 CpuOnlineRestorer() {
121 for (int cpu = 1; cpu < GetCpuCount(); ++cpu) {
122 online_map_[cpu] = IsCpuOnline(cpu);
123 }
124 }
125
~CpuOnlineRestorer()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
CpuToggleThread(CpuToggleThreadArg * arg)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
RecordInChildProcess(int record_cpu,int record_duration_in_second)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.
TEST(cpu_offline,offline_while_recording)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
OpenHardwareEventOnCpu(int cpu)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.
TEST(cpu_offline,offline_while_recording_on_another_cpu)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
main(int argc,char ** argv)256 int main(int argc, char** argv) {
257 InitLogging(argv, android::base::StderrLogger);
258 testing::InitGoogleTest(&argc, argv);
259 return RUN_ALL_TESTS();
260 }
261