summaryrefslogtreecommitdiff
path: root/simpleperf/cmd_record_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'simpleperf/cmd_record_test.cpp')
-rw-r--r--simpleperf/cmd_record_test.cpp307
1 files changed, 64 insertions, 243 deletions
diff --git a/simpleperf/cmd_record_test.cpp b/simpleperf/cmd_record_test.cpp
index 184f9359..fdc26e60 100644
--- a/simpleperf/cmd_record_test.cpp
+++ b/simpleperf/cmd_record_test.cpp
@@ -23,7 +23,6 @@
#include <android-base/file.h>
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
-#include <android-base/strings.h>
#include <map>
#include <memory>
@@ -32,7 +31,6 @@
#include "command.h"
#include "environment.h"
-#include "ETMRecorder.h"
#include "event_selection_set.h"
#include "get_test_data.h"
#include "record.h"
@@ -40,7 +38,6 @@
#include "test_util.h"
#include "thread_tree.h"
-using namespace simpleperf;
using namespace PerfFileFormat;
static std::unique_ptr<Command> RecordCmd() {
@@ -389,11 +386,12 @@ TEST(record_cmd, kernel_symbol) {
ASSERT_TRUE(success);
}
-static void ProcessSymbolsInPerfDataFile(
- const std::string& perf_data_file,
- const std::function<bool(const Symbol&, uint32_t)>& callback) {
- auto reader = RecordFileReader::CreateInstance(perf_data_file);
- ASSERT_TRUE(reader);
+// Check if dumped symbols in perf.data matches our expectation.
+static bool CheckDumpedSymbols(const std::string& path, bool allow_dumped_symbols) {
+ std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(path);
+ if (!reader) {
+ return false;
+ }
std::string file_path;
uint32_t file_type;
uint64_t min_vaddr;
@@ -401,24 +399,13 @@ static void ProcessSymbolsInPerfDataFile(
std::vector<Symbol> symbols;
std::vector<uint64_t> dex_file_offsets;
size_t read_pos = 0;
+ bool has_dumped_symbols = false;
while (reader->ReadFileFeature(read_pos, &file_path, &file_type, &min_vaddr,
&file_offset_of_min_vaddr, &symbols, &dex_file_offsets)) {
- for (const auto& symbol : symbols) {
- if (callback(symbol, file_type)) {
- return;
- }
+ if (!symbols.empty()) {
+ has_dumped_symbols = true;
}
}
-}
-
-// Check if dumped symbols in perf.data matches our expectation.
-static bool CheckDumpedSymbols(const std::string& path, bool allow_dumped_symbols) {
- bool has_dumped_symbols = false;
- auto callback = [&](const Symbol&, uint32_t) {
- has_dumped_symbols = true;
- return true;
- };
- ProcessSymbolsInPerfDataFile(path, callback);
// It is possible that there are no samples hitting functions having symbols.
// So "allow_dumped_symbols = true" doesn't guarantee "has_dumped_symbols = true".
if (!allow_dumped_symbols && has_dumped_symbols) {
@@ -454,14 +441,24 @@ TEST(record_cmd, dump_kernel_symbols) {
}
TemporaryFile tmpfile;
ASSERT_TRUE(RunRecordCmd({"-a", "-o", tmpfile.path, "sleep", "1"}));
+ std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
+ ASSERT_TRUE(reader != nullptr);
+ std::map<int, SectionDesc> section_map = reader->FeatureSectionDescriptors();
+ ASSERT_NE(section_map.find(FEAT_FILE), section_map.end());
+ std::string file_path;
+ uint32_t file_type;
+ uint64_t min_vaddr;
+ uint64_t file_offset_of_min_vaddr;
+ std::vector<Symbol> symbols;
+ std::vector<uint64_t> dex_file_offsets;
+ size_t read_pos = 0;
bool has_kernel_symbols = false;
- auto callback = [&](const Symbol&, uint32_t file_type) {
- if (file_type == DSO_KERNEL) {
+ while (reader->ReadFileFeature(read_pos, &file_path, &file_type, &min_vaddr,
+ &file_offset_of_min_vaddr, &symbols, &dex_file_offsets)) {
+ if (file_type == DSO_KERNEL && !symbols.empty()) {
has_kernel_symbols = true;
}
- return has_kernel_symbols;
- };
- ProcessSymbolsInPerfDataFile(tmpfile.path, callback);
+ }
ASSERT_TRUE(has_kernel_symbols);
}
@@ -566,7 +563,8 @@ TEST(record_cmd, record_meta_info_feature) {
ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
ASSERT_TRUE(reader);
- auto& info_map = reader->GetMetaInfoFeature();
+ std::unordered_map<std::string, std::string> info_map;
+ ASSERT_TRUE(reader->ReadMetaInfoFeature(&info_map));
ASSERT_NE(info_map.find("simpleperf_version"), info_map.end());
ASSERT_NE(info_map.find("timestamp"), info_map.end());
#if defined(__ANDROID__)
@@ -604,7 +602,8 @@ TEST(record_cmd, trace_offcpu_option) {
ASSERT_TRUE(RunRecordCmd({"--trace-offcpu", "-f", "1000"}, tmpfile.path));
std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
ASSERT_TRUE(reader);
- auto info_map = reader->GetMetaInfoFeature();
+ std::unordered_map<std::string, std::string> info_map;
+ ASSERT_TRUE(reader->ReadMetaInfoFeature(&info_map));
ASSERT_EQ(info_map["trace_offcpu"], "true");
CheckEventType(tmpfile.path, "sched:sched_switch", 1u, 0u);
}
@@ -623,7 +622,8 @@ TEST(record_cmd, clockid_option) {
ASSERT_TRUE(RunRecordCmd({"--clockid", "monotonic"}, tmpfile.path));
std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
ASSERT_TRUE(reader);
- auto info_map = reader->GetMetaInfoFeature();
+ std::unordered_map<std::string, std::string> info_map;
+ ASSERT_TRUE(reader->ReadMetaInfoFeature(&info_map));
ASSERT_EQ(info_map["clockid"], "monotonic");
}
}
@@ -744,82 +744,47 @@ TEST(record_cmd, cpu_percent_option) {
ASSERT_FALSE(RunRecordCmd({"--cpu-percent", "101"}));
}
-class RecordingAppHelper {
- public:
- bool InstallApk(const std::string& apk_path, const std::string& package_name) {
- if (Workload::RunCmd({"pm", "install", "-t", "--abi", GetABI(), apk_path})) {
- installed_packages_.emplace_back(package_name);
- return true;
- }
- return false;
- }
-
- bool StartApp(const std::string& start_cmd) {
- app_start_proc_ = Workload::CreateWorkload(android::base::Split(start_cmd, " "));
- return app_start_proc_ && app_start_proc_->Start();
- }
-
- bool RecordData(const std::string& record_cmd) {
- std::vector<std::string> args = android::base::Split(record_cmd, " ");
- args.emplace_back("-o");
- args.emplace_back(perf_data_file_.path);
- return RecordCmd()->Run(args);
- }
-
- bool CheckData(const std::function<bool(const char*)>& process_symbol) {
- bool success = false;
- auto callback = [&](const Symbol& symbol, uint32_t) {
- if (process_symbol(symbol.DemangledName())) {
- success = true;
- }
- return success;
- };
- ProcessSymbolsInPerfDataFile(perf_data_file_.path, callback);
- return success;
- }
-
- ~RecordingAppHelper() {
- for (auto& package : installed_packages_) {
- Workload::RunCmd({"pm", "uninstall", package});
- }
- }
-
- private:
- const char* GetABI() {
-#if defined(__i386__)
- return "x86";
-#elif defined(__x86_64__)
- return "x86_64";
-#elif defined(__aarch64__)
- return "arm64-v8a";
-#elif defined(__arm__)
- return "armeabi-v7a";
-#else
- #error "unrecognized ABI"
-#endif
- }
-
- std::vector<std::string> installed_packages_;
- std::unique_ptr<Workload> app_start_proc_;
- TemporaryFile perf_data_file_;
-};
-
static void TestRecordingApps(const std::string& app_name) {
- RecordingAppHelper helper;
// Bring the app to foreground to avoid no samples.
- ASSERT_TRUE(helper.StartApp("am start " + app_name + "/.MainActivity"));
-
- ASSERT_TRUE(helper.RecordData("--app " + app_name + " -g --duration 3"));
+ ASSERT_TRUE(Workload::RunCmd({"am", "start", app_name + "/.MainActivity"}));
+ TemporaryFile tmpfile;
+ ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "--app", app_name, "-g", "--duration", "3"}));
+ std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
+ ASSERT_TRUE(reader);
+ // Check if having samples.
+ bool has_sample = false;
+ ASSERT_TRUE(reader->ReadDataSection([&](std::unique_ptr<Record> r) {
+ if (r->type() == PERF_RECORD_SAMPLE) {
+ has_sample = true;
+ }
+ return true;
+ }));
+ ASSERT_TRUE(has_sample);
// Check if we can profile Java code by looking for a Java method name in dumped symbols, which
// is app_name + ".MainActivity$1.run".
const std::string expected_class_name = app_name + ".MainActivity";
const std::string expected_method_name = "run";
- auto process_symbol = [&](const char* name) {
- return strstr(name, expected_class_name.c_str()) != nullptr &&
- strstr(name, expected_method_name.c_str()) != nullptr;
- };
- ASSERT_TRUE(helper.CheckData(process_symbol));
+ std::string file_path;
+ uint32_t file_type;
+ uint64_t min_vaddr;
+ uint64_t file_offset_of_min_vaddr;
+ std::vector<Symbol> symbols;
+ std::vector<uint64_t> dex_file_offsets;
+ size_t read_pos = 0;
+ bool has_java_symbol = false;
+ ASSERT_TRUE(reader->HasFeature(FEAT_FILE));
+ while (reader->ReadFileFeature(read_pos, &file_path, &file_type, &min_vaddr,
+ &file_offset_of_min_vaddr, &symbols, &dex_file_offsets)) {
+ for (const auto& symbol : symbols) {
+ const char* name = symbol.DemangledName();
+ if (strstr(name, expected_class_name.c_str()) != nullptr &&
+ strstr(name, expected_method_name.c_str()) != nullptr) {
+ has_java_symbol = true;
+ }
+ }
+ }
+ ASSERT_TRUE(has_java_symbol);
}
TEST(record_cmd, app_option_for_debuggable_app) {
@@ -833,147 +798,3 @@ TEST(record_cmd, app_option_for_profileable_app) {
TEST_REQUIRE_APPS();
TestRecordingApps("com.android.simpleperf.profileable");
}
-
-TEST(record_cmd, record_java_app) {
- RecordingAppHelper helper;
- // 1. Install apk.
- ASSERT_TRUE(helper.InstallApk(GetTestData("DisplayBitmaps.apk"),
- "com.example.android.displayingbitmaps"));
- ASSERT_TRUE(helper.InstallApk(GetTestData("DisplayBitmapsTest.apk"),
- "com.example.android.displayingbitmaps.test"));
-
- // 2. Start the app.
- ASSERT_TRUE(
- helper.StartApp("am instrument -w -r -e debug false -e class "
- "com.example.android.displayingbitmaps.tests.GridViewTest "
- "com.example.android.displayingbitmaps.test/"
- "androidx.test.runner.AndroidJUnitRunner"));
-
- // 3. Record perf.data.
- ASSERT_TRUE(helper.RecordData(
- "-e cpu-clock --app com.example.android.displayingbitmaps -g --duration 10"));
-
- // 4. Check perf.data.
- auto process_symbol = [&](const char* name) {
-#if !defined(IN_CTS_TEST)
- const char* expected_name_with_keyguard = "androidx.test.runner"; // when screen is locked
- if (strstr(name, expected_name_with_keyguard) != nullptr) {
- return true;
- }
-#endif
- const char* expected_name = "androidx.test.espresso"; // when screen stays awake
- return strstr(name, expected_name) != nullptr;
- };
- ASSERT_TRUE(helper.CheckData(process_symbol));
-}
-
-TEST(record_cmd, record_native_app) {
- RecordingAppHelper helper;
- // 1. Install apk.
- ASSERT_TRUE(helper.InstallApk(GetTestData("EndlessTunnel.apk"), "com.google.sample.tunnel"));
-
- // 2. Start the app.
- ASSERT_TRUE(
- helper.StartApp("am start -n com.google.sample.tunnel/android.app.NativeActivity -a "
- "android.intent.action.MAIN -c android.intent.category.LAUNCHER"));
-
- // 3. Record perf.data.
- ASSERT_TRUE(helper.RecordData("-e cpu-clock --app com.google.sample.tunnel -g --duration 10"));
-
- // 4. Check perf.data.
- auto process_symbol = [&](const char* name) {
-#if !defined(IN_CTS_TEST)
- const char* expected_name_with_keyguard = "NativeActivity"; // when screen is locked
- if (strstr(name, expected_name_with_keyguard) != nullptr) {
- return true;
- }
-#endif
- const char* expected_name = "PlayScene::DoFrame"; // when screen is awake
- return strstr(name, expected_name) != nullptr;
- };
- ASSERT_TRUE(helper.CheckData(process_symbol));
-}
-
-TEST(record_cmd, no_cut_samples_option) {
- TEST_REQUIRE_HW_COUNTER();
- ASSERT_TRUE(RunRecordCmd({"--no-cut-samples"}));
-}
-
-TEST(record_cmd, cs_etm_event) {
- if (!ETMRecorder::GetInstance().CheckEtmSupport()) {
- GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
- return;
- }
- TemporaryFile tmpfile;
- ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm"}, tmpfile.path));
- std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
- ASSERT_TRUE(reader);
-
- // cs-etm uses sample period instead of sample freq.
- ASSERT_EQ(reader->AttrSection().size(), 1u);
- const perf_event_attr* attr = reader->AttrSection()[0].attr;
- ASSERT_EQ(attr->freq, 0);
- ASSERT_EQ(attr->sample_period, 1);
-
- bool has_auxtrace_info = false;
- bool has_auxtrace = false;
- bool has_aux = false;
- ASSERT_TRUE(reader->ReadDataSection([&](std::unique_ptr<Record> r) {
- if (r->type() == PERF_RECORD_AUXTRACE_INFO) {
- has_auxtrace_info = true;
- } else if (r->type() == PERF_RECORD_AUXTRACE) {
- has_auxtrace = true;
- } else if (r->type() == PERF_RECORD_AUX) {
- has_aux = true;
- }
- return true;
- }));
- ASSERT_TRUE(has_auxtrace_info);
- ASSERT_TRUE(has_auxtrace);
- ASSERT_TRUE(has_aux);
-}
-
-TEST(record_cmd, aux_buffer_size_option) {
- if (!ETMRecorder::GetInstance().CheckEtmSupport()) {
- GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
- return;
- }
- ASSERT_TRUE(RunRecordCmd({"-e", "cs-etm", "--aux-buffer-size", "1m"}));
- // not page size aligned
- ASSERT_FALSE(RunRecordCmd({"-e", "cs-etm", "--aux-buffer-size", "1024"}));
- // not power of two
- ASSERT_FALSE(RunRecordCmd({"-e", "cs-etm", "--aux-buffer-size", "12k"}));
-}
-
-TEST(record_cmd, include_filter_option) {
- TEST_REQUIRE_HW_COUNTER();
- if (!ETMRecorder::GetInstance().CheckEtmSupport()) {
- GTEST_LOG_(INFO) << "Omit this test since etm isn't supported on this device";
- return;
- }
- FILE* fp = popen("which sleep", "r");
- ASSERT_TRUE(fp != nullptr);
- std::string path;
- ASSERT_TRUE(android::base::ReadFdToString(fileno(fp), &path));
- pclose(fp);
- path = android::base::Trim(path);
- std::string sleep_exec_path;
- ASSERT_TRUE(android::base::Realpath(path, &sleep_exec_path));
- // --include-filter doesn't apply to cpu-cycles.
- ASSERT_FALSE(RunRecordCmd({"--include-filter", sleep_exec_path}));
- TemporaryFile record_file;
- ASSERT_TRUE(
- RunRecordCmd({"-e", "cs-etm", "--include-filter", sleep_exec_path}, record_file.path));
- TemporaryFile inject_file;
- ASSERT_TRUE(
- CreateCommandInstance("inject")->Run({"-i", record_file.path, "-o", inject_file.path}));
- std::string data;
- ASSERT_TRUE(android::base::ReadFileToString(inject_file.path, &data));
- // Only instructions in sleep_exec_path are traced.
- for (auto& line : android::base::Split(data, "\n")) {
- if (android::base::StartsWith(line, "dso ")) {
- std::string dso = line.substr(strlen("dso "), sleep_exec_path.size());
- ASSERT_EQ(dso, sleep_exec_path);
- }
- }
-} \ No newline at end of file