diff options
Diffstat (limited to 'simpleperf/cmd_dumprecord.cpp')
-rw-r--r-- | simpleperf/cmd_dumprecord.cpp | 179 |
1 files changed, 179 insertions, 0 deletions
diff --git a/simpleperf/cmd_dumprecord.cpp b/simpleperf/cmd_dumprecord.cpp new file mode 100644 index 00000000..4ee93942 --- /dev/null +++ b/simpleperf/cmd_dumprecord.cpp @@ -0,0 +1,179 @@ +/* + * 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 <inttypes.h> + +#include <map> +#include <string> +#include <vector> + +#include <base/logging.h> +#include <base/stringprintf.h> + +#include "command.h" +#include "event_attr.h" +#include "record.h" +#include "record_file.h" + +using namespace PerfFileFormat; + +class DumpRecordCommandImpl { + public: + DumpRecordCommandImpl() : record_filename_("perf.data") { + } + + bool Run(const std::vector<std::string>& args); + + private: + bool ParseOptions(const std::vector<std::string>& args); + void DumpFileHeader(); + void DumpAttrSection(); + void DumpDataSection(); + + std::string record_filename_; + std::unique_ptr<RecordFileReader> record_file_reader_; + + std::vector<int> features_; +}; + +bool DumpRecordCommandImpl::Run(const std::vector<std::string>& args) { + if (!ParseOptions(args)) { + return false; + } + record_file_reader_ = RecordFileReader::CreateInstance(record_filename_); + if (record_file_reader_ == nullptr) { + return false; + } + DumpFileHeader(); + DumpAttrSection(); + DumpDataSection(); + + return true; +} + +bool DumpRecordCommandImpl::ParseOptions(const std::vector<std::string>& args) { + if (args.size() == 2) { + record_filename_ = args[1]; + } + return true; +} + +static const std::string GetFeatureName(int feature); + +void DumpRecordCommandImpl::DumpFileHeader() { + const FileHeader* header = record_file_reader_->FileHeader(); + printf("magic: "); + for (size_t i = 0; i < 8; ++i) { + printf("%c", header->magic[i]); + } + printf("\n"); + printf("header_size: %" PRId64 "\n", header->header_size); + if (header->header_size != sizeof(*header)) { + PLOG(WARNING) << "record file header size doesn't match expected header size " + << sizeof(*header); + } + printf("attr_size: %" PRId64 "\n", header->attr_size); + if (header->attr_size != sizeof(FileAttr)) { + PLOG(WARNING) << "record file attr size doesn't match expected attr size " << sizeof(FileAttr); + } + printf("attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n", header->attrs.offset, + header->attrs.size); + printf("data[file section]: offset %" PRId64 ", size %" PRId64 "\n", header->data.offset, + header->data.size); + printf("event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n", + header->event_types.offset, header->event_types.size); + + features_.clear(); + for (size_t i = 0; i < FEAT_MAX_NUM; ++i) { + size_t j = i / 8; + size_t k = i % 8; + if ((header->features[j] & (1 << k)) != 0) { + features_.push_back(i); + } + } + for (auto& feature : features_) { + printf("feature: %s\n", GetFeatureName(feature).c_str()); + } +} + +static const std::string GetFeatureName(int feature) { + static std::map<int, std::string> feature_name_map = { + {FEAT_TRACING_DATA, "tracing_data"}, + {FEAT_BUILD_ID, "build_id"}, + {FEAT_HOSTNAME, "hostname"}, + {FEAT_OSRELEASE, "osrelease"}, + {FEAT_VERSION, "version"}, + {FEAT_ARCH, "arch"}, + {FEAT_NRCPUS, "nrcpus"}, + {FEAT_CPUDESC, "cpudesc"}, + {FEAT_CPUID, "cpuid"}, + {FEAT_TOTAL_MEM, "total_mem"}, + {FEAT_CMDLINE, "cmdline"}, + {FEAT_EVENT_DESC, "event_desc"}, + {FEAT_CPU_TOPOLOGY, "cpu_topology"}, + {FEAT_NUMA_TOPOLOGY, "numa_topology"}, + {FEAT_BRANCH_STACK, "branck_stack"}, + {FEAT_PMU_MAPPINGS, "pmu_mappings"}, + {FEAT_GROUP_DESC, "group_desc"}, + }; + auto it = feature_name_map.find(feature); + if (it != feature_name_map.end()) { + return it->second; + } + return android::base::StringPrintf("unknown_feature(%d)", feature); +} + +void DumpRecordCommandImpl::DumpAttrSection() { + std::vector<const FileAttr*> attrs = record_file_reader_->AttrSection(); + for (size_t i = 0; i < attrs.size(); ++i) { + auto& attr = attrs[i]; + printf("file_attr %zu:\n", i + 1); + DumpPerfEventAttr(attr->attr, 1); + printf(" ids[file_section]: offset %" PRId64 ", size %" PRId64 "\n", attr->ids.offset, + attr->ids.size); + std::vector<uint64_t> ids = record_file_reader_->IdsForAttr(attr); + if (ids.size() > 0) { + printf(" ids:"); + for (auto& id : ids) { + printf(" %" PRId64, id); + } + printf("\n"); + } + } +} + +void DumpRecordCommandImpl::DumpDataSection() { + std::vector<std::unique_ptr<const Record>> records = record_file_reader_->DataSection(); + for (auto& record : records) { + record->Dump(); + } +} + +class DumpRecordCommand : public Command { + public: + DumpRecordCommand() + : Command("dump", "dump perf record file", + "Usage: simpleperf dumprecord [options] [perf_record_file]\n" + " Dump different parts of a perf record file. Default file is perf.data.\n") { + } + + bool Run(const std::vector<std::string>& args) override { + DumpRecordCommandImpl impl; + return impl.Run(args); + } +}; + +DumpRecordCommand dumprecord_cmd; |