OSDN Git Service

Merge "simpleperf: update simpleperf prebuilts to build 4120823."
[android-x86/system-extras.git] / simpleperf / cmd_record_test.cpp
index 0198fd1..571a3ca 100644 (file)
 
 #include <gtest/gtest.h>
 
+#include <unistd.h>
+
+#include <android-base/file.h>
 #include <android-base/stringprintf.h>
 #include <android-base/test_utils.h>
 
 #include <map>
 #include <memory>
+#include <thread>
 
 #include "command.h"
 #include "environment.h"
@@ -29,6 +33,7 @@
 #include "record.h"
 #include "record_file.h"
 #include "test_util.h"
+#include "thread_tree.h"
 
 using namespace PerfFileFormat;
 
@@ -87,7 +92,8 @@ TEST(record_cmd, dump_kernel_mmap) {
     if (record->type() == PERF_RECORD_MMAP) {
       const MmapRecord* mmap_record =
           static_cast<const MmapRecord*>(record.get());
-      if (strcmp(mmap_record->filename, DEFAULT_KERNEL_MMAP_NAME) == 0) {
+      if (strcmp(mmap_record->filename, DEFAULT_KERNEL_MMAP_NAME) == 0 ||
+          strcmp(mmap_record->filename, DEFAULT_KERNEL_MMAP_NAME_PERF) == 0) {
         have_kernel_mmap = true;
         break;
       }
@@ -133,16 +139,31 @@ TEST(record_cmd, fp_callchain_sampling) {
   ASSERT_TRUE(RunRecordCmd({"--call-graph", "fp"}));
 }
 
+TEST(record_cmd, fp_callchain_sampling_warning_on_arm) {
+  if (GetBuildArch() != ARCH_ARM) {
+    GTEST_LOG_(INFO) << "This test does nothing as it only tests on arm arch.";
+    return;
+  }
+  ASSERT_EXIT(
+      {
+        exit(RunRecordCmd({"--call-graph", "fp"}) ? 0 : 1);
+      },
+      testing::ExitedWithCode(0), "doesn't work well on arm");
+}
+
 TEST(record_cmd, system_wide_fp_callchain_sampling) {
   TEST_IN_ROOT(ASSERT_TRUE(RunRecordCmd({"-a", "--call-graph", "fp"})));
 }
 
 TEST(record_cmd, dwarf_callchain_sampling) {
   if (IsDwarfCallChainSamplingSupported()) {
-    ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf"}));
-    ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf,16384"}));
-    ASSERT_FALSE(RunRecordCmd({"--call-graph", "dwarf,65536"}));
-    ASSERT_TRUE(RunRecordCmd({"-g"}));
+    std::vector<std::unique_ptr<Workload>> workloads;
+    CreateProcesses(1, &workloads);
+    std::string pid = std::to_string(workloads[0]->GetPid());
+    ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf"}));
+    ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf,16384"}));
+    ASSERT_FALSE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf,65536"}));
+    ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g"}));
   } else {
     GTEST_LOG_(INFO) << "This test does nothing as dwarf callchain sampling is "
                         "not supported on this device.";
@@ -170,7 +191,10 @@ TEST(record_cmd, no_unwind_option) {
 
 TEST(record_cmd, post_unwind_option) {
   if (IsDwarfCallChainSamplingSupported()) {
-    ASSERT_TRUE(RunRecordCmd({"--call-graph", "dwarf", "--post-unwind"}));
+    std::vector<std::unique_ptr<Workload>> workloads;
+    CreateProcesses(1, &workloads);
+    std::string pid = std::to_string(workloads[0]->GetPid());
+    ASSERT_TRUE(RunRecordCmd({"-p", pid, "--call-graph", "dwarf", "--post-unwind"}));
   } else {
     GTEST_LOG_(INFO) << "This test does nothing as dwarf callchain sampling is "
                         "not supported on this device.";
@@ -223,17 +247,18 @@ static void CheckKernelSymbol(const std::string& path, bool need_kallsyms,
       has_kernel_symbol_records = true;
     }
   }
-  ASSERT_EQ(need_kallsyms, has_kernel_symbol_records);
+  bool require_kallsyms = need_kallsyms && CheckKernelSymbolAddresses();
+  ASSERT_EQ(require_kallsyms, has_kernel_symbol_records);
   *success = true;
 }
 
 TEST(record_cmd, kernel_symbol) {
   TemporaryFile tmpfile;
-  ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
+  ASSERT_TRUE(RunRecordCmd({"--no-dump-symbols"}, tmpfile.path));
   bool success;
   CheckKernelSymbol(tmpfile.path, true, &success);
   ASSERT_TRUE(success);
-  ASSERT_TRUE(RunRecordCmd({"--no-dump-kernel-symbols"}, tmpfile.path));
+  ASSERT_TRUE(RunRecordCmd({"--no-dump-symbols", "--no-dump-kernel-symbols"}, tmpfile.path));
   CheckKernelSymbol(tmpfile.path, false, &success);
   ASSERT_TRUE(success);
 }
@@ -278,24 +303,52 @@ static void CheckDsoSymbolRecords(const std::string& path,
   *success = true;
 }
 
-TEST(record_cmd, dump_symbols) {
+TEST(record_cmd, no_dump_symbols) {
   TemporaryFile tmpfile;
   ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
   bool success;
-  CheckDsoSymbolRecords(tmpfile.path, false, &success);
-  ASSERT_TRUE(success);
-  ASSERT_TRUE(RunRecordCmd({"--dump-symbols"}, tmpfile.path));
   CheckDsoSymbolRecords(tmpfile.path, true, &success);
   ASSERT_TRUE(success);
+  ASSERT_TRUE(RunRecordCmd({"--no-dump-symbols"}, tmpfile.path));
+  CheckDsoSymbolRecords(tmpfile.path, false, &success);
+  ASSERT_TRUE(success);
   if (IsDwarfCallChainSamplingSupported()) {
-    ASSERT_TRUE(RunRecordCmd({"-g"}, tmpfile.path));
+    std::vector<std::unique_ptr<Workload>> workloads;
+    CreateProcesses(1, &workloads);
+    std::string pid = std::to_string(workloads[0]->GetPid());
+    ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g"}, tmpfile.path));
     bool success;
-    CheckDsoSymbolRecords(tmpfile.path, false, &success);
-    ASSERT_TRUE(success);
-    ASSERT_TRUE(RunRecordCmd({"-g", "--dump-symbols"}, tmpfile.path));
     CheckDsoSymbolRecords(tmpfile.path, true, &success);
     ASSERT_TRUE(success);
+    ASSERT_TRUE(RunRecordCmd({"-p", pid, "-g", "--no-dump-symbols"}, tmpfile.path));
+    CheckDsoSymbolRecords(tmpfile.path, false, &success);
+    ASSERT_TRUE(success);
+  }
+}
+
+TEST(record_cmd, dump_kernel_symbols) {
+  if (!IsRoot()) {
+    GTEST_LOG_(INFO) << "Test requires root privilege";
+    return;
   }
+  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;
+  std::vector<Symbol> symbols;
+  size_t read_pos = 0;
+  bool has_kernel_symbols = false;
+  while (reader->ReadFileFeature(read_pos, &file_path, &file_type, &min_vaddr, &symbols)) {
+    if (file_type == DSO_KERNEL && !symbols.empty()) {
+      has_kernel_symbols = true;
+    }
+  }
+  ASSERT_TRUE(has_kernel_symbols);
 }
 
 TEST(record_cmd, group_option) {
@@ -314,3 +367,73 @@ TEST(record_cmd, duration_option) {
   ASSERT_TRUE(
       RecordCmd()->Run({"--duration", "1", "-o", tmpfile.path, "sleep", "2"}));
 }
+
+TEST(record_cmd, support_modifier_for_clock_events) {
+  for (const std::string& e : {"cpu-clock", "task-clock"}) {
+    for (const std::string& m : {"u", "k"}) {
+      ASSERT_TRUE(RunRecordCmd({"-e", e + ":" + m})) << "event " << e << ":"
+                                                     << m;
+    }
+  }
+}
+
+TEST(record_cmd, handle_SIGHUP) {
+  TemporaryFile tmpfile;
+  std::thread thread([]() {
+    sleep(1);
+    kill(getpid(), SIGHUP);
+  });
+  thread.detach();
+  ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "sleep", "1000000"}));
+}
+
+TEST(record_cmd, stop_when_no_more_targets) {
+  TemporaryFile tmpfile;
+  std::atomic<int> tid(0);
+  std::thread thread([&]() {
+    tid = gettid();
+    sleep(1);
+  });
+  thread.detach();
+  while (tid == 0);
+  ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "-t", std::to_string(tid)}));
+}
+
+TEST(record_cmd, donot_stop_when_having_targets) {
+  std::vector<std::unique_ptr<Workload>> workloads;
+  CreateProcesses(1, &workloads);
+  std::string pid = std::to_string(workloads[0]->GetPid());
+  uint64_t start_time_in_ns = GetSystemClock();
+  TemporaryFile tmpfile;
+  ASSERT_TRUE(RecordCmd()->Run({"-o", tmpfile.path, "-p", pid, "--duration", "3"}));
+  uint64_t end_time_in_ns = GetSystemClock();
+  ASSERT_GT(end_time_in_ns - start_time_in_ns, static_cast<uint64_t>(2e9));
+}
+
+TEST(record_cmd, start_profiling_fd_option) {
+  int pipefd[2];
+  ASSERT_EQ(0, pipe(pipefd));
+  int read_fd = pipefd[0];
+  int write_fd = pipefd[1];
+  ASSERT_EXIT(
+      {
+        close(read_fd);
+        exit(RunRecordCmd({"--start_profiling_fd", std::to_string(write_fd)}) ? 0 : 1);
+      },
+      testing::ExitedWithCode(0), "");
+  close(write_fd);
+  std::string s;
+  ASSERT_TRUE(android::base::ReadFdToString(read_fd, &s));
+  close(read_fd);
+  ASSERT_EQ("STARTED", s);
+}
+
+TEST(record_cmd, record_meta_info_feature) {
+  TemporaryFile tmpfile;
+  ASSERT_TRUE(RunRecordCmd({}, tmpfile.path));
+  std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile.path);
+  ASSERT_TRUE(reader != nullptr);
+  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());
+}