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