cmd_dumprecord.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286
  1. /*
  2. * Copyright (C) 2015 The Android Open Source Project
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <inttypes.h>
  17. #include <map>
  18. #include <string>
  19. #include <vector>
  20. #include <android-base/logging.h>
  21. #include <android-base/stringprintf.h>
  22. #include <android-base/strings.h>
  23. #include "command.h"
  24. #include "event_attr.h"
  25. #include "event_type.h"
  26. #include "perf_regs.h"
  27. #include "record.h"
  28. #include "record_file.h"
  29. #include "utils.h"
  30. using namespace PerfFileFormat;
  31. class DumpRecordCommand : public Command {
  32. public:
  33. DumpRecordCommand()
  34. : Command("dump", "dump perf record file",
  35. "Usage: simpleperf dumprecord [options] [perf_record_file]\n"
  36. " Dump different parts of a perf record file. Default file is perf.data.\n"),
  37. record_filename_("perf.data"), record_file_arch_(GetBuildArch()) {
  38. }
  39. bool Run(const std::vector<std::string>& args);
  40. private:
  41. bool ParseOptions(const std::vector<std::string>& args);
  42. void DumpFileHeader();
  43. void DumpAttrSection();
  44. bool DumpDataSection();
  45. bool DumpFeatureSection();
  46. std::string record_filename_;
  47. std::unique_ptr<RecordFileReader> record_file_reader_;
  48. ArchType record_file_arch_;
  49. };
  50. bool DumpRecordCommand::Run(const std::vector<std::string>& args) {
  51. if (!ParseOptions(args)) {
  52. return false;
  53. }
  54. record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
  55. if (record_file_reader_ == nullptr) {
  56. return false;
  57. }
  58. std::string arch = record_file_reader_->ReadFeatureString(FEAT_ARCH);
  59. if (!arch.empty()) {
  60. record_file_arch_ = GetArchType(arch);
  61. if (record_file_arch_ == ARCH_UNSUPPORTED) {
  62. return false;
  63. }
  64. }
  65. ScopedCurrentArch scoped_arch(record_file_arch_);
  66. std::unique_ptr<ScopedEventTypes> scoped_event_types;
  67. if (record_file_reader_->HasFeature(PerfFileFormat::FEAT_META_INFO)) {
  68. std::unordered_map<std::string, std::string> meta_info;
  69. if (!record_file_reader_->ReadMetaInfoFeature(&meta_info)) {
  70. return false;
  71. }
  72. auto it = meta_info.find("event_type_info");
  73. if (it != meta_info.end()) {
  74. scoped_event_types.reset(new ScopedEventTypes(it->second));
  75. }
  76. }
  77. DumpFileHeader();
  78. DumpAttrSection();
  79. if (!DumpDataSection()) {
  80. return false;
  81. }
  82. return DumpFeatureSection();
  83. }
  84. bool DumpRecordCommand::ParseOptions(const std::vector<std::string>& args) {
  85. if (args.size() == 1) {
  86. record_filename_ = args[0];
  87. } else if (args.size() > 1) {
  88. ReportUnknownOption(args, 1);
  89. return false;
  90. }
  91. return true;
  92. }
  93. static const std::string GetFeatureNameOrUnknown(int feature) {
  94. std::string name = GetFeatureName(feature);
  95. return name.empty() ? android::base::StringPrintf("unknown_feature(%d)", feature) : name;
  96. }
  97. void DumpRecordCommand::DumpFileHeader() {
  98. const FileHeader& header = record_file_reader_->FileHeader();
  99. printf("magic: ");
  100. for (size_t i = 0; i < 8; ++i) {
  101. printf("%c", header.magic[i]);
  102. }
  103. printf("\n");
  104. printf("header_size: %" PRId64 "\n", header.header_size);
  105. if (header.header_size != sizeof(header)) {
  106. PLOG(WARNING) << "record file header size " << header.header_size
  107. << "doesn't match expected header size " << sizeof(header);
  108. }
  109. printf("attr_size: %" PRId64 "\n", header.attr_size);
  110. if (header.attr_size != sizeof(FileAttr)) {
  111. PLOG(WARNING) << "record file attr size " << header.attr_size
  112. << " doesn't match expected attr size " << sizeof(FileAttr);
  113. }
  114. printf("attrs[file section]: offset %" PRId64 ", size %" PRId64 "\n", header.attrs.offset,
  115. header.attrs.size);
  116. printf("data[file section]: offset %" PRId64 ", size %" PRId64 "\n", header.data.offset,
  117. header.data.size);
  118. printf("event_types[file section]: offset %" PRId64 ", size %" PRId64 "\n",
  119. header.event_types.offset, header.event_types.size);
  120. std::vector<int> features;
  121. for (size_t i = 0; i < FEAT_MAX_NUM; ++i) {
  122. size_t j = i / 8;
  123. size_t k = i % 8;
  124. if ((header.features[j] & (1 << k)) != 0) {
  125. features.push_back(i);
  126. }
  127. }
  128. for (auto& feature : features) {
  129. printf("feature: %s\n", GetFeatureNameOrUnknown(feature).c_str());
  130. }
  131. }
  132. void DumpRecordCommand::DumpAttrSection() {
  133. std::vector<EventAttrWithId> attrs = record_file_reader_->AttrSection();
  134. for (size_t i = 0; i < attrs.size(); ++i) {
  135. const auto& attr = attrs[i];
  136. printf("attr %zu:\n", i + 1);
  137. DumpPerfEventAttr(*attr.attr, 1);
  138. if (!attr.ids.empty()) {
  139. printf(" ids:");
  140. for (const auto& id : attr.ids) {
  141. printf(" %" PRId64, id);
  142. }
  143. printf("\n");
  144. }
  145. }
  146. }
  147. bool DumpRecordCommand::DumpDataSection() {
  148. ThreadTree thread_tree;
  149. thread_tree.ShowIpForUnknownSymbol();
  150. record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree);
  151. auto get_symbol_function = [&](uint32_t pid, uint32_t tid, uint64_t ip, std::string& dso_name,
  152. std::string& symbol_name, uint64_t& vaddr_in_file,
  153. bool in_kernel) {
  154. ThreadEntry* thread = thread_tree.FindThreadOrNew(pid, tid);
  155. const MapEntry* map = thread_tree.FindMap(thread, ip, in_kernel);
  156. Dso* dso;
  157. const Symbol* symbol = thread_tree.FindSymbol(map, ip, &vaddr_in_file, &dso);
  158. dso_name = dso->Path();
  159. symbol_name = symbol->DemangledName();
  160. };
  161. auto record_callback = [&](std::unique_ptr<Record> r) {
  162. r->Dump();
  163. thread_tree.Update(*r);
  164. if (r->type() == PERF_RECORD_SAMPLE) {
  165. SampleRecord& sr = *static_cast<SampleRecord*>(r.get());
  166. bool in_kernel = sr.InKernel();
  167. if (sr.sample_type & PERF_SAMPLE_CALLCHAIN) {
  168. PrintIndented(1, "callchain:\n");
  169. for (size_t i = 0; i < sr.callchain_data.ip_nr; ++i) {
  170. if (sr.callchain_data.ips[i] >= PERF_CONTEXT_MAX) {
  171. if (sr.callchain_data.ips[i] == PERF_CONTEXT_USER) {
  172. in_kernel = false;
  173. }
  174. continue;
  175. }
  176. std::string dso_name;
  177. std::string symbol_name;
  178. uint64_t vaddr_in_file;
  179. get_symbol_function(sr.tid_data.pid, sr.tid_data.tid, sr.callchain_data.ips[i],
  180. dso_name, symbol_name, vaddr_in_file, in_kernel);
  181. PrintIndented(2, "%s (%s[+%" PRIx64 "])\n", symbol_name.c_str(), dso_name.c_str(),
  182. vaddr_in_file);
  183. }
  184. }
  185. } else if (r->type() == SIMPLE_PERF_RECORD_CALLCHAIN) {
  186. CallChainRecord& cr = *static_cast<CallChainRecord*>(r.get());
  187. PrintIndented(1, "callchain:\n");
  188. for (size_t i = 0; i < cr.ip_nr; ++i) {
  189. std::string dso_name;
  190. std::string symbol_name;
  191. uint64_t vaddr_in_file;
  192. get_symbol_function(cr.pid, cr.tid, cr.ips[i], dso_name, symbol_name, vaddr_in_file,
  193. false);
  194. PrintIndented(2, "%s (%s[+%" PRIx64 "])\n", symbol_name.c_str(), dso_name.c_str(),
  195. vaddr_in_file);
  196. }
  197. }
  198. return true;
  199. };
  200. return record_file_reader_->ReadDataSection(record_callback);
  201. }
  202. bool DumpRecordCommand::DumpFeatureSection() {
  203. std::map<int, SectionDesc> section_map = record_file_reader_->FeatureSectionDescriptors();
  204. for (const auto& pair : section_map) {
  205. int feature = pair.first;
  206. const auto& section = pair.second;
  207. printf("feature section for %s: offset %" PRId64 ", size %" PRId64 "\n",
  208. GetFeatureNameOrUnknown(feature).c_str(), section.offset, section.size);
  209. if (feature == FEAT_BUILD_ID) {
  210. std::vector<BuildIdRecord> records = record_file_reader_->ReadBuildIdFeature();
  211. for (auto& r : records) {
  212. r.Dump(1);
  213. }
  214. } else if (feature == FEAT_OSRELEASE) {
  215. std::string s = record_file_reader_->ReadFeatureString(feature);
  216. PrintIndented(1, "osrelease: %s\n", s.c_str());
  217. } else if (feature == FEAT_ARCH) {
  218. std::string s = record_file_reader_->ReadFeatureString(feature);
  219. PrintIndented(1, "arch: %s\n", s.c_str());
  220. } else if (feature == FEAT_CMDLINE) {
  221. std::vector<std::string> cmdline = record_file_reader_->ReadCmdlineFeature();
  222. PrintIndented(1, "cmdline: %s\n", android::base::Join(cmdline, ' ').c_str());
  223. } else if (feature == FEAT_FILE) {
  224. std::string file_path;
  225. uint32_t file_type;
  226. uint64_t min_vaddr;
  227. uint64_t file_offset_of_min_vaddr;
  228. std::vector<Symbol> symbols;
  229. std::vector<uint64_t> dex_file_offsets;
  230. size_t read_pos = 0;
  231. PrintIndented(1, "file:\n");
  232. while (record_file_reader_->ReadFileFeature(read_pos, &file_path, &file_type,
  233. &min_vaddr, &file_offset_of_min_vaddr,
  234. &symbols, &dex_file_offsets)) {
  235. PrintIndented(2, "file_path %s\n", file_path.c_str());
  236. PrintIndented(2, "file_type %s\n", DsoTypeToString(static_cast<DsoType>(file_type)));
  237. PrintIndented(2, "min_vaddr 0x%" PRIx64 "\n", min_vaddr);
  238. PrintIndented(2, "file_offset_of_min_vaddr 0x%" PRIx64 "\n", file_offset_of_min_vaddr);
  239. PrintIndented(2, "symbols:\n");
  240. for (const auto& symbol : symbols) {
  241. PrintIndented(3, "%s [0x%" PRIx64 "-0x%" PRIx64 "]\n", symbol.DemangledName(),
  242. symbol.addr, symbol.addr + symbol.len);
  243. }
  244. if (file_type == static_cast<uint32_t>(DSO_DEX_FILE)) {
  245. PrintIndented(2, "dex_file_offsets:\n");
  246. for (uint64_t offset : dex_file_offsets) {
  247. PrintIndented(3, "0x%" PRIx64 "\n", offset);
  248. }
  249. }
  250. }
  251. } else if (feature == FEAT_META_INFO) {
  252. std::unordered_map<std::string, std::string> info_map;
  253. if (!record_file_reader_->ReadMetaInfoFeature(&info_map)) {
  254. return false;
  255. }
  256. PrintIndented(1, "meta_info:\n");
  257. for (auto& pair : info_map) {
  258. PrintIndented(2, "%s = %s\n", pair.first.c_str(), pair.second.c_str());
  259. }
  260. }
  261. }
  262. return true;
  263. }
  264. void RegisterDumpRecordCommand() {
  265. RegisterCommand("dump", [] { return std::unique_ptr<Command>(new DumpRecordCommand); });
  266. }