blob: a4bd6f397ea3caaaf55887ea44ee3b93995c9847 [file] [log] [blame]
Yabin Cui2672dea2015-05-21 12:17:23 -07001/*
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
Yabin Cui6e51bef2016-02-23 21:41:03 -080019#include <set>
20#include <unordered_map>
21
Yabin Cuib1a885b2016-02-14 19:18:02 -080022#include <android-base/file.h>
Yabin Cui6e51bef2016-02-23 21:41:03 -080023#include <android-base/strings.h>
Yabin Cuib1a885b2016-02-14 19:18:02 -080024#include <android-base/test_utils.h>
25
Yabin Cui2672dea2015-05-21 12:17:23 -070026#include "command.h"
Yabin Cui19e6b6d2016-03-10 11:49:57 -080027#include "event_selection_set.h"
Yabin Cuib1a885b2016-02-14 19:18:02 -080028#include "get_test_data.h"
Yabin Cui8f680f62016-03-18 18:47:43 -070029#include "perf_regs.h"
Yabin Cuib1a885b2016-02-14 19:18:02 -080030#include "read_apk.h"
Yabin Cui6e51bef2016-02-23 21:41:03 -080031#include "test_util.h"
Yabin Cui2672dea2015-05-21 12:17:23 -070032
33static std::unique_ptr<Command> ReportCmd() {
34 return CreateCommandInstance("report");
35}
36
37class ReportCommandTest : public ::testing::Test {
38 protected:
Yabin Cui6e51bef2016-02-23 21:41:03 -080039 void Report(const std::string perf_data,
40 const std::vector<std::string>& add_args = std::vector<std::string>()) {
41 ReportRaw(GetTestData(perf_data), add_args);
Yabin Cui2672dea2015-05-21 12:17:23 -070042 }
Yabin Cui6e51bef2016-02-23 21:41:03 -080043
44 void ReportRaw(const std::string perf_data,
45 const std::vector<std::string>& add_args = std::vector<std::string>()) {
46 success = false;
47 std::vector<std::string> args = {"-i", perf_data,
48 "--symfs", GetTestDataDir(), "-o", tmp_file.path};
49 args.insert(args.end(), add_args.begin(), add_args.end());
50 ASSERT_TRUE(ReportCmd()->Run(args));
51 ASSERT_TRUE(android::base::ReadFileToString(tmp_file.path, &content));
52 ASSERT_TRUE(!content.empty());
53 std::vector<std::string> raw_lines = android::base::Split(content, "\n");
54 lines.clear();
55 for (const auto& line : raw_lines) {
56 std::string s = android::base::Trim(line);
57 if (!s.empty()) {
58 lines.push_back(s);
59 }
60 }
61 ASSERT_GE(lines.size(), 2u);
62 success = true;
63 }
64
65 TemporaryFile tmp_file;
66 std::string content;
67 std::vector<std::string> lines;
68 bool success;
Yabin Cui2672dea2015-05-21 12:17:23 -070069};
70
Yabin Cui6e51bef2016-02-23 21:41:03 -080071TEST_F(ReportCommandTest, no_option) {
72 Report(PERF_DATA);
73 ASSERT_TRUE(success);
74 ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
Yabin Cui2672dea2015-05-21 12:17:23 -070075}
76
Yabin Cui05400532016-03-17 21:18:53 -070077TEST_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
Yabin Cui2672dea2015-05-21 12:17:23 -070083TEST_F(ReportCommandTest, sort_option_pid) {
Yabin Cui6e51bef2016-02-23 21:41:03 -080084 Report(PERF_DATA, {"--sort", "pid"});
85 ASSERT_TRUE(success);
86 size_t line_index = 0;
87 while (line_index < lines.size() && lines[line_index].find("Pid") == std::string::npos) {
88 line_index++;
89 }
90 ASSERT_LT(line_index + 2, lines.size());
Yabin Cui2672dea2015-05-21 12:17:23 -070091}
92
Yabin Cui6e51bef2016-02-23 21:41:03 -080093TEST_F(ReportCommandTest, sort_option_more_than_one) {
94 Report(PERF_DATA, {"--sort", "comm,pid,dso,symbol"});
95 ASSERT_TRUE(success);
96 size_t line_index = 0;
97 while (line_index < lines.size() && lines[line_index].find("Overhead") == std::string::npos) {
98 line_index++;
99 }
100 ASSERT_LT(line_index + 1, lines.size());
101 ASSERT_NE(lines[line_index].find("Command"), std::string::npos);
102 ASSERT_NE(lines[line_index].find("Pid"), std::string::npos);
103 ASSERT_NE(lines[line_index].find("Shared Object"), std::string::npos);
104 ASSERT_NE(lines[line_index].find("Symbol"), std::string::npos);
105 ASSERT_EQ(lines[line_index].find("Tid"), std::string::npos);
Yabin Cui2672dea2015-05-21 12:17:23 -0700106}
Yabin Cui8a530e32015-06-23 20:42:01 -0700107
Yabin Cuiecb9a302015-07-01 10:00:52 -0700108TEST_F(ReportCommandTest, children_option) {
Yabin Cui6e51bef2016-02-23 21:41:03 -0800109 Report(CALLGRAPH_FP_PERF_DATA, {"--children", "--sort", "symbol"});
110 ASSERT_TRUE(success);
111 std::unordered_map<std::string, std::pair<double, double>> map;
112 for (size_t i = 0; i < lines.size(); ++i) {
113 char name[1024];
114 std::pair<double, double> pair;
115 if (sscanf(lines[i].c_str(), "%lf%%%lf%%%s", &pair.first, &pair.second, name) == 3) {
116 map.insert(std::make_pair(name, pair));
117 }
118 }
119 ASSERT_NE(map.find("GlobalFunc"), map.end());
120 ASSERT_NE(map.find("main"), map.end());
121 auto func_pair = map["GlobalFunc"];
122 auto main_pair = map["main"];
123 ASSERT_GE(main_pair.first, func_pair.first);
124 ASSERT_GE(func_pair.first, func_pair.second);
125 ASSERT_GE(func_pair.second, main_pair.second);
126}
127
128static bool CheckCalleeMode(std::vector<std::string>& lines) {
129 bool found = false;
130 for (size_t i = 0; i + 2 < lines.size(); ++i) {
131 if (lines[i].find("GlobalFunc") != std::string::npos &&
132 lines[i + 1].find("|") != std::string::npos &&
133 lines[i + 2].find("main") != std::string::npos) {
134 found = true;
135 break;
136 }
137 }
138 return found;
139}
140
141static bool CheckCallerMode(std::vector<std::string>& lines) {
142 bool found = false;
143 for (size_t i = 0; i + 2 < lines.size(); ++i) {
144 if (lines[i].find("main") != std::string::npos &&
145 lines[i + 1].find("|") != std::string::npos &&
146 lines[i + 2].find("GlobalFunc") != std::string::npos) {
147 found = true;
148 break;
149 }
150 }
151 return found;
Yabin Cuiecb9a302015-07-01 10:00:52 -0700152}
153
154TEST_F(ReportCommandTest, callgraph_option) {
Yabin Cui6e51bef2016-02-23 21:41:03 -0800155 Report(CALLGRAPH_FP_PERF_DATA, {"-g"});
156 ASSERT_TRUE(success);
157 ASSERT_TRUE(CheckCalleeMode(lines));
158 Report(CALLGRAPH_FP_PERF_DATA, {"-g", "callee"});
159 ASSERT_TRUE(success);
160 ASSERT_TRUE(CheckCalleeMode(lines));
161 Report(CALLGRAPH_FP_PERF_DATA, {"-g", "caller"});
162 ASSERT_TRUE(success);
163 ASSERT_TRUE(CheckCallerMode(lines));
164}
165
166static bool AllItemsWithString(std::vector<std::string>& lines, const std::vector<std::string>& strs) {
167 size_t line_index = 0;
168 while (line_index < lines.size() && lines[line_index].find("Overhead") == std::string::npos) {
169 line_index++;
170 }
171 if (line_index == lines.size() || line_index + 1 == lines.size()) {
172 return false;
173 }
174 line_index++;
175 for (; line_index < lines.size(); ++line_index) {
176 bool exist = false;
177 for (auto& s : strs) {
178 if (lines[line_index].find(s) != std::string::npos) {
179 exist = true;
180 break;
181 }
182 }
183 if (!exist) {
184 return false;
185 }
186 }
187 return true;
Yabin Cuiecb9a302015-07-01 10:00:52 -0700188}
189
Yabin Cui38e573e2015-08-06 11:25:09 -0700190TEST_F(ReportCommandTest, pid_filter_option) {
Yabin Cui6e51bef2016-02-23 21:41:03 -0800191 Report(PERF_DATA);
192 ASSERT_TRUE("success");
193 ASSERT_FALSE(AllItemsWithString(lines, {"26083"}));
194 ASSERT_FALSE(AllItemsWithString(lines, {"26083", "26090"}));
195 Report(PERF_DATA, {"--pids", "26083"});
196 ASSERT_TRUE(success);
197 ASSERT_TRUE(AllItemsWithString(lines, {"26083"}));
198 Report(PERF_DATA, {"--pids", "26083,26090"});
199 ASSERT_TRUE(success);
200 ASSERT_TRUE(AllItemsWithString(lines, {"26083", "26090"}));
Yabin Cui38e573e2015-08-06 11:25:09 -0700201}
202
203TEST_F(ReportCommandTest, tid_filter_option) {
Yabin Cui6e51bef2016-02-23 21:41:03 -0800204 Report(PERF_DATA);
205 ASSERT_TRUE("success");
206 ASSERT_FALSE(AllItemsWithString(lines, {"26083"}));
207 ASSERT_FALSE(AllItemsWithString(lines, {"26083", "26090"}));
208 Report(PERF_DATA, {"--tids", "26083"});
209 ASSERT_TRUE(success);
210 ASSERT_TRUE(AllItemsWithString(lines, {"26083"}));
211 Report(PERF_DATA, {"--tids", "26083,26090"});
212 ASSERT_TRUE(success);
213 ASSERT_TRUE(AllItemsWithString(lines, {"26083", "26090"}));
Yabin Cui38e573e2015-08-06 11:25:09 -0700214}
215
216TEST_F(ReportCommandTest, comm_filter_option) {
Yabin Cui6e51bef2016-02-23 21:41:03 -0800217 Report(PERF_DATA, {"--sort", "comm"});
218 ASSERT_TRUE(success);
219 ASSERT_FALSE(AllItemsWithString(lines, {"t1"}));
220 ASSERT_FALSE(AllItemsWithString(lines, {"t1", "t2"}));
221 Report(PERF_DATA, {"--sort", "comm", "--comms", "t1"});
222 ASSERT_TRUE(success);
223 ASSERT_TRUE(AllItemsWithString(lines, {"t1"}));
224 Report(PERF_DATA, {"--sort", "comm", "--comms", "t1,t2"});
225 ASSERT_TRUE(success);
226 ASSERT_TRUE(AllItemsWithString(lines, {"t1", "t2"}));
Yabin Cui38e573e2015-08-06 11:25:09 -0700227}
228
229TEST_F(ReportCommandTest, dso_filter_option) {
Yabin Cui6e51bef2016-02-23 21:41:03 -0800230 Report(PERF_DATA, {"--sort", "dso"});
231 ASSERT_TRUE(success);
232 ASSERT_FALSE(AllItemsWithString(lines, {"/t1"}));
233 ASSERT_FALSE(AllItemsWithString(lines, {"/t1", "/t2"}));
234 Report(PERF_DATA, {"--sort", "dso", "--dsos", "/t1"});
235 ASSERT_TRUE(success);
236 ASSERT_TRUE(AllItemsWithString(lines, {"/t1"}));
237 Report(PERF_DATA, {"--sort", "dso", "--dsos", "/t1,/t2"});
238 ASSERT_TRUE(success);
239 ASSERT_TRUE(AllItemsWithString(lines, {"/t1", "/t2"}));
Yabin Cui38e573e2015-08-06 11:25:09 -0700240}
241
Yabin Cui6e51bef2016-02-23 21:41:03 -0800242TEST_F(ReportCommandTest, use_branch_address) {
243 Report(BRANCH_PERF_DATA, {"-b", "--sort", "symbol_from,symbol_to"});
244 std::set<std::pair<std::string, std::string>> hit_set;
245 bool after_overhead = false;
246 for (const auto& line : lines) {
247 if (!after_overhead && line.find("Overhead") != std::string::npos) {
248 after_overhead = true;
249 } else if (after_overhead) {
250 char from[80];
251 char to[80];
252 if (sscanf(line.c_str(), "%*f%%%s%s", from, to) == 2) {
253 hit_set.insert(std::make_pair<std::string, std::string>(from, to));
254 }
255 }
Yabin Cui8a530e32015-06-23 20:42:01 -0700256 }
Yabin Cui6e51bef2016-02-23 21:41:03 -0800257 ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>("GlobalFunc", "CalledFunc")),
258 hit_set.end());
259 ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>("CalledFunc", "GlobalFunc")),
260 hit_set.end());
Yabin Cui8a530e32015-06-23 20:42:01 -0700261}
Yabin Cui3c8c2132015-08-13 20:30:20 -0700262
Yabin Cui8f680f62016-03-18 18:47:43 -0700263TEST_F(ReportCommandTest, report_symbols_of_nativelib_in_apk) {
264 Report(NATIVELIB_IN_APK_PERF_DATA);
265 ASSERT_TRUE(success);
266 ASSERT_NE(content.find(GetUrlInApk(APK_FILE, NATIVELIB_IN_APK)), std::string::npos);
267 ASSERT_NE(content.find("Func2"), std::string::npos);
268}
269
Yabin Cui19e6b6d2016-03-10 11:49:57 -0800270#if defined(__linux__)
Yabin Cui6e51bef2016-02-23 21:41:03 -0800271
272static std::unique_ptr<Command> RecordCmd() {
273 return CreateCommandInstance("record");
Yabin Cui3c8c2132015-08-13 20:30:20 -0700274}
Yabin Cuib1a885b2016-02-14 19:18:02 -0800275
Yabin Cui6e51bef2016-02-23 21:41:03 -0800276TEST_F(ReportCommandTest, dwarf_callgraph) {
Yabin Cui19e6b6d2016-03-10 11:49:57 -0800277 if (IsDwarfCallChainSamplingSupported()) {
278 TemporaryFile tmp_file;
279 ASSERT_TRUE(RecordCmd()->Run({"-g", "-o", tmp_file.path, "sleep", SLEEP_SEC}));
280 ReportRaw(tmp_file.path, {"-g"});
281 ASSERT_TRUE(success);
282 } else {
283 GTEST_LOG_(INFO)
284 << "This test does nothing as dwarf callchain sampling is not supported on this device.";
285 }
Yabin Cui6e51bef2016-02-23 21:41:03 -0800286}
287
Yabin Cui8f680f62016-03-18 18:47:43 -0700288TEST_F(ReportCommandTest, report_dwarf_callgraph_of_nativelib_in_apk) {
289 // NATIVELIB_IN_APK_PERF_DATA is recorded on arm64, so can only report callgraph on arm64.
290 if (GetBuildArch() == ARCH_ARM64) {
291 Report(NATIVELIB_IN_APK_PERF_DATA, {"-g"});
292 ASSERT_NE(content.find(GetUrlInApk(APK_FILE, NATIVELIB_IN_APK)), std::string::npos);
293 ASSERT_NE(content.find("Func2"), std::string::npos);
294 ASSERT_NE(content.find("Func1"), std::string::npos);
295 ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
296 } else {
297 GTEST_LOG_(INFO) << "This test does nothing as it is only run on arm64 devices";
298 }
299}
300
Yabin Cui6e51bef2016-02-23 21:41:03 -0800301#endif
302