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 <algorithm> 18 #include <cctype> 19 #include <functional> 20 #include <iterator> 21 #include <memory> 22 #include <mutex> 23 #include <regex> 24 #include <string> 25 26 #include <fcntl.h> 27 #include <stdio.h> 28 #include <libgen.h> 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 32 #include <android-base/file.h> 33 #include <android-base/logging.h> 34 #include <android-base/macros.h> 35 #include <android-base/stringprintf.h> 36 #include <android-base/strings.h> 37 #include <android-base/test_utils.h> 38 #include <android-base/thread_annotations.h> 39 #include <gtest/gtest.h> 40 #include <zlib.h> 41 42 #include "config.h" 43 #include "configreader.h" 44 #include "map_utils.h" 45 #include "perfprofdcore.h" 46 #include "perfprofd_cmdline.h" 47 #include "perfprofd_threaded_handler.h" 48 #include "quipper_helper.h" 49 #include "symbolizer.h" 50 51 #include "perfprofd_record.pb.h" 52 53 using namespace android::perfprofd::quipper; 54 55 static_assert(android::base::kEnableDChecks, "Expected DCHECKs to be enabled"); 56 57 // 58 // Set to argv[0] on startup 59 // 60 static std::string gExecutableRealpath; 61 62 namespace { 63 64 using android::base::LogId; 65 using android::base::LogSeverity; 66 67 class TestLogHelper { 68 public: 69 void Install() { 70 using namespace std::placeholders; 71 android::base::SetLogger( 72 std::bind(&TestLogHelper::TestLogFunction, this, _1, _2, _3, _4, _5, _6)); 73 } 74 75 std::string JoinTestLog(const char* delimiter) { 76 std::unique_lock<std::mutex> ul(lock_); 77 return android::base::Join(test_log_messages_, delimiter); 78 } 79 template <typename Predicate> 80 std::string JoinTestLog(const char* delimiter, Predicate pred) { 81 std::unique_lock<std::mutex> ul(lock_); 82 std::vector<std::string> tmp; 83 std::copy_if(test_log_messages_.begin(), 84 test_log_messages_.end(), 85 std::back_inserter(tmp), 86 pred); 87 return android::base::Join(tmp, delimiter); 88 } 89 90 private: 91 void TestLogFunction(LogId log_id, 92 LogSeverity severity, 93 const char* tag, 94 const char* file, 95 unsigned int line, 96 const char* message) { 97 std::unique_lock<std::mutex> ul(lock_); 98 constexpr char log_characters[] = "VDIWEFF"; 99 char severity_char = log_characters[severity]; 100 test_log_messages_.push_back(android::base::StringPrintf("%c: %s", severity_char, message)); 101 102 if (severity >= LogSeverity::FATAL_WITHOUT_ABORT) { 103 android::base::StderrLogger(log_id, severity, tag, file, line, message); 104 } 105 } 106 107 private: 108 std::mutex lock_; 109 110 std::vector<std::string> test_log_messages_; 111 }; 112 113 } // namespace 114 115 // Path to perf executable on device 116 #define PERFPATH "/system/bin/perf" 117 118 // Temporary config file that we will emit for the daemon to read 119 #define CONFIGFILE "perfprofd.conf" 120 121 static bool bothWhiteSpace(char lhs, char rhs) 122 { 123 return (std::isspace(lhs) && std::isspace(rhs)); 124 } 125 126 // 127 // Squeeze out repeated whitespace from expected/actual logs. 128 // 129 static std::string squeezeWhite(const std::string &str, 130 const char *tag, 131 bool dump=false) 132 { 133 if (dump) { fprintf(stderr, "raw %s is %s\n", tag, str.c_str()); } 134 std::string result(str); 135 std::replace(result.begin(), result.end(), '\n', ' '); 136 auto new_end = std::unique(result.begin(), result.end(), bothWhiteSpace); 137 result.erase(new_end, result.end()); 138 while (result.begin() != result.end() && std::isspace(*result.rbegin())) { 139 result.pop_back(); 140 } 141 if (dump) { fprintf(stderr, "squeezed %s is %s\n", tag, result.c_str()); } 142 return result; 143 } 144 145 // 146 // Replace all occurrences of a string with another string. 147 // 148 static std::string replaceAll(const std::string &str, 149 const std::string &from, 150 const std::string &to) 151 { 152 std::string ret = ""; 153 size_t pos = 0; 154 while (pos < str.size()) { 155 size_t found = str.find(from, pos); 156 if (found == std::string::npos) { 157 ret += str.substr(pos); 158 break; 159 } 160 ret += str.substr(pos, found - pos) + to; 161 pos = found + from.size(); 162 } 163 return ret; 164 } 165 166 // 167 // Replace occurrences of special variables in the string. 168 // 169 #ifdef __ANDROID__ 170 static std::string expandVars(const std::string &str) { 171 #ifdef __LP64__ 172 return replaceAll(str, "$NATIVE_TESTS", "/data/nativetest64"); 173 #else 174 return replaceAll(str, "$NATIVE_TESTS", "/data/nativetest"); 175 #endif 176 } 177 #endif 178 179 class PerfProfdTest : public testing::Test { 180 protected: 181 virtual void SetUp() { 182 test_logger.Install(); 183 create_dirs(); 184 } 185 186 virtual void TearDown() { 187 android::base::SetLogger(android::base::StderrLogger); 188 189 // TODO: proper management of test files. For now, use old system() code. 190 for (const auto dir : { &dest_dir, &conf_dir }) { 191 std::string cmd("rm -rf "); 192 cmd += *dir; 193 int ret = system(cmd.c_str()); 194 CHECK_EQ(0, ret); 195 } 196 } 197 198 protected: 199 // 200 // Check to see if the log messages emitted by the daemon 201 // match the expected result. By default we use a partial 202 // match, e.g. if we see the expected excerpt anywhere in the 203 // result, it's a match (for exact match, set exact to true) 204 // 205 void CompareLogMessages(const std::string& expected, 206 const char* testpoint, 207 bool exactMatch = false) { 208 std::string sqexp = squeezeWhite(expected, "expected"); 209 210 // Strip out JIT errors. 211 std::regex jit_regex("E: Failed to open ELF file: [^ ]*ashmem/dalvik-jit-code-cache.*"); 212 auto strip_jit = [&](const std::string& str) { 213 std::smatch jit_match; 214 return !std::regex_match(str, jit_match, jit_regex); 215 }; 216 std::string sqact = squeezeWhite(test_logger.JoinTestLog(" ", strip_jit), "actual"); 217 218 if (exactMatch) { 219 EXPECT_STREQ(sqexp.c_str(), sqact.c_str()); 220 } else { 221 std::size_t foundpos = sqact.find(sqexp); 222 bool wasFound = true; 223 if (foundpos == std::string::npos) { 224 std::cerr << testpoint << ": expected result not found\n"; 225 std::cerr << " Actual: \"" << sqact << "\"\n"; 226 std::cerr << " Expected: \"" << sqexp << "\"\n"; 227 wasFound = false; 228 } 229 EXPECT_TRUE(wasFound); 230 } 231 } 232 233 // test_dir is the directory containing the test executable and 234 // any files associated with the test (will be created by the harness). 235 std::string test_dir; 236 237 // dest_dir is a temporary directory that we're using as the destination directory. 238 // It is backed by temp_dir1. 239 std::string dest_dir; 240 241 // conf_dir is a temporary directory that we're using as the configuration directory. 242 // It is backed by temp_dir2. 243 std::string conf_dir; 244 245 TestLogHelper test_logger; 246 247 private: 248 void create_dirs() { 249 temp_dir1.reset(new TemporaryDir()); 250 temp_dir2.reset(new TemporaryDir()); 251 dest_dir = temp_dir1->path; 252 conf_dir = temp_dir2->path; 253 test_dir = android::base::Dirname(gExecutableRealpath); 254 } 255 256 std::unique_ptr<TemporaryDir> temp_dir1; 257 std::unique_ptr<TemporaryDir> temp_dir2; 258 }; 259 260 /// 261 /// Helper class to kick off a run of the perfprofd daemon with a specific 262 /// config file. 263 /// 264 class PerfProfdRunner { 265 public: 266 explicit PerfProfdRunner(const std::string& config_dir) 267 : config_dir_(config_dir) 268 { 269 config_path_ = config_dir + "/" CONFIGFILE; 270 } 271 272 ~PerfProfdRunner() 273 { 274 remove_processed_file(); 275 } 276 277 void addToConfig(const std::string &line) 278 { 279 config_text_ += line; 280 config_text_ += "\n"; 281 } 282 283 void remove_semaphore_file() 284 { 285 std::string semaphore(config_dir_); 286 semaphore += "/" SEMAPHORE_FILENAME; 287 unlink(semaphore.c_str()); 288 } 289 290 void create_semaphore_file() 291 { 292 std::string semaphore(config_dir_); 293 semaphore += "/" SEMAPHORE_FILENAME; 294 close(open(semaphore.c_str(), O_WRONLY|O_CREAT, 0600)); 295 } 296 297 void write_processed_file(int start_seq, int end_seq) 298 { 299 std::string processed = config_dir_ + "/" PROCESSED_FILENAME; 300 FILE *fp = fopen(processed.c_str(), "w"); 301 for (int i = start_seq; i < end_seq; i++) { 302 fprintf(fp, "%d\n", i); 303 } 304 fclose(fp); 305 } 306 307 void remove_processed_file() 308 { 309 std::string processed = config_dir_ + "/" PROCESSED_FILENAME; 310 unlink(processed.c_str()); 311 } 312 313 struct LoggingConfig : public Config { 314 void Sleep(size_t seconds) override { 315 // Log sleep calls but don't sleep. 316 LOG(INFO) << "sleep " << seconds << " seconds"; 317 } 318 319 bool IsProfilingEnabled() const override { 320 // 321 // Check for existence of semaphore file in config directory 322 // 323 if (access(config_directory.c_str(), F_OK) == -1) { 324 PLOG(WARNING) << "unable to open config directory " << config_directory; 325 return false; 326 } 327 328 // Check for existence of semaphore file 329 std::string semaphore_filepath = config_directory 330 + "/" + SEMAPHORE_FILENAME; 331 if (access(semaphore_filepath.c_str(), F_OK) == -1) { 332 return false; 333 } 334 335 return true; 336 } 337 }; 338 339 int invoke() 340 { 341 static const char *argv[3] = { "perfprofd", "-c", "" }; 342 argv[2] = config_path_.c_str(); 343 344 writeConfigFile(config_path_, config_text_); 345 346 // execute daemon main 347 LoggingConfig config; 348 return perfprofd_main(3, (char **) argv, &config); 349 } 350 351 private: 352 std::string config_dir_; 353 std::string config_path_; 354 std::string config_text_; 355 356 void writeConfigFile(const std::string &config_path, 357 const std::string &config_text) 358 { 359 FILE *fp = fopen(config_path.c_str(), "w"); 360 ASSERT_TRUE(fp != nullptr); 361 fprintf(fp, "%s\n", config_text.c_str()); 362 fclose(fp); 363 } 364 }; 365 366 //...................................................................... 367 368 static std::string encoded_file_path(const std::string& dest_dir, 369 int seq) { 370 return android::base::StringPrintf("%s/perf.data.encoded.%d", 371 dest_dir.c_str(), seq); 372 } 373 374 static void readEncodedProfile(const std::string& dest_dir, 375 bool compressed, 376 android::perfprofd::PerfprofdRecord& encodedProfile) 377 { 378 struct stat statb; 379 int perf_data_stat_result = stat(encoded_file_path(dest_dir, 0).c_str(), &statb); 380 ASSERT_NE(-1, perf_data_stat_result); 381 382 // read 383 std::string encoded; 384 encoded.resize(statb.st_size); 385 FILE *ifp = fopen(encoded_file_path(dest_dir, 0).c_str(), "r"); 386 ASSERT_NE(nullptr, ifp); 387 size_t items_read = fread((void*) encoded.data(), statb.st_size, 1, ifp); 388 ASSERT_EQ(1, items_read); 389 fclose(ifp); 390 391 // uncompress 392 if (compressed && !encoded.empty()) { 393 z_stream stream; 394 stream.zalloc = Z_NULL; 395 stream.zfree = Z_NULL; 396 stream.opaque = Z_NULL; 397 398 { 399 constexpr int kWindowBits = 15; 400 constexpr int kGzipEncoding = 16; 401 int init_result = inflateInit2(&stream, kWindowBits | kGzipEncoding); 402 if (init_result != Z_OK) { 403 LOG(ERROR) << "Could not initialize libz stream " << init_result; 404 return; 405 } 406 } 407 408 std::string buf; 409 buf.reserve(2 * encoded.size()); 410 stream.avail_in = encoded.size(); 411 stream.next_in = reinterpret_cast<Bytef*>(const_cast<char*>(encoded.data())); 412 413 int result; 414 do { 415 uint8_t chunk[1024]; 416 stream.next_out = static_cast<Bytef*>(chunk); 417 stream.avail_out = arraysize(chunk); 418 419 result = inflate(&stream, 0); 420 const size_t amount = arraysize(chunk) - stream.avail_out; 421 if (amount > 0) { 422 if (buf.capacity() - buf.size() < amount) { 423 buf.reserve(buf.capacity() + 64u * 1024u); 424 CHECK_LE(amount, buf.capacity() - buf.size()); 425 } 426 size_t index = buf.size(); 427 buf.resize(buf.size() + amount); 428 memcpy(reinterpret_cast<uint8_t*>(const_cast<char*>(buf.data())) + index, chunk, amount); 429 } 430 } while (result == Z_OK); 431 inflateEnd(&stream); 432 if (result != Z_STREAM_END) { 433 LOG(ERROR) << "Finished with not-Z_STREAM_END " << result; 434 return; 435 } 436 encoded = buf; 437 } 438 439 // decode 440 encodedProfile.ParseFromString(encoded); 441 } 442 443 #define RAW_RESULT(x) #x 444 445 TEST_F(PerfProfdTest, TestUtil) 446 { 447 EXPECT_EQ("", replaceAll("", "", "")); 448 EXPECT_EQ("zzbc", replaceAll("abc", "a", "zz")); 449 EXPECT_EQ("azzc", replaceAll("abc", "b", "zz")); 450 EXPECT_EQ("abzz", replaceAll("abc", "c", "zz")); 451 EXPECT_EQ("xxyyzz", replaceAll("abc", "abc", "xxyyzz")); 452 } 453 454 TEST_F(PerfProfdTest, MissingGMS) 455 { 456 // 457 // AWP requires cooperation between the daemon and the GMS core 458 // piece. If we're running on a device that has an old or damaged 459 // version of GMS core, then the config directory we're interested in 460 // may not be there. This test insures that the daemon does the 461 // right thing in this case. 462 // 463 PerfProfdRunner runner(conf_dir); 464 runner.addToConfig("only_debug_build=0"); 465 runner.addToConfig("trace_config_read=0"); 466 runner.addToConfig("config_directory=/does/not/exist"); 467 runner.addToConfig("main_loop_iterations=1"); 468 runner.addToConfig("use_fixed_seed=1"); 469 runner.addToConfig("collection_interval=100"); 470 471 // Kick off daemon 472 int daemon_main_return_code = runner.invoke(); 473 474 // Check return code from daemon 475 EXPECT_EQ(0, daemon_main_return_code); 476 477 // Verify log contents 478 const std::string expected = RAW_RESULT( 479 I: sleep 90 seconds 480 W: unable to open config directory /does/not/exist: No such file or directory 481 I: profile collection skipped (missing config directory) 482 ); 483 484 // check to make sure entire log matches 485 CompareLogMessages(expected, "MissingGMS"); 486 } 487 488 489 TEST_F(PerfProfdTest, MissingOptInSemaphoreFile) 490 { 491 // 492 // Android device owners must opt in to "collect and report usage 493 // data" in order for us to be able to collect profiles. The opt-in 494 // check is performed in the GMS core component; if the check 495 // passes, then it creates a semaphore file for the daemon to pick 496 // up on. 497 // 498 PerfProfdRunner runner(conf_dir); 499 runner.addToConfig("only_debug_build=0"); 500 std::string cfparam("config_directory="); cfparam += conf_dir; 501 runner.addToConfig(cfparam); 502 std::string ddparam("destination_directory="); ddparam += dest_dir; 503 runner.addToConfig(ddparam); 504 runner.addToConfig("main_loop_iterations=1"); 505 runner.addToConfig("use_fixed_seed=1"); 506 runner.addToConfig("collection_interval=100"); 507 508 runner.remove_semaphore_file(); 509 510 // Kick off daemon 511 int daemon_main_return_code = runner.invoke(); 512 513 // Check return code from daemon 514 EXPECT_EQ(0, daemon_main_return_code); 515 516 // Verify log contents 517 const std::string expected = RAW_RESULT( 518 I: profile collection skipped (missing config directory) 519 ); 520 // check to make sure log excerpt matches 521 CompareLogMessages(expected, "MissingOptInSemaphoreFile"); 522 } 523 524 TEST_F(PerfProfdTest, MissingPerfExecutable) 525 { 526 // 527 // Perfprofd uses the 'simpleperf' tool to collect profiles 528 // (although this may conceivably change in the future). This test 529 // checks to make sure that if 'simpleperf' is not present we bail out 530 // from collecting profiles. 531 // 532 PerfProfdRunner runner(conf_dir); 533 runner.addToConfig("only_debug_build=0"); 534 runner.addToConfig("trace_config_read=1"); 535 std::string cfparam("config_directory="); cfparam += conf_dir; 536 runner.addToConfig(cfparam); 537 std::string ddparam("destination_directory="); ddparam += dest_dir; 538 runner.addToConfig(ddparam); 539 runner.addToConfig("main_loop_iterations=1"); 540 runner.addToConfig("use_fixed_seed=1"); 541 runner.addToConfig("collection_interval=100"); 542 runner.addToConfig("perf_path=/does/not/exist"); 543 544 // Create semaphore file 545 runner.create_semaphore_file(); 546 547 // Kick off daemon 548 int daemon_main_return_code = runner.invoke(); 549 550 // Check return code from daemon 551 EXPECT_EQ(0, daemon_main_return_code); 552 553 // expected log contents 554 const std::string expected = RAW_RESULT( 555 I: profile collection skipped (missing 'perf' executable) 556 ); 557 // check to make sure log excerpt matches 558 CompareLogMessages(expected, "MissingPerfExecutable"); 559 } 560 561 TEST_F(PerfProfdTest, BadPerfRun) 562 { 563 // 564 // Perf tools tend to be tightly coupled with a specific kernel 565 // version -- if things are out of sync perf could fail or 566 // crash. This test makes sure that we detect such a case and log 567 // the error. 568 // 569 PerfProfdRunner runner(conf_dir); 570 runner.addToConfig("only_debug_build=0"); 571 std::string cfparam("config_directory="); cfparam += conf_dir; 572 runner.addToConfig(cfparam); 573 std::string ddparam("destination_directory="); ddparam += dest_dir; 574 runner.addToConfig(ddparam); 575 runner.addToConfig("main_loop_iterations=1"); 576 runner.addToConfig("use_fixed_seed=1"); 577 runner.addToConfig("collection_interval=100"); 578 #ifdef __ANDROID__ 579 runner.addToConfig("perf_path=/system/bin/false"); 580 #else 581 runner.addToConfig("perf_path=/bin/false"); 582 #endif 583 584 // Create semaphore file 585 runner.create_semaphore_file(); 586 587 // Kick off daemon 588 int daemon_main_return_code = runner.invoke(); 589 590 // Check return code from daemon 591 EXPECT_EQ(0, daemon_main_return_code); 592 593 // Verify log contents 594 const std::string expected = RAW_RESULT( 595 W: perf bad exit status 1 596 W: profile collection failed 597 ); 598 599 // check to make sure log excerpt matches 600 CompareLogMessages(expected, "BadPerfRun"); 601 } 602 603 TEST_F(PerfProfdTest, ConfigFileParsing) 604 { 605 // 606 // Gracefully handly malformed items in the config file 607 // 608 PerfProfdRunner runner(conf_dir); 609 runner.addToConfig("only_debug_build=0"); 610 runner.addToConfig("main_loop_iterations=1"); 611 runner.addToConfig("collection_interval=100"); 612 runner.addToConfig("use_fixed_seed=1"); 613 runner.addToConfig("destination_directory=/does/not/exist"); 614 615 // assorted bad syntax 616 runner.addToConfig("collection_interval=-1"); 617 runner.addToConfig("nonexistent_key=something"); 618 runner.addToConfig("no_equals_stmt"); 619 620 // Kick off daemon 621 int daemon_main_return_code = runner.invoke(); 622 623 // Check return code from daemon 624 EXPECT_EQ(0, daemon_main_return_code); 625 626 // Verify log contents 627 const std::string expected = RAW_RESULT( 628 W: line 6: malformed unsigned value (ignored) 629 W: line 7: unknown option 'nonexistent_key' ignored 630 W: line 8: line malformed (no '=' found) 631 ); 632 633 // check to make sure log excerpt matches 634 CompareLogMessages(expected, "ConfigFileParsing"); 635 } 636 637 TEST_F(PerfProfdTest, ProfileCollectionAnnotations) 638 { 639 unsigned util1 = collect_cpu_utilization(); 640 EXPECT_LE(util1, 100); 641 EXPECT_GE(util1, 0); 642 643 // NB: expectation is that when we run this test, the device will be 644 // completed booted, will be on charger, and will not have the camera 645 // active. 646 EXPECT_FALSE(get_booting()); 647 #ifdef __ANDROID__ 648 EXPECT_TRUE(get_charging()); 649 #endif 650 EXPECT_FALSE(get_camera_active()); 651 } 652 653 namespace { 654 655 template <typename Iterator> 656 size_t CountEvents(const quipper::PerfDataProto& proto) { 657 size_t count = 0; 658 for (Iterator it(proto); it != it.end(); ++it) { 659 count++; 660 } 661 return count; 662 } 663 664 size_t CountCommEvents(const quipper::PerfDataProto& proto) { 665 return CountEvents<CommEventIterator>(proto); 666 } 667 size_t CountMmapEvents(const quipper::PerfDataProto& proto) { 668 return CountEvents<MmapEventIterator>(proto); 669 } 670 size_t CountSampleEvents(const quipper::PerfDataProto& proto) { 671 return CountEvents<SampleEventIterator>(proto); 672 } 673 size_t CountForkEvents(const quipper::PerfDataProto& proto) { 674 return CountEvents<ForkEventIterator>(proto); 675 } 676 size_t CountExitEvents(const quipper::PerfDataProto& proto) { 677 return CountEvents<ExitEventIterator>(proto); 678 } 679 680 std::string CreateStats(const quipper::PerfDataProto& proto) { 681 std::ostringstream oss; 682 oss << "Mmap events: " << CountMmapEvents(proto) << std::endl; 683 oss << "Sample events: " << CountSampleEvents(proto) << std::endl; 684 oss << "Comm events: " << CountCommEvents(proto) << std::endl; 685 oss << "Fork events: " << CountForkEvents(proto) << std::endl; 686 oss << "Exit events: " << CountExitEvents(proto) << std::endl; 687 return oss.str(); 688 } 689 690 std::string FormatSampleEvent(const quipper::PerfDataProto_SampleEvent& sample) { 691 std::ostringstream oss; 692 if (sample.has_pid()) { 693 oss << "pid=" << sample.pid(); 694 } 695 if (sample.has_tid()) { 696 oss << " tid=" << sample.tid(); 697 } 698 if (sample.has_ip()) { 699 oss << " ip=" << sample.ip(); 700 } 701 if (sample.has_addr()) { 702 oss << " addr=" << sample.addr(); 703 } 704 if (sample.callchain_size() > 0) { 705 oss << " callchain="; 706 for (uint64_t cc : sample.callchain()) { 707 oss << "->" << cc; 708 } 709 } 710 return oss.str(); 711 } 712 713 } 714 715 struct BasicRunWithCannedPerf : PerfProfdTest { 716 void VerifyBasicCannedProfile(const android::perfprofd::PerfprofdRecord& encodedProfile) { 717 ASSERT_TRUE(encodedProfile.has_perf_data()) << test_logger.JoinTestLog(" "); 718 const quipper::PerfDataProto& perf_data = encodedProfile.perf_data(); 719 720 // Expect 21108 events. 721 EXPECT_EQ(21108, perf_data.events_size()) << CreateStats(perf_data); 722 723 EXPECT_EQ(48, CountMmapEvents(perf_data)) << CreateStats(perf_data); 724 EXPECT_EQ(19986, CountSampleEvents(perf_data)) << CreateStats(perf_data); 725 EXPECT_EQ(1033, CountCommEvents(perf_data)) << CreateStats(perf_data); 726 EXPECT_EQ(15, CountForkEvents(perf_data)) << CreateStats(perf_data); 727 EXPECT_EQ(26, CountExitEvents(perf_data)) << CreateStats(perf_data); 728 729 if (HasNonfatalFailure()) { 730 FAIL(); 731 } 732 733 { 734 MmapEventIterator mmap(perf_data); 735 constexpr std::pair<const char*, uint64_t> kMmapEvents[] = { 736 std::make_pair("[kernel.kallsyms]_text", 0), 737 std::make_pair("/system/lib/libc.so", 3067412480u), 738 std::make_pair("/system/vendor/lib/libdsutils.so", 3069911040u), 739 std::make_pair("/system/lib/libc.so", 3067191296u), 740 std::make_pair("/system/lib/libc++.so", 3069210624u), 741 std::make_pair("/data/dalvik-cache/arm/system@framework (at) boot.oat", 1900048384u), 742 std::make_pair("/system/lib/libjavacore.so", 2957135872u), 743 std::make_pair("/system/vendor/lib/libqmi_encdec.so", 3006644224u), 744 std::make_pair("/data/dalvik-cache/arm/system@framework (at) wifi-service.jar@classes.dex", 745 3010351104u), 746 std::make_pair("/system/lib/libart.so", 3024150528u), 747 std::make_pair("/system/lib/libz.so", 3056410624u), 748 std::make_pair("/system/lib/libicui18n.so", 3057610752u), 749 }; 750 for (auto& pair : kMmapEvents) { 751 EXPECT_STREQ(pair.first, mmap->mmap_event().filename().c_str()); 752 EXPECT_EQ(pair.second, mmap->mmap_event().start()) << pair.first; 753 ++mmap; 754 } 755 } 756 757 { 758 CommEventIterator comm(perf_data); 759 constexpr const char* kCommEvents[] = { 760 "init", "kthreadd", "ksoftirqd/0", "kworker/u:0H", "migration/0", "khelper", 761 "netns", "modem_notifier", "smd_channel_clo", "smsm_cb_wq", "rpm-smd", "kworker/u:1H", 762 }; 763 for (auto str : kCommEvents) { 764 EXPECT_STREQ(str, comm->comm_event().comm().c_str()); 765 ++comm; 766 } 767 } 768 769 { 770 SampleEventIterator samples(perf_data); 771 constexpr const char* kSampleEvents[] = { 772 "pid=0 tid=0 ip=3222720196", 773 "pid=0 tid=0 ip=3222910876", 774 "pid=0 tid=0 ip=3222910876", 775 "pid=0 tid=0 ip=3222910876", 776 "pid=0 tid=0 ip=3222910876", 777 "pid=0 tid=0 ip=3222910876", 778 "pid=0 tid=0 ip=3222910876", 779 "pid=3 tid=3 ip=3231975108", 780 "pid=5926 tid=5926 ip=3231964952", 781 "pid=5926 tid=5926 ip=3225342428", 782 "pid=5926 tid=5926 ip=3223841448", 783 "pid=5926 tid=5926 ip=3069807920", 784 }; 785 for (auto str : kSampleEvents) { 786 EXPECT_STREQ(str, FormatSampleEvent(samples->sample_event()).c_str()); 787 ++samples; 788 } 789 790 // Skip some samples. 791 for (size_t i = 0; i != 5000; ++i) { 792 ++samples; 793 } 794 constexpr const char* kSampleEvents2[] = { 795 "pid=5938 tid=5938 ip=3069630992", 796 "pid=5938 tid=5938 ip=3069626616", 797 "pid=5938 tid=5938 ip=3069626636", 798 "pid=5938 tid=5938 ip=3069637212", 799 "pid=5938 tid=5938 ip=3069637208", 800 "pid=5938 tid=5938 ip=3069637252", 801 "pid=5938 tid=5938 ip=3069346040", 802 "pid=5938 tid=5938 ip=3069637128", 803 "pid=5938 tid=5938 ip=3069626616", 804 }; 805 for (auto str : kSampleEvents2) { 806 EXPECT_STREQ(str, FormatSampleEvent(samples->sample_event()).c_str()); 807 ++samples; 808 } 809 810 // Skip some samples. 811 for (size_t i = 0; i != 5000; ++i) { 812 ++samples; 813 } 814 constexpr const char* kSampleEvents3[] = { 815 "pid=5938 tid=5938 ip=3069912036", 816 "pid=5938 tid=5938 ip=3069637260", 817 "pid=5938 tid=5938 ip=3069631024", 818 "pid=5938 tid=5938 ip=3069346064", 819 "pid=5938 tid=5938 ip=3069637356", 820 "pid=5938 tid=5938 ip=3069637144", 821 "pid=5938 tid=5938 ip=3069912036", 822 "pid=5938 tid=5938 ip=3069912036", 823 "pid=5938 tid=5938 ip=3069631244", 824 }; 825 for (auto str : kSampleEvents3) { 826 EXPECT_STREQ(str, FormatSampleEvent(samples->sample_event()).c_str()); 827 ++samples; 828 } 829 } 830 } 831 }; 832 833 TEST_F(BasicRunWithCannedPerf, Basic) 834 { 835 // 836 // Verify the portion of the daemon that reads and encodes 837 // perf.data files. Here we run the encoder on a canned perf.data 838 // file and verify that the resulting protobuf contains what 839 // we think it should contain. 840 // 841 std::string input_perf_data(test_dir); 842 input_perf_data += "/canned.perf.data"; 843 844 // Set up config to avoid these annotations (they are tested elsewhere) 845 ConfigReader config_reader; 846 config_reader.overrideUnsignedEntry("collect_cpu_utilization", 0); 847 config_reader.overrideUnsignedEntry("collect_charging_state", 0); 848 config_reader.overrideUnsignedEntry("collect_camera_active", 0); 849 850 // Disable compression. 851 config_reader.overrideUnsignedEntry("compress", 0); 852 853 PerfProfdRunner::LoggingConfig config; 854 config_reader.FillConfig(&config); 855 856 // Kick off encoder and check return code 857 PROFILE_RESULT result = 858 encode_to_proto(input_perf_data, encoded_file_path(dest_dir, 0).c_str(), config, 0, nullptr); 859 ASSERT_EQ(OK_PROFILE_COLLECTION, result) << test_logger.JoinTestLog(" "); 860 861 // Read and decode the resulting perf.data.encoded file 862 android::perfprofd::PerfprofdRecord encodedProfile; 863 readEncodedProfile(dest_dir, false, encodedProfile); 864 865 VerifyBasicCannedProfile(encodedProfile); 866 } 867 868 TEST_F(BasicRunWithCannedPerf, Compressed) 869 { 870 // 871 // Verify the portion of the daemon that reads and encodes 872 // perf.data files. Here we run the encoder on a canned perf.data 873 // file and verify that the resulting protobuf contains what 874 // we think it should contain. 875 // 876 std::string input_perf_data(test_dir); 877 input_perf_data += "/canned.perf.data"; 878 879 // Set up config to avoid these annotations (they are tested elsewhere) 880 ConfigReader config_reader; 881 config_reader.overrideUnsignedEntry("collect_cpu_utilization", 0); 882 config_reader.overrideUnsignedEntry("collect_charging_state", 0); 883 config_reader.overrideUnsignedEntry("collect_camera_active", 0); 884 885 // Enable compression. 886 config_reader.overrideUnsignedEntry("compress", 1); 887 888 PerfProfdRunner::LoggingConfig config; 889 config_reader.FillConfig(&config); 890 891 // Kick off encoder and check return code 892 PROFILE_RESULT result = 893 encode_to_proto(input_perf_data, encoded_file_path(dest_dir, 0).c_str(), config, 0, nullptr); 894 ASSERT_EQ(OK_PROFILE_COLLECTION, result) << test_logger.JoinTestLog(" "); 895 896 // Read and decode the resulting perf.data.encoded file 897 android::perfprofd::PerfprofdRecord encodedProfile; 898 readEncodedProfile(dest_dir, true, encodedProfile); 899 900 VerifyBasicCannedProfile(encodedProfile); 901 } 902 903 TEST_F(BasicRunWithCannedPerf, WithSymbolizer) 904 { 905 // 906 // Verify the portion of the daemon that reads and encodes 907 // perf.data files. Here we run the encoder on a canned perf.data 908 // file and verify that the resulting protobuf contains what 909 // we think it should contain. 910 // 911 std::string input_perf_data(test_dir); 912 input_perf_data += "/canned.perf.data"; 913 914 // Set up config to avoid these annotations (they are tested elsewhere) 915 ConfigReader config_reader; 916 config_reader.overrideUnsignedEntry("collect_cpu_utilization", 0); 917 config_reader.overrideUnsignedEntry("collect_charging_state", 0); 918 config_reader.overrideUnsignedEntry("collect_camera_active", 0); 919 920 // Disable compression. 921 config_reader.overrideUnsignedEntry("compress", 0); 922 923 PerfProfdRunner::LoggingConfig config; 924 config_reader.FillConfig(&config); 925 926 // Kick off encoder and check return code 927 struct TestSymbolizer : public perfprofd::Symbolizer { 928 std::string Decode(const std::string& dso, uint64_t address) override { 929 return dso + "@" + std::to_string(address); 930 } 931 bool GetMinExecutableVAddr(const std::string& dso, uint64_t* addr) override { 932 *addr = 4096; 933 return true; 934 } 935 }; 936 TestSymbolizer test_symbolizer; 937 PROFILE_RESULT result = 938 encode_to_proto(input_perf_data, 939 encoded_file_path(dest_dir, 0).c_str(), 940 config, 941 0, 942 &test_symbolizer); 943 ASSERT_EQ(OK_PROFILE_COLLECTION, result); 944 945 // Read and decode the resulting perf.data.encoded file 946 android::perfprofd::PerfprofdRecord encodedProfile; 947 readEncodedProfile(dest_dir, false, encodedProfile); 948 949 VerifyBasicCannedProfile(encodedProfile); 950 951 auto find_symbol = [&](const std::string& filename) 952 -> const android::perfprofd::PerfprofdRecord_SymbolInfo* { 953 for (auto& symbol_info : encodedProfile.symbol_info()) { 954 if (symbol_info.filename() == filename) { 955 return &symbol_info; 956 } 957 } 958 return nullptr; 959 }; 960 auto all_filenames = [&]() { 961 std::ostringstream oss; 962 for (auto& symbol_info : encodedProfile.symbol_info()) { 963 oss << " " << symbol_info.filename(); 964 } 965 return oss.str(); 966 }; 967 968 EXPECT_TRUE(find_symbol("/data/app/com.google.android.apps.plus-1/lib/arm/libcronet.so") 969 != nullptr) << all_filenames() << test_logger.JoinTestLog("\n"); 970 EXPECT_TRUE(find_symbol("/data/dalvik-cache/arm/system@framework (at) wifi-service.jar@classes.dex") 971 != nullptr) << all_filenames(); 972 EXPECT_TRUE(find_symbol("/data/dalvik-cache/arm/data@app (at) com.google.android.gms-2@base.apk@" 973 "classes.dex") 974 != nullptr) << all_filenames(); 975 EXPECT_TRUE(find_symbol("/data/dalvik-cache/arm/system@framework (at) boot.oat") != nullptr) 976 << all_filenames(); 977 } 978 979 TEST_F(PerfProfdTest, CallchainRunWithCannedPerf) 980 { 981 // This test makes sure that the perf.data converter 982 // can handle call chains. 983 // 984 std::string input_perf_data(test_dir); 985 input_perf_data += "/callchain.canned.perf.data"; 986 987 // Set up config to avoid these annotations (they are tested elsewhere) 988 ConfigReader config_reader; 989 config_reader.overrideUnsignedEntry("collect_cpu_utilization", 0); 990 config_reader.overrideUnsignedEntry("collect_charging_state", 0); 991 config_reader.overrideUnsignedEntry("collect_camera_active", 0); 992 993 // Disable compression. 994 config_reader.overrideUnsignedEntry("compress", 0); 995 996 PerfProfdRunner::LoggingConfig config; 997 config_reader.FillConfig(&config); 998 999 // Kick off encoder and check return code 1000 PROFILE_RESULT result = 1001 encode_to_proto(input_perf_data, encoded_file_path(dest_dir, 0).c_str(), config, 0, nullptr); 1002 ASSERT_EQ(OK_PROFILE_COLLECTION, result); 1003 1004 // Read and decode the resulting perf.data.encoded file 1005 android::perfprofd::PerfprofdRecord encodedProfile; 1006 readEncodedProfile(dest_dir, false, encodedProfile); 1007 1008 1009 ASSERT_TRUE(encodedProfile.has_perf_data()); 1010 const quipper::PerfDataProto& perf_data = encodedProfile.perf_data(); 1011 1012 // Expect 21108 events. 1013 EXPECT_EQ(2224, perf_data.events_size()) << CreateStats(perf_data); 1014 1015 { 1016 SampleEventIterator samples(perf_data); 1017 constexpr const char* kSampleEvents[] = { 1018 "0: pid=6225 tid=6225 ip=18446743798834668032 callchain=->18446744073709551488->" 1019 "18446743798834668032->18446743798834782596->18446743798834784624->" 1020 "18446743798835055136->18446743798834788016->18446743798834789192->" 1021 "18446743798834789512->18446743798834790216->18446743798833756776", 1022 "1: pid=6225 tid=6225 ip=18446743798835685700 callchain=->18446744073709551488->" 1023 "18446743798835685700->18446743798835688704->18446743798835650964->" 1024 "18446743798834612104->18446743798834612276->18446743798835055528->" 1025 "18446743798834788016->18446743798834789192->18446743798834789512->" 1026 "18446743798834790216->18446743798833756776", 1027 "2: pid=6225 tid=6225 ip=18446743798835055804 callchain=->18446744073709551488->" 1028 "18446743798835055804->18446743798834788016->18446743798834789192->" 1029 "18446743798834789512->18446743798834790216->18446743798833756776", 1030 "3: pid=6225 tid=6225 ip=18446743798835991212 callchain=->18446744073709551488->" 1031 "18446743798835991212->18446743798834491060->18446743798834675572->" 1032 "18446743798834676516->18446743798834612172->18446743798834612276->" 1033 "18446743798835056664->18446743798834788016->18446743798834789192->" 1034 "18446743798834789512->18446743798834790216->18446743798833756776", 1035 "4: pid=6225 tid=6225 ip=18446743798844881108 callchain=->18446744073709551488->" 1036 "18446743798844881108->18446743798834836140->18446743798834846384->" 1037 "18446743798834491100->18446743798834675572->18446743798834676516->" 1038 "18446743798834612172->18446743798834612276->18446743798835056784->" 1039 "18446743798834788016->18446743798834789192->18446743798834789512->" 1040 "18446743798834790216->18446743798833756776", 1041 }; 1042 size_t cmp_index = 0; 1043 for (size_t index = 0; samples != samples.end(); ++samples, ++index) { 1044 if (samples->sample_event().callchain_size() > 0) { 1045 std::ostringstream oss; 1046 oss << index << ": " << FormatSampleEvent(samples->sample_event()); 1047 EXPECT_STREQ(kSampleEvents[cmp_index], oss.str().c_str()); 1048 cmp_index++; 1049 if (cmp_index == arraysize(kSampleEvents)) { 1050 break; 1051 } 1052 } 1053 } 1054 } 1055 } 1056 1057 #ifdef __ANDROID__ 1058 1059 TEST_F(PerfProfdTest, BasicRunWithLivePerf) 1060 { 1061 // 1062 // Basic test to exercise the main loop of the daemon. It includes 1063 // a live 'perf' run 1064 // 1065 PerfProfdRunner runner(conf_dir); 1066 runner.addToConfig("only_debug_build=0"); 1067 std::string ddparam("destination_directory="); ddparam += dest_dir; 1068 runner.addToConfig(ddparam); 1069 std::string cfparam("config_directory="); cfparam += conf_dir; 1070 runner.addToConfig(cfparam); 1071 runner.addToConfig("main_loop_iterations=1"); 1072 runner.addToConfig("use_fixed_seed=12345678"); 1073 runner.addToConfig("max_unprocessed_profiles=100"); 1074 runner.addToConfig("collection_interval=9999"); 1075 runner.addToConfig("sample_duration=2"); 1076 // Avoid the symbolizer for spurious messages. 1077 runner.addToConfig("use_elf_symbolizer=0"); 1078 1079 // Disable compression. 1080 runner.addToConfig("compress=0"); 1081 1082 // Create semaphore file 1083 runner.create_semaphore_file(); 1084 1085 // Kick off daemon 1086 int daemon_main_return_code = runner.invoke(); 1087 1088 // Check return code from daemon 1089 ASSERT_EQ(0, daemon_main_return_code); 1090 1091 // Read and decode the resulting perf.data.encoded file 1092 android::perfprofd::PerfprofdRecord encodedProfile; 1093 readEncodedProfile(dest_dir, false, encodedProfile); 1094 1095 // Examine what we get back. Since it's a live profile, we can't 1096 // really do much in terms of verifying the contents. 1097 EXPECT_LT(0, encodedProfile.perf_data().events_size()); 1098 1099 // Verify log contents 1100 const std::string expected = std::string( 1101 "I: starting Android Wide Profiling daemon ") + 1102 "I: config file path set to " + conf_dir + "/perfprofd.conf " + 1103 RAW_RESULT( 1104 I: random seed set to 12345678 1105 I: sleep 674 seconds 1106 I: initiating profile collection 1107 I: sleep 2 seconds 1108 I: profile collection complete 1109 I: sleep 9325 seconds 1110 I: finishing Android Wide Profiling daemon 1111 ); 1112 // check to make sure log excerpt matches 1113 CompareLogMessages(expandVars(expected), "BasicRunWithLivePerf", true); 1114 } 1115 1116 TEST_F(PerfProfdTest, MultipleRunWithLivePerf) 1117 { 1118 // 1119 // Basic test to exercise the main loop of the daemon. It includes 1120 // a live 'perf' run 1121 // 1122 PerfProfdRunner runner(conf_dir); 1123 runner.addToConfig("only_debug_build=0"); 1124 std::string ddparam("destination_directory="); ddparam += dest_dir; 1125 runner.addToConfig(ddparam); 1126 std::string cfparam("config_directory="); cfparam += conf_dir; 1127 runner.addToConfig(cfparam); 1128 runner.addToConfig("main_loop_iterations=3"); 1129 runner.addToConfig("use_fixed_seed=12345678"); 1130 runner.addToConfig("collection_interval=9999"); 1131 runner.addToConfig("sample_duration=2"); 1132 // Avoid the symbolizer for spurious messages. 1133 runner.addToConfig("use_elf_symbolizer=0"); 1134 1135 // Disable compression. 1136 runner.addToConfig("compress=0"); 1137 1138 runner.write_processed_file(1, 2); 1139 1140 // Create semaphore file 1141 runner.create_semaphore_file(); 1142 1143 // Kick off daemon 1144 int daemon_main_return_code = runner.invoke(); 1145 1146 // Check return code from daemon 1147 ASSERT_EQ(0, daemon_main_return_code); 1148 1149 // Read and decode the resulting perf.data.encoded file 1150 android::perfprofd::PerfprofdRecord encodedProfile; 1151 readEncodedProfile(dest_dir, false, encodedProfile); 1152 1153 // Examine what we get back. Since it's a live profile, we can't 1154 // really do much in terms of verifying the contents. 1155 EXPECT_LT(0, encodedProfile.perf_data().events_size()); 1156 1157 // Examine that encoded.1 file is removed while encoded.{0|2} exists. 1158 EXPECT_EQ(0, access(encoded_file_path(dest_dir, 0).c_str(), F_OK)); 1159 EXPECT_NE(0, access(encoded_file_path(dest_dir, 1).c_str(), F_OK)); 1160 EXPECT_EQ(0, access(encoded_file_path(dest_dir, 2).c_str(), F_OK)); 1161 1162 // Verify log contents 1163 const std::string expected = std::string( 1164 "I: starting Android Wide Profiling daemon ") + 1165 "I: config file path set to " + conf_dir + "/perfprofd.conf " + 1166 RAW_RESULT( 1167 I: random seed set to 12345678 1168 I: sleep 674 seconds 1169 I: initiating profile collection 1170 I: sleep 2 seconds 1171 I: profile collection complete 1172 I: sleep 9325 seconds 1173 I: sleep 4974 seconds 1174 I: initiating profile collection 1175 I: sleep 2 seconds 1176 I: profile collection complete 1177 I: sleep 5025 seconds 1178 I: sleep 501 seconds 1179 I: initiating profile collection 1180 I: sleep 2 seconds 1181 I: profile collection complete 1182 I: sleep 9498 seconds 1183 I: finishing Android Wide Profiling daemon 1184 ); 1185 // check to make sure log excerpt matches 1186 CompareLogMessages(expandVars(expected), "BasicRunWithLivePerf", true); 1187 } 1188 1189 TEST_F(PerfProfdTest, CallChainRunWithLivePerf) 1190 { 1191 // 1192 // Collect a callchain profile, so as to exercise the code in 1193 // perf_data post-processing that digests callchains. 1194 // 1195 PerfProfdRunner runner(conf_dir); 1196 std::string ddparam("destination_directory="); ddparam += dest_dir; 1197 runner.addToConfig(ddparam); 1198 std::string cfparam("config_directory="); cfparam += conf_dir; 1199 runner.addToConfig(cfparam); 1200 runner.addToConfig("main_loop_iterations=1"); 1201 runner.addToConfig("use_fixed_seed=12345678"); 1202 runner.addToConfig("max_unprocessed_profiles=100"); 1203 runner.addToConfig("collection_interval=9999"); 1204 runner.addToConfig("stack_profile=1"); 1205 runner.addToConfig("sample_duration=2"); 1206 // Avoid the symbolizer for spurious messages. 1207 runner.addToConfig("use_elf_symbolizer=0"); 1208 1209 // Disable compression. 1210 runner.addToConfig("compress=0"); 1211 1212 // Create semaphore file 1213 runner.create_semaphore_file(); 1214 1215 // Kick off daemon 1216 int daemon_main_return_code = runner.invoke(); 1217 1218 // Check return code from daemon 1219 ASSERT_EQ(0, daemon_main_return_code); 1220 1221 // Read and decode the resulting perf.data.encoded file 1222 android::perfprofd::PerfprofdRecord encodedProfile; 1223 readEncodedProfile(dest_dir, false, encodedProfile); 1224 1225 // Examine what we get back. Since it's a live profile, we can't 1226 // really do much in terms of verifying the contents. 1227 EXPECT_LT(0, encodedProfile.perf_data().events_size()); 1228 1229 // Verify log contents 1230 const std::string expected = std::string( 1231 "I: starting Android Wide Profiling daemon ") + 1232 "I: config file path set to " + conf_dir + "/perfprofd.conf " + 1233 RAW_RESULT( 1234 I: random seed set to 12345678 1235 I: sleep 674 seconds 1236 I: initiating profile collection 1237 I: sleep 2 seconds 1238 I: profile collection complete 1239 I: sleep 9325 seconds 1240 I: finishing Android Wide Profiling daemon 1241 ); 1242 // check to make sure log excerpt matches 1243 CompareLogMessages(expandVars(expected), "CallChainRunWithLivePerf", true); 1244 1245 // Check that we have at least one SampleEvent with a callchain. 1246 SampleEventIterator samples(encodedProfile.perf_data()); 1247 bool found_callchain = false; 1248 while (!found_callchain && samples != samples.end()) { 1249 found_callchain = samples->sample_event().callchain_size() > 0; 1250 } 1251 EXPECT_TRUE(found_callchain) << CreateStats(encodedProfile.perf_data()); 1252 } 1253 1254 #endif 1255 1256 class RangeMapTest : public testing::Test { 1257 }; 1258 1259 TEST_F(RangeMapTest, TestRangeMap) { 1260 using namespace android::perfprofd; 1261 1262 RangeMap<std::string, uint64_t> map; 1263 auto print = [&]() { 1264 std::ostringstream oss; 1265 for (auto& aggr_sym : map) { 1266 oss << aggr_sym.first << "#" << aggr_sym.second.symbol; 1267 oss << "["; 1268 for (auto& x : aggr_sym.second.offsets) { 1269 oss << x << ","; 1270 } 1271 oss << "]"; 1272 } 1273 return oss.str(); 1274 }; 1275 1276 EXPECT_STREQ("", print().c_str()); 1277 1278 map.Insert("a", 10); 1279 EXPECT_STREQ("10#a[10,]", print().c_str()); 1280 map.Insert("a", 100); 1281 EXPECT_STREQ("10#a[10,100,]", print().c_str()); 1282 map.Insert("a", 1); 1283 EXPECT_STREQ("1#a[1,10,100,]", print().c_str()); 1284 map.Insert("a", 1); 1285 EXPECT_STREQ("1#a[1,10,100,]", print().c_str()); 1286 map.Insert("a", 2); 1287 EXPECT_STREQ("1#a[1,2,10,100,]", print().c_str()); 1288 1289 map.Insert("b", 200); 1290 EXPECT_STREQ("1#a[1,2,10,100,]200#b[200,]", print().c_str()); 1291 map.Insert("b", 199); 1292 EXPECT_STREQ("1#a[1,2,10,100,]199#b[199,200,]", print().c_str()); 1293 1294 map.Insert("c", 50); 1295 EXPECT_STREQ("1#a[1,2,10,]50#c[50,]100#a[100,]199#b[199,200,]", print().c_str()); 1296 } 1297 1298 class ThreadedHandlerTest : public PerfProfdTest { 1299 public: 1300 void SetUp() override { 1301 PerfProfdTest::SetUp(); 1302 threaded_handler_.reset(new android::perfprofd::ThreadedHandler()); 1303 } 1304 1305 void TearDown() override { 1306 threaded_handler_.reset(); 1307 PerfProfdTest::TearDown(); 1308 } 1309 1310 protected: 1311 std::unique_ptr<android::perfprofd::ThreadedHandler> threaded_handler_; 1312 }; 1313 1314 TEST_F(ThreadedHandlerTest, Basic) { 1315 std::string error_msg; 1316 EXPECT_FALSE(threaded_handler_->StopProfiling(&error_msg)); 1317 } 1318 1319 #ifdef __ANDROID__ 1320 #define ThreadedHandlerTestName(x) x 1321 #else 1322 #define ThreadedHandlerTestName(x) DISABLED_ ## x 1323 #endif 1324 1325 TEST_F(ThreadedHandlerTest, ThreadedHandlerTestName(Live)) { 1326 auto config_fn = [](android::perfprofd::ThreadedConfig& config) { 1327 // Use some values that make it likely that things don't fail quickly. 1328 config.main_loop_iterations = 0; 1329 config.collection_interval_in_s = 1000000; 1330 }; 1331 std::string error_msg; 1332 ASSERT_TRUE(threaded_handler_->StartProfiling(config_fn, &error_msg)) << error_msg; 1333 EXPECT_TRUE(threaded_handler_->StopProfiling(&error_msg)) << error_msg; 1334 } 1335 1336 int main(int argc, char **argv) { 1337 // Always log to cerr, so that device failures are visible. 1338 android::base::SetLogger(android::base::StderrLogger); 1339 1340 CHECK(android::base::Realpath(argv[0], &gExecutableRealpath)); 1341 1342 // switch to / before starting testing (perfprofd 1343 // should be location-independent) 1344 chdir("/"); 1345 testing::InitGoogleTest(&argc, argv); 1346 return RUN_ALL_TESTS(); 1347 } 1348