From 9fd3cc1048a3d0338df4a48760dfd655560992a1 Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Thu, 25 Jun 2015 17:42:23 -0700 Subject: [PATCH] Simpleperf: support build on mac. Bug: 19483574 Change-Id: I6c28541944bc0a4e6fc07d7ea5a8fb5f71890510 --- simpleperf/Android.mk | 86 +++++++-- simpleperf/cmd_list.cpp | 6 +- simpleperf/cmd_record.cpp | 4 +- simpleperf/cmd_stat.cpp | 29 +-- simpleperf/darwin_support/asm/byteorder.h | 15 ++ simpleperf/darwin_support/linux/ioctl.h | 19 ++ simpleperf/darwin_support/linux/types.h | 23 +++ simpleperf/dso.cpp | 13 +- simpleperf/environment_fake.cpp | 22 +++ simpleperf/event_fd.cpp | 5 + simpleperf/event_fd.h | 2 + simpleperf/event_selection_set.cpp | 16 +- simpleperf/event_selection_set.h | 2 +- simpleperf/event_type.cpp | 24 +-- simpleperf/event_type.h | 6 +- simpleperf/record_file_reader.cpp | 198 +++++++++++++++++++++ .../{record_file.cpp => record_file_writer.cpp} | 166 ----------------- simpleperf/record_test.cpp | 6 +- simpleperf/utils.h | 4 +- 19 files changed, 413 insertions(+), 233 deletions(-) create mode 100644 simpleperf/darwin_support/asm/byteorder.h create mode 100644 simpleperf/darwin_support/linux/ioctl.h create mode 100644 simpleperf/darwin_support/linux/types.h create mode 100644 simpleperf/environment_fake.cpp create mode 100644 simpleperf/record_file_reader.cpp rename simpleperf/{record_file.cpp => record_file_writer.cpp} (66%) diff --git a/simpleperf/Android.mk b/simpleperf/Android.mk index 4642e2a5..278bc246 100644 --- a/simpleperf/Android.mk +++ b/simpleperf/Android.mk @@ -17,8 +17,11 @@ 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 diff --git a/simpleperf/cmd_list.cpp b/simpleperf/cmd_list.cpp index 221f3fb7..e65756a4 100644 --- a/simpleperf/cmd_list.cpp +++ b/simpleperf/cmd_list.cpp @@ -22,14 +22,16 @@ #include #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& 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()); } } diff --git a/simpleperf/cmd_record.cpp b/simpleperf/cmd_record.cpp index 59cc3dc5..f91100a9 100644 --- a/simpleperf/cmd_record.cpp +++ b/simpleperf/cmd_record.cpp @@ -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 { diff --git a/simpleperf/cmd_stat.cpp b/simpleperf/cmd_stat.cpp index 83a4a3fc..d4b19239 100644 --- a/simpleperf/cmd_stat.cpp +++ b/simpleperf/cmd_stat.cpp @@ -27,9 +27,10 @@ #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& args, std::vector* 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>& counters_map, std::chrono::steady_clock::duration counting_duration); @@ -103,7 +104,9 @@ bool StatCommand::Run(const std::vector& args) { return false; } } - SetEventSelection(); + if (!SetEventSelection()) { + return false; + } // 2. Create workload. std::unique_ptr workload; @@ -216,10 +219,8 @@ bool StatCommand::ParseOptions(const std::vector& args, return true; } -bool StatCommand::AddMeasuredEventType(const std::string& event_type_name, - bool report_unsupported_type) { - std::unique_ptr event_type_modifier = - ParseEventType(event_type_name, report_unsupported_type); +bool StatCommand::AddMeasuredEventType(const std::string& event_type_name) { + std::unique_ptr 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 index 00000000..d118abcf --- /dev/null +++ b/simpleperf/darwin_support/asm/byteorder.h @@ -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 index 00000000..f5807367 --- /dev/null +++ b/simpleperf/darwin_support/linux/ioctl.h @@ -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 index 00000000..30478eb2 --- /dev/null +++ b/simpleperf/darwin_support/linux/types.h @@ -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 + +typedef uint8_t __u8; +typedef uint16_t __u16; +typedef uint32_t __u32; +typedef uint64_t __u64; +typedef int64_t __s64; diff --git a/simpleperf/dso.cpp b/simpleperf/dso.cpp index b5880ca6..562727b2 100644 --- a/simpleperf/dso.cpp +++ b/simpleperf/dso.cpp @@ -29,7 +29,9 @@ bool SymbolComparator::operator()(const std::unique_ptr& symbol1, const SymbolEntry* DsoEntry::FindSymbol(uint64_t offset_in_dso) { std::unique_ptr 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(symbol)); } @@ -93,6 +97,7 @@ static void FixupSymbolLength(DsoEntry* dso) { } } +// TODO: Fix the way to get kernel symbols. See b/22179177. std::unique_ptr DsoFactory::LoadKernel() { std::unique_ptr 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(symbol)); } diff --git a/simpleperf/environment_fake.cpp b/simpleperf/environment_fake.cpp new file mode 100644 index 00000000..e8c9dd82 --- /dev/null +++ b/simpleperf/environment_fake.cpp @@ -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) { + return false; +} diff --git a/simpleperf/event_fd.cpp b/simpleperf/event_fd.cpp index 547be299..9c5e4ab6 100644 --- a/simpleperf/event_fd.cpp +++ b/simpleperf/event_fd.cpp @@ -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; +} diff --git a/simpleperf/event_fd.h b/simpleperf/event_fd.h index bcacc283..1fe5af00 100644 --- a/simpleperf/event_fd.h +++ b/simpleperf/event_fd.h @@ -97,4 +97,6 @@ class EventFd { DISALLOW_COPY_AND_ASSIGN(EventFd); }; +bool IsEventAttrSupportedByKernel(perf_event_attr attr); + #endif // SIMPLE_PERF_EVENT_FD_H_ diff --git a/simpleperf/event_selection_set.cpp b/simpleperf/event_selection_set.cpp index 0f23c149..a9a0f969 100644 --- a/simpleperf/event_selection_set.cpp +++ b/simpleperf/event_selection_set.cpp @@ -24,18 +24,17 @@ #include "event_type.h" bool IsBranchSamplingSupported() { - std::unique_ptr 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) { diff --git a/simpleperf/event_selection_set.h b/simpleperf/event_selection_set.h index adf34403..e52ec5f7 100644 --- a/simpleperf/event_selection_set.h +++ b/simpleperf/event_selection_set.h @@ -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(); diff --git a/simpleperf/event_type.cpp b/simpleperf/event_type.cpp index 56a17b8c..526cfa53 100644 --- a/simpleperf/event_type.cpp +++ b/simpleperf/event_type.cpp @@ -36,16 +36,6 @@ static const std::vector 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 GetTracepointEventTypes() { std::vector 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 ParseEventType(const std::string& event_type_str, - bool report_unsupported_type) { +std::unique_ptr ParseEventType(const std::string& event_type_str) { static std::string modifier_characters = "ukhGHp"; std::unique_ptr event_type_modifier(new EventTypeAndModifier); std::string name = event_type_str; @@ -138,13 +122,13 @@ std::unique_ptr 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; diff --git a/simpleperf/event_type.h b/simpleperf/event_type.h index 9c365faf..df2f782d 100644 --- a/simpleperf/event_type.h +++ b/simpleperf/event_type.h @@ -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& 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 ParseEventType(const std::string& event_type_str, - bool report_unsupported_type = true); +std::unique_ptr 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 index 00000000..8407d32b --- /dev/null +++ b/simpleperf/record_file_reader.cpp @@ -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 +#include +#include +#include +#include +#include + +#include + +#include "perf_event.h" +#include "record.h" +#include "utils.h" + +using namespace PerfFileFormat; + +std::unique_ptr 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(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(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(mmap_addr); + mmap_len_ = mmap_len; + return true; +} + +const FileHeader* RecordFileReader::FileHeader() { + return reinterpret_cast(mmap_addr_); +} + +std::vector RecordFileReader::AttrSection() { + std::vector result; + const struct FileHeader* header = FileHeader(); + size_t attr_count = header->attrs.size / header->attr_size; + const FileAttr* attr = reinterpret_cast(mmap_addr_ + header->attrs.offset); + for (size_t i = 0; i < attr_count; ++i) { + result.push_back(attr++); + } + return result; +} + +std::vector RecordFileReader::IdsForAttr(const FileAttr* attr) { + std::vector result; + size_t id_count = attr->ids.size / sizeof(uint64_t); + const uint64_t* id = reinterpret_cast(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& r1, + const std::unique_ptr& 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(r1.get())->time_data.time + : r1->sample_id.time_data.time); + uint64_t time2 = (is_r2_sample ? static_cast(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> RecordFileReader::DataSection() { + std::vector> 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(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& RecordFileReader::FeatureSectionDescriptors() { + if (feature_sections_.empty()) { + std::vector 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(mmap_addr_ + feature_section_offset); + for (auto& feature : features) { + feature_sections_.insert(std::make_pair(feature, *p)); + ++p; + } + } + return feature_sections_; +} + +std::vector RecordFileReader::ReadCmdlineFeature() { + const std::map& section_map = FeatureSectionDescriptors(); + auto it = section_map.find(FEAT_CMDLINE); + if (it == section_map.end()) { + return std::vector(); + } + SectionDesc section = it->second; + const char* p = DataAtOffset(section.offset); + const char* end = DataAtOffset(section.offset + section.size); + std::vector 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; +} diff --git a/simpleperf/record_file.cpp b/simpleperf/record_file_writer.cpp similarity index 66% rename from simpleperf/record_file.cpp rename to simpleperf/record_file_writer.cpp index 2f6bf109..deb0adad 100644 --- a/simpleperf/record_file.cpp +++ b/simpleperf/record_file_writer.cpp @@ -361,169 +361,3 @@ bool RecordFileWriter::Close() { record_fp_ = nullptr; return result; } - -std::unique_ptr 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(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(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(mmap_addr); - mmap_len_ = mmap_len; - return true; -} - -const FileHeader* RecordFileReader::FileHeader() { - return reinterpret_cast(mmap_addr_); -} - -std::vector RecordFileReader::AttrSection() { - std::vector result; - const struct FileHeader* header = FileHeader(); - size_t attr_count = header->attrs.size / header->attr_size; - const FileAttr* attr = reinterpret_cast(mmap_addr_ + header->attrs.offset); - for (size_t i = 0; i < attr_count; ++i) { - result.push_back(attr++); - } - return result; -} - -std::vector RecordFileReader::IdsForAttr(const FileAttr* attr) { - std::vector result; - size_t id_count = attr->ids.size / sizeof(uint64_t); - const uint64_t* id = reinterpret_cast(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& r1, - const std::unique_ptr& 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(r1.get())->time_data.time - : r1->sample_id.time_data.time); - uint64_t time2 = (is_r2_sample ? static_cast(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> RecordFileReader::DataSection() { - std::vector> 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(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& RecordFileReader::FeatureSectionDescriptors() { - if (feature_sections_.empty()) { - std::vector 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(mmap_addr_ + feature_section_offset); - for (auto& feature : features) { - feature_sections_.insert(std::make_pair(feature, *p)); - ++p; - } - } - return feature_sections_; -} - -std::vector RecordFileReader::ReadCmdlineFeature() { - const std::map& section_map = FeatureSectionDescriptors(); - auto it = section_map.find(FEAT_CMDLINE); - if (it == section_map.end()) { - return std::vector(); - } - SectionDesc section = it->second; - const char* p = DataAtOffset(section.offset); - const char* end = DataAtOffset(section.offset + section.size); - std::vector 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; -} diff --git a/simpleperf/record_test.cpp b/simpleperf/record_test.cpp index a15972b6..96262a84 100644 --- a/simpleperf/record_test.cpp +++ b/simpleperf/record_test.cpp @@ -24,9 +24,9 @@ class RecordTest : public ::testing::Test { protected: virtual void SetUp() { - std::unique_ptr 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 diff --git a/simpleperf/utils.h b/simpleperf/utils.h index 1108f725..14969748 100644 --- a/simpleperf/utils.h +++ b/simpleperf/utils.h @@ -57,7 +57,7 @@ class SignalHandlerRegister { public: SignalHandlerRegister(const std::vector& 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> saved_signal_handlers_; + std::vector> saved_signal_handlers_; }; template -- 2.11.0