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 <set>
20 #include <unordered_map>
21 
22 #include <android-base/file.h>
23 #include <android-base/strings.h>
24 
25 #include "command.h"
26 #include "get_test_data.h"
27 #include "perf_regs.h"
28 #include "read_apk.h"
29 #include "test_util.h"
30 
ReportCmd()31 static std::unique_ptr<Command> ReportCmd() {
32   return CreateCommandInstance("report");
33 }
34 
35 class ReportCommandTest : public ::testing::Test {
36  protected:
Report(const std::string & perf_data,const std::vector<std::string> & add_args=std::vector<std::string> ())37   void Report(
38       const std::string& perf_data,
39       const std::vector<std::string>& add_args = std::vector<std::string>()) {
40     ReportRaw(GetTestData(perf_data), add_args);
41   }
42 
ReportRaw(const std::string & perf_data,const std::vector<std::string> & add_args=std::vector<std::string> ())43   void ReportRaw(
44       const std::string& perf_data,
45       const std::vector<std::string>& add_args = std::vector<std::string>()) {
46     success = false;
47     TemporaryFile tmp_file;
48     std::vector<std::string> args = {
49         "-i", perf_data, "--symfs", GetTestDataDir(), "-o", tmp_file.path};
50     args.insert(args.end(), add_args.begin(), add_args.end());
51     ASSERT_TRUE(ReportCmd()->Run(args));
52     ASSERT_TRUE(android::base::ReadFileToString(tmp_file.path, &content));
53     ASSERT_TRUE(!content.empty());
54     std::vector<std::string> raw_lines = android::base::Split(content, "\n");
55     lines.clear();
56     for (const auto& line : raw_lines) {
57       std::string s = android::base::Trim(line);
58       if (!s.empty()) {
59         lines.push_back(s);
60       }
61     }
62     ASSERT_GE(lines.size(), 2u);
63     success = true;
64   }
65 
66   std::string content;
67   std::vector<std::string> lines;
68   bool success;
69 };
70 
TEST_F(ReportCommandTest,no_option)71 TEST_F(ReportCommandTest, no_option) {
72   Report(PERF_DATA);
73   ASSERT_TRUE(success);
74   ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
75 }
76 
TEST_F(ReportCommandTest,report_symbol_from_elf_file_with_mini_debug_info)77 TEST_F(ReportCommandTest, report_symbol_from_elf_file_with_mini_debug_info) {
78   Report(PERF_DATA_WITH_MINI_DEBUG_INFO);
79   ASSERT_TRUE(success);
80   ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
81 }
82 
TEST_F(ReportCommandTest,sort_option_pid)83 TEST_F(ReportCommandTest, sort_option_pid) {
84   Report(PERF_DATA, {"--sort", "pid"});
85   ASSERT_TRUE(success);
86   size_t line_index = 0;
87   while (line_index < lines.size() &&
88          lines[line_index].find("Pid") == std::string::npos) {
89     line_index++;
90   }
91   ASSERT_LT(line_index + 2, lines.size());
92 }
93 
TEST_F(ReportCommandTest,sort_option_more_than_one)94 TEST_F(ReportCommandTest, sort_option_more_than_one) {
95   Report(PERF_DATA, {"--sort", "comm,pid,dso,symbol"});
96   ASSERT_TRUE(success);
97   size_t line_index = 0;
98   while (line_index < lines.size() &&
99          lines[line_index].find("Overhead") == std::string::npos) {
100     line_index++;
101   }
102   ASSERT_LT(line_index + 1, lines.size());
103   ASSERT_NE(lines[line_index].find("Command"), std::string::npos);
104   ASSERT_NE(lines[line_index].find("Pid"), std::string::npos);
105   ASSERT_NE(lines[line_index].find("Shared Object"), std::string::npos);
106   ASSERT_NE(lines[line_index].find("Symbol"), std::string::npos);
107   ASSERT_EQ(lines[line_index].find("Tid"), std::string::npos);
108 }
109 
TEST_F(ReportCommandTest,children_option)110 TEST_F(ReportCommandTest, children_option) {
111   Report(CALLGRAPH_FP_PERF_DATA, {"--children", "--sort", "symbol"});
112   ASSERT_TRUE(success);
113   std::unordered_map<std::string, std::pair<double, double>> map;
114   for (size_t i = 0; i < lines.size(); ++i) {
115     char name[1024];
116     std::pair<double, double> pair;
117     if (sscanf(lines[i].c_str(), "%lf%%%lf%%%s", &pair.first, &pair.second,
118                name) == 3) {
119       map.insert(std::make_pair(name, pair));
120     }
121   }
122   ASSERT_NE(map.find("GlobalFunc"), map.end());
123   ASSERT_NE(map.find("main"), map.end());
124   auto func_pair = map["GlobalFunc"];
125   auto main_pair = map["main"];
126   ASSERT_GE(main_pair.first, func_pair.first);
127   ASSERT_GE(func_pair.first, func_pair.second);
128   ASSERT_GE(func_pair.second, main_pair.second);
129 }
130 
CheckCalleeMode(std::vector<std::string> & lines)131 static bool CheckCalleeMode(std::vector<std::string>& lines) {
132   bool found = false;
133   for (size_t i = 0; i + 1 < lines.size(); ++i) {
134     if (lines[i].find("GlobalFunc") != std::string::npos &&
135         lines[i + 1].find("main") != std::string::npos) {
136       found = true;
137       break;
138     }
139   }
140   return found;
141 }
142 
CheckCallerMode(std::vector<std::string> & lines)143 static bool CheckCallerMode(std::vector<std::string>& lines) {
144   bool found = false;
145   for (size_t i = 0; i + 1 < lines.size(); ++i) {
146     if (lines[i].find("main") != std::string::npos &&
147         lines[i + 1].find("GlobalFunc") != std::string::npos) {
148       found = true;
149       break;
150     }
151   }
152   return found;
153 }
154 
TEST_F(ReportCommandTest,callgraph_option)155 TEST_F(ReportCommandTest, callgraph_option) {
156   Report(CALLGRAPH_FP_PERF_DATA, {"-g"});
157   ASSERT_TRUE(success);
158   ASSERT_TRUE(CheckCallerMode(lines));
159   Report(CALLGRAPH_FP_PERF_DATA, {"-g", "callee"});
160   ASSERT_TRUE(success);
161   ASSERT_TRUE(CheckCalleeMode(lines));
162   Report(CALLGRAPH_FP_PERF_DATA, {"-g", "caller"});
163   ASSERT_TRUE(success);
164   ASSERT_TRUE(CheckCallerMode(lines));
165 }
166 
AllItemsWithString(std::vector<std::string> & lines,const std::vector<std::string> & strs)167 static bool AllItemsWithString(std::vector<std::string>& lines,
168                                const std::vector<std::string>& strs) {
169   size_t line_index = 0;
170   while (line_index < lines.size() &&
171          lines[line_index].find("Overhead") == std::string::npos) {
172     line_index++;
173   }
174   if (line_index == lines.size() || line_index + 1 == lines.size()) {
175     return false;
176   }
177   line_index++;
178   for (; line_index < lines.size(); ++line_index) {
179     bool exist = false;
180     for (auto& s : strs) {
181       if (lines[line_index].find(s) != std::string::npos) {
182         exist = true;
183         break;
184       }
185     }
186     if (!exist) {
187       return false;
188     }
189   }
190   return true;
191 }
192 
TEST_F(ReportCommandTest,pid_filter_option)193 TEST_F(ReportCommandTest, pid_filter_option) {
194   Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS, {"--sort", "pid"});
195   ASSERT_TRUE(success);
196   ASSERT_FALSE(AllItemsWithString(lines, {"17441"}));
197   ASSERT_FALSE(AllItemsWithString(lines, {"17441", "17443"}));
198   Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS,
199          {"--sort", "pid", "--pids", "17441"});
200   ASSERT_TRUE(success);
201   ASSERT_TRUE(AllItemsWithString(lines, {"17441"}));
202   Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS,
203          {"--sort", "pid", "--pids", "17441,17443"});
204   ASSERT_TRUE(success);
205   ASSERT_TRUE(AllItemsWithString(lines, {"17441", "17443"}));
206 
207   // Test that --pids option is not the same as --tids option.
208   // Thread 17445 and 17441 are in process 17441.
209   Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS,
210          {"--sort", "tid", "--pids", "17441"});
211   ASSERT_TRUE(success);
212   ASSERT_NE(content.find("17441"), std::string::npos);
213   ASSERT_NE(content.find("17445"), std::string::npos);
214 }
215 
TEST_F(ReportCommandTest,wrong_pid_filter_option)216 TEST_F(ReportCommandTest, wrong_pid_filter_option) {
217   ASSERT_EXIT(
218       {
219         Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS, {"--pids", "2,bogus"});
220         exit(success ? 0 : 1);
221       },
222       testing::ExitedWithCode(1), "invalid id in --pids option: bogus");
223 }
224 
TEST_F(ReportCommandTest,tid_filter_option)225 TEST_F(ReportCommandTest, tid_filter_option) {
226   Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS, {"--sort", "tid"});
227   ASSERT_TRUE(success);
228   ASSERT_FALSE(AllItemsWithString(lines, {"17441"}));
229   ASSERT_FALSE(AllItemsWithString(lines, {"17441", "17445"}));
230   Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS,
231          {"--sort", "tid", "--tids", "17441"});
232   ASSERT_TRUE(success);
233   ASSERT_TRUE(AllItemsWithString(lines, {"17441"}));
234   Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS,
235          {"--sort", "tid", "--tids", "17441,17445"});
236   ASSERT_TRUE(success);
237   ASSERT_TRUE(AllItemsWithString(lines, {"17441", "17445"}));
238 }
239 
TEST_F(ReportCommandTest,wrong_tid_filter_option)240 TEST_F(ReportCommandTest, wrong_tid_filter_option) {
241   ASSERT_EXIT(
242       {
243         Report(PERF_DATA_WITH_MULTIPLE_PIDS_AND_TIDS, {"--tids", "2,bogus"});
244         exit(success ? 0 : 1);
245       },
246       testing::ExitedWithCode(1), "invalid id in --tids option: bogus");
247 }
248 
TEST_F(ReportCommandTest,comm_filter_option)249 TEST_F(ReportCommandTest, comm_filter_option) {
250   Report(PERF_DATA, {"--sort", "comm"});
251   ASSERT_TRUE(success);
252   ASSERT_FALSE(AllItemsWithString(lines, {"t1"}));
253   ASSERT_FALSE(AllItemsWithString(lines, {"t1", "t2"}));
254   Report(PERF_DATA, {"--sort", "comm", "--comms", "t1"});
255   ASSERT_TRUE(success);
256   ASSERT_TRUE(AllItemsWithString(lines, {"t1"}));
257   Report(PERF_DATA, {"--sort", "comm", "--comms", "t1,t2"});
258   ASSERT_TRUE(success);
259   ASSERT_TRUE(AllItemsWithString(lines, {"t1", "t2"}));
260 }
261 
TEST_F(ReportCommandTest,dso_filter_option)262 TEST_F(ReportCommandTest, dso_filter_option) {
263   Report(PERF_DATA, {"--sort", "dso"});
264   ASSERT_TRUE(success);
265   ASSERT_FALSE(AllItemsWithString(lines, {"/t1"}));
266   ASSERT_FALSE(AllItemsWithString(lines, {"/t1", "/t2"}));
267   Report(PERF_DATA, {"--sort", "dso", "--dsos", "/t1"});
268   ASSERT_TRUE(success);
269   ASSERT_TRUE(AllItemsWithString(lines, {"/t1"}));
270   Report(PERF_DATA, {"--sort", "dso", "--dsos", "/t1,/t2"});
271   ASSERT_TRUE(success);
272   ASSERT_TRUE(AllItemsWithString(lines, {"/t1", "/t2"}));
273 }
274 
TEST_F(ReportCommandTest,symbol_filter_option)275 TEST_F(ReportCommandTest, symbol_filter_option) {
276   Report(PERF_DATA_WITH_SYMBOLS, {"--sort", "symbol"});
277   ASSERT_TRUE(success);
278   ASSERT_FALSE(AllItemsWithString(lines, {"func2(int, int)"}));
279   ASSERT_FALSE(AllItemsWithString(lines, {"main", "func2(int, int)"}));
280   Report(PERF_DATA_WITH_SYMBOLS,
281          {"--sort", "symbol", "--symbols", "func2(int, int)"});
282   ASSERT_TRUE(success);
283   ASSERT_TRUE(AllItemsWithString(lines, {"func2(int, int)"}));
284   Report(PERF_DATA_WITH_SYMBOLS,
285          {"--sort", "symbol", "--symbols", "main;func2(int, int)"});
286   ASSERT_TRUE(success);
287   ASSERT_TRUE(AllItemsWithString(lines, {"main", "func2(int, int)"}));
288 }
289 
TEST_F(ReportCommandTest,use_branch_address)290 TEST_F(ReportCommandTest, use_branch_address) {
291   Report(BRANCH_PERF_DATA, {"-b", "--sort", "symbol_from,symbol_to"});
292   std::set<std::pair<std::string, std::string>> hit_set;
293   bool after_overhead = false;
294   for (const auto& line : lines) {
295     if (!after_overhead && line.find("Overhead") != std::string::npos) {
296       after_overhead = true;
297     } else if (after_overhead) {
298       char from[80];
299       char to[80];
300       if (sscanf(line.c_str(), "%*f%%%s%s", from, to) == 2) {
301         hit_set.insert(std::make_pair<std::string, std::string>(from, to));
302       }
303     }
304   }
305   ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>(
306                 "GlobalFunc", "CalledFunc")),
307             hit_set.end());
308   ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>(
309                 "CalledFunc", "GlobalFunc")),
310             hit_set.end());
311 }
312 
TEST_F(ReportCommandTest,report_symbols_of_nativelib_in_apk)313 TEST_F(ReportCommandTest, report_symbols_of_nativelib_in_apk) {
314   Report(NATIVELIB_IN_APK_PERF_DATA);
315   ASSERT_TRUE(success);
316   ASSERT_NE(content.find(GetUrlInApk(APK_FILE, NATIVELIB_IN_APK)),
317             std::string::npos);
318   ASSERT_NE(content.find("Func2"), std::string::npos);
319 }
320 
TEST_F(ReportCommandTest,report_more_than_one_event_types)321 TEST_F(ReportCommandTest, report_more_than_one_event_types) {
322   Report(PERF_DATA_WITH_TWO_EVENT_TYPES);
323   ASSERT_TRUE(success);
324   size_t pos = 0;
325   ASSERT_NE(pos = content.find("cpu-cycles", pos), std::string::npos);
326   ASSERT_NE(pos = content.find("Samples:", pos), std::string::npos);
327   ASSERT_NE(pos = content.find("cpu-clock", pos), std::string::npos);
328   ASSERT_NE(pos = content.find("Samples:", pos), std::string::npos);
329 }
330 
TEST_F(ReportCommandTest,report_kernel_symbol)331 TEST_F(ReportCommandTest, report_kernel_symbol) {
332   Report(PERF_DATA_WITH_KERNEL_SYMBOL);
333   ASSERT_TRUE(success);
334   ASSERT_NE(content.find("perf_event_aux"), std::string::npos);
335 }
336 
TEST_F(ReportCommandTest,report_dumped_symbols)337 TEST_F(ReportCommandTest, report_dumped_symbols) {
338   Report(PERF_DATA_WITH_SYMBOLS);
339   ASSERT_TRUE(success);
340   ASSERT_NE(content.find("main"), std::string::npos);
341   Report(PERF_DATA_WITH_SYMBOLS_FOR_NONZERO_MINVADDR_DSO);
342   ASSERT_TRUE(success);
343   ASSERT_NE(content.find("memcpy"), std::string::npos);
344 }
345 
TEST_F(ReportCommandTest,report_dumped_symbols_with_symfs_dir)346 TEST_F(ReportCommandTest, report_dumped_symbols_with_symfs_dir) {
347   // Check if we can report symbols when they appear both in perf.data and symfs dir.
348   Report(PERF_DATA_WITH_SYMBOLS, {"--symfs", GetTestDataDir()});
349   ASSERT_TRUE(success);
350   ASSERT_NE(content.find("main"), std::string::npos);
351 }
352 
TEST_F(ReportCommandTest,report_without_symfs_dir)353 TEST_F(ReportCommandTest, report_without_symfs_dir) {
354   TemporaryFile tmpfile;
355   ASSERT_TRUE(ReportCmd()->Run({"-i", GetTestData(PERF_DATA), "-o", tmpfile.path}));
356 }
357 
TEST_F(ReportCommandTest,report_sort_vaddr_in_file)358 TEST_F(ReportCommandTest, report_sort_vaddr_in_file) {
359   Report(PERF_DATA, {"--sort", "vaddr_in_file"});
360   ASSERT_TRUE(success);
361   ASSERT_NE(content.find("VaddrInFile"), std::string::npos);
362 }
363 
TEST_F(ReportCommandTest,check_build_id)364 TEST_F(ReportCommandTest, check_build_id) {
365   Report(PERF_DATA_FOR_BUILD_ID_CHECK,
366          {"--symfs", GetTestData(CORRECT_SYMFS_FOR_BUILD_ID_CHECK)});
367   ASSERT_TRUE(success);
368   ASSERT_NE(content.find("main"), std::string::npos);
369   ASSERT_EXIT(
370       {
371         Report(PERF_DATA_FOR_BUILD_ID_CHECK,
372                {"--symfs", GetTestData(WRONG_SYMFS_FOR_BUILD_ID_CHECK)});
373         if (!success) {
374           exit(1);
375         }
376         if (content.find("main") != std::string::npos) {
377           exit(2);
378         }
379         exit(0);
380       },
381       testing::ExitedWithCode(0), "failed to read symbols from /elf_for_build_id_check");
382 }
383 
TEST_F(ReportCommandTest,no_show_ip_option)384 TEST_F(ReportCommandTest, no_show_ip_option) {
385   Report(PERF_DATA);
386   ASSERT_TRUE(success);
387   ASSERT_EQ(content.find("unknown"), std::string::npos);
388   Report(PERF_DATA, {"--no-show-ip"});
389   ASSERT_TRUE(success);
390   ASSERT_NE(content.find("unknown"), std::string::npos);
391 }
392 
TEST_F(ReportCommandTest,no_symbol_table_warning)393 TEST_F(ReportCommandTest, no_symbol_table_warning) {
394   ASSERT_EXIT(
395       {
396         Report(PERF_DATA,
397                {"--symfs", GetTestData(SYMFS_FOR_NO_SYMBOL_TABLE_WARNING)});
398         if (!success) {
399           exit(1);
400         }
401         if (content.find("GlobalFunc") != std::string::npos) {
402           exit(2);
403         }
404         exit(0);
405       },
406       testing::ExitedWithCode(0), "elf doesn't contain symbol table");
407 }
408 
TEST_F(ReportCommandTest,read_elf_file_warning)409 TEST_F(ReportCommandTest, read_elf_file_warning) {
410   ASSERT_EXIT(
411       {
412         Report(PERF_DATA,
413                {"--symfs", GetTestData(SYMFS_FOR_READ_ELF_FILE_WARNING)});
414         if (!success) {
415           exit(1);
416         }
417         if (content.find("GlobalFunc") != std::string::npos) {
418           exit(2);
419         }
420         exit(0);
421       },
422       testing::ExitedWithCode(0), "failed to read symbols from /elf: File not found");
423 }
424 
TEST_F(ReportCommandTest,report_data_generated_by_linux_perf)425 TEST_F(ReportCommandTest, report_data_generated_by_linux_perf) {
426   Report(PERF_DATA_GENERATED_BY_LINUX_PERF);
427   ASSERT_TRUE(success);
428 }
429 
TEST_F(ReportCommandTest,max_stack_and_percent_limit_option)430 TEST_F(ReportCommandTest, max_stack_and_percent_limit_option) {
431   Report(PERF_DATA_MAX_STACK_AND_PERCENT_LIMIT, {"-g"});
432   ASSERT_TRUE(success);
433   ASSERT_NE(content.find("89.03"), std::string::npos);
434 
435   Report(PERF_DATA_MAX_STACK_AND_PERCENT_LIMIT, {"-g", "--max-stack", "0"});
436   ASSERT_TRUE(success);
437   ASSERT_EQ(content.find("89.03"), std::string::npos);
438   Report(PERF_DATA_MAX_STACK_AND_PERCENT_LIMIT, {"-g", "--max-stack", "2"});
439   ASSERT_TRUE(success);
440   ASSERT_NE(content.find("89.03"), std::string::npos);
441 
442   Report(PERF_DATA_MAX_STACK_AND_PERCENT_LIMIT,
443          {"-g", "--percent-limit", "90"});
444   ASSERT_TRUE(success);
445   ASSERT_EQ(content.find("89.03"), std::string::npos);
446   Report(PERF_DATA_MAX_STACK_AND_PERCENT_LIMIT,
447          {"-g", "--percent-limit", "70"});
448   ASSERT_TRUE(success);
449   ASSERT_NE(content.find("89.03"), std::string::npos);
450 }
451 
TEST_F(ReportCommandTest,kallsyms_option)452 TEST_F(ReportCommandTest, kallsyms_option) {
453   Report(PERF_DATA, {"--kallsyms", GetTestData("kallsyms")});
454   ASSERT_TRUE(success);
455   ASSERT_NE(content.find("FakeKernelSymbol"), std::string::npos);
456 }
457 
TEST_F(ReportCommandTest,invalid_perf_data)458 TEST_F(ReportCommandTest, invalid_perf_data) {
459   ASSERT_FALSE(ReportCmd()->Run({"-i", GetTestData(INVALID_PERF_DATA)}));
460 }
461 
TEST_F(ReportCommandTest,raw_period_option)462 TEST_F(ReportCommandTest, raw_period_option) {
463   Report(PERF_DATA, {"--raw-period"});
464   ASSERT_TRUE(success);
465   ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
466   ASSERT_EQ(content.find('%'), std::string::npos);
467 }
468 
TEST_F(ReportCommandTest,full_callgraph_option)469 TEST_F(ReportCommandTest, full_callgraph_option) {
470   Report(CALLGRAPH_FP_PERF_DATA, {"-g"});
471   ASSERT_TRUE(success);
472   ASSERT_NE(content.find("skipped in brief callgraph mode"), std::string::npos);
473   Report(CALLGRAPH_FP_PERF_DATA, {"-g", "--full-callgraph"});
474   ASSERT_TRUE(success);
475   ASSERT_EQ(content.find("skipped in brief callgraph mode"), std::string::npos);
476 }
477 
TEST_F(ReportCommandTest,report_offcpu_time)478 TEST_F(ReportCommandTest, report_offcpu_time) {
479   Report(PERF_DATA_WITH_TRACE_OFFCPU, {"--children"});
480   ASSERT_TRUE(success);
481   ASSERT_NE(content.find("Time in ns"), std::string::npos);
482   bool found = false;
483   for (auto& line : lines) {
484     if (line.find("SleepFunction") != std::string::npos) {
485       ASSERT_NE(line.find("38.76%"), std::string::npos);
486       found = true;
487       break;
488     }
489   }
490   ASSERT_TRUE(found);
491 }
492 
TEST_F(ReportCommandTest,report_big_trace_data)493 TEST_F(ReportCommandTest, report_big_trace_data) {
494   Report(PERF_DATA_WITH_BIG_TRACE_DATA);
495   ASSERT_TRUE(success);
496 }
497 
498 #if defined(__linux__)
499 #include "event_selection_set.h"
500 
RecordCmd()501 static std::unique_ptr<Command> RecordCmd() {
502   return CreateCommandInstance("record");
503 }
504 
TEST_F(ReportCommandTest,dwarf_callgraph)505 TEST_F(ReportCommandTest, dwarf_callgraph) {
506   TEST_REQUIRE_HW_COUNTER();
507   OMIT_TEST_ON_NON_NATIVE_ABIS();
508   ASSERT_TRUE(IsDwarfCallChainSamplingSupported());
509   std::vector<std::unique_ptr<Workload>> workloads;
510   CreateProcesses(1, &workloads);
511   std::string pid = std::to_string(workloads[0]->GetPid());
512   TemporaryFile tmp_file;
513   ASSERT_TRUE(
514       RecordCmd()->Run({"-p", pid, "-g", "-o", tmp_file.path, "sleep", SLEEP_SEC}));
515   ReportRaw(tmp_file.path, {"-g"});
516   ASSERT_TRUE(success);
517 }
518 
TEST_F(ReportCommandTest,report_dwarf_callgraph_of_nativelib_in_apk)519 TEST_F(ReportCommandTest, report_dwarf_callgraph_of_nativelib_in_apk) {
520   Report(NATIVELIB_IN_APK_PERF_DATA, {"-g"});
521   ASSERT_NE(content.find(GetUrlInApk(APK_FILE, NATIVELIB_IN_APK)),
522             std::string::npos);
523   ASSERT_NE(content.find("Func2"), std::string::npos);
524   ASSERT_NE(content.find("Func1"), std::string::npos);
525   ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
526 }
527 
TEST_F(ReportCommandTest,exclude_kernel_callchain)528 TEST_F(ReportCommandTest, exclude_kernel_callchain) {
529   TEST_REQUIRE_HW_COUNTER();
530   TEST_REQUIRE_HOST_ROOT();
531   OMIT_TEST_ON_NON_NATIVE_ABIS();
532   std::vector<std::unique_ptr<Workload>> workloads;
533   CreateProcesses(1, &workloads);
534   std::string pid = std::to_string(workloads[0]->GetPid());
535   TemporaryFile tmpfile;
536   ASSERT_TRUE(RecordCmd()->Run({"--trace-offcpu", "-e", "cpu-cycles:u", "-p", pid,
537                                 "--duration", "2", "-o", tmpfile.path, "-g"}));
538   ReportRaw(tmpfile.path, {"-g"});
539   ASSERT_TRUE(success);
540   ASSERT_EQ(content.find("[kernel.kallsyms]"), std::string::npos);
541 }
542 
543 #endif
544