OSDN Git Service

Simpleperf: support build on mac.
authorYabin Cui <yabinc@google.com>
Fri, 26 Jun 2015 00:42:23 +0000 (17:42 -0700)
committerYabin Cui <yabinc@google.com>
Mon, 29 Jun 2015 21:48:38 +0000 (14:48 -0700)
Bug: 19483574
Change-Id: I6c28541944bc0a4e6fc07d7ea5a8fb5f71890510

19 files changed:
simpleperf/Android.mk
simpleperf/cmd_list.cpp
simpleperf/cmd_record.cpp
simpleperf/cmd_stat.cpp
simpleperf/darwin_support/asm/byteorder.h [new file with mode: 0644]
simpleperf/darwin_support/linux/ioctl.h [new file with mode: 0644]
simpleperf/darwin_support/linux/types.h [new file with mode: 0644]
simpleperf/dso.cpp
simpleperf/environment_fake.cpp [new file with mode: 0644]
simpleperf/event_fd.cpp
simpleperf/event_fd.h
simpleperf/event_selection_set.cpp
simpleperf/event_selection_set.h
simpleperf/event_type.cpp
simpleperf/event_type.h
simpleperf/record_file_reader.cpp [new file with mode: 0644]
simpleperf/record_file_writer.cpp [moved from simpleperf/record_file.cpp with 66% similarity]
simpleperf/record_test.cpp
simpleperf/utils.h

index 4642e2a..278bc24 100644 (file)
 LOCAL_PATH := $(call my-dir)
 
 simpleperf_common_cppflags := -std=c++11 -Wall -Wextra -Werror -Wunused
-simpleperf_use_bionic_perf_event_h_flag := -DUSE_BIONIC_PERF_EVENT_H -I bionic
-simpleperf_host_common_cppflags := $(simpleperf_common_cppflags) $(simpleperf_use_bionic_perf_event_h_flag)
+simpleperf_host_common_cppflags := $(simpleperf_common_cppflags) \
+                                   -DUSE_BIONIC_PERF_EVENT_H -I bionic \
+
+simpleperf_host_darwin_cppflags := $(simpleperf_host_common_cppflags) \
+                                   -I $(LOCAL_PATH)/darwin_support \
 
 simpleperf_common_shared_libraries := \
   libbase \
@@ -26,27 +29,37 @@ simpleperf_common_shared_libraries := \
 
 LLVM_ROOT_PATH := external/llvm
 
-libsimpleperf_src_files := \
+# libsimpleperf
+# =========================================================
+libsimpleperf_common_src_files := \
   cmd_dumprecord.cpp \
   cmd_help.cpp \
-  cmd_list.cpp \
-  cmd_record.cpp \
   cmd_report.cpp \
-  cmd_stat.cpp \
   command.cpp \
   dso.cpp \
-  environment.cpp \
   event_attr.cpp \
-  event_fd.cpp \
-  event_selection_set.cpp \
   event_type.cpp \
   read_elf.cpp \
   record.cpp \
-  record_file.cpp \
+  record_file_reader.cpp \
   sample_tree.cpp \
   utils.cpp \
+
+libsimpleperf_src_files := \
+  $(libsimpleperf_common_src_files) \
+  cmd_list.cpp \
+  cmd_record.cpp \
+  cmd_stat.cpp \
+  environment.cpp \
+  event_fd.cpp \
+  event_selection_set.cpp \
+  record_file_writer.cpp \
   workload.cpp \
 
+libsimpleperf_darwin_src_files := \
+  $(libsimpleperf_common_src_files) \
+  environment_fake.cpp \
+
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
 LOCAL_CPPFLAGS := $(simpleperf_common_cppflags)
@@ -75,6 +88,22 @@ include $(LLVM_HOST_BUILD_MK)
 include $(BUILD_HOST_STATIC_LIBRARY)
 endif
 
+ifeq ($(HOST_OS),darwin)
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_CPPFLAGS := $(simpleperf_host_darwin_cppflags)
+LOCAL_SRC_FILES := $(libsimpleperf_darwin_src_files)
+LOCAL_SHARED_LIBRARIES := $(simpleperf_common_shared_libraries)
+LOCAL_MODULE := libsimpleperf
+LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(LLVM_ROOT_PATH)/llvm.mk
+include $(LLVM_HOST_BUILD_MK)
+include $(BUILD_HOST_SHARED_LIBRARY)
+endif
+
+# simpleperf
+# =========================================================
 include $(CLEAR_VARS)
 LOCAL_CLANG := true
 LOCAL_CPPFLAGS := $(simpleperf_common_cppflags)
@@ -101,20 +130,37 @@ LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_EXECUTABLE)
 endif
 
+ifeq ($(HOST_OS),darwin)
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_CPPFLAGS := $(simpleperf_host_darwin_cppflags)
+LOCAL_SRC_FILES := main.cpp
+LOCAL_SHARED_LIBRARIES := libsimpleperf $(simpleperf_common_shared_libraries)
+LOCAL_MODULE := simpleperf
+LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_HOST_EXECUTABLE)
+endif
+
+# simpleperf_unit_test
+# =========================================================
+simpleperf_unit_test_common_src_files := \
+  command_test.cpp \
+  gtest_main.cpp \
+  record_test.cpp \
+  sample_tree_test.cpp \
+
 simpleperf_unit_test_src_files := \
+  $(simpleperf_unit_test_common_src_files) \
   cmd_dumprecord_test.cpp \
   cmd_list_test.cpp \
   cmd_record_test.cpp \
   cmd_report_test.cpp \
   cmd_stat_test.cpp \
-  command_test.cpp \
   cpu_offline_test.cpp \
   environment_test.cpp \
-  gtest_main.cpp \
   read_elf_test.cpp \
   record_file_test.cpp \
-  record_test.cpp \
-  sample_tree_test.cpp \
   workload_test.cpp \
 
 include $(CLEAR_VARS)
@@ -140,3 +186,15 @@ LOCAL_MODULE_TAGS := optional
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 include $(BUILD_HOST_NATIVE_TEST)
 endif
+
+ifeq ($(HOST_OS),darwin)
+include $(CLEAR_VARS)
+LOCAL_CLANG := true
+LOCAL_CPPFLAGS := $(simpleperf_host_darwin_cppflags)
+LOCAL_SRC_FILES := $(simpleperf_unit_test_common_src_files)
+LOCAL_SHARED_LIBRARIES := libsimpleperf $(simpleperf_common_shared_libraries)
+LOCAL_MODULE := simpleperf_unit_test
+LOCAL_MODULE_TAGS := optional
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+include $(BUILD_HOST_NATIVE_TEST)
+endif
index 221f3fb..e65756a 100644 (file)
 #include <base/logging.h>
 
 #include "command.h"
+#include "event_attr.h"
+#include "event_fd.h"
 #include "event_type.h"
-#include "perf_event.h"
 
 static void PrintEventTypesOfType(uint32_t type, const std::string& type_name,
                                   const std::vector<EventType>& event_types) {
   printf("List of %s:\n", type_name.c_str());
   for (auto& event_type : event_types) {
-    if (event_type.type == type && event_type.IsSupportedByKernel()) {
+    if (event_type.type == type &&
+        IsEventAttrSupportedByKernel(CreateDefaultPerfEventAttr(event_type))) {
       printf("  %s\n", event_type.name.c_str());
     }
   }
index 59cc3dc..f91100a 100644 (file)
@@ -339,7 +339,9 @@ bool RecordCommand::SetMeasuredEventType(const std::string& event_type_name) {
 }
 
 bool RecordCommand::SetEventSelection() {
-  event_selection_set_.AddEventType(*measured_event_type_modifier_);
+  if (!event_selection_set_.AddEventType(*measured_event_type_modifier_)) {
+    return false;
+  }
   if (use_sample_freq_) {
     event_selection_set_.SetSampleFreq(sample_freq_);
   } else {
index 83a4a3f..d4b1923 100644 (file)
 
 #include "command.h"
 #include "environment.h"
+#include "event_attr.h"
+#include "event_fd.h"
 #include "event_selection_set.h"
 #include "event_type.h"
-#include "perf_event.h"
 #include "utils.h"
 #include "workload.h"
 
@@ -76,9 +77,9 @@ class StatCommand : public Command {
 
  private:
   bool ParseOptions(const std::vector<std::string>& args, std::vector<std::string>* non_option_args);
-  bool AddMeasuredEventType(const std::string& event_type_name, bool report_unsupported_type = true);
+  bool AddMeasuredEventType(const std::string& event_type_name);
   bool AddDefaultMeasuredEventTypes();
-  void SetEventSelection();
+  bool SetEventSelection();
   bool ShowCounters(const std::map<const EventType*, std::vector<PerfCounter>>& counters_map,
                     std::chrono::steady_clock::duration counting_duration);
 
@@ -103,7 +104,9 @@ bool StatCommand::Run(const std::vector<std::string>& args) {
       return false;
     }
   }
-  SetEventSelection();
+  if (!SetEventSelection()) {
+    return false;
+  }
 
   // 2. Create workload.
   std::unique_ptr<Workload> workload;
@@ -216,10 +219,8 @@ bool StatCommand::ParseOptions(const std::vector<std::string>& args,
   return true;
 }
 
-bool StatCommand::AddMeasuredEventType(const std::string& event_type_name,
-                                       bool report_unsupported_type) {
-  std::unique_ptr<EventTypeAndModifier> event_type_modifier =
-      ParseEventType(event_type_name, report_unsupported_type);
+bool StatCommand::AddMeasuredEventType(const std::string& event_type_name) {
+  std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType(event_type_name);
   if (event_type_modifier == nullptr) {
     return false;
   }
@@ -230,7 +231,10 @@ bool StatCommand::AddMeasuredEventType(const std::string& event_type_name,
 bool StatCommand::AddDefaultMeasuredEventTypes() {
   for (auto& name : default_measured_event_types) {
     // It is not an error when some event types in the default list are not supported by the kernel.
-    AddMeasuredEventType(name, false);
+    const EventType* type = FindEventTypeByName(name);
+    if (type != nullptr && IsEventAttrSupportedByKernel(CreateDefaultPerfEventAttr(*type))) {
+      AddMeasuredEventType(name);
+    }
   }
   if (measured_event_types_.empty()) {
     LOG(ERROR) << "Failed to add any supported default measured types";
@@ -239,11 +243,14 @@ bool StatCommand::AddDefaultMeasuredEventTypes() {
   return true;
 }
 
-void StatCommand::SetEventSelection() {
+bool StatCommand::SetEventSelection() {
   for (auto& pair : measured_event_types_) {
-    event_selection_set_.AddEventType(pair.second);
+    if (!event_selection_set_.AddEventType(pair.second)) {
+      return false;
+    }
   }
   event_selection_set_.SetInherit(child_inherit_);
+  return true;
 }
 
 bool StatCommand::ShowCounters(
diff --git a/simpleperf/darwin_support/asm/byteorder.h b/simpleperf/darwin_support/asm/byteorder.h
new file mode 100644 (file)
index 0000000..d118abc
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
diff --git a/simpleperf/darwin_support/linux/ioctl.h b/simpleperf/darwin_support/linux/ioctl.h
new file mode 100644 (file)
index 0000000..f580736
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define __IO(type, nr)
+#define __IOR(type, nr, size)
+#define __IOW(type, nr, size)
diff --git a/simpleperf/darwin_support/linux/types.h b/simpleperf/darwin_support/linux/types.h
new file mode 100644 (file)
index 0000000..30478eb
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+typedef uint8_t __u8;
+typedef uint16_t __u16;
+typedef uint32_t __u32;
+typedef uint64_t __u64;
+typedef int64_t __s64;
index b5880ca..562727b 100644 (file)
@@ -29,7 +29,9 @@ bool SymbolComparator::operator()(const std::unique_ptr<SymbolEntry>& symbol1,
 
 const SymbolEntry* DsoEntry::FindSymbol(uint64_t offset_in_dso) {
   std::unique_ptr<SymbolEntry> symbol(new SymbolEntry{
-      .name = "", .addr = offset_in_dso, .len = 0,
+      "",             // name
+      offset_in_dso,  // addr
+      0,              // len
   });
 
   auto it = symbols.upper_bound(symbol);
@@ -73,7 +75,9 @@ static bool IsKernelFunctionSymbol(const KernelSymbol& symbol) {
 static bool KernelSymbolCallback(const KernelSymbol& kernel_symbol, DsoEntry* dso) {
   if (IsKernelFunctionSymbol(kernel_symbol)) {
     SymbolEntry* symbol = new SymbolEntry{
-        .name = kernel_symbol.name, .addr = kernel_symbol.addr, .len = 0,
+        kernel_symbol.name,  // name
+        kernel_symbol.addr,  // addr
+        0,                   // len
     };
     dso->symbols.insert(std::unique_ptr<SymbolEntry>(symbol));
   }
@@ -93,6 +97,7 @@ static void FixupSymbolLength(DsoEntry* dso) {
   }
 }
 
+// TODO: Fix the way to get kernel symbols. See b/22179177.
 std::unique_ptr<DsoEntry> DsoFactory::LoadKernel() {
   std::unique_ptr<DsoEntry> dso(new DsoEntry);
   dso->path = "[kernel.kallsyms]";
@@ -107,7 +112,9 @@ static void ParseSymbolCallback(const ElfFileSymbol& elf_symbol, DsoEntry* dso,
                                 bool (*filter)(const ElfFileSymbol&)) {
   if (filter(elf_symbol)) {
     SymbolEntry* symbol = new SymbolEntry{
-        .name = elf_symbol.name, .addr = elf_symbol.start_in_file, .len = elf_symbol.len,
+        elf_symbol.name,           // name
+        elf_symbol.start_in_file,  // addr
+        elf_symbol.len,            // len
     };
     dso->symbols.insert(std::unique_ptr<SymbolEntry>(symbol));
   }
diff --git a/simpleperf/environment_fake.cpp b/simpleperf/environment_fake.cpp
new file mode 100644 (file)
index 0000000..e8c9dd8
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// Add fake functions to build successfully on non-linux environments.
+#include "environment.h"
+
+bool ProcessKernelSymbols(const std::string&, std::function<bool(const KernelSymbol&)>) {
+  return false;
+}
index 547be29..9c5e4ab 100644 (file)
@@ -168,3 +168,8 @@ void EventFd::PreparePollForMmapData(pollfd* poll_fd) {
   poll_fd->fd = perf_event_fd_;
   poll_fd->events = POLLIN;
 }
+
+bool IsEventAttrSupportedByKernel(perf_event_attr attr) {
+  auto event_fd = EventFd::OpenEventFile(attr, getpid(), -1, false);
+  return event_fd != nullptr;
+}
index bcacc28..1fe5af0 100644 (file)
@@ -97,4 +97,6 @@ class EventFd {
   DISALLOW_COPY_AND_ASSIGN(EventFd);
 };
 
+bool IsEventAttrSupportedByKernel(perf_event_attr attr);
+
 #endif  // SIMPLE_PERF_EVENT_FD_H_
index 0f23c14..a9a0f96 100644 (file)
 #include "event_type.h"
 
 bool IsBranchSamplingSupported() {
-  std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles", false);
-  if (event_type_modifier == nullptr) {
+  const EventType* type = FindEventTypeByName("cpu-cycles");
+  if (type == nullptr) {
     return false;
   }
-  perf_event_attr attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
+  perf_event_attr attr = CreateDefaultPerfEventAttr(*type);
   attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
   attr.branch_sample_type = PERF_SAMPLE_BRANCH_ANY;
-  auto event_fd = EventFd::OpenEventFile(attr, getpid(), -1, false);
-  return event_fd != nullptr;
+  return IsEventAttrSupportedByKernel(attr);
 }
 
-void EventSelectionSet::AddEventType(const EventTypeAndModifier& event_type_modifier) {
+bool EventSelectionSet::AddEventType(const EventTypeAndModifier& event_type_modifier) {
   EventSelection selection;
   selection.event_type = event_type_modifier.event_type;
   selection.event_attr = CreateDefaultPerfEventAttr(event_type_modifier.event_type);
@@ -45,7 +44,12 @@ void EventSelectionSet::AddEventType(const EventTypeAndModifier& event_type_modi
   selection.event_attr.exclude_host = event_type_modifier.exclude_host;
   selection.event_attr.exclude_guest = event_type_modifier.exclude_guest;
   selection.event_attr.precise_ip = event_type_modifier.precise_ip;
+  if (!IsEventAttrSupportedByKernel(selection.event_attr)) {
+    LOG(ERROR) << "Event type '" << selection.event_type.name << "' is not supported by the kernel";
+    return false;
+  }
   selections_.push_back(std::move(selection));
+  return true;
 }
 
 void EventSelectionSet::SetEnableOnExec(bool enable) {
index adf3440..e52ec5f 100644 (file)
@@ -46,7 +46,7 @@ class EventSelectionSet {
     return selections_.empty();
   }
 
-  void AddEventType(const EventTypeAndModifier& event_type_modifier);
+  bool AddEventType(const EventTypeAndModifier& event_type_modifier);
 
   void SetEnableOnExec(bool enable);
   bool GetEnableOnExec();
index 56a17b8..526cfa5 100644 (file)
@@ -36,16 +36,6 @@ static const std::vector<EventType> static_event_type_array = {
 #include "event_type_table.h"
 };
 
-static bool IsEventTypeSupportedByKernel(const EventType& event_type) {
-  auto event_fd =
-      EventFd::OpenEventFile(CreateDefaultPerfEventAttr(event_type), getpid(), -1, false);
-  return event_fd != nullptr;
-}
-
-bool EventType::IsSupportedByKernel() const {
-  return IsEventTypeSupportedByKernel(*this);
-}
-
 static const std::vector<EventType> GetTracepointEventTypes() {
   std::vector<EventType> result;
   const std::string tracepoint_dirname = "/sys/kernel/debug/tracing/events";
@@ -96,7 +86,7 @@ const EventType* FindEventTypeByConfig(uint32_t type, uint64_t config) {
   return nullptr;
 }
 
-static const EventType* FindEventTypeByName(const std::string& name, bool report_unsupported_type) {
+const EventType* FindEventTypeByName(const std::string& name) {
   const EventType* result = nullptr;
   for (auto& event_type : GetAllEventTypes()) {
     if (event_type.name == name) {
@@ -109,16 +99,10 @@ static const EventType* FindEventTypeByName(const std::string& name, bool report
                << "', try `simpleperf list` to list all possible event type names";
     return nullptr;
   }
-  if (!result->IsSupportedByKernel()) {
-    (report_unsupported_type ? PLOG(ERROR) : PLOG(DEBUG)) << "Event type '" << result->name
-                                                          << "' is not supported by the kernel";
-    return nullptr;
-  }
   return result;
 }
 
-std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_type_str,
-                                                     bool report_unsupported_type) {
+std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_type_str) {
   static std::string modifier_characters = "ukhGHp";
   std::unique_ptr<EventTypeAndModifier> event_type_modifier(new EventTypeAndModifier);
   std::string name = event_type_str;
@@ -138,13 +122,13 @@ std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_ty
       modifier = event_type_str.substr(comm_pos + 1);
     }
   }
-  const EventType* event_type = FindEventTypeByName(name, report_unsupported_type);
+  const EventType* event_type = FindEventTypeByName(name);
   if (event_type == nullptr) {
     // Try if the modifier belongs to the event type name, like some tracepoint events.
     if (!modifier.empty()) {
       name = event_type_str;
       modifier.clear();
-      event_type = FindEventTypeByName(name, report_unsupported_type);
+      event_type = FindEventTypeByName(name);
     }
     if (event_type == nullptr) {
       return nullptr;
index 9c365fa..df2f782 100644 (file)
@@ -35,8 +35,6 @@ struct EventType {
   EventType() : type(0), config(0) {
   }
 
-  bool IsSupportedByKernel() const;
-
   std::string name;
   uint32_t type;
   uint64_t config;
@@ -44,6 +42,7 @@ struct EventType {
 
 const std::vector<EventType>& GetAllEventTypes();
 const EventType* FindEventTypeByConfig(uint32_t type, uint64_t config);
+const EventType* FindEventTypeByName(const std::string& name);
 
 struct EventTypeAndModifier {
   EventType event_type;
@@ -64,7 +63,6 @@ struct EventTypeAndModifier {
   }
 };
 
-std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_type_str,
-                                                     bool report_unsupported_type = true);
+std::unique_ptr<EventTypeAndModifier> ParseEventType(const std::string& event_type_str);
 
 #endif  // SIMPLE_PERF_EVENT_H_
diff --git a/simpleperf/record_file_reader.cpp b/simpleperf/record_file_reader.cpp
new file mode 100644 (file)
index 0000000..8407d32
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "record_file.h"
+
+#include <fcntl.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <set>
+#include <vector>
+
+#include <base/logging.h>
+
+#include "perf_event.h"
+#include "record.h"
+#include "utils.h"
+
+using namespace PerfFileFormat;
+
+std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) {
+  int fd = open(filename.c_str(), O_RDONLY | O_CLOEXEC);
+  if (fd == -1) {
+    PLOG(ERROR) << "failed to open record file '" << filename << "'";
+    return nullptr;
+  }
+  auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fd));
+  if (!reader->MmapFile()) {
+    return nullptr;
+  }
+  return reader;
+}
+
+RecordFileReader::RecordFileReader(const std::string& filename, int fd)
+    : filename_(filename), record_fd_(fd), mmap_addr_(nullptr), mmap_len_(0) {
+}
+
+RecordFileReader::~RecordFileReader() {
+  if (record_fd_ != -1) {
+    Close();
+  }
+}
+
+bool RecordFileReader::Close() {
+  bool result = true;
+  if (munmap(const_cast<char*>(mmap_addr_), mmap_len_) == -1) {
+    PLOG(ERROR) << "failed to munmap() record file '" << filename_ << "'";
+    result = false;
+  }
+  if (close(record_fd_) == -1) {
+    PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
+    result = false;
+  }
+  record_fd_ = -1;
+  return result;
+}
+
+bool RecordFileReader::MmapFile() {
+  off_t file_size = lseek(record_fd_, 0, SEEK_END);
+  if (file_size == -1) {
+    return false;
+  }
+  size_t mmap_len = file_size;
+  void* mmap_addr = mmap(nullptr, mmap_len, PROT_READ, MAP_SHARED, record_fd_, 0);
+  if (mmap_addr == MAP_FAILED) {
+    PLOG(ERROR) << "failed to mmap() record file '" << filename_ << "'";
+    return false;
+  }
+
+  mmap_addr_ = reinterpret_cast<const char*>(mmap_addr);
+  mmap_len_ = mmap_len;
+  return true;
+}
+
+const FileHeader* RecordFileReader::FileHeader() {
+  return reinterpret_cast<const struct FileHeader*>(mmap_addr_);
+}
+
+std::vector<const FileAttr*> RecordFileReader::AttrSection() {
+  std::vector<const FileAttr*> result;
+  const struct FileHeader* header = FileHeader();
+  size_t attr_count = header->attrs.size / header->attr_size;
+  const FileAttr* attr = reinterpret_cast<const FileAttr*>(mmap_addr_ + header->attrs.offset);
+  for (size_t i = 0; i < attr_count; ++i) {
+    result.push_back(attr++);
+  }
+  return result;
+}
+
+std::vector<uint64_t> RecordFileReader::IdsForAttr(const FileAttr* attr) {
+  std::vector<uint64_t> result;
+  size_t id_count = attr->ids.size / sizeof(uint64_t);
+  const uint64_t* id = reinterpret_cast<const uint64_t*>(mmap_addr_ + attr->ids.offset);
+  for (size_t i = 0; i < id_count; ++i) {
+    result.push_back(*id++);
+  }
+  return result;
+}
+
+static bool IsRecordHappensBefore(const std::unique_ptr<const Record>& r1,
+                                  const std::unique_ptr<const Record>& r2) {
+  bool is_r1_sample = (r1->header.type == PERF_RECORD_SAMPLE);
+  bool is_r2_sample = (r2->header.type == PERF_RECORD_SAMPLE);
+  uint64_t time1 = (is_r1_sample ? static_cast<const SampleRecord*>(r1.get())->time_data.time
+                                 : r1->sample_id.time_data.time);
+  uint64_t time2 = (is_r2_sample ? static_cast<const SampleRecord*>(r2.get())->time_data.time
+                                 : r2->sample_id.time_data.time);
+  // The record with smaller time happens first.
+  if (time1 != time2) {
+    return time1 < time2;
+  }
+  // If happening at the same time, make non-sample records before sample records,
+  // because non-sample records may contain useful information to parse sample records.
+  if (is_r1_sample != is_r2_sample) {
+    return is_r1_sample ? false : true;
+  }
+  // Otherwise, don't care of the order.
+  return false;
+}
+
+std::vector<std::unique_ptr<const Record>> RecordFileReader::DataSection() {
+  std::vector<std::unique_ptr<const Record>> result;
+  const struct FileHeader* header = FileHeader();
+  auto file_attrs = AttrSection();
+  CHECK(file_attrs.size() > 0);
+  perf_event_attr attr = file_attrs[0]->attr;
+
+  const char* end = mmap_addr_ + header->data.offset + header->data.size;
+  const char* p = mmap_addr_ + header->data.offset;
+  while (p < end) {
+    const perf_event_header* header = reinterpret_cast<const perf_event_header*>(p);
+    if (p + header->size <= end) {
+      result.push_back(std::move(ReadRecordFromBuffer(attr, header)));
+    }
+    p += header->size;
+  }
+  if ((attr.sample_type & PERF_SAMPLE_TIME) && attr.sample_id_all) {
+    std::sort(result.begin(), result.end(), IsRecordHappensBefore);
+  }
+  return result;
+}
+
+const std::map<int, SectionDesc>& RecordFileReader::FeatureSectionDescriptors() {
+  if (feature_sections_.empty()) {
+    std::vector<int> features;
+    const struct FileHeader* header = FileHeader();
+    for (size_t i = 0; i < sizeof(header->features); ++i) {
+      for (size_t j = 0; j < 8; ++j) {
+        if (header->features[i] & (1 << j)) {
+          features.push_back(i * 8 + j);
+        }
+      }
+    }
+    uint64_t feature_section_offset = header->data.offset + header->data.size;
+    const SectionDesc* p = reinterpret_cast<const SectionDesc*>(mmap_addr_ + feature_section_offset);
+    for (auto& feature : features) {
+      feature_sections_.insert(std::make_pair(feature, *p));
+      ++p;
+    }
+  }
+  return feature_sections_;
+}
+
+std::vector<std::string> RecordFileReader::ReadCmdlineFeature() {
+  const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
+  auto it = section_map.find(FEAT_CMDLINE);
+  if (it == section_map.end()) {
+    return std::vector<std::string>();
+  }
+  SectionDesc section = it->second;
+  const char* p = DataAtOffset(section.offset);
+  const char* end = DataAtOffset(section.offset + section.size);
+  std::vector<std::string> cmdline;
+  uint32_t arg_count;
+  MoveFromBinaryFormat(arg_count, p);
+  CHECK_LE(p, end);
+  for (size_t i = 0; i < arg_count; ++i) {
+    uint32_t len;
+    MoveFromBinaryFormat(len, p);
+    CHECK_LE(p + len, end);
+    cmdline.push_back(p);
+    p += len;
+  }
+  return cmdline;
+}
similarity index 66%
rename from simpleperf/record_file.cpp
rename to simpleperf/record_file_writer.cpp
index 2f6bf10..deb0ada 100644 (file)
@@ -361,169 +361,3 @@ bool RecordFileWriter::Close() {
   record_fp_ = nullptr;
   return result;
 }
-
-std::unique_ptr<RecordFileReader> RecordFileReader::CreateInstance(const std::string& filename) {
-  int fd = open(filename.c_str(), O_RDONLY | O_CLOEXEC);
-  if (fd == -1) {
-    PLOG(ERROR) << "failed to open record file '" << filename << "'";
-    return nullptr;
-  }
-  auto reader = std::unique_ptr<RecordFileReader>(new RecordFileReader(filename, fd));
-  if (!reader->MmapFile()) {
-    return nullptr;
-  }
-  return reader;
-}
-
-RecordFileReader::RecordFileReader(const std::string& filename, int fd)
-    : filename_(filename), record_fd_(fd), mmap_addr_(nullptr), mmap_len_(0) {
-}
-
-RecordFileReader::~RecordFileReader() {
-  if (record_fd_ != -1) {
-    Close();
-  }
-}
-
-bool RecordFileReader::Close() {
-  bool result = true;
-  if (munmap(const_cast<char*>(mmap_addr_), mmap_len_) == -1) {
-    PLOG(ERROR) << "failed to munmap() record file '" << filename_ << "'";
-    result = false;
-  }
-  if (close(record_fd_) == -1) {
-    PLOG(ERROR) << "failed to close record file '" << filename_ << "'";
-    result = false;
-  }
-  record_fd_ = -1;
-  return result;
-}
-
-bool RecordFileReader::MmapFile() {
-  off64_t file_size = lseek64(record_fd_, 0, SEEK_END);
-  if (file_size == -1) {
-    return false;
-  }
-  size_t mmap_len = file_size;
-  void* mmap_addr = mmap(nullptr, mmap_len, PROT_READ, MAP_SHARED, record_fd_, 0);
-  if (mmap_addr == MAP_FAILED) {
-    PLOG(ERROR) << "failed to mmap() record file '" << filename_ << "'";
-    return false;
-  }
-
-  mmap_addr_ = reinterpret_cast<const char*>(mmap_addr);
-  mmap_len_ = mmap_len;
-  return true;
-}
-
-const FileHeader* RecordFileReader::FileHeader() {
-  return reinterpret_cast<const struct FileHeader*>(mmap_addr_);
-}
-
-std::vector<const FileAttr*> RecordFileReader::AttrSection() {
-  std::vector<const FileAttr*> result;
-  const struct FileHeader* header = FileHeader();
-  size_t attr_count = header->attrs.size / header->attr_size;
-  const FileAttr* attr = reinterpret_cast<const FileAttr*>(mmap_addr_ + header->attrs.offset);
-  for (size_t i = 0; i < attr_count; ++i) {
-    result.push_back(attr++);
-  }
-  return result;
-}
-
-std::vector<uint64_t> RecordFileReader::IdsForAttr(const FileAttr* attr) {
-  std::vector<uint64_t> result;
-  size_t id_count = attr->ids.size / sizeof(uint64_t);
-  const uint64_t* id = reinterpret_cast<const uint64_t*>(mmap_addr_ + attr->ids.offset);
-  for (size_t i = 0; i < id_count; ++i) {
-    result.push_back(*id++);
-  }
-  return result;
-}
-
-static bool IsRecordHappensBefore(const std::unique_ptr<const Record>& r1,
-                                  const std::unique_ptr<const Record>& r2) {
-  bool is_r1_sample = (r1->header.type == PERF_RECORD_SAMPLE);
-  bool is_r2_sample = (r2->header.type == PERF_RECORD_SAMPLE);
-  uint64_t time1 = (is_r1_sample ? static_cast<const SampleRecord*>(r1.get())->time_data.time
-                                 : r1->sample_id.time_data.time);
-  uint64_t time2 = (is_r2_sample ? static_cast<const SampleRecord*>(r2.get())->time_data.time
-                                 : r2->sample_id.time_data.time);
-  // The record with smaller time happens first.
-  if (time1 != time2) {
-    return time1 < time2;
-  }
-  // If happening at the same time, make non-sample records before sample records,
-  // because non-sample records may contain useful information to parse sample records.
-  if (is_r1_sample != is_r2_sample) {
-    return is_r1_sample ? false : true;
-  }
-  // Otherwise, don't care of the order.
-  return false;
-}
-
-std::vector<std::unique_ptr<const Record>> RecordFileReader::DataSection() {
-  std::vector<std::unique_ptr<const Record>> result;
-  const struct FileHeader* header = FileHeader();
-  auto file_attrs = AttrSection();
-  CHECK(file_attrs.size() > 0);
-  perf_event_attr attr = file_attrs[0]->attr;
-
-  const char* end = mmap_addr_ + header->data.offset + header->data.size;
-  const char* p = mmap_addr_ + header->data.offset;
-  while (p < end) {
-    const perf_event_header* header = reinterpret_cast<const perf_event_header*>(p);
-    if (p + header->size <= end) {
-      result.push_back(std::move(ReadRecordFromBuffer(attr, header)));
-    }
-    p += header->size;
-  }
-  if ((attr.sample_type & PERF_SAMPLE_TIME) && attr.sample_id_all) {
-    std::sort(result.begin(), result.end(), IsRecordHappensBefore);
-  }
-  return result;
-}
-
-const std::map<int, SectionDesc>& RecordFileReader::FeatureSectionDescriptors() {
-  if (feature_sections_.empty()) {
-    std::vector<int> features;
-    const struct FileHeader* header = FileHeader();
-    for (size_t i = 0; i < sizeof(header->features); ++i) {
-      for (size_t j = 0; j < 8; ++j) {
-        if (header->features[i] & (1 << j)) {
-          features.push_back(i * 8 + j);
-        }
-      }
-    }
-    uint64_t feature_section_offset = header->data.offset + header->data.size;
-    const SectionDesc* p = reinterpret_cast<const SectionDesc*>(mmap_addr_ + feature_section_offset);
-    for (auto& feature : features) {
-      feature_sections_.insert(std::make_pair(feature, *p));
-      ++p;
-    }
-  }
-  return feature_sections_;
-}
-
-std::vector<std::string> RecordFileReader::ReadCmdlineFeature() {
-  const std::map<int, SectionDesc>& section_map = FeatureSectionDescriptors();
-  auto it = section_map.find(FEAT_CMDLINE);
-  if (it == section_map.end()) {
-    return std::vector<std::string>();
-  }
-  SectionDesc section = it->second;
-  const char* p = DataAtOffset(section.offset);
-  const char* end = DataAtOffset(section.offset + section.size);
-  std::vector<std::string> cmdline;
-  uint32_t arg_count;
-  MoveFromBinaryFormat(arg_count, p);
-  CHECK_LE(p, end);
-  for (size_t i = 0; i < arg_count; ++i) {
-    uint32_t len;
-    MoveFromBinaryFormat(len, p);
-    CHECK_LE(p + len, end);
-    cmdline.push_back(p);
-    p += len;
-  }
-  return cmdline;
-}
index a15972b..96262a8 100644 (file)
@@ -24,9 +24,9 @@
 class RecordTest : public ::testing::Test {
  protected:
   virtual void SetUp() {
-    std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType("cpu-cycles");
-    ASSERT_TRUE(event_type_modifier != nullptr);
-    event_attr = CreateDefaultPerfEventAttr(event_type_modifier->event_type);
+    const EventType* type = FindEventTypeByName("cpu-cycles");
+    ASSERT_TRUE(type != nullptr);
+    event_attr = CreateDefaultPerfEventAttr(*type);
   }
 
   template <class RecordType>
index 1108f72..1496974 100644 (file)
@@ -57,7 +57,7 @@ class SignalHandlerRegister {
  public:
   SignalHandlerRegister(const std::vector<int>& signums, void (*handler)(int)) {
     for (auto& sig : signums) {
-      sighandler_t old_handler = signal(sig, handler);
+      sig_t old_handler = signal(sig, handler);
       saved_signal_handlers_.push_back(std::make_pair(sig, old_handler));
     }
   }
@@ -69,7 +69,7 @@ class SignalHandlerRegister {
   }
 
  private:
-  std::vector<std::pair<int, sighandler_t>> saved_signal_handlers_;
+  std::vector<std::pair<int, sig_t>> saved_signal_handlers_;
 };
 
 template <class T>