simpleperf: port cmd_report_test to nonlinux.
And fix one build_id bug introduced by previous patch.
Bug: 26962895
Change-Id: Ibb8bd6ec77ee862bb01c26342d3b3024468e75b2
(cherry picked from commit 6e51bef9aa101307523946df301ca90215d0ee82)
diff --git a/simpleperf/Android.mk b/simpleperf/Android.mk
index 5c5642b..36372e9 100644
--- a/simpleperf/Android.mk
+++ b/simpleperf/Android.mk
@@ -176,6 +176,7 @@
# simpleperf_unit_test
# =========================================================
simpleperf_unit_test_src_files := \
+ cmd_report_test.cpp \
command_test.cpp \
gtest_main.cpp \
read_apk_test.cpp \
@@ -187,7 +188,6 @@
cmd_dumprecord_test.cpp \
cmd_list_test.cpp \
cmd_record_test.cpp \
- cmd_report_test.cpp \
cmd_stat_test.cpp \
environment_test.cpp \
record_file_test.cpp \
diff --git a/simpleperf/cmd_dumprecord_test.cpp b/simpleperf/cmd_dumprecord_test.cpp
index f23ae16..574fb2a 100644
--- a/simpleperf/cmd_dumprecord_test.cpp
+++ b/simpleperf/cmd_dumprecord_test.cpp
@@ -17,6 +17,7 @@
#include <gtest/gtest.h>
#include "command.h"
+#include "test_util.h"
class DumpRecordCommandTest : public ::testing::Test {
protected:
@@ -32,11 +33,11 @@
};
TEST_F(DumpRecordCommandTest, no_options) {
- ASSERT_TRUE(record_cmd->Run({"-a", "sleep", "1"}));
+ ASSERT_TRUE(record_cmd->Run({"-a", "sleep", SLEEP_SEC}));
ASSERT_TRUE(dumprecord_cmd->Run({}));
}
TEST_F(DumpRecordCommandTest, record_file_option) {
- ASSERT_TRUE(record_cmd->Run({"-a", "-o", "perf2.data", "sleep", "1"}));
+ ASSERT_TRUE(record_cmd->Run({"-a", "-o", "perf2.data", "sleep", SLEEP_SEC}));
ASSERT_TRUE(dumprecord_cmd->Run({"perf2.data"}));
}
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index ca38a05..6f54fc6 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -32,32 +32,32 @@
}
TEST(record_cmd, no_options) {
- ASSERT_TRUE(RecordCmd()->Run({"sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"sleep", SLEEP_SEC}));
}
TEST(record_cmd, system_wide_option) {
- ASSERT_TRUE(RecordCmd()->Run({"-a", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"-a", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, sample_period_option) {
- ASSERT_TRUE(RecordCmd()->Run({"-c", "100000", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"-c", "100000", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, event_option) {
- ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-clock", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-clock", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, freq_option) {
- ASSERT_TRUE(RecordCmd()->Run({"-f", "99", "sleep", "1"}));
- ASSERT_TRUE(RecordCmd()->Run({"-F", "99", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"-f", "99", "sleep", SLEEP_SEC}));
+ ASSERT_TRUE(RecordCmd()->Run({"-F", "99", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, output_file_option) {
- ASSERT_TRUE(RecordCmd()->Run({"-o", "perf2.data", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"-o", "perf2.data", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, dump_kernel_mmap) {
- ASSERT_TRUE(RecordCmd()->Run({"sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"sleep", SLEEP_SEC}));
std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance("perf.data");
ASSERT_TRUE(reader != nullptr);
std::vector<std::unique_ptr<Record>> records = reader->DataSection();
@@ -76,7 +76,7 @@
}
TEST(record_cmd, dump_build_id_feature) {
- ASSERT_TRUE(RecordCmd()->Run({"sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"sleep", SLEEP_SEC}));
std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance("perf.data");
ASSERT_TRUE(reader != nullptr);
const FileHeader& file_header = reader->FileHeader();
@@ -85,16 +85,16 @@
}
TEST(record_cmd, tracepoint_event) {
- ASSERT_TRUE(RecordCmd()->Run({"-a", "-e", "sched:sched_switch", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"-a", "-e", "sched:sched_switch", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, branch_sampling) {
if (IsBranchSamplingSupported()) {
- ASSERT_TRUE(RecordCmd()->Run({"-a", "-b", "sleep", "1"}));
- ASSERT_TRUE(RecordCmd()->Run({"-j", "any,any_call,any_ret,ind_call", "sleep", "1"}));
- ASSERT_TRUE(RecordCmd()->Run({"-j", "any,k", "sleep", "1"}));
- ASSERT_TRUE(RecordCmd()->Run({"-j", "any,u", "sleep", "1"}));
- ASSERT_FALSE(RecordCmd()->Run({"-j", "u", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"-a", "-b", "sleep", SLEEP_SEC}));
+ ASSERT_TRUE(RecordCmd()->Run({"-j", "any,any_call,any_ret,ind_call", "sleep", SLEEP_SEC}));
+ ASSERT_TRUE(RecordCmd()->Run({"-j", "any,k", "sleep", SLEEP_SEC}));
+ ASSERT_TRUE(RecordCmd()->Run({"-j", "any,u", "sleep", SLEEP_SEC}));
+ ASSERT_FALSE(RecordCmd()->Run({"-j", "u", "sleep", SLEEP_SEC}));
} else {
GTEST_LOG_(INFO)
<< "This test does nothing as branch stack sampling is not supported on this device.";
@@ -102,18 +102,18 @@
}
TEST(record_cmd, event_modifier) {
- ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles:u", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles:u", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, fp_callchain_sampling) {
- ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "fp", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "fp", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, dwarf_callchain_sampling) {
if (IsDwarfCallChainSamplingSupported()) {
- ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "sleep", "1"}));
- ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf,16384", "sleep", "1"}));
- ASSERT_TRUE(RecordCmd()->Run({"-g", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "sleep", SLEEP_SEC}));
+ ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf,16384", "sleep", SLEEP_SEC}));
+ ASSERT_TRUE(RecordCmd()->Run({"-g", "sleep", SLEEP_SEC}));
} else {
GTEST_LOG_(INFO)
<< "This test does nothing as dwarf callchain sampling is not supported on this device.";
@@ -122,24 +122,24 @@
TEST(record_cmd, no_unwind_option) {
if (IsDwarfCallChainSamplingSupported()) {
- ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "--no-unwind", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "--no-unwind", "sleep", SLEEP_SEC}));
} else {
GTEST_LOG_(INFO)
<< "This test does nothing as dwarf callchain sampling is not supported on this device.";
}
- ASSERT_FALSE(RecordCmd()->Run({"--no-unwind", "sleep", "1"}));
+ ASSERT_FALSE(RecordCmd()->Run({"--no-unwind", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, post_unwind_option) {
if (IsDwarfCallChainSamplingSupported()) {
- ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "--post-unwind", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "dwarf", "--post-unwind", "sleep", SLEEP_SEC}));
} else {
GTEST_LOG_(INFO)
<< "This test does nothing as dwarf callchain sampling is not supported on this device.";
}
- ASSERT_FALSE(RecordCmd()->Run({"--post-unwind", "sleep", "1"}));
+ ASSERT_FALSE(RecordCmd()->Run({"--post-unwind", "sleep", SLEEP_SEC}));
ASSERT_FALSE(
- RecordCmd()->Run({"--call-graph", "dwarf", "--no-unwind", "--post-unwind", "sleep", "1"}));
+ RecordCmd()->Run({"--call-graph", "dwarf", "--no-unwind", "--post-unwind", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, existing_processes) {
@@ -164,17 +164,17 @@
}
TEST(record_cmd, more_than_one_event_types) {
- ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles,cpu-clock", "sleep", "1"}));
- ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles", "-e", "cpu-clock", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles,cpu-clock", "sleep", SLEEP_SEC}));
+ ASSERT_TRUE(RecordCmd()->Run({"-e", "cpu-cycles", "-e", "cpu-clock", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, cpu_option) {
- ASSERT_TRUE(RecordCmd()->Run({"--cpu", "0", "sleep", "1"}));
- ASSERT_TRUE(RecordCmd()->Run({"--cpu", "0", "-a", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"--cpu", "0", "sleep", SLEEP_SEC}));
+ ASSERT_TRUE(RecordCmd()->Run({"--cpu", "0", "-a", "sleep", SLEEP_SEC}));
}
TEST(record_cmd, mmap_page_option) {
- ASSERT_TRUE(RecordCmd()->Run({"-m", "1", "sleep", "1"}));
- ASSERT_FALSE(RecordCmd()->Run({"-m", "0", "sleep", "1"}));
- ASSERT_FALSE(RecordCmd()->Run({"-m", "7", "sleep", "1"}));
+ ASSERT_TRUE(RecordCmd()->Run({"-m", "1", "sleep", SLEEP_SEC}));
+ ASSERT_FALSE(RecordCmd()->Run({"-m", "0", "sleep", SLEEP_SEC}));
+ ASSERT_FALSE(RecordCmd()->Run({"-m", "7", "sleep", SLEEP_SEC}));
}
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index afdd9fd..a5ece01 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -16,17 +16,17 @@
#include <gtest/gtest.h>
+#include <set>
+#include <unordered_map>
+
#include <android-base/file.h>
+#include <android-base/strings.h>
#include <android-base/test_utils.h>
#include "command.h"
-#include "event_selection_set.h"
#include "get_test_data.h"
#include "read_apk.h"
-
-static std::unique_ptr<Command> RecordCmd() {
- return CreateCommandInstance("record");
-}
+#include "test_util.h"
static std::unique_ptr<Command> ReportCmd() {
return CreateCommandInstance("report");
@@ -34,86 +34,242 @@
class ReportCommandTest : public ::testing::Test {
protected:
- static void SetUpTestCase() {
- ASSERT_TRUE(RecordCmd()->Run({"-a", "sleep", "1"}));
- ASSERT_TRUE(RecordCmd()->Run({"-a", "-o", "perf2.data", "sleep", "1"}));
- ASSERT_TRUE(RecordCmd()->Run({"--call-graph", "fp", "-o", "perf_g.data", "sleep", "1"}));
+ void Report(const std::string perf_data,
+ const std::vector<std::string>& add_args = std::vector<std::string>()) {
+ ReportRaw(GetTestData(perf_data), add_args);
}
+
+ void ReportRaw(const std::string perf_data,
+ const std::vector<std::string>& add_args = std::vector<std::string>()) {
+ success = false;
+ std::vector<std::string> args = {"-i", perf_data,
+ "--symfs", GetTestDataDir(), "-o", tmp_file.path};
+ args.insert(args.end(), add_args.begin(), add_args.end());
+ ASSERT_TRUE(ReportCmd()->Run(args));
+ ASSERT_TRUE(android::base::ReadFileToString(tmp_file.path, &content));
+ ASSERT_TRUE(!content.empty());
+ std::vector<std::string> raw_lines = android::base::Split(content, "\n");
+ lines.clear();
+ for (const auto& line : raw_lines) {
+ std::string s = android::base::Trim(line);
+ if (!s.empty()) {
+ lines.push_back(s);
+ }
+ }
+ ASSERT_GE(lines.size(), 2u);
+ success = true;
+ }
+
+ TemporaryFile tmp_file;
+ std::string content;
+ std::vector<std::string> lines;
+ bool success;
};
-TEST_F(ReportCommandTest, no_options) {
- ASSERT_TRUE(ReportCmd()->Run({}));
-}
-
-TEST_F(ReportCommandTest, input_file_option) {
- ASSERT_TRUE(ReportCmd()->Run({"-i", "perf2.data"}));
+TEST_F(ReportCommandTest, no_option) {
+ Report(PERF_DATA);
+ ASSERT_TRUE(success);
+ ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
}
TEST_F(ReportCommandTest, sort_option_pid) {
- ASSERT_TRUE(ReportCmd()->Run({"--sort", "pid"}));
+ Report(PERF_DATA, {"--sort", "pid"});
+ ASSERT_TRUE(success);
+ size_t line_index = 0;
+ while (line_index < lines.size() && lines[line_index].find("Pid") == std::string::npos) {
+ line_index++;
+ }
+ ASSERT_LT(line_index + 2, lines.size());
}
-TEST_F(ReportCommandTest, sort_option_all) {
- ASSERT_TRUE(ReportCmd()->Run({"--sort", "comm,pid,dso,symbol"}));
+TEST_F(ReportCommandTest, sort_option_more_than_one) {
+ Report(PERF_DATA, {"--sort", "comm,pid,dso,symbol"});
+ ASSERT_TRUE(success);
+ size_t line_index = 0;
+ while (line_index < lines.size() && lines[line_index].find("Overhead") == std::string::npos) {
+ line_index++;
+ }
+ ASSERT_LT(line_index + 1, lines.size());
+ ASSERT_NE(lines[line_index].find("Command"), std::string::npos);
+ ASSERT_NE(lines[line_index].find("Pid"), std::string::npos);
+ ASSERT_NE(lines[line_index].find("Shared Object"), std::string::npos);
+ ASSERT_NE(lines[line_index].find("Symbol"), std::string::npos);
+ ASSERT_EQ(lines[line_index].find("Tid"), std::string::npos);
}
TEST_F(ReportCommandTest, children_option) {
- ASSERT_TRUE(ReportCmd()->Run({"--children", "-i", "perf_g.data"}));
+ Report(CALLGRAPH_FP_PERF_DATA, {"--children", "--sort", "symbol"});
+ ASSERT_TRUE(success);
+ std::unordered_map<std::string, std::pair<double, double>> map;
+ for (size_t i = 0; i < lines.size(); ++i) {
+ char name[1024];
+ std::pair<double, double> pair;
+ if (sscanf(lines[i].c_str(), "%lf%%%lf%%%s", &pair.first, &pair.second, name) == 3) {
+ map.insert(std::make_pair(name, pair));
+ }
+ }
+ ASSERT_NE(map.find("GlobalFunc"), map.end());
+ ASSERT_NE(map.find("main"), map.end());
+ auto func_pair = map["GlobalFunc"];
+ auto main_pair = map["main"];
+ ASSERT_GE(main_pair.first, func_pair.first);
+ ASSERT_GE(func_pair.first, func_pair.second);
+ ASSERT_GE(func_pair.second, main_pair.second);
+}
+
+static bool CheckCalleeMode(std::vector<std::string>& lines) {
+ bool found = false;
+ for (size_t i = 0; i + 2 < lines.size(); ++i) {
+ if (lines[i].find("GlobalFunc") != std::string::npos &&
+ lines[i + 1].find("|") != std::string::npos &&
+ lines[i + 2].find("main") != std::string::npos) {
+ found = true;
+ break;
+ }
+ }
+ return found;
+}
+
+static bool CheckCallerMode(std::vector<std::string>& lines) {
+ bool found = false;
+ for (size_t i = 0; i + 2 < lines.size(); ++i) {
+ if (lines[i].find("main") != std::string::npos &&
+ lines[i + 1].find("|") != std::string::npos &&
+ lines[i + 2].find("GlobalFunc") != std::string::npos) {
+ found = true;
+ break;
+ }
+ }
+ return found;
}
TEST_F(ReportCommandTest, callgraph_option) {
- ASSERT_TRUE(ReportCmd()->Run({"-g", "-i", "perf_g.data"}));
- ASSERT_TRUE(ReportCmd()->Run({"-g", "callee", "-i", "perf_g.data"}));
- ASSERT_TRUE(ReportCmd()->Run({"-g", "caller", "-i", "perf_g.data"}));
+ Report(CALLGRAPH_FP_PERF_DATA, {"-g"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(CheckCalleeMode(lines));
+ Report(CALLGRAPH_FP_PERF_DATA, {"-g", "callee"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(CheckCalleeMode(lines));
+ Report(CALLGRAPH_FP_PERF_DATA, {"-g", "caller"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(CheckCallerMode(lines));
+}
+
+static bool AllItemsWithString(std::vector<std::string>& lines, const std::vector<std::string>& strs) {
+ size_t line_index = 0;
+ while (line_index < lines.size() && lines[line_index].find("Overhead") == std::string::npos) {
+ line_index++;
+ }
+ if (line_index == lines.size() || line_index + 1 == lines.size()) {
+ return false;
+ }
+ line_index++;
+ for (; line_index < lines.size(); ++line_index) {
+ bool exist = false;
+ for (auto& s : strs) {
+ if (lines[line_index].find(s) != std::string::npos) {
+ exist = true;
+ break;
+ }
+ }
+ if (!exist) {
+ return false;
+ }
+ }
+ return true;
}
TEST_F(ReportCommandTest, pid_filter_option) {
- ASSERT_TRUE(ReportCmd()->Run({"--pids", "0"}));
- ASSERT_TRUE(ReportCmd()->Run({"--pids", "0,1"}));
+ Report(PERF_DATA);
+ ASSERT_TRUE("success");
+ ASSERT_FALSE(AllItemsWithString(lines, {"26083"}));
+ ASSERT_FALSE(AllItemsWithString(lines, {"26083", "26090"}));
+ Report(PERF_DATA, {"--pids", "26083"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(AllItemsWithString(lines, {"26083"}));
+ Report(PERF_DATA, {"--pids", "26083,26090"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(AllItemsWithString(lines, {"26083", "26090"}));
}
TEST_F(ReportCommandTest, tid_filter_option) {
- ASSERT_TRUE(ReportCmd()->Run({"--tids", "0"}));
- ASSERT_TRUE(ReportCmd()->Run({"--tids", "0,1"}));
+ Report(PERF_DATA);
+ ASSERT_TRUE("success");
+ ASSERT_FALSE(AllItemsWithString(lines, {"26083"}));
+ ASSERT_FALSE(AllItemsWithString(lines, {"26083", "26090"}));
+ Report(PERF_DATA, {"--tids", "26083"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(AllItemsWithString(lines, {"26083"}));
+ Report(PERF_DATA, {"--tids", "26083,26090"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(AllItemsWithString(lines, {"26083", "26090"}));
}
TEST_F(ReportCommandTest, comm_filter_option) {
- ASSERT_TRUE(ReportCmd()->Run({"--comms", "swapper"}));
- ASSERT_TRUE(ReportCmd()->Run({"--comms", "swapper,simpleperf"}));
+ Report(PERF_DATA, {"--sort", "comm"});
+ ASSERT_TRUE(success);
+ ASSERT_FALSE(AllItemsWithString(lines, {"t1"}));
+ ASSERT_FALSE(AllItemsWithString(lines, {"t1", "t2"}));
+ Report(PERF_DATA, {"--sort", "comm", "--comms", "t1"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(AllItemsWithString(lines, {"t1"}));
+ Report(PERF_DATA, {"--sort", "comm", "--comms", "t1,t2"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(AllItemsWithString(lines, {"t1", "t2"}));
}
TEST_F(ReportCommandTest, dso_filter_option) {
- ASSERT_TRUE(ReportCmd()->Run({"--dsos", "[kernel.kallsyms]"}));
- ASSERT_TRUE(ReportCmd()->Run({"--dsos", "[kernel.kallsyms],/init"}));
+ Report(PERF_DATA, {"--sort", "dso"});
+ ASSERT_TRUE(success);
+ ASSERT_FALSE(AllItemsWithString(lines, {"/t1"}));
+ ASSERT_FALSE(AllItemsWithString(lines, {"/t1", "/t2"}));
+ Report(PERF_DATA, {"--sort", "dso", "--dsos", "/t1"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(AllItemsWithString(lines, {"/t1"}));
+ Report(PERF_DATA, {"--sort", "dso", "--dsos", "/t1,/t2"});
+ ASSERT_TRUE(success);
+ ASSERT_TRUE(AllItemsWithString(lines, {"/t1", "/t2"}));
}
-TEST(report_cmd, use_branch_address) {
- if (IsBranchSamplingSupported()) {
- ASSERT_TRUE(RecordCmd()->Run({"-b", "sleep", "1"}));
- ASSERT_TRUE(
- ReportCmd()->Run({"-b", "--sort", "comm,pid,dso_from,symbol_from,dso_to,symbol_to"}));
- } else {
- GTEST_LOG_(INFO)
- << "This test does nothing as branch stack sampling is not supported on this device.";
+TEST_F(ReportCommandTest, use_branch_address) {
+ Report(BRANCH_PERF_DATA, {"-b", "--sort", "symbol_from,symbol_to"});
+ std::set<std::pair<std::string, std::string>> hit_set;
+ bool after_overhead = false;
+ for (const auto& line : lines) {
+ if (!after_overhead && line.find("Overhead") != std::string::npos) {
+ after_overhead = true;
+ } else if (after_overhead) {
+ char from[80];
+ char to[80];
+ if (sscanf(line.c_str(), "%*f%%%s%s", from, to) == 2) {
+ hit_set.insert(std::make_pair<std::string, std::string>(from, to));
+ }
+ }
}
+ ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>("GlobalFunc", "CalledFunc")),
+ hit_set.end());
+ ASSERT_NE(hit_set.find(std::make_pair<std::string, std::string>("CalledFunc", "GlobalFunc")),
+ hit_set.end());
}
-TEST(report_cmd, dwarf_callgraph) {
- if (IsDwarfCallChainSamplingSupported()) {
- ASSERT_TRUE(RecordCmd()->Run({"-g", "-o", "perf_dwarf.data", "sleep", "1"}));
- ASSERT_TRUE(ReportCmd()->Run({"-g", "-i", "perf_dwarf.data"}));
- } else {
- GTEST_LOG_(INFO)
- << "This test does nothing as dwarf callchain sampling is not supported on this device.";
- }
+#if defined(__ANDROID__) || defined(__linux__)
+
+static std::unique_ptr<Command> RecordCmd() {
+ return CreateCommandInstance("record");
}
-TEST(report_cmd, report_symbols_of_nativelib_in_apk) {
+TEST_F(ReportCommandTest, dwarf_callgraph) {
TemporaryFile tmp_file;
- ASSERT_TRUE(ReportCmd()->Run({"-i", GetTestData(NATIVELIB_IN_APK_PERF_DATA),
- "--symfs", GetTestDataDir(), "-o", tmp_file.path}));
- std::string content;
- ASSERT_TRUE(android::base::ReadFileToString(tmp_file.path, &content));
+ ASSERT_TRUE(RecordCmd()->Run({"-g", "-o", tmp_file.path, "sleep", SLEEP_SEC}));
+ ReportRaw(tmp_file.path, {"-g"});
+ ASSERT_TRUE(success);
+}
+
+#endif
+
+TEST_F(ReportCommandTest, report_symbols_of_nativelib_in_apk) {
+ Report(NATIVELIB_IN_APK_PERF_DATA);
+ ASSERT_TRUE(success);
ASSERT_NE(content.find(GetUrlInApk(APK_FILE, NATIVELIB_IN_APK)), std::string::npos);
ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
}
diff --git a/simpleperf/get_test_data.h b/simpleperf/get_test_data.h
index bceedc0..00d1a0b 100644
--- a/simpleperf/get_test_data.h
+++ b/simpleperf/get_test_data.h
@@ -24,6 +24,12 @@
std::string GetTestData(const std::string& filename);
const std::string& GetTestDataDir();
+static const std::string PERF_DATA = "perf.data";
+static const std::string CALLGRAPH_FP_PERF_DATA = "perf_g_fp.data";
+static const std::string BRANCH_PERF_DATA = "perf_b.data";
+
+static const std::string ELF_FILE = "elf";
+
static const std::string APK_FILE = "data/app/com.example.hellojni-1/base.apk";
static const std::string NATIVELIB_IN_APK = "lib/arm64-v8a/libhello-jni.so";
static const std::string NATIVELIB_IN_APK_PERF_DATA = "has_embedded_native_libs_apk_perf.data";
@@ -31,7 +37,7 @@
constexpr size_t NATIVELIB_OFFSET_IN_APK = 0x8000;
constexpr size_t NATIVELIB_SIZE_IN_APK = 0x15d8;
-static BuildId elf_file_build_id("7600329e31058e12b145d153ef27cd40e1a5f7b9");
+static BuildId elf_file_build_id("0b12a384a9f4a3f3659b7171ca615dbec3a81f71");
static BuildId native_lib_build_id("b46f51cb9c4b71fb08a2fdbefc2c187894f14008");
diff --git a/simpleperf/read_apk_test.cpp b/simpleperf/read_apk_test.cpp
index aeedbbe..e983a25 100644
--- a/simpleperf/read_apk_test.cpp
+++ b/simpleperf/read_apk_test.cpp
@@ -23,7 +23,7 @@
TEST(read_apk, IsValidApkPath) {
ASSERT_FALSE(IsValidApkPath("/dev/zero"));
- ASSERT_FALSE(IsValidApkPath(GetTestData("elf_file")));
+ ASSERT_FALSE(IsValidApkPath(GetTestData(ELF_FILE)));
ASSERT_TRUE(IsValidApkPath(GetTestData(APK_FILE)));
}
diff --git a/simpleperf/read_elf.cpp b/simpleperf/read_elf.cpp
index e66e68e..6551629 100644
--- a/simpleperf/read_elf.cpp
+++ b/simpleperf/read_elf.cpp
@@ -184,7 +184,9 @@
if (!IsValidElfPath(filename)) {
return false;
}
- return GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id);
+ bool result = GetBuildIdFromEmbeddedElfFile(filename, 0, 0, build_id);
+ LOG(VERBOSE) << "GetBuildIdFromElfFile(" << filename << ") => " << build_id->ToString();
+ return result;
}
bool GetBuildIdFromEmbeddedElfFile(const std::string& filename, uint64_t file_offset,
diff --git a/simpleperf/read_elf_test.cpp b/simpleperf/read_elf_test.cpp
index 920da27..929540f 100644
--- a/simpleperf/read_elf_test.cpp
+++ b/simpleperf/read_elf_test.cpp
@@ -23,7 +23,7 @@
TEST(read_elf, GetBuildIdFromElfFile) {
BuildId build_id;
- ASSERT_TRUE(GetBuildIdFromElfFile(GetTestData("elf_file"), &build_id));
+ ASSERT_TRUE(GetBuildIdFromElfFile(GetTestData(ELF_FILE), &build_id));
ASSERT_EQ(build_id, BuildId(elf_file_build_id));
}
@@ -50,14 +50,14 @@
TEST(read_elf, parse_symbols_from_elf_file_with_correct_build_id) {
std::map<std::string, ElfFileSymbol> symbols;
- ASSERT_TRUE(ParseSymbolsFromElfFile(GetTestData("elf_file"), elf_file_build_id,
+ ASSERT_TRUE(ParseSymbolsFromElfFile(GetTestData(ELF_FILE), elf_file_build_id,
std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
CheckElfFileSymbols(symbols);
}
TEST(read_elf, parse_symbols_from_elf_file_without_build_id) {
std::map<std::string, ElfFileSymbol> symbols;
- ASSERT_TRUE(ParseSymbolsFromElfFile(GetTestData("elf_file"), BuildId(),
+ ASSERT_TRUE(ParseSymbolsFromElfFile(GetTestData(ELF_FILE), BuildId(),
std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
CheckElfFileSymbols(symbols);
}
@@ -65,7 +65,7 @@
TEST(read_elf, parse_symbols_from_elf_file_with_wrong_build_id) {
BuildId build_id("01010101010101010101");
std::map<std::string, ElfFileSymbol> symbols;
- ASSERT_FALSE(ParseSymbolsFromElfFile(GetTestData("elf_file"), build_id,
+ ASSERT_FALSE(ParseSymbolsFromElfFile(GetTestData(ELF_FILE), build_id,
std::bind(ParseSymbol, std::placeholders::_1, &symbols)));
}
@@ -87,5 +87,5 @@
TEST(read_elf, IsValidElfPath) {
ASSERT_FALSE(IsValidElfPath("/dev/zero"));
ASSERT_FALSE(IsValidElfPath("/sys/devices/system/cpu/online"));
- ASSERT_TRUE(IsValidElfPath(GetTestData("elf_file")));
+ ASSERT_TRUE(IsValidElfPath(GetTestData(ELF_FILE)));
}
diff --git a/simpleperf/record.cpp b/simpleperf/record.cpp
index 660634c..5c048fb 100644
--- a/simpleperf/record.cpp
+++ b/simpleperf/record.cpp
@@ -534,7 +534,7 @@
const char* p = reinterpret_cast<const char*>(pheader + 1);
const char* end = reinterpret_cast<const char*>(pheader) + pheader->size;
MoveFromBinaryFormat(pid, p);
- build_id = BuildId(p);
+ build_id = BuildId(p, BUILD_ID_SIZE);
p += ALIGN(build_id.Size(), 8);
filename = p;
p += ALIGN(filename.size() + 1, 64);
diff --git a/simpleperf/test_util.h b/simpleperf/test_util.h
index 734a48b..cfbe493 100644
--- a/simpleperf/test_util.h
+++ b/simpleperf/test_util.h
@@ -15,10 +15,13 @@
*/
#include <map>
+#include <string>
#include "read_elf.h"
#include "workload.h"
+static const std::string SLEEP_SEC = "0.001";
+
void CreateProcesses(size_t count, std::vector<std::unique_ptr<Workload>>* workloads);
void ParseSymbol(const ElfFileSymbol& symbol, std::map<std::string, ElfFileSymbol>* symbols);
diff --git a/simpleperf/testdata/elf b/simpleperf/testdata/elf
new file mode 100644
index 0000000..f63c25c
--- /dev/null
+++ b/simpleperf/testdata/elf
Binary files differ
diff --git a/simpleperf/testdata/elf_file b/simpleperf/testdata/elf_file
deleted file mode 100644
index 53b589a..0000000
--- a/simpleperf/testdata/elf_file
+++ /dev/null
Binary files differ
diff --git a/simpleperf/testdata/elf_file_source.cpp b/simpleperf/testdata/elf_file_source.cpp
new file mode 100644
index 0000000..3cfd00b
--- /dev/null
+++ b/simpleperf/testdata/elf_file_source.cpp
@@ -0,0 +1,20 @@
+#include <pthread.h>
+
+volatile int GlobalVar;
+
+extern "C" void CalledFunc() {
+ GlobalVar++;
+}
+
+extern "C" void GlobalFunc() {
+ for (int i = 0; i < 1000000; ++i) {
+ CalledFunc();
+ }
+}
+
+int main() {
+ while (true) {
+ GlobalFunc();
+ }
+ return 0;
+}
diff --git a/simpleperf/testdata/perf.data b/simpleperf/testdata/perf.data
new file mode 100644
index 0000000..64a59da
--- /dev/null
+++ b/simpleperf/testdata/perf.data
Binary files differ
diff --git a/simpleperf/testdata/perf_b.data b/simpleperf/testdata/perf_b.data
new file mode 100644
index 0000000..e514944
--- /dev/null
+++ b/simpleperf/testdata/perf_b.data
Binary files differ
diff --git a/simpleperf/testdata/perf_g_fp.data b/simpleperf/testdata/perf_g_fp.data
new file mode 100644
index 0000000..de9cf53
--- /dev/null
+++ b/simpleperf/testdata/perf_g_fp.data
Binary files differ