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 <thread> 28 #include <unordered_map> 29 30 #include <android-base/file.h> 31 #include <android-base/logging.h> 32 #include <android-base/stringprintf.h> 33 34 #include "environment.h" 35 #include "event_attr.h" 36 #include "event_fd.h" 37 #include "event_type.h" 38 #include "utils.h" 39 40 static auto test_duration_for_long_tests = std::chrono::seconds(120); 41 static auto cpu_hotplug_interval = std::chrono::microseconds(1000); 42 static bool verbose_mode = false; 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 std::this_thread::sleep_for(std::chrono::milliseconds(500)); 75 CHECK(!IsMpdecisionRunning()); 76 } 77 78 void EnableMpdecision() { 79 int ret = __system_property_set("ctl.start", "mpdecision"); 80 CHECK_EQ(0, ret); 81 std::this_thread::sleep_for(std::chrono::milliseconds(500)); 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, bool* has_error) { 96 std::string filename = android::base::StringPrintf("/sys/devices/system/cpu/cpu%d/online", cpu); 97 std::string content; 98 bool ret = android::base::ReadFileToString(filename, &content); 99 if (!ret) { 100 PLOG(ERROR) << "failed to read file " << filename; 101 *has_error = true; 102 return false; 103 } 104 *has_error = false; 105 return (content.find('1') != std::string::npos); 106 } 107 108 static bool SetCpuOnline(int cpu, bool online) { 109 bool has_error; 110 bool ret = IsCpuOnline(cpu, &has_error); 111 if (has_error) { 112 return false; 113 } 114 if (ret == online) { 115 return true; 116 } 117 std::string filename = android::base::StringPrintf("/sys/devices/system/cpu/cpu%d/online", cpu); 118 std::string content = online ? "1" : "0"; 119 ret = android::base::WriteStringToFile(content, filename); 120 if (!ret) { 121 ret = IsCpuOnline(cpu, &has_error); 122 if (has_error) { 123 return false; 124 } 125 if (online == ret) { 126 return true; 127 } 128 PLOG(ERROR) << "failed to write " << content << " to " << filename; 129 return false; 130 } 131 // Kernel needs time to offline/online cpus, so use a loop to wait here. 132 size_t retry_count = 0; 133 while (true) { 134 ret = IsCpuOnline(cpu, &has_error); 135 if (has_error) { 136 return false; 137 } 138 if (ret == online) { 139 break; 140 } 141 LOG(ERROR) << "reading cpu retry count = " << retry_count << ", requested = " << online 142 << ", real = " << ret; 143 if (++retry_count == 10000) { 144 LOG(ERROR) << "setting cpu " << cpu << (online ? " online" : " offline") << " seems not to take effect"; 145 return false; 146 } 147 std::this_thread::sleep_for(std::chrono::milliseconds(1)); 148 } 149 return true; 150 } 151 152 static int GetCpuCount() { 153 return static_cast<int>(sysconf(_SC_NPROCESSORS_CONF)); 154 } 155 156 class CpuOnlineRestorer { 157 public: 158 CpuOnlineRestorer() { 159 for (int cpu = 1; cpu < GetCpuCount(); ++cpu) { 160 bool has_error; 161 bool ret = IsCpuOnline(cpu, &has_error); 162 if (has_error) { 163 continue; 164 } 165 online_map_[cpu] = ret; 166 } 167 } 168 169 ~CpuOnlineRestorer() { 170 for (const auto& pair : online_map_) { 171 SetCpuOnline(pair.first, pair.second); 172 } 173 } 174 175 private: 176 std::unordered_map<int, bool> online_map_; 177 }; 178 179 bool FindAHotpluggableCpu(int* hotpluggable_cpu) { 180 if (!IsRoot()) { 181 GTEST_LOG_(INFO) << "This test needs root privilege to hotplug cpu."; 182 return false; 183 } 184 for (int cpu = 1; cpu < GetCpuCount(); ++cpu) { 185 bool has_error; 186 bool online = IsCpuOnline(cpu, &has_error); 187 if (has_error) { 188 continue; 189 } 190 if (SetCpuOnline(cpu, !online)) { 191 *hotpluggable_cpu = cpu; 192 return true; 193 } 194 } 195 GTEST_LOG_(INFO) << "There is no hotpluggable cpu."; 196 return false; 197 } 198 199 struct CpuToggleThreadArg { 200 int toggle_cpu; 201 std::atomic<bool> end_flag; 202 std::atomic<bool> cpu_hotplug_failed; 203 204 CpuToggleThreadArg(int cpu) 205 : toggle_cpu(cpu), end_flag(false), cpu_hotplug_failed(false) { 206 } 207 }; 208 209 static void CpuToggleThread(CpuToggleThreadArg* arg) { 210 while (!arg->end_flag) { 211 if (!SetCpuOnline(arg->toggle_cpu, true)) { 212 arg->cpu_hotplug_failed = true; 213 break; 214 } 215 std::this_thread::sleep_for(cpu_hotplug_interval); 216 if (!SetCpuOnline(arg->toggle_cpu, false)) { 217 arg->cpu_hotplug_failed = true; 218 break; 219 } 220 std::this_thread::sleep_for(cpu_hotplug_interval); 221 } 222 } 223 224 // http://b/25193162. 225 TEST(cpu_offline, offline_while_recording) { 226 ScopedMpdecisionKiller scoped_mpdecision_killer; 227 CpuOnlineRestorer cpuonline_restorer; 228 if (GetCpuCount() == 1) { 229 GTEST_LOG_(INFO) << "This test does nothing, because there is only one cpu in the system."; 230 return; 231 } 232 // Start cpu hotpluger. 233 int test_cpu; 234 if (!FindAHotpluggableCpu(&test_cpu)) { 235 return; 236 } 237 CpuToggleThreadArg cpu_toggle_arg(test_cpu); 238 std::thread cpu_toggle_thread(CpuToggleThread, &cpu_toggle_arg); 239 240 std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles"); 241 ASSERT_TRUE(event_type_modifier != nullptr); 242 perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type); 243 attr.disabled = 0; 244 attr.enable_on_exec = 0; 245 246 auto start_time = std::chrono::steady_clock::now(); 247 auto cur_time = start_time; 248 auto end_time = std::chrono::steady_clock::now() + test_duration_for_long_tests; 249 auto report_step = std::chrono::seconds(15); 250 size_t iterations = 0; 251 252 while (cur_time < end_time && !cpu_toggle_arg.cpu_hotplug_failed) { 253 if (cur_time + report_step < std::chrono::steady_clock::now()) { 254 // Report test time. 255 auto diff = std::chrono::duration_cast<std::chrono::seconds>( 256 std::chrono::steady_clock::now() - start_time); 257 if (verbose_mode) { 258 GTEST_LOG_(INFO) << "Have Tested " << (diff.count() / 60.0) << " minutes."; 259 } 260 cur_time = std::chrono::steady_clock::now(); 261 } 262 263 std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(attr, -1, test_cpu, nullptr, false); 264 if (event_fd == nullptr) { 265 // Failed to open because the test_cpu is offline. 266 continue; 267 } 268 iterations++; 269 if (verbose_mode) { 270 GTEST_LOG_(INFO) << "Test offline while recording for " << iterations << " times."; 271 } 272 } 273 if (cpu_toggle_arg.cpu_hotplug_failed) { 274 GTEST_LOG_(INFO) << "Test ends because of cpu hotplug failure."; 275 } 276 cpu_toggle_arg.end_flag = true; 277 cpu_toggle_thread.join(); 278 } 279 280 // http://b/25193162. 281 TEST(cpu_offline, offline_while_ioctl_enable) { 282 ScopedMpdecisionKiller scoped_mpdecision_killer; 283 CpuOnlineRestorer cpuonline_restorer; 284 if (GetCpuCount() == 1) { 285 GTEST_LOG_(INFO) << "This test does nothing, because there is only one cpu in the system."; 286 return; 287 } 288 // Start cpu hotpluger. 289 int test_cpu; 290 if (!FindAHotpluggableCpu(&test_cpu)) { 291 return; 292 } 293 CpuToggleThreadArg cpu_toggle_arg(test_cpu); 294 std::thread cpu_toggle_thread(CpuToggleThread, &cpu_toggle_arg); 295 296 std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles"); 297 ASSERT_TRUE(event_type_modifier != nullptr); 298 perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type); 299 attr.disabled = 1; 300 attr.enable_on_exec = 0; 301 302 auto start_time = std::chrono::steady_clock::now(); 303 auto cur_time = start_time; 304 auto end_time = std::chrono::steady_clock::now() + test_duration_for_long_tests; 305 auto report_step = std::chrono::seconds(15); 306 size_t iterations = 0; 307 308 while (cur_time < end_time && !cpu_toggle_arg.cpu_hotplug_failed) { 309 if (cur_time + report_step < std::chrono::steady_clock::now()) { 310 // Report test time. 311 auto diff = std::chrono::duration_cast<std::chrono::seconds>( 312 std::chrono::steady_clock::now() - start_time); 313 if (verbose_mode) { 314 GTEST_LOG_(INFO) << "Have Tested " << (diff.count() / 60.0) << " minutes."; 315 } 316 cur_time = std::chrono::steady_clock::now(); 317 318 } 319 std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(attr, -1, test_cpu, nullptr, false); 320 if (event_fd == nullptr) { 321 // Failed to open because the test_cpu is offline. 322 continue; 323 } 324 // Wait a little for the event to be installed on test_cpu's perf context. 325 std::this_thread::sleep_for(std::chrono::milliseconds(1)); 326 ASSERT_TRUE(event_fd->EnableEvent()); 327 iterations++; 328 if (verbose_mode) { 329 GTEST_LOG_(INFO) << "Test offline while ioctl(PERF_EVENT_IOC_ENABLE) for " << iterations << " times."; 330 } 331 } 332 if (cpu_toggle_arg.cpu_hotplug_failed) { 333 GTEST_LOG_(INFO) << "Test ends because of cpu hotplug failure."; 334 } 335 cpu_toggle_arg.end_flag = true; 336 cpu_toggle_thread.join(); 337 } 338 339 struct CpuSpinThreadArg { 340 int spin_cpu; 341 std::atomic<pid_t> tid; 342 std::atomic<bool> end_flag; 343 }; 344 345 static void CpuSpinThread(CpuSpinThreadArg* arg) { 346 arg->tid = gettid(); 347 while (!arg->end_flag) { 348 cpu_set_t mask; 349 CPU_ZERO(&mask); 350 CPU_SET(arg->spin_cpu, &mask); 351 // If toggle_cpu is offline, setaffinity fails. So call it in a loop to 352 // make sure current thread mostly runs on toggle_cpu. 353 sched_setaffinity(arg->tid, sizeof(mask), &mask); 354 } 355 } 356 357 // http://b/28086229. 358 TEST(cpu_offline, offline_while_user_process_profiling) { 359 ScopedMpdecisionKiller scoped_mpdecision_killer; 360 CpuOnlineRestorer cpuonline_restorer; 361 // Start cpu hotpluger. 362 int test_cpu; 363 if (!FindAHotpluggableCpu(&test_cpu)) { 364 return; 365 } 366 CpuToggleThreadArg cpu_toggle_arg(test_cpu); 367 std::thread cpu_toggle_thread(CpuToggleThread, &cpu_toggle_arg); 368 369 // Start cpu spinner. 370 CpuSpinThreadArg cpu_spin_arg; 371 cpu_spin_arg.spin_cpu = test_cpu; 372 cpu_spin_arg.tid = 0; 373 cpu_spin_arg.end_flag = false; 374 std::thread cpu_spin_thread(CpuSpinThread, &cpu_spin_arg); 375 while (cpu_spin_arg.tid == 0) { 376 std::this_thread::sleep_for(std::chrono::milliseconds(1)); 377 } 378 379 std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles"); 380 ASSERT_TRUE(event_type_modifier != nullptr); 381 perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type); 382 // Enable profiling in perf_event_open system call. 383 attr.disabled = 0; 384 attr.enable_on_exec = 0; 385 386 auto start_time = std::chrono::steady_clock::now(); 387 auto cur_time = start_time; 388 auto end_time = start_time + test_duration_for_long_tests; 389 auto report_step = std::chrono::seconds(15); 390 size_t iterations = 0; 391 392 while (cur_time < end_time && !cpu_toggle_arg.cpu_hotplug_failed) { 393 if (cur_time + report_step < std::chrono::steady_clock::now()) { 394 auto diff = std::chrono::duration_cast<std::chrono::seconds>( 395 std::chrono::steady_clock::now() - start_time); 396 if (verbose_mode) { 397 GTEST_LOG_(INFO) << "Have Tested " << (diff.count() / 60.0) << " minutes."; 398 } 399 cur_time = std::chrono::steady_clock::now(); 400 } 401 // Test if the cpu pmu is still usable. 402 ASSERT_TRUE(EventFd::OpenEventFile(attr, 0, -1, nullptr, true) != nullptr); 403 404 std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(attr, cpu_spin_arg.tid, 405 test_cpu, nullptr, false); 406 if (event_fd == nullptr) { 407 // Failed to open because the test_cpu is offline. 408 continue; 409 } 410 // profile for a while. 411 std::this_thread::sleep_for(std::chrono::milliseconds(1)); 412 iterations++; 413 if (verbose_mode) { 414 GTEST_LOG_(INFO) << "Test offline while user process profiling for " << iterations << " times."; 415 } 416 } 417 if (cpu_toggle_arg.cpu_hotplug_failed) { 418 GTEST_LOG_(INFO) << "Test ends because of cpu hotplug failure."; 419 } 420 cpu_toggle_arg.end_flag = true; 421 cpu_toggle_thread.join(); 422 cpu_spin_arg.end_flag = true; 423 cpu_spin_thread.join(); 424 // Check if the cpu-cycle event is still available on test_cpu. 425 if (SetCpuOnline(test_cpu, true)) { 426 ASSERT_TRUE(EventFd::OpenEventFile(attr, -1, test_cpu, nullptr, true) != nullptr); 427 } 428 } 429 430 // http://b/19863147. 431 TEST(cpu_offline, offline_while_recording_on_another_cpu) { 432 ScopedMpdecisionKiller scoped_mpdecision_killer; 433 CpuOnlineRestorer cpuonline_restorer; 434 435 if (GetCpuCount() == 1) { 436 GTEST_LOG_(INFO) << "This test does nothing, because there is only one cpu in the system."; 437 return; 438 } 439 int test_cpu; 440 if (!FindAHotpluggableCpu(&test_cpu)) { 441 return; 442 } 443 std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles"); 444 perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type); 445 attr.disabled = 0; 446 attr.enable_on_exec = 0; 447 448 const size_t TEST_ITERATION_COUNT = 10u; 449 for (size_t i = 0; i < TEST_ITERATION_COUNT; ++i) { 450 int record_cpu = 0; 451 if (!SetCpuOnline(test_cpu, true)) { 452 break; 453 } 454 std::unique_ptr<EventFd> event_fd = EventFd::OpenEventFile(attr, getpid(), record_cpu, nullptr); 455 ASSERT_TRUE(event_fd != nullptr); 456 if (!SetCpuOnline(test_cpu, false)) { 457 break; 458 } 459 event_fd = nullptr; 460 event_fd = EventFd::OpenEventFile(attr, getpid(), record_cpu, nullptr); 461 ASSERT_TRUE(event_fd != nullptr); 462 } 463 } 464 465 int main(int argc, char** argv) { 466 for (int i = 1; i < argc; ++i) { 467 if (strcmp(argv[i], "--help") == 0) { 468 printf("--long_test_duration <second> Set test duration for long tests. Default is 120s.\n"); 469 printf("--cpu_hotplug_interval <microseconds> Set cpu hotplug interval. Default is 1000us.\n"); 470 printf("--verbose Show verbose log.\n"); 471 } else if (strcmp(argv[i], "--long_test_duration") == 0) { 472 if (i + 1 < argc) { 473 int second_count = atoi(argv[i+1]); 474 if (second_count <= 0) { 475 fprintf(stderr, "Invalid arg for --long_test_duration.\n"); 476 return 1; 477 } 478 test_duration_for_long_tests = std::chrono::seconds(second_count); 479 i++; 480 } 481 } else if (strcmp(argv[i], "--cpu_hotplug_interval") == 0) { 482 if (i + 1 < argc) { 483 int microsecond_count = atoi(argv[i+1]); 484 if (microsecond_count <= 0) { 485 fprintf(stderr, "Invalid arg for --cpu_hotplug_interval\n"); 486 return 1; 487 } 488 cpu_hotplug_interval = std::chrono::microseconds(microsecond_count); 489 i++; 490 } 491 } else if (strcmp(argv[i], "--verbose") == 0) { 492 verbose_mode = true; 493 } 494 } 495 android::base::InitLogging(argv, android::base::StderrLogger); 496 testing::InitGoogleTest(&argc, argv); 497 return RUN_ALL_TESTS(); 498 } 499