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