OSDN Git Service

Merge "Perfprofd: Fix tests"
[android-x86/system-extras.git] / perfprofd / tests / perfprofd_test.cc
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 <memory>
20 #include <regex>
21 #include <string>
22
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <libgen.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28
29 #include <android-base/file.h>
30 #include <android-base/logging.h>
31 #include <android-base/properties.h>
32 #include <android-base/stringprintf.h>
33 #include <android-base/test_utils.h>
34 #include <gtest/gtest.h>
35
36 #include "config.h"
37 #include "configreader.h"
38 #include "perfprofdcore.h"
39 #include "perfprofdutils.h"
40 #include "perfprofdmockutils.h"
41
42 #include "perf_profile.pb.h"
43 #include "google/protobuf/text_format.h"
44
45 //
46 // Set to argv[0] on startup
47 //
48 static std::string gExecutableRealpath;
49
50 // Path to perf executable on device
51 #define PERFPATH "/system/bin/perf"
52
53 // Temporary config file that we will emit for the daemon to read
54 #define CONFIGFILE "perfprofd.conf"
55
56 class PerfProfdTest : public testing::Test {
57  protected:
58   virtual void SetUp() {
59     mock_perfprofdutils_init();
60     create_dirs();
61   }
62
63   virtual void TearDown() {
64     mock_perfprofdutils_finish();
65
66     // TODO: proper management of test files. For now, use old system() code.
67     for (const auto dir : { &dest_dir, &conf_dir }) {
68       std::string cmd("rm -rf ");
69       cmd += *dir;
70       int ret = system(cmd.c_str());
71       CHECK_EQ(0, ret);
72     }
73   }
74
75  protected:
76   // test_dir is the directory containing the test executable and
77   // any files associated with the test (will be created by the harness).
78   std::string test_dir;
79
80   // dest_dir is a temporary directory that we're using as the destination directory.
81   // It is backed by temp_dir1.
82   std::string dest_dir;
83
84   // conf_dir is a temporary directory that we're using as the configuration directory.
85   // It is backed by temp_dir2.
86   std::string conf_dir;
87
88  private:
89   void create_dirs() {
90     temp_dir1.reset(new TemporaryDir());
91     temp_dir2.reset(new TemporaryDir());
92     dest_dir = temp_dir1->path;
93     conf_dir = temp_dir2->path;
94     test_dir = android::base::Dirname(gExecutableRealpath);
95   }
96
97   std::unique_ptr<TemporaryDir> temp_dir1;
98   std::unique_ptr<TemporaryDir> temp_dir2;
99 };
100
101 static bool bothWhiteSpace(char lhs, char rhs)
102 {
103   return (std::isspace(lhs) && std::isspace(rhs));
104 }
105
106 //
107 // Squeeze out repeated whitespace from expected/actual logs.
108 //
109 static std::string squeezeWhite(const std::string &str,
110                                 const char *tag,
111                                 bool dump=false)
112 {
113   if (dump) { fprintf(stderr, "raw %s is %s\n", tag, str.c_str()); }
114   std::string result(str);
115   std::replace(result.begin(), result.end(), '\n', ' ');
116   auto new_end = std::unique(result.begin(), result.end(), bothWhiteSpace);
117   result.erase(new_end, result.end());
118   while (result.begin() != result.end() && std::isspace(*result.rbegin())) {
119     result.pop_back();
120   }
121   if (dump) { fprintf(stderr, "squeezed %s is %s\n", tag, result.c_str()); }
122   return result;
123 }
124
125 //
126 // Replace all occurrences of a string with another string.
127 //
128 static std::string replaceAll(const std::string &str,
129                               const std::string &from,
130                               const std::string &to)
131 {
132   std::string ret = "";
133   size_t pos = 0;
134   while (pos < str.size()) {
135     size_t found = str.find(from, pos);
136     if (found == std::string::npos) {
137       ret += str.substr(pos);
138       break;
139     }
140     ret += str.substr(pos, found - pos) + to;
141     pos = found + from.size();
142   }
143   return ret;
144 }
145
146 //
147 // Replace occurrences of special variables in the string.
148 //
149 static std::string expandVars(const std::string &str) {
150 #ifdef __LP64__
151   return replaceAll(str, "$NATIVE_TESTS", "/data/nativetest64");
152 #else
153   return replaceAll(str, "$NATIVE_TESTS", "/data/nativetest");
154 #endif
155 }
156
157 ///
158 /// Helper class to kick off a run of the perfprofd daemon with a specific
159 /// config file.
160 ///
161 class PerfProfdRunner {
162  public:
163   explicit PerfProfdRunner(const std::string& config_dir)
164       : config_dir_(config_dir)
165   {
166     config_path_ = config_dir + "/" CONFIGFILE;
167   }
168
169   ~PerfProfdRunner()
170   {
171     remove_processed_file();
172   }
173
174   void addToConfig(const std::string &line)
175   {
176     config_text_ += line;
177     config_text_ += "\n";
178   }
179
180   void remove_semaphore_file()
181   {
182     std::string semaphore(config_dir_);
183     semaphore += "/" SEMAPHORE_FILENAME;
184     unlink(semaphore.c_str());
185   }
186
187   void create_semaphore_file()
188   {
189     std::string semaphore(config_dir_);
190     semaphore += "/" SEMAPHORE_FILENAME;
191     close(open(semaphore.c_str(), O_WRONLY|O_CREAT, 0600));
192   }
193
194   void write_processed_file(int start_seq, int end_seq)
195   {
196     std::string processed = config_dir_ + "/" PROCESSED_FILENAME;
197     FILE *fp = fopen(processed.c_str(), "w");
198     for (int i = start_seq; i < end_seq; i++) {
199       fprintf(fp, "%d\n", i);
200     }
201     fclose(fp);
202   }
203
204   void remove_processed_file()
205   {
206     std::string processed = config_dir_ + "/" PROCESSED_FILENAME;
207     unlink(processed.c_str());
208   }
209
210   struct LoggingConfig : public Config {
211     void Sleep(size_t seconds) override {
212       // Log sleep calls but don't sleep.
213       perfprofd_log_info("sleep %d seconds", seconds);
214     }
215
216     bool IsProfilingEnabled() const override {
217       //
218       // Check for existence of semaphore file in config directory
219       //
220       if (access(config_directory.c_str(), F_OK) == -1) {
221         W_ALOGW("unable to open config directory %s: (%s)",
222                 config_directory.c_str(), strerror(errno));
223         return false;
224       }
225
226       // Check for existence of semaphore file
227       std::string semaphore_filepath = config_directory
228           + "/" + SEMAPHORE_FILENAME;
229       if (access(semaphore_filepath.c_str(), F_OK) == -1) {
230         return false;
231       }
232
233       return true;
234     }
235   };
236
237   int invoke()
238   {
239     static const char *argv[3] = { "perfprofd", "-c", "" };
240     argv[2] = config_path_.c_str();
241
242     writeConfigFile(config_path_, config_text_);
243
244     // execute daemon main
245     LoggingConfig config;
246     return perfprofd_main(3, (char **) argv, &config);
247   }
248
249  private:
250   std::string config_dir_;
251   std::string config_path_;
252   std::string config_text_;
253
254   void writeConfigFile(const std::string &config_path,
255                        const std::string &config_text)
256   {
257     FILE *fp = fopen(config_path.c_str(), "w");
258     ASSERT_TRUE(fp != nullptr);
259     fprintf(fp, "%s\n", config_text.c_str());
260     fclose(fp);
261   }
262 };
263
264 //......................................................................
265
266 static std::string encoded_file_path(const std::string& dest_dir,
267                                      int seq) {
268   return android::base::StringPrintf("%s/perf.data.encoded.%d",
269                                      dest_dir.c_str(), seq);
270 }
271
272 static void readEncodedProfile(const std::string& dest_dir,
273                                const char *testpoint,
274                                wireless_android_play_playlog::AndroidPerfProfile &encodedProfile)
275 {
276   struct stat statb;
277   int perf_data_stat_result = stat(encoded_file_path(dest_dir, 0).c_str(), &statb);
278   ASSERT_NE(-1, perf_data_stat_result);
279
280   // read
281   std::string encoded;
282   encoded.resize(statb.st_size);
283   FILE *ifp = fopen(encoded_file_path(dest_dir, 0).c_str(), "r");
284   ASSERT_NE(nullptr, ifp);
285   size_t items_read = fread((void*) encoded.data(), statb.st_size, 1, ifp);
286   ASSERT_EQ(1, items_read);
287   fclose(ifp);
288
289   // decode
290   encodedProfile.ParseFromString(encoded);
291 }
292
293 static std::string encodedLoadModuleToString(const wireless_android_play_playlog::LoadModule &lm)
294 {
295   std::stringstream ss;
296   ss << "name: \"" << lm.name() << "\"\n";
297   if (lm.build_id() != "") {
298     ss << "build_id: \"" << lm.build_id() << "\"\n";
299   }
300   return ss.str();
301 }
302
303 static std::string encodedModuleSamplesToString(const wireless_android_play_playlog::LoadModuleSamples &mod)
304 {
305   std::stringstream ss;
306
307   ss << "load_module_id: " << mod.load_module_id() << "\n";
308   for (size_t k = 0; k < mod.address_samples_size(); k++) {
309     const auto &sample = mod.address_samples(k);
310     ss << "  address_samples {\n";
311     for (size_t l = 0; l < mod.address_samples(k).address_size();
312          l++) {
313       auto address = mod.address_samples(k).address(l);
314       ss << "    address: " << address << "\n";
315     }
316     ss << "    count: " << sample.count() << "\n";
317     ss << "  }\n";
318   }
319   return ss.str();
320 }
321
322 #define RAW_RESULT(x) #x
323
324 //
325 // Check to see if the log messages emitted by the daemon
326 // match the expected result. By default we use a partial
327 // match, e.g. if we see the expected excerpt anywhere in the
328 // result, it's a match (for exact match, set exact to true)
329 //
330 static void compareLogMessages(const std::string &actual,
331                                const std::string &expected,
332                                const char *testpoint,
333                                bool exactMatch=false)
334 {
335    std::string sqexp = squeezeWhite(expected, "expected");
336    std::string sqact = squeezeWhite(actual, "actual");
337    if (exactMatch) {
338      EXPECT_STREQ(sqexp.c_str(), sqact.c_str());
339    } else {
340      std::size_t foundpos = sqact.find(sqexp);
341      bool wasFound = true;
342      if (foundpos == std::string::npos) {
343        std::cerr << testpoint << ": expected result not found\n";
344        std::cerr << " Actual: \"" << sqact << "\"\n";
345        std::cerr << " Expected: \"" << sqexp << "\"\n";
346        wasFound = false;
347      }
348      EXPECT_TRUE(wasFound);
349    }
350 }
351
352 TEST_F(PerfProfdTest, TestUtil)
353 {
354   EXPECT_EQ("", replaceAll("", "", ""));
355   EXPECT_EQ("zzbc", replaceAll("abc", "a", "zz"));
356   EXPECT_EQ("azzc", replaceAll("abc", "b", "zz"));
357   EXPECT_EQ("abzz", replaceAll("abc", "c", "zz"));
358   EXPECT_EQ("xxyyzz", replaceAll("abc", "abc", "xxyyzz"));
359 }
360
361 TEST_F(PerfProfdTest, MissingGMS)
362 {
363   //
364   // AWP requires cooperation between the daemon and the GMS core
365   // piece. If we're running on a device that has an old or damaged
366   // version of GMS core, then the config directory we're interested in
367   // may not be there. This test insures that the daemon does the
368   // right thing in this case.
369   //
370   PerfProfdRunner runner(conf_dir);
371   runner.addToConfig("only_debug_build=0");
372   runner.addToConfig("trace_config_read=0");
373   runner.addToConfig("config_directory=/does/not/exist");
374   runner.addToConfig("main_loop_iterations=1");
375   runner.addToConfig("use_fixed_seed=1");
376   runner.addToConfig("collection_interval=100");
377
378   // Kick off daemon
379   int daemon_main_return_code = runner.invoke();
380
381   // Check return code from daemon
382   EXPECT_EQ(0, daemon_main_return_code);
383
384   // Verify log contents
385   const std::string expected = RAW_RESULT(
386       I: sleep 90 seconds
387       W: unable to open config directory /does/not/exist: (No such file or directory)
388       I: profile collection skipped (missing config directory)
389                                           );
390
391   // check to make sure entire log matches
392   compareLogMessages(mock_perfprofdutils_getlogged(),
393                      expected, "MissingGMS");
394 }
395
396
397 TEST_F(PerfProfdTest, MissingOptInSemaphoreFile)
398 {
399   //
400   // Android device owners must opt in to "collect and report usage
401   // data" in order for us to be able to collect profiles. The opt-in
402   // check is performed in the GMS core component; if the check
403   // passes, then it creates a semaphore file for the daemon to pick
404   // up on.
405   //
406   PerfProfdRunner runner(conf_dir);
407   runner.addToConfig("only_debug_build=0");
408   std::string cfparam("config_directory="); cfparam += conf_dir;
409   runner.addToConfig(cfparam);
410   std::string ddparam("destination_directory="); ddparam += dest_dir;
411   runner.addToConfig(ddparam);
412   runner.addToConfig("main_loop_iterations=1");
413   runner.addToConfig("use_fixed_seed=1");
414   runner.addToConfig("collection_interval=100");
415
416   runner.remove_semaphore_file();
417
418   // Kick off daemon
419   int daemon_main_return_code = runner.invoke();
420
421   // Check return code from daemon
422   EXPECT_EQ(0, daemon_main_return_code);
423
424   // Verify log contents
425   const std::string expected = RAW_RESULT(
426       I: profile collection skipped (missing config directory)
427                                           );
428   // check to make sure log excerpt matches
429   compareLogMessages(mock_perfprofdutils_getlogged(),
430                      expected, "MissingOptInSemaphoreFile");
431 }
432
433 TEST_F(PerfProfdTest, MissingPerfExecutable)
434 {
435   //
436   // Perfprofd uses the 'simpleperf' tool to collect profiles
437   // (although this may conceivably change in the future). This test
438   // checks to make sure that if 'simpleperf' is not present we bail out
439   // from collecting profiles.
440   //
441   PerfProfdRunner runner(conf_dir);
442   runner.addToConfig("only_debug_build=0");
443   runner.addToConfig("trace_config_read=1");
444   std::string cfparam("config_directory="); cfparam += conf_dir;
445   runner.addToConfig(cfparam);
446   std::string ddparam("destination_directory="); ddparam += dest_dir;
447   runner.addToConfig(ddparam);
448   runner.addToConfig("main_loop_iterations=1");
449   runner.addToConfig("use_fixed_seed=1");
450   runner.addToConfig("collection_interval=100");
451   runner.addToConfig("perf_path=/does/not/exist");
452
453   // Create semaphore file
454   runner.create_semaphore_file();
455
456   // Kick off daemon
457   int daemon_main_return_code = runner.invoke();
458
459   // Check return code from daemon
460   EXPECT_EQ(0, daemon_main_return_code);
461
462   // expected log contents
463   const std::string expected = RAW_RESULT(
464       I: profile collection skipped (missing 'perf' executable)
465                                           );
466   // check to make sure log excerpt matches
467   compareLogMessages(mock_perfprofdutils_getlogged(),
468                      expected, "MissingPerfExecutable");
469 }
470
471 TEST_F(PerfProfdTest, BadPerfRun)
472 {
473   //
474   // Perf tools tend to be tightly coupled with a specific kernel
475   // version -- if things are out of sync perf could fail or
476   // crash. This test makes sure that we detect such a case and log
477   // the error.
478   //
479   PerfProfdRunner runner(conf_dir);
480   runner.addToConfig("only_debug_build=0");
481   std::string cfparam("config_directory="); cfparam += conf_dir;
482   runner.addToConfig(cfparam);
483   std::string ddparam("destination_directory="); ddparam += dest_dir;
484   runner.addToConfig(ddparam);
485   runner.addToConfig("main_loop_iterations=1");
486   runner.addToConfig("use_fixed_seed=1");
487   runner.addToConfig("collection_interval=100");
488   runner.addToConfig("perf_path=/system/bin/false");
489
490   // Create semaphore file
491   runner.create_semaphore_file();
492
493   // Kick off daemon
494   int daemon_main_return_code = runner.invoke();
495
496   // Check return code from daemon
497   EXPECT_EQ(0, daemon_main_return_code);
498
499   // Verify log contents
500   const std::string expected = RAW_RESULT(
501       I: profile collection failed (perf record returned bad exit status)
502                                           );
503
504   // check to make sure log excerpt matches
505   compareLogMessages(mock_perfprofdutils_getlogged(),
506                      expected, "BadPerfRun");
507 }
508
509 TEST_F(PerfProfdTest, ConfigFileParsing)
510 {
511   //
512   // Gracefully handly malformed items in the config file
513   //
514   PerfProfdRunner runner(conf_dir);
515   runner.addToConfig("only_debug_build=0");
516   runner.addToConfig("main_loop_iterations=1");
517   runner.addToConfig("collection_interval=100");
518   runner.addToConfig("use_fixed_seed=1");
519   runner.addToConfig("destination_directory=/does/not/exist");
520
521   // assorted bad syntax
522   runner.addToConfig("collection_interval=0");
523   runner.addToConfig("collection_interval=-1");
524   runner.addToConfig("collection_interval=2");
525   runner.addToConfig("nonexistent_key=something");
526   runner.addToConfig("no_equals_stmt");
527
528   // Kick off daemon
529   int daemon_main_return_code = runner.invoke();
530
531   // Check return code from daemon
532   EXPECT_EQ(0, daemon_main_return_code);
533
534   // Verify log contents
535   const std::string expected = RAW_RESULT(
536       W: line 6: specified value 0 for 'collection_interval' outside permitted range [100 4294967295] (ignored)
537       W: line 7: malformed unsigned value (ignored)
538       W: line 8: specified value 2 for 'collection_interval' outside permitted range [100 4294967295] (ignored)
539       W: line 9: unknown option 'nonexistent_key' ignored
540       W: line 10: line malformed (no '=' found)
541                                           );
542
543   // check to make sure log excerpt matches
544   compareLogMessages(mock_perfprofdutils_getlogged(),
545                      expected, "ConfigFileParsing");
546 }
547
548 TEST_F(PerfProfdTest, ProfileCollectionAnnotations)
549 {
550   unsigned util1 = collect_cpu_utilization();
551   EXPECT_LE(util1, 100);
552   EXPECT_GE(util1, 0);
553
554   // NB: expectation is that when we run this test, the device will be
555   // completed booted, will be on charger, and will not have the camera
556   // active.
557   EXPECT_FALSE(get_booting());
558   EXPECT_TRUE(get_charging());
559   EXPECT_FALSE(get_camera_active());
560 }
561
562 TEST_F(PerfProfdTest, BasicRunWithCannedPerf)
563 {
564   //
565   // Verify the portion of the daemon that reads and encodes
566   // perf.data files. Here we run the encoder on a canned perf.data
567   // file and verify that the resulting protobuf contains what
568   // we think it should contain.
569   //
570   std::string input_perf_data(test_dir);
571   input_perf_data += "/canned.perf.data";
572
573   // Set up config to avoid these annotations (they are tested elsewhere)
574   ConfigReader config_reader;
575   config_reader.overrideUnsignedEntry("collect_cpu_utilization", 0);
576   config_reader.overrideUnsignedEntry("collect_charging_state", 0);
577   config_reader.overrideUnsignedEntry("collect_camera_active", 0);
578   PerfProfdRunner::LoggingConfig config;
579   config_reader.FillConfig(&config);
580
581   // Kick off encoder and check return code
582   PROFILE_RESULT result =
583       encode_to_proto(input_perf_data, encoded_file_path(dest_dir, 0).c_str(), config, 0);
584   EXPECT_EQ(OK_PROFILE_COLLECTION, result);
585
586   // Read and decode the resulting perf.data.encoded file
587   wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
588   readEncodedProfile(dest_dir,
589                      "BasicRunWithCannedPerf",
590                      encodedProfile);
591
592   // Expect 45 programs
593   EXPECT_EQ(45, encodedProfile.programs_size());
594
595   // Check a couple of load modules
596   { const auto &lm0 = encodedProfile.load_modules(0);
597     std::string act_lm0 = encodedLoadModuleToString(lm0);
598     std::string sqact0 = squeezeWhite(act_lm0, "actual for lm 0");
599     const std::string expected_lm0 = RAW_RESULT(
600         name: "/data/app/com.google.android.apps.plus-1/lib/arm/libcronet.so"
601                                                 );
602     std::string sqexp0 = squeezeWhite(expected_lm0, "expected_lm0");
603     EXPECT_STREQ(sqexp0.c_str(), sqact0.c_str());
604   }
605   { const auto &lm9 = encodedProfile.load_modules(9);
606     std::string act_lm9 = encodedLoadModuleToString(lm9);
607     std::string sqact9 = squeezeWhite(act_lm9, "actual for lm 9");
608     const std::string expected_lm9 = RAW_RESULT(
609         name: "/system/lib/libandroid_runtime.so" build_id: "8164ed7b3a8b8f5a220d027788922510"
610                                                 );
611     std::string sqexp9 = squeezeWhite(expected_lm9, "expected_lm9");
612     EXPECT_STREQ(sqexp9.c_str(), sqact9.c_str());
613   }
614
615   // Examine some of the samples now
616   { const auto &p1 = encodedProfile.programs(0);
617     const auto &lm1 = p1.modules(0);
618     std::string act_lm1 = encodedModuleSamplesToString(lm1);
619     std::string sqact1 = squeezeWhite(act_lm1, "actual for lm1");
620     const std::string expected_lm1 = RAW_RESULT(
621         load_module_id: 9 address_samples { address: 296100 count: 1 }
622                                                 );
623     std::string sqexp1 = squeezeWhite(expected_lm1, "expected_lm1");
624     EXPECT_STREQ(sqexp1.c_str(), sqact1.c_str());
625   }
626   { const auto &p1 = encodedProfile.programs(2);
627     const auto &lm2 = p1.modules(0);
628     std::string act_lm2 = encodedModuleSamplesToString(lm2);
629     std::string sqact2 = squeezeWhite(act_lm2, "actual for lm2");
630     const std::string expected_lm2 = RAW_RESULT(
631         load_module_id: 2
632         address_samples { address: 28030244 count: 1 }
633         address_samples { address: 29657840 count: 1 }
634                                                 );
635     std::string sqexp2 = squeezeWhite(expected_lm2, "expected_lm2");
636     EXPECT_STREQ(sqexp2.c_str(), sqact2.c_str());
637   }
638 }
639
640 TEST_F(PerfProfdTest, CallchainRunWithCannedPerf)
641 {
642   // This test makes sure that the perf.data converter
643   // can handle call chains.
644   //
645   std::string input_perf_data(test_dir);
646   input_perf_data += "/callchain.canned.perf.data";
647
648   // Set up config to avoid these annotations (they are tested elsewhere)
649   ConfigReader config_reader;
650   config_reader.overrideUnsignedEntry("collect_cpu_utilization", 0);
651   config_reader.overrideUnsignedEntry("collect_charging_state", 0);
652   config_reader.overrideUnsignedEntry("collect_camera_active", 0);
653   PerfProfdRunner::LoggingConfig config;
654   config_reader.FillConfig(&config);
655
656   // Kick off encoder and check return code
657   PROFILE_RESULT result =
658       encode_to_proto(input_perf_data, encoded_file_path(dest_dir, 0).c_str(), config, 0);
659   EXPECT_EQ(OK_PROFILE_COLLECTION, result);
660
661   // Read and decode the resulting perf.data.encoded file
662   wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
663   readEncodedProfile(dest_dir,
664                      "BasicRunWithCannedPerf",
665                      encodedProfile);
666
667
668   // Expect 3 programs 8 load modules
669   EXPECT_EQ(3, encodedProfile.programs_size());
670   EXPECT_EQ(8, encodedProfile.load_modules_size());
671
672   // Check a couple of load modules
673   { const auto &lm0 = encodedProfile.load_modules(0);
674     std::string act_lm0 = encodedLoadModuleToString(lm0);
675     std::string sqact0 = squeezeWhite(act_lm0, "actual for lm 0");
676     const std::string expected_lm0 = RAW_RESULT(
677         name: "/system/bin/dex2oat"
678         build_id: "ee12bd1a1de39422d848f249add0afc4"
679                                                 );
680     std::string sqexp0 = squeezeWhite(expected_lm0, "expected_lm0");
681     EXPECT_STREQ(sqexp0.c_str(), sqact0.c_str());
682   }
683   { const auto &lm1 = encodedProfile.load_modules(1);
684     std::string act_lm1 = encodedLoadModuleToString(lm1);
685     std::string sqact1 = squeezeWhite(act_lm1, "actual for lm 1");
686     const std::string expected_lm1 = RAW_RESULT(
687         name: "/system/bin/linker"
688         build_id: "a36715f673a4a0aa76ef290124c516cc"
689                                                 );
690     std::string sqexp1 = squeezeWhite(expected_lm1, "expected_lm1");
691     EXPECT_STREQ(sqexp1.c_str(), sqact1.c_str());
692   }
693
694   // Examine some of the samples now
695   { const auto &p0 = encodedProfile.programs(0);
696     const auto &lm1 = p0.modules(0);
697     std::string act_lm1 = encodedModuleSamplesToString(lm1);
698     std::string sqact1 = squeezeWhite(act_lm1, "actual for lm1");
699     const std::string expected_lm1 = RAW_RESULT(
700         load_module_id: 0
701         address_samples { address: 108552 count: 2 }
702                                                 );
703     std::string sqexp1 = squeezeWhite(expected_lm1, "expected_lm1");
704     EXPECT_STREQ(sqexp1.c_str(), sqact1.c_str());
705   }
706   { const auto &p4 = encodedProfile.programs(2);
707     const auto &lm2 = p4.modules(1);
708     std::string act_lm2 = encodedModuleSamplesToString(lm2);
709     std::string sqact2 = squeezeWhite(act_lm2, "actual for lm2");
710     const std::string expected_lm2 = RAW_RESULT(
711         load_module_id: 2 address_samples { address: 403913 count: 1 } address_samples { address: 840761 count: 1 } address_samples { address: 846481 count: 1 } address_samples { address: 999053 count: 1 } address_samples { address: 1012959 count: 1 } address_samples { address: 1524309 count: 1 } address_samples { address: 1580779 count: 1 } address_samples { address: 4287986288 count: 1 }
712                                                 );
713     std::string sqexp2 = squeezeWhite(expected_lm2, "expected_lm2");
714     EXPECT_STREQ(sqexp2.c_str(), sqact2.c_str());
715   }
716 }
717
718 TEST_F(PerfProfdTest, BasicRunWithLivePerf)
719 {
720   //
721   // Basic test to exercise the main loop of the daemon. It includes
722   // a live 'perf' run
723   //
724   PerfProfdRunner runner(conf_dir);
725   runner.addToConfig("only_debug_build=0");
726   std::string ddparam("destination_directory="); ddparam += dest_dir;
727   runner.addToConfig(ddparam);
728   std::string cfparam("config_directory="); cfparam += conf_dir;
729   runner.addToConfig(cfparam);
730   runner.addToConfig("main_loop_iterations=1");
731   runner.addToConfig("use_fixed_seed=12345678");
732   runner.addToConfig("max_unprocessed_profiles=100");
733   runner.addToConfig("collection_interval=9999");
734   runner.addToConfig("sample_duration=2");
735
736   // Create semaphore file
737   runner.create_semaphore_file();
738
739   // Kick off daemon
740   int daemon_main_return_code = runner.invoke();
741
742   // Check return code from daemon
743   EXPECT_EQ(0, daemon_main_return_code);
744
745   // Read and decode the resulting perf.data.encoded file
746   wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
747   readEncodedProfile(dest_dir, "BasicRunWithLivePerf", encodedProfile);
748
749   // Examine what we get back. Since it's a live profile, we can't
750   // really do much in terms of verifying the contents.
751   EXPECT_LT(0, encodedProfile.programs_size());
752
753   // Verify log contents
754   const std::string expected = std::string(
755       "I: starting Android Wide Profiling daemon ") +
756       "I: config file path set to " + conf_dir + "/perfprofd.conf " +
757       RAW_RESULT(
758       I: random seed set to 12345678
759       I: sleep 674 seconds
760       I: initiating profile collection
761       I: sleep 2 seconds
762       I: profile collection complete
763       I: sleep 9325 seconds
764       I: finishing Android Wide Profiling daemon
765                                           );
766   // check to make sure log excerpt matches
767   compareLogMessages(mock_perfprofdutils_getlogged(),
768                      expandVars(expected), "BasicRunWithLivePerf", true);
769 }
770
771 TEST_F(PerfProfdTest, MultipleRunWithLivePerf)
772 {
773   //
774   // Basic test to exercise the main loop of the daemon. It includes
775   // a live 'perf' run
776   //
777   PerfProfdRunner runner(conf_dir);
778   runner.addToConfig("only_debug_build=0");
779   std::string ddparam("destination_directory="); ddparam += dest_dir;
780   runner.addToConfig(ddparam);
781   std::string cfparam("config_directory="); cfparam += conf_dir;
782   runner.addToConfig(cfparam);
783   runner.addToConfig("main_loop_iterations=3");
784   runner.addToConfig("use_fixed_seed=12345678");
785   runner.addToConfig("collection_interval=9999");
786   runner.addToConfig("sample_duration=2");
787   runner.write_processed_file(1, 2);
788
789   // Create semaphore file
790   runner.create_semaphore_file();
791
792   // Kick off daemon
793   int daemon_main_return_code = runner.invoke();
794
795   // Check return code from daemon
796   EXPECT_EQ(0, daemon_main_return_code);
797
798   // Read and decode the resulting perf.data.encoded file
799   wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
800   readEncodedProfile(dest_dir, "BasicRunWithLivePerf", encodedProfile);
801
802   // Examine what we get back. Since it's a live profile, we can't
803   // really do much in terms of verifying the contents.
804   EXPECT_LT(0, encodedProfile.programs_size());
805
806   // Examine that encoded.1 file is removed while encoded.{0|2} exists.
807   EXPECT_EQ(0, access(encoded_file_path(dest_dir, 0).c_str(), F_OK));
808   EXPECT_NE(0, access(encoded_file_path(dest_dir, 1).c_str(), F_OK));
809   EXPECT_EQ(0, access(encoded_file_path(dest_dir, 2).c_str(), F_OK));
810
811   // Verify log contents
812   const std::string expected = std::string(
813       "I: starting Android Wide Profiling daemon ") +
814       "I: config file path set to " + conf_dir + "/perfprofd.conf " +
815       RAW_RESULT(
816       I: random seed set to 12345678
817       I: sleep 674 seconds
818       I: initiating profile collection
819       I: sleep 2 seconds
820       I: profile collection complete
821       I: sleep 9325 seconds
822       I: sleep 4974 seconds
823       I: initiating profile collection
824       I: sleep 2 seconds
825       I: profile collection complete
826       I: sleep 5025 seconds
827       I: sleep 501 seconds
828       I: initiating profile collection
829       I: sleep 2 seconds
830       I: profile collection complete
831       I: sleep 9498 seconds
832       I: finishing Android Wide Profiling daemon
833                                           );
834   // check to make sure log excerpt matches
835   compareLogMessages(mock_perfprofdutils_getlogged(),
836                      expandVars(expected), "BasicRunWithLivePerf", true);
837 }
838
839 TEST_F(PerfProfdTest, CallChainRunWithLivePerf)
840 {
841   //
842   // Collect a callchain profile, so as to exercise the code in
843   // perf_data post-processing that digests callchains.
844   //
845   PerfProfdRunner runner(conf_dir);
846   std::string ddparam("destination_directory="); ddparam += dest_dir;
847   runner.addToConfig(ddparam);
848   std::string cfparam("config_directory="); cfparam += conf_dir;
849   runner.addToConfig(cfparam);
850   runner.addToConfig("main_loop_iterations=1");
851   runner.addToConfig("use_fixed_seed=12345678");
852   runner.addToConfig("max_unprocessed_profiles=100");
853   runner.addToConfig("collection_interval=9999");
854   runner.addToConfig("stack_profile=1");
855   runner.addToConfig("sample_duration=2");
856
857   // Create semaphore file
858   runner.create_semaphore_file();
859
860   // Kick off daemon
861   int daemon_main_return_code = runner.invoke();
862
863   // Check return code from daemon
864   EXPECT_EQ(0, daemon_main_return_code);
865
866   // Read and decode the resulting perf.data.encoded file
867   wireless_android_play_playlog::AndroidPerfProfile encodedProfile;
868   readEncodedProfile(dest_dir, "CallChainRunWithLivePerf", encodedProfile);
869
870   // Examine what we get back. Since it's a live profile, we can't
871   // really do much in terms of verifying the contents.
872   EXPECT_LT(0, encodedProfile.programs_size());
873
874   // Verify log contents
875   const std::string expected = std::string(
876       "I: starting Android Wide Profiling daemon ") +
877       "I: config file path set to " + conf_dir + "/perfprofd.conf " +
878       RAW_RESULT(
879       I: random seed set to 12345678
880       I: sleep 674 seconds
881       I: initiating profile collection
882       I: sleep 2 seconds
883       I: profile collection complete
884       I: sleep 9325 seconds
885       I: finishing Android Wide Profiling daemon
886                                           );
887   // check to make sure log excerpt matches
888   compareLogMessages(mock_perfprofdutils_getlogged(),
889                      expandVars(expected), "CallChainRunWithLivePerf", true);
890 }
891
892 int main(int argc, char **argv) {
893   // Always log to cerr, so that device failures are visible.
894   android::base::SetLogger(android::base::StderrLogger);
895
896   CHECK(android::base::Realpath(argv[0], &gExecutableRealpath));
897
898   // switch to / before starting testing (perfprofd
899   // should be location-independent)
900   chdir("/");
901   testing::InitGoogleTest(&argc, argv);
902   return RUN_ALL_TESTS();
903 }