summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--simpleperf/cmd_report_test.cpp27
-rw-r--r--simpleperf/get_test_data.h38
-rw-r--r--simpleperf/gtest_main.cpp15
-rw-r--r--simpleperf/main.cpp16
-rw-r--r--simpleperf/read_apk.cpp4
-rw-r--r--simpleperf/read_apk_test.cpp7
-rw-r--r--simpleperf/testdata/data/app/com.example.hellojni-1/base.apkbin89200 -> 6599967 bytes
-rw-r--r--simpleperf/testdata/has_embedded_native_libs_apk_perf.databin46988 -> 487976 bytes
-rw-r--r--simpleperf/utils.cpp17
-rw-r--r--simpleperf/utils.h4
10 files changed, 96 insertions, 32 deletions
diff --git a/simpleperf/cmd_report_test.cpp b/simpleperf/cmd_report_test.cpp
index bf1ff469..a4bd6f39 100644
--- a/simpleperf/cmd_report_test.cpp
+++ b/simpleperf/cmd_report_test.cpp
@@ -26,6 +26,7 @@
#include "command.h"
#include "event_selection_set.h"
#include "get_test_data.h"
+#include "perf_regs.h"
#include "read_apk.h"
#include "test_util.h"
@@ -259,6 +260,13 @@ TEST_F(ReportCommandTest, use_branch_address) {
hit_set.end());
}
+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("Func2"), std::string::npos);
+}
+
#if defined(__linux__)
static std::unique_ptr<Command> RecordCmd() {
@@ -277,11 +285,18 @@ TEST_F(ReportCommandTest, dwarf_callgraph) {
}
}
+TEST_F(ReportCommandTest, report_dwarf_callgraph_of_nativelib_in_apk) {
+ // NATIVELIB_IN_APK_PERF_DATA is recorded on arm64, so can only report callgraph on arm64.
+ if (GetBuildArch() == ARCH_ARM64) {
+ Report(NATIVELIB_IN_APK_PERF_DATA, {"-g"});
+ ASSERT_NE(content.find(GetUrlInApk(APK_FILE, NATIVELIB_IN_APK)), std::string::npos);
+ ASSERT_NE(content.find("Func2"), std::string::npos);
+ ASSERT_NE(content.find("Func1"), std::string::npos);
+ ASSERT_NE(content.find("GlobalFunc"), std::string::npos);
+ } else {
+ GTEST_LOG_(INFO) << "This test does nothing as it is only run on arm64 devices";
+ }
+}
+
#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 e485e7b9..c380a7de 100644
--- a/simpleperf/get_test_data.h
+++ b/simpleperf/get_test_data.h
@@ -26,23 +26,45 @@ const std::string& GetTestDataDir();
bool IsRoot();
+// The source code of elf and elf_with_mini_debug_info is testdata/elf_file_source.cpp.
+static const std::string ELF_FILE = "elf";
+static const std::string ELF_FILE_WITH_MINI_DEBUG_INFO = "elf_with_mini_debug_info";
+// perf.data is generated by sampling on three processes running different
+// executables: elf, t1, t2 (all generated by elf_file_source.cpp, but with different
+// executable name).
static const std::string PERF_DATA = "perf.data";
+// perf_g_fp.data is generated by sampling on one process running elf using --call-graph fp option.
static const std::string CALLGRAPH_FP_PERF_DATA = "perf_g_fp.data";
+// perf_b.data is generated by sampling on one process running elf using -b option.
static const std::string BRANCH_PERF_DATA = "perf_b.data";
+// perf_with_mini_debug_info.data is generated by sampling on one process running
+// elf_with_mini_debug_info.
static const std::string PERF_DATA_WITH_MINI_DEBUG_INFO = "perf_with_mini_debug_info.data";
-static const std::string ELF_FILE = "elf";
-static const std::string ELF_FILE_WITH_MINI_DEBUG_INFO = "elf_with_mini_debug_info";
+static BuildId elf_file_build_id("0b12a384a9f4a3f3659b7171ca615dbec3a81f71");
+
+// To generate apk supporting execution on shared libraries in apk:
+// 1. Add android:extractNativeLibs=false in AndroidManifest.xml.
+// 2. Use `zip -0` to store native libraries in apk without compression.
+// 3. Use `zipalign -p 4096` to make native libraries in apk start at page boundaries.
+//
+// The logical in libhello-jni.so is as below:
+// volatile int GlobalVar;
+//
+// while (true) {
+// GlobalFunc() -> Func1() -> Func2()
+// }
+// And most time is spent in Func2().
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";
+// has_embedded_native_libs_apk_perf.data is generated by sampling on one process running
+// APK_FILE using -g --no-unwind option.
static const std::string NATIVELIB_IN_APK_PERF_DATA = "has_embedded_native_libs_apk_perf.data";
+// The offset and size info are extracted from the generated apk file to run read_apk tests.
+constexpr size_t NATIVELIB_OFFSET_IN_APK = 0x639000;
+constexpr size_t NATIVELIB_SIZE_IN_APK = 0x1678;
-constexpr size_t NATIVELIB_OFFSET_IN_APK = 0x8000;
-constexpr size_t NATIVELIB_SIZE_IN_APK = 0x15d8;
-
-static BuildId elf_file_build_id("0b12a384a9f4a3f3659b7171ca615dbec3a81f71");
-
-static BuildId native_lib_build_id("b46f51cb9c4b71fb08a2fdbefc2c187894f14008");
+static BuildId native_lib_build_id("8ed5755a7fdc07586ca228b8ee21621bce2c7a97");
#endif // SIMPLE_PERF_GET_TEST_DATA_H_
diff --git a/simpleperf/gtest_main.cpp b/simpleperf/gtest_main.cpp
index 099bd81b..1d0a5c9e 100644
--- a/simpleperf/gtest_main.cpp
+++ b/simpleperf/gtest_main.cpp
@@ -59,6 +59,7 @@ static bool ExtractTestDataFromElfSection() {
LOG(ERROR) << "failed to start iterating zip entries";
return false;
}
+ std::unique_ptr<void, decltype(&EndIteration)> guard(cookie, EndIteration);
ZipEntry entry;
ZipString name;
while (Next(cookie, &entry, &name) == 0) {
@@ -87,7 +88,6 @@ static bool ExtractTestDataFromElfSection() {
return false;
}
}
- EndIteration(cookie);
return true;
}
#endif // defined(__ANDROID__)
@@ -95,13 +95,26 @@ static bool ExtractTestDataFromElfSection() {
int main(int argc, char** argv) {
InitLogging(argv, android::base::StderrLogger);
testing::InitGoogleTest(&argc, argv);
+ android::base::LogSeverity log_severity = android::base::WARNING;
for (int i = 1; i < argc; ++i) {
if (strcmp(argv[i], "-t") == 0 && i + 1 < argc) {
testdata_dir = argv[i + 1];
i++;
+ } else if (strcmp(argv[i], "--log") == 0) {
+ if (i + 1 < argc) {
+ ++i;
+ if (!GetLogSeverity(argv[i], &log_severity)) {
+ LOG(ERROR) << "Unknown log severity: " << argv[i];
+ return 1;
+ }
+ } else {
+ LOG(ERROR) << "Missing argument for --log option.\n";
+ return 1;
+ }
}
}
+ android::base::ScopedLogSeverity severity(log_severity);
#if defined(__ANDROID__)
std::unique_ptr<TemporaryDir> tmp_dir;
diff --git a/simpleperf/main.cpp b/simpleperf/main.cpp
index 75313a54..0a73c2db 100644
--- a/simpleperf/main.cpp
+++ b/simpleperf/main.cpp
@@ -15,21 +15,14 @@
*/
#include <string.h>
-#include <map>
+
#include <string>
#include <vector>
#include <android-base/logging.h>
#include "command.h"
-
-static std::map<std::string, android::base::LogSeverity> log_severity_map = {
- {"verbose", android::base::VERBOSE},
- {"debug", android::base::DEBUG},
- {"warning", android::base::WARNING},
- {"error", android::base::ERROR},
- {"fatal", android::base::FATAL},
-};
+#include "utils.h"
int main(int argc, char** argv) {
InitLogging(argv, android::base::StderrLogger);
@@ -42,10 +35,7 @@ int main(int argc, char** argv) {
} else if (strcmp(argv[i], "--log") == 0) {
if (i + 1 < argc) {
++i;
- auto it = log_severity_map.find(argv[i]);
- if (it != log_severity_map.end()) {
- log_severity = it->second;
- } else {
+ if (!GetLogSeverity(argv[i], &log_severity)) {
LOG(ERROR) << "Unknown log severity: " << argv[i];
return 1;
}
diff --git a/simpleperf/read_apk.cpp b/simpleperf/read_apk.cpp
index 18c76c23..af72cdf8 100644
--- a/simpleperf/read_apk.cpp
+++ b/simpleperf/read_apk.cpp
@@ -24,10 +24,11 @@
#include <sys/types.h>
#include <unistd.h>
+#include <memory>
+
#include <android-base/file.h>
#include <android-base/logging.h>
#include <ziparchive/zip_archive.h>
-
#include "read_elf.h"
#include "utils.h"
@@ -52,6 +53,7 @@ std::unique_ptr<EmbeddedElf> ApkInspector::FindElfInApkByOffsetWithoutCache(cons
if (!IsValidApkPath(apk_path)) {
return nullptr;
}
+
FileHelper fhelper = FileHelper::OpenReadOnly(apk_path);
if (!fhelper) {
return nullptr;
diff --git a/simpleperf/read_apk_test.cpp b/simpleperf/read_apk_test.cpp
index e983a254..d7b30c52 100644
--- a/simpleperf/read_apk_test.cpp
+++ b/simpleperf/read_apk_test.cpp
@@ -31,9 +31,12 @@ TEST(read_apk, FindElfInApkByOffset) {
ApkInspector inspector;
ASSERT_TRUE(inspector.FindElfInApkByOffset("/dev/null", 0) == nullptr);
ASSERT_TRUE(inspector.FindElfInApkByOffset(GetTestData(APK_FILE), 0) == nullptr);
- EmbeddedElf* ee = inspector.FindElfInApkByOffset(GetTestData(APK_FILE), 0x9000);
+ // Test if we can read the EmbeddedElf using an offset inside its [offset, offset+size] range
+ // in the apk file.
+ EmbeddedElf* ee = inspector.FindElfInApkByOffset(GetTestData(APK_FILE),
+ NATIVELIB_OFFSET_IN_APK + NATIVELIB_SIZE_IN_APK / 2);
ASSERT_TRUE(ee != nullptr);
- ASSERT_EQ(ee->entry_name(), NATIVELIB_IN_APK);
+ ASSERT_EQ(NATIVELIB_IN_APK, ee->entry_name());
ASSERT_EQ(NATIVELIB_OFFSET_IN_APK, ee->entry_offset());
ASSERT_EQ(NATIVELIB_SIZE_IN_APK, ee->entry_size());
}
diff --git a/simpleperf/testdata/data/app/com.example.hellojni-1/base.apk b/simpleperf/testdata/data/app/com.example.hellojni-1/base.apk
index c757e9e8..95ea93a3 100644
--- a/simpleperf/testdata/data/app/com.example.hellojni-1/base.apk
+++ b/simpleperf/testdata/data/app/com.example.hellojni-1/base.apk
Binary files differ
diff --git a/simpleperf/testdata/has_embedded_native_libs_apk_perf.data b/simpleperf/testdata/has_embedded_native_libs_apk_perf.data
index f85c9d3f..fafbbbc6 100644
--- a/simpleperf/testdata/has_embedded_native_libs_apk_perf.data
+++ b/simpleperf/testdata/has_embedded_native_libs_apk_perf.data
Binary files differ
diff --git a/simpleperf/utils.cpp b/simpleperf/utils.cpp
index f2418a65..dd09fbd3 100644
--- a/simpleperf/utils.cpp
+++ b/simpleperf/utils.cpp
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <algorithm>
+#include <map>
#include <string>
#include <android-base/file.h>
@@ -230,3 +231,19 @@ bool XzDecompress(const std::string& compressed_data, std::string* decompressed_
*decompressed_data = std::move(dst);
return true;
}
+
+bool GetLogSeverity(const std::string& name, android::base::LogSeverity* severity) {
+ static std::map<std::string, android::base::LogSeverity> log_severity_map = {
+ {"verbose", android::base::VERBOSE},
+ {"debug", android::base::DEBUG},
+ {"warning", android::base::WARNING},
+ {"error", android::base::ERROR},
+ {"fatal", android::base::FATAL},
+ };
+ auto it = log_severity_map.find(name);
+ if (it != log_severity_map.end()) {
+ *severity = it->second;
+ return true;
+ }
+ return false;
+}
diff --git a/simpleperf/utils.h b/simpleperf/utils.h
index c5c43664..04245012 100644
--- a/simpleperf/utils.h
+++ b/simpleperf/utils.h
@@ -22,6 +22,7 @@
#include <string>
#include <vector>
+#include <android-base/logging.h>
#include <android-base/macros.h>
#include <ziparchive/zip_archive.h>
@@ -82,7 +83,6 @@ class FileHelper {
DISALLOW_COPY_AND_ASSIGN(FileHelper);
};
-
class ArchiveHelper {
public:
ArchiveHelper(int fd, const std::string& debug_filename);
@@ -121,4 +121,6 @@ bool MkdirWithParents(const std::string& path);
bool XzDecompress(const std::string& compressed_data, std::string* decompressed_data);
+bool GetLogSeverity(const std::string& name, android::base::LogSeverity* severity);
+
#endif // SIMPLE_PERF_UTILS_H_