OSDN Git Service

Merge "Crypto performance benchmark" into nyc-dev
[android-x86/system-extras.git] / simpleperf / cmd_report_test.cpp
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 #include <android-base/test_utils.h>
25
26 #include "command.h"
27 #include "get_test_data.h"
28 #include "read_apk.h"
29 #include "test_util.h"
30
31 static std::unique_ptr<Command> ReportCmd() {
32   return CreateCommandInstance("report");
33 }
34
35 class ReportCommandTest : public ::testing::Test {
36  protected:
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);
40   }
41
42   void ReportRaw(const std::string perf_data,
43                  const std::vector<std::string>& add_args = std::vector<std::string>()) {
44     success = false;
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");
52     lines.clear();
53     for (const auto& line : raw_lines) {
54       std::string s = android::base::Trim(line);
55       if (!s.empty()) {
56         lines.push_back(s);
57       }
58     }
59     ASSERT_GE(lines.size(), 2u);
60     success = true;
61   }
62
63   TemporaryFile tmp_file;
64   std::string content;
65   std::vector<std::string> lines;
66   bool success;
67 };
68
69 TEST_F(ReportCommandTest, no_option) {
70   Report(PERF_DATA);
71   ASSERT_TRUE(success);
72   ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
73 }
74
75 TEST_F(ReportCommandTest, sort_option_pid) {
76   Report(PERF_DATA, {"--sort", "pid"});
77   ASSERT_TRUE(success);
78   size_t line_index = 0;
79   while (line_index < lines.size() && lines[line_index].find("Pid") == std::string::npos) {
80     line_index++;
81   }
82   ASSERT_LT(line_index + 2, lines.size());
83 }
84
85 TEST_F(ReportCommandTest, sort_option_more_than_one) {
86   Report(PERF_DATA, {"--sort", "comm,pid,dso,symbol"});
87   ASSERT_TRUE(success);
88   size_t line_index = 0;
89   while (line_index < lines.size() && lines[line_index].find("Overhead") == std::string::npos) {
90     line_index++;
91   }
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);
98 }
99
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) {
105     char name[1024];
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));
109     }
110   }
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);
118 }
119
120 static bool CheckCalleeMode(std::vector<std::string>& lines) {
121   bool found = false;
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) {
126       found = true;
127       break;
128     }
129   }
130   return found;
131 }
132
133 static bool CheckCallerMode(std::vector<std::string>& lines) {
134   bool found = false;
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) {
139       found = true;
140       break;
141     }
142   }
143   return found;
144 }
145
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));
156 }
157
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) {
161     line_index++;
162   }
163   if (line_index == lines.size() || line_index + 1 == lines.size()) {
164     return false;
165   }
166   line_index++;
167   for (; line_index < lines.size(); ++line_index) {
168     bool exist = false;
169     for (auto& s : strs) {
170       if (lines[line_index].find(s) != std::string::npos) {
171         exist = true;
172         break;
173       }
174     }
175     if (!exist) {
176       return false;
177     }
178   }
179   return true;
180 }
181
182 TEST_F(ReportCommandTest, pid_filter_option) {
183   Report(PERF_DATA);
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"}));
193 }
194
195 TEST_F(ReportCommandTest, tid_filter_option) {
196   Report(PERF_DATA);
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"}));
206 }
207
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"}));
219 }
220
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"}));
232 }
233
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) {
242       char from[80];
243       char to[80];
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));
246       }
247     }
248   }
249   ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>("GlobalFunc", "CalledFunc")),
250             hit_set.end());
251   ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>("CalledFunc", "GlobalFunc")),
252             hit_set.end());
253 }
254
255 #if defined(__ANDROID__) || defined(__linux__)
256
257 static std::unique_ptr<Command> RecordCmd() {
258   return CreateCommandInstance("record");
259 }
260
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);
266 }
267
268 #endif
269
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);
275 }