2 * Copyright (C) 2015 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <gtest/gtest.h>
20 #include <unordered_map>
22 #include <android-base/file.h>
23 #include <android-base/strings.h>
24 #include <android-base/test_utils.h>
27 #include "get_test_data.h"
29 #include "test_util.h"
31 static std::unique_ptr<Command> ReportCmd() {
32 return CreateCommandInstance("report");
35 class ReportCommandTest : public ::testing::Test {
37 void Report(const std::string perf_data,
38 const std::vector<std::string>& add_args = std::vector<std::string>()) {
39 ReportRaw(GetTestData(perf_data), add_args);
42 void ReportRaw(const std::string perf_data,
43 const std::vector<std::string>& add_args = std::vector<std::string>()) {
45 std::vector<std::string> args = {"-i", perf_data,
46 "--symfs", GetTestDataDir(), "-o", tmp_file.path};
47 args.insert(args.end(), add_args.begin(), add_args.end());
48 ASSERT_TRUE(ReportCmd()->Run(args));
49 ASSERT_TRUE(android::base::ReadFileToString(tmp_file.path, &content));
50 ASSERT_TRUE(!content.empty());
51 std::vector<std::string> raw_lines = android::base::Split(content, "\n");
53 for (const auto& line : raw_lines) {
54 std::string s = android::base::Trim(line);
59 ASSERT_GE(lines.size(), 2u);
63 TemporaryFile tmp_file;
65 std::vector<std::string> lines;
69 TEST_F(ReportCommandTest, no_option) {
72 ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
75 TEST_F(ReportCommandTest, sort_option_pid) {
76 Report(PERF_DATA, {"--sort", "pid"});
78 size_t line_index = 0;
79 while (line_index < lines.size() && lines[line_index].find("Pid") == std::string::npos) {
82 ASSERT_LT(line_index + 2, lines.size());
85 TEST_F(ReportCommandTest, sort_option_more_than_one) {
86 Report(PERF_DATA, {"--sort", "comm,pid,dso,symbol"});
88 size_t line_index = 0;
89 while (line_index < lines.size() && lines[line_index].find("Overhead") == std::string::npos) {
92 ASSERT_LT(line_index + 1, lines.size());
93 ASSERT_NE(lines[line_index].find("Command"), std::string::npos);
94 ASSERT_NE(lines[line_index].find("Pid"), std::string::npos);
95 ASSERT_NE(lines[line_index].find("Shared Object"), std::string::npos);
96 ASSERT_NE(lines[line_index].find("Symbol"), std::string::npos);
97 ASSERT_EQ(lines[line_index].find("Tid"), std::string::npos);
100 TEST_F(ReportCommandTest, children_option) {
101 Report(CALLGRAPH_FP_PERF_DATA, {"--children", "--sort", "symbol"});
102 ASSERT_TRUE(success);
103 std::unordered_map<std::string, std::pair<double, double>> map;
104 for (size_t i = 0; i < lines.size(); ++i) {
106 std::pair<double, double> pair;
107 if (sscanf(lines[i].c_str(), "%lf%%%lf%%%s", &pair.first, &pair.second, name) == 3) {
108 map.insert(std::make_pair(name, pair));
111 ASSERT_NE(map.find("GlobalFunc"), map.end());
112 ASSERT_NE(map.find("main"), map.end());
113 auto func_pair = map["GlobalFunc"];
114 auto main_pair = map["main"];
115 ASSERT_GE(main_pair.first, func_pair.first);
116 ASSERT_GE(func_pair.first, func_pair.second);
117 ASSERT_GE(func_pair.second, main_pair.second);
120 static bool CheckCalleeMode(std::vector<std::string>& lines) {
122 for (size_t i = 0; i + 2 < lines.size(); ++i) {
123 if (lines[i].find("GlobalFunc") != std::string::npos &&
124 lines[i + 1].find("|") != std::string::npos &&
125 lines[i + 2].find("main") != std::string::npos) {
133 static bool CheckCallerMode(std::vector<std::string>& lines) {
135 for (size_t i = 0; i + 2 < lines.size(); ++i) {
136 if (lines[i].find("main") != std::string::npos &&
137 lines[i + 1].find("|") != std::string::npos &&
138 lines[i + 2].find("GlobalFunc") != std::string::npos) {
146 TEST_F(ReportCommandTest, callgraph_option) {
147 Report(CALLGRAPH_FP_PERF_DATA, {"-g"});
148 ASSERT_TRUE(success);
149 ASSERT_TRUE(CheckCalleeMode(lines));
150 Report(CALLGRAPH_FP_PERF_DATA, {"-g", "callee"});
151 ASSERT_TRUE(success);
152 ASSERT_TRUE(CheckCalleeMode(lines));
153 Report(CALLGRAPH_FP_PERF_DATA, {"-g", "caller"});
154 ASSERT_TRUE(success);
155 ASSERT_TRUE(CheckCallerMode(lines));
158 static bool AllItemsWithString(std::vector<std::string>& lines, const std::vector<std::string>& strs) {
159 size_t line_index = 0;
160 while (line_index < lines.size() && lines[line_index].find("Overhead") == std::string::npos) {
163 if (line_index == lines.size() || line_index + 1 == lines.size()) {
167 for (; line_index < lines.size(); ++line_index) {
169 for (auto& s : strs) {
170 if (lines[line_index].find(s) != std::string::npos) {
182 TEST_F(ReportCommandTest, pid_filter_option) {
184 ASSERT_TRUE("success");
185 ASSERT_FALSE(AllItemsWithString(lines, {"26083"}));
186 ASSERT_FALSE(AllItemsWithString(lines, {"26083", "26090"}));
187 Report(PERF_DATA, {"--pids", "26083"});
188 ASSERT_TRUE(success);
189 ASSERT_TRUE(AllItemsWithString(lines, {"26083"}));
190 Report(PERF_DATA, {"--pids", "26083,26090"});
191 ASSERT_TRUE(success);
192 ASSERT_TRUE(AllItemsWithString(lines, {"26083", "26090"}));
195 TEST_F(ReportCommandTest, tid_filter_option) {
197 ASSERT_TRUE("success");
198 ASSERT_FALSE(AllItemsWithString(lines, {"26083"}));
199 ASSERT_FALSE(AllItemsWithString(lines, {"26083", "26090"}));
200 Report(PERF_DATA, {"--tids", "26083"});
201 ASSERT_TRUE(success);
202 ASSERT_TRUE(AllItemsWithString(lines, {"26083"}));
203 Report(PERF_DATA, {"--tids", "26083,26090"});
204 ASSERT_TRUE(success);
205 ASSERT_TRUE(AllItemsWithString(lines, {"26083", "26090"}));
208 TEST_F(ReportCommandTest, comm_filter_option) {
209 Report(PERF_DATA, {"--sort", "comm"});
210 ASSERT_TRUE(success);
211 ASSERT_FALSE(AllItemsWithString(lines, {"t1"}));
212 ASSERT_FALSE(AllItemsWithString(lines, {"t1", "t2"}));
213 Report(PERF_DATA, {"--sort", "comm", "--comms", "t1"});
214 ASSERT_TRUE(success);
215 ASSERT_TRUE(AllItemsWithString(lines, {"t1"}));
216 Report(PERF_DATA, {"--sort", "comm", "--comms", "t1,t2"});
217 ASSERT_TRUE(success);
218 ASSERT_TRUE(AllItemsWithString(lines, {"t1", "t2"}));
221 TEST_F(ReportCommandTest, dso_filter_option) {
222 Report(PERF_DATA, {"--sort", "dso"});
223 ASSERT_TRUE(success);
224 ASSERT_FALSE(AllItemsWithString(lines, {"/t1"}));
225 ASSERT_FALSE(AllItemsWithString(lines, {"/t1", "/t2"}));
226 Report(PERF_DATA, {"--sort", "dso", "--dsos", "/t1"});
227 ASSERT_TRUE(success);
228 ASSERT_TRUE(AllItemsWithString(lines, {"/t1"}));
229 Report(PERF_DATA, {"--sort", "dso", "--dsos", "/t1,/t2"});
230 ASSERT_TRUE(success);
231 ASSERT_TRUE(AllItemsWithString(lines, {"/t1", "/t2"}));
234 TEST_F(ReportCommandTest, use_branch_address) {
235 Report(BRANCH_PERF_DATA, {"-b", "--sort", "symbol_from,symbol_to"});
236 std::set<std::pair<std::string, std::string>> hit_set;
237 bool after_overhead = false;
238 for (const auto& line : lines) {
239 if (!after_overhead && line.find("Overhead") != std::string::npos) {
240 after_overhead = true;
241 } else if (after_overhead) {
244 if (sscanf(line.c_str(), "%*f%%%s%s", from, to) == 2) {
245 hit_set.insert(std::make_pair<std::string, std::string>(from, to));
249 ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>("GlobalFunc", "CalledFunc")),
251 ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>("CalledFunc", "GlobalFunc")),
255 #if defined(__ANDROID__) || defined(__linux__)
257 static std::unique_ptr<Command> RecordCmd() {
258 return CreateCommandInstance("record");
261 TEST_F(ReportCommandTest, dwarf_callgraph) {
262 TemporaryFile tmp_file;
263 ASSERT_TRUE(RecordCmd()->Run({"-g", "-o", tmp_file.path, "sleep", SLEEP_SEC}));
264 ReportRaw(tmp_file.path, {"-g"});
265 ASSERT_TRUE(success);
270 TEST_F(ReportCommandTest, report_symbols_of_nativelib_in_apk) {
271 Report(NATIVELIB_IN_APK_PERF_DATA);
272 ASSERT_TRUE(success);
273 ASSERT_NE(content.find(GetUrlInApk(APK_FILE, NATIVELIB_IN_APK)), std::string::npos);
274 ASSERT_NE(content.find("GlobalFunc"), std::string::npos);