OSDN Git Service

ANRdaemon: move trace result from /sdcard to /data am: d93aa41807
[android-x86/system-extras.git] / simpleperf / cmd_record.cpp
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
17 #include <libgen.h>
18 #include <poll.h>
19 #include <signal.h>
20 #include <sys/utsname.h>
21 #include <unistd.h>
22 #include <set>
23 #include <string>
24 #include <unordered_map>
25 #include <vector>
26
27 #include <android-base/logging.h>
28 #include <android-base/strings.h>
29
30 #include "command.h"
31 #include "dwarf_unwind.h"
32 #include "environment.h"
33 #include "event_selection_set.h"
34 #include "event_type.h"
35 #include "read_apk.h"
36 #include "read_elf.h"
37 #include "record.h"
38 #include "record_file.h"
39 #include "scoped_signal_handler.h"
40 #include "thread_tree.h"
41 #include "utils.h"
42 #include "workload.h"
43
44 static std::string default_measured_event_type = "cpu-cycles";
45
46 static std::unordered_map<std::string, uint64_t> branch_sampling_type_map = {
47     {"u", PERF_SAMPLE_BRANCH_USER},
48     {"k", PERF_SAMPLE_BRANCH_KERNEL},
49     {"any", PERF_SAMPLE_BRANCH_ANY},
50     {"any_call", PERF_SAMPLE_BRANCH_ANY_CALL},
51     {"any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN},
52     {"ind_call", PERF_SAMPLE_BRANCH_IND_CALL},
53 };
54
55 static volatile bool signaled;
56 static void signal_handler(int) {
57   signaled = true;
58 }
59
60 // Used in cpu-hotplug test.
61 bool system_wide_perf_event_open_failed = false;
62
63 class RecordCommand : public Command {
64  public:
65   RecordCommand()
66       : Command(
67             "record", "record sampling info in perf.data",
68             "Usage: simpleperf record [options] [command [command-args]]\n"
69             "    Gather sampling information when running [command].\n"
70             "    -a           System-wide collection.\n"
71             "    -b           Enable take branch stack sampling. Same as '-j any'\n"
72             "    -c count     Set event sample period.\n"
73             "    --call-graph fp | dwarf[,<dump_stack_size>]\n"
74             "                 Enable call graph recording. Use frame pointer or dwarf as the\n"
75             "                 method to parse call graph in stack. Default is dwarf,8192.\n"
76             "    --cpu cpu_item1,cpu_item2,...\n"
77             "                 Collect samples only on the selected cpus. cpu_item can be cpu\n"
78             "                 number like 1, or cpu range like 0-3.\n"
79             "    -e event1[:modifier1],event2[:modifier2],...\n"
80             "                 Select the event list to sample. Use `simpleperf list` to find\n"
81             "                 all possible event names. Modifiers can be added to define\n"
82             "                 how the event should be monitored. Possible modifiers are:\n"
83             "                   u - monitor user space events only\n"
84             "                   k - monitor kernel space events only\n"
85             "    -f freq      Set event sample frequency.\n"
86             "    -F freq      Same as '-f freq'.\n"
87             "    -g           Same as '--call-graph dwarf'.\n"
88             "    -j branch_filter1,branch_filter2,...\n"
89             "                 Enable taken branch stack sampling. Each sample\n"
90             "                 captures a series of consecutive taken branches.\n"
91             "                 The following filters are defined:\n"
92             "                   any: any type of branch\n"
93             "                   any_call: any function call or system call\n"
94             "                   any_ret: any function return or system call return\n"
95             "                   ind_call: any indirect branch\n"
96             "                   u: only when the branch target is at the user level\n"
97             "                   k: only when the branch target is in the kernel\n"
98             "                 This option requires at least one branch type among any,\n"
99             "                 any_call, any_ret, ind_call.\n"
100             "    -m mmap_pages\n"
101             "                 Set the size of the buffer used to receiving sample data from\n"
102             "                 the kernel. It should be a power of 2. The default value is 16.\n"
103             "    --no-inherit\n"
104             "                 Don't record created child threads/processes.\n"
105             "    --no-unwind  If `--call-graph dwarf` option is used, then the user's stack will\n"
106             "                 be unwound by default. Use this option to disable the unwinding of\n"
107             "                 the user's stack.\n"
108             "    -o record_file_name    Set record file name, default is perf.data.\n"
109             "    -p pid1,pid2,...\n"
110             "                 Record events on existing processes. Mutually exclusive with -a.\n"
111             "    --post-unwind\n"
112             "                 If `--call-graph dwarf` option is used, then the user's stack will\n"
113             "                 be unwound while recording by default. But it may lose records as\n"
114             "                 stacking unwinding can be time consuming. Use this option to unwind\n"
115             "                 the user's stack after recording.\n"
116             "    -t tid1,tid2,...\n"
117             "                 Record events on existing threads. Mutually exclusive with -a.\n"),
118         use_sample_freq_(true),
119         sample_freq_(4000),
120         system_wide_collection_(false),
121         branch_sampling_(0),
122         fp_callchain_sampling_(false),
123         dwarf_callchain_sampling_(false),
124         dump_stack_size_in_dwarf_sampling_(8192),
125         unwind_dwarf_callchain_(true),
126         post_unwind_(false),
127         child_inherit_(true),
128         perf_mmap_pages_(16),
129         record_filename_("perf.data"),
130         sample_record_count_(0) {
131     signaled = false;
132     scoped_signal_handler_.reset(
133         new ScopedSignalHandler({SIGCHLD, SIGINT, SIGTERM}, signal_handler));
134   }
135
136   bool Run(const std::vector<std::string>& args);
137
138   static bool ReadMmapDataCallback(const char* data, size_t size);
139
140  private:
141   bool ParseOptions(const std::vector<std::string>& args, std::vector<std::string>* non_option_args);
142   bool AddMeasuredEventType(const std::string& event_type_name);
143   bool SetEventSelection();
144   bool CreateAndInitRecordFile();
145   std::unique_ptr<RecordFileWriter> CreateRecordFile(const std::string& filename);
146   bool DumpKernelAndModuleMmaps();
147   bool DumpThreadCommAndMmaps(bool all_threads, const std::vector<pid_t>& selected_threads);
148   bool CollectRecordsFromKernel(const char* data, size_t size);
149   bool ProcessRecord(Record* record);
150   void UpdateRecordForEmbeddedElfPath(Record* record);
151   void UnwindRecord(Record* record);
152   bool PostUnwind(const std::vector<std::string>& args);
153   bool DumpAdditionalFeatures(const std::vector<std::string>& args);
154   bool DumpBuildIdFeature();
155   void CollectHitFileInfo(Record* record);
156   std::pair<std::string, uint64_t> TestForEmbeddedElf(Dso *dso, uint64_t pgoff);
157
158   bool use_sample_freq_;    // Use sample_freq_ when true, otherwise using sample_period_.
159   uint64_t sample_freq_;    // Sample 'sample_freq_' times per second.
160   uint64_t sample_period_;  // Sample once when 'sample_period_' events occur.
161
162   bool system_wide_collection_;
163   uint64_t branch_sampling_;
164   bool fp_callchain_sampling_;
165   bool dwarf_callchain_sampling_;
166   uint32_t dump_stack_size_in_dwarf_sampling_;
167   bool unwind_dwarf_callchain_;
168   bool post_unwind_;
169   bool child_inherit_;
170   std::vector<pid_t> monitored_threads_;
171   std::vector<int> cpus_;
172   std::vector<EventTypeAndModifier> measured_event_types_;
173   EventSelectionSet event_selection_set_;
174
175   // mmap pages used by each perf event file, should be a power of 2.
176   size_t perf_mmap_pages_;
177
178   std::unique_ptr<RecordCache> record_cache_;
179   ThreadTree thread_tree_;
180   std::string record_filename_;
181   std::unique_ptr<RecordFileWriter> record_file_writer_;
182
183   std::set<std::string> hit_kernel_modules_;
184   std::set<std::string> hit_user_files_;
185
186   std::unique_ptr<ScopedSignalHandler> scoped_signal_handler_;
187   uint64_t sample_record_count_;
188 };
189
190 bool RecordCommand::Run(const std::vector<std::string>& args) {
191   if (!CheckPerfEventLimit()) {
192     return false;
193   }
194
195   // 1. Parse options, and use default measured event type if not given.
196   std::vector<std::string> workload_args;
197   if (!ParseOptions(args, &workload_args)) {
198     return false;
199   }
200   if (measured_event_types_.empty()) {
201     if (!AddMeasuredEventType(default_measured_event_type)) {
202       return false;
203     }
204   }
205   if (!SetEventSelection()) {
206     return false;
207   }
208
209   // 2. Create workload.
210   std::unique_ptr<Workload> workload;
211   if (!workload_args.empty()) {
212     workload = Workload::CreateWorkload(workload_args);
213     if (workload == nullptr) {
214       return false;
215     }
216   }
217   if (!system_wide_collection_ && monitored_threads_.empty()) {
218     if (workload != nullptr) {
219       monitored_threads_.push_back(workload->GetPid());
220       event_selection_set_.SetEnableOnExec(true);
221     } else {
222       LOG(ERROR) << "No threads to monitor. Try `simpleperf help record` for help\n";
223       return false;
224     }
225   }
226
227   // 3. Open perf_event_files, create memory mapped buffers for perf_event_files, add prepare poll
228   //    for perf_event_files.
229   if (system_wide_collection_) {
230     if (!event_selection_set_.OpenEventFilesForCpus(cpus_)) {
231       system_wide_perf_event_open_failed = true;
232       return false;
233     }
234   } else {
235     if (!event_selection_set_.OpenEventFilesForThreadsOnCpus(monitored_threads_, cpus_)) {
236       return false;
237     }
238   }
239   if (!event_selection_set_.MmapEventFiles(perf_mmap_pages_)) {
240     return false;
241   }
242   std::vector<pollfd> pollfds;
243   event_selection_set_.PreparePollForEventFiles(&pollfds);
244
245   // 4. Create perf.data.
246   if (!CreateAndInitRecordFile()) {
247     return false;
248   }
249
250   // 5. Write records in mmap buffers of perf_event_files to output file while workload is running.
251   if (workload != nullptr && !workload->Start()) {
252     return false;
253   }
254   record_cache_.reset(
255       new RecordCache(*event_selection_set_.FindEventAttrByType(measured_event_types_[0])));
256   auto callback = std::bind(&RecordCommand::CollectRecordsFromKernel, this, std::placeholders::_1,
257                             std::placeholders::_2);
258   while (true) {
259     if (!event_selection_set_.ReadMmapEventData(callback)) {
260       return false;
261     }
262     if (signaled) {
263       break;
264     }
265     poll(&pollfds[0], pollfds.size(), -1);
266   }
267   std::vector<std::unique_ptr<Record>> records = record_cache_->PopAll();
268   for (auto& r : records) {
269     if (!ProcessRecord(r.get())) {
270       return false;
271     }
272   }
273
274   // 6. Dump additional features, and close record file.
275   if (!DumpAdditionalFeatures(args)) {
276     return false;
277   }
278   if (!record_file_writer_->Close()) {
279     return false;
280   }
281
282   // 7. Unwind dwarf callchain.
283   if (post_unwind_) {
284     if (!PostUnwind(args)) {
285       return false;
286     }
287   }
288   LOG(VERBOSE) << "Record " << sample_record_count_ << " samples.";
289   return true;
290 }
291
292 bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
293                                  std::vector<std::string>* non_option_args) {
294   std::set<pid_t> tid_set;
295   size_t i;
296   for (i = 0; i < args.size() && args[i].size() > 0 && args[i][0] == '-'; ++i) {
297     if (args[i] == "-a") {
298       system_wide_collection_ = true;
299     } else if (args[i] == "-b") {
300       branch_sampling_ = branch_sampling_type_map["any"];
301     } else if (args[i] == "-c") {
302       if (!NextArgumentOrError(args, &i)) {
303         return false;
304       }
305       char* endptr;
306       sample_period_ = strtoull(args[i].c_str(), &endptr, 0);
307       if (*endptr != '\0' || sample_period_ == 0) {
308         LOG(ERROR) << "Invalid sample period: '" << args[i] << "'";
309         return false;
310       }
311       use_sample_freq_ = false;
312     } else if (args[i] == "--call-graph") {
313       if (!NextArgumentOrError(args, &i)) {
314         return false;
315       }
316       std::vector<std::string> strs = android::base::Split(args[i], ",");
317       if (strs[0] == "fp") {
318         fp_callchain_sampling_ = true;
319         dwarf_callchain_sampling_ = false;
320       } else if (strs[0] == "dwarf") {
321         fp_callchain_sampling_ = false;
322         dwarf_callchain_sampling_ = true;
323         if (strs.size() > 1) {
324           char* endptr;
325           uint64_t size = strtoull(strs[1].c_str(), &endptr, 0);
326           if (*endptr != '\0' || size > UINT_MAX) {
327             LOG(ERROR) << "invalid dump stack size in --call-graph option: " << strs[1];
328             return false;
329           }
330           if ((size & 7) != 0) {
331             LOG(ERROR) << "dump stack size " << size << " is not 8-byte aligned.";
332             return false;
333           }
334           dump_stack_size_in_dwarf_sampling_ = static_cast<uint32_t>(size);
335         }
336       } else {
337         LOG(ERROR) << "unexpected argument for --call-graph option: " << args[i];
338         return false;
339       }
340     } else if (args[i] == "--cpu") {
341       if (!NextArgumentOrError(args, &i)) {
342         return false;
343       }
344       cpus_ = GetCpusFromString(args[i]);
345     } else if (args[i] == "-e") {
346       if (!NextArgumentOrError(args, &i)) {
347         return false;
348       }
349       std::vector<std::string> event_types = android::base::Split(args[i], ",");
350       for (auto& event_type : event_types) {
351         if (!AddMeasuredEventType(event_type)) {
352           return false;
353         }
354       }
355     } else if (args[i] == "-f" || args[i] == "-F") {
356       if (!NextArgumentOrError(args, &i)) {
357         return false;
358       }
359       char* endptr;
360       sample_freq_ = strtoull(args[i].c_str(), &endptr, 0);
361       if (*endptr != '\0' || sample_freq_ == 0) {
362         LOG(ERROR) << "Invalid sample frequency: '" << args[i] << "'";
363         return false;
364       }
365       use_sample_freq_ = true;
366     } else if (args[i] == "-g") {
367       fp_callchain_sampling_ = false;
368       dwarf_callchain_sampling_ = true;
369     } else if (args[i] == "-j") {
370       if (!NextArgumentOrError(args, &i)) {
371         return false;
372       }
373       std::vector<std::string> branch_sampling_types = android::base::Split(args[i], ",");
374       for (auto& type : branch_sampling_types) {
375         auto it = branch_sampling_type_map.find(type);
376         if (it == branch_sampling_type_map.end()) {
377           LOG(ERROR) << "unrecognized branch sampling filter: " << type;
378           return false;
379         }
380         branch_sampling_ |= it->second;
381       }
382     } else if (args[i] == "-m") {
383       if (!NextArgumentOrError(args, &i)) {
384         return false;
385       }
386       char* endptr;
387       uint64_t pages = strtoull(args[i].c_str(), &endptr, 0);
388       if (*endptr != '\0' || !IsPowerOfTwo(pages)) {
389         LOG(ERROR) << "Invalid mmap_pages: '" << args[i] << "'";
390         return false;
391       }
392       perf_mmap_pages_ = pages;
393     } else if (args[i] == "--no-inherit") {
394       child_inherit_ = false;
395     } else if (args[i] == "--no-unwind") {
396       unwind_dwarf_callchain_ = false;
397     } else if (args[i] == "-o") {
398       if (!NextArgumentOrError(args, &i)) {
399         return false;
400       }
401       record_filename_ = args[i];
402     } else if (args[i] == "-p") {
403       if (!NextArgumentOrError(args, &i)) {
404         return false;
405       }
406       if (!GetValidThreadsFromProcessString(args[i], &tid_set)) {
407         return false;
408       }
409     } else if (args[i] == "--post-unwind") {
410       post_unwind_ = true;
411     } else if (args[i] == "-t") {
412       if (!NextArgumentOrError(args, &i)) {
413         return false;
414       }
415       if (!GetValidThreadsFromThreadString(args[i], &tid_set)) {
416         return false;
417       }
418     } else {
419       ReportUnknownOption(args, i);
420       return false;
421     }
422   }
423
424   if (!dwarf_callchain_sampling_) {
425     if (!unwind_dwarf_callchain_) {
426       LOG(ERROR) << "--no-unwind is only used with `--call-graph dwarf` option.";
427       return false;
428     }
429     unwind_dwarf_callchain_ = false;
430   }
431   if (post_unwind_) {
432     if (!dwarf_callchain_sampling_) {
433       LOG(ERROR) << "--post-unwind is only used with `--call-graph dwarf` option.";
434       return false;
435     }
436     if (!unwind_dwarf_callchain_) {
437       LOG(ERROR) << "--post-unwind can't be used with `--no-unwind` option.";
438       return false;
439     }
440   }
441
442   monitored_threads_.insert(monitored_threads_.end(), tid_set.begin(), tid_set.end());
443   if (system_wide_collection_ && !monitored_threads_.empty()) {
444     LOG(ERROR)
445         << "Record system wide and existing processes/threads can't be used at the same time.";
446     return false;
447   }
448
449   if (non_option_args != nullptr) {
450     non_option_args->clear();
451     for (; i < args.size(); ++i) {
452       non_option_args->push_back(args[i]);
453     }
454   }
455   return true;
456 }
457
458 bool RecordCommand::AddMeasuredEventType(const std::string& event_type_name) {
459   std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType(event_type_name);
460   if (event_type_modifier == nullptr) {
461     return false;
462   }
463   measured_event_types_.push_back(*event_type_modifier);
464   return true;
465 }
466
467 bool RecordCommand::SetEventSelection() {
468   for (auto& event_type : measured_event_types_) {
469     if (!event_selection_set_.AddEventType(event_type)) {
470       return false;
471     }
472   }
473   if (use_sample_freq_) {
474     event_selection_set_.SetSampleFreq(sample_freq_);
475   } else {
476     event_selection_set_.SetSamplePeriod(sample_period_);
477   }
478   event_selection_set_.SampleIdAll();
479   if (!event_selection_set_.SetBranchSampling(branch_sampling_)) {
480     return false;
481   }
482   if (fp_callchain_sampling_) {
483     event_selection_set_.EnableFpCallChainSampling();
484   } else if (dwarf_callchain_sampling_) {
485     if (!event_selection_set_.EnableDwarfCallChainSampling(dump_stack_size_in_dwarf_sampling_)) {
486       return false;
487     }
488   }
489   event_selection_set_.SetInherit(child_inherit_);
490   return true;
491 }
492
493 bool RecordCommand::CreateAndInitRecordFile() {
494   record_file_writer_ = CreateRecordFile(record_filename_);
495   if (record_file_writer_ == nullptr) {
496     return false;
497   }
498   if (!DumpKernelAndModuleMmaps()) {
499     return false;
500   }
501   if (!DumpThreadCommAndMmaps(system_wide_collection_, monitored_threads_)) {
502     return false;
503   }
504   return true;
505 }
506
507 std::unique_ptr<RecordFileWriter> RecordCommand::CreateRecordFile(const std::string& filename) {
508   std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(filename);
509   if (writer == nullptr) {
510     return nullptr;
511   }
512
513   std::vector<AttrWithId> attr_ids;
514   for (auto& event_type : measured_event_types_) {
515     AttrWithId attr_id;
516     attr_id.attr = event_selection_set_.FindEventAttrByType(event_type);
517     CHECK(attr_id.attr != nullptr);
518     const std::vector<std::unique_ptr<EventFd>>* fds =
519         event_selection_set_.FindEventFdsByType(event_type);
520     CHECK(fds != nullptr);
521     for (auto& fd : *fds) {
522       attr_id.ids.push_back(fd->Id());
523     }
524     attr_ids.push_back(attr_id);
525   }
526   if (!writer->WriteAttrSection(attr_ids)) {
527     return nullptr;
528   }
529   return writer;
530 }
531
532 bool RecordCommand::DumpKernelAndModuleMmaps() {
533   KernelMmap kernel_mmap;
534   std::vector<KernelMmap> module_mmaps;
535   GetKernelAndModuleMmaps(&kernel_mmap, &module_mmaps);
536
537   const perf_event_attr* attr = event_selection_set_.FindEventAttrByType(measured_event_types_[0]);
538   CHECK(attr != nullptr);
539   MmapRecord mmap_record = CreateMmapRecord(*attr, true, UINT_MAX, 0, kernel_mmap.start_addr,
540                                             kernel_mmap.len, 0, kernel_mmap.filepath);
541   if (!ProcessRecord(&mmap_record)) {
542     return false;
543   }
544   for (auto& module_mmap : module_mmaps) {
545     MmapRecord mmap_record = CreateMmapRecord(*attr, true, UINT_MAX, 0, module_mmap.start_addr,
546                                               module_mmap.len, 0, module_mmap.filepath);
547     if (!ProcessRecord(&mmap_record)) {
548       return false;
549     }
550   }
551   return true;
552 }
553
554 bool RecordCommand::DumpThreadCommAndMmaps(bool all_threads,
555                                            const std::vector<pid_t>& selected_threads) {
556   std::vector<ThreadComm> thread_comms;
557   if (!GetThreadComms(&thread_comms)) {
558     return false;
559   }
560   // Decide which processes and threads to dump.
561   std::set<pid_t> dump_processes;
562   std::set<pid_t> dump_threads;
563   for (auto& tid : selected_threads) {
564     dump_threads.insert(tid);
565   }
566   for (auto& thread : thread_comms) {
567     if (dump_threads.find(thread.tid) != dump_threads.end()) {
568       dump_processes.insert(thread.pid);
569     }
570   }
571
572   const perf_event_attr* attr = event_selection_set_.FindEventAttrByType(measured_event_types_[0]);
573   CHECK(attr != nullptr);
574
575   // Dump processes.
576   for (auto& thread : thread_comms) {
577     if (thread.pid != thread.tid) {
578       continue;
579     }
580     if (!all_threads && dump_processes.find(thread.pid) == dump_processes.end()) {
581       continue;
582     }
583     CommRecord record = CreateCommRecord(*attr, thread.pid, thread.tid, thread.comm);
584     if (!ProcessRecord(&record)) {
585       return false;
586     }
587     std::vector<ThreadMmap> thread_mmaps;
588     if (!GetThreadMmapsInProcess(thread.pid, &thread_mmaps)) {
589       // The thread may exit before we get its info.
590       continue;
591     }
592     for (auto& thread_mmap : thread_mmaps) {
593       if (thread_mmap.executable == 0) {
594         continue;  // No need to dump non-executable mmap info.
595       }
596       MmapRecord record =
597           CreateMmapRecord(*attr, false, thread.pid, thread.tid, thread_mmap.start_addr,
598                            thread_mmap.len, thread_mmap.pgoff, thread_mmap.name);
599       if (!ProcessRecord(&record)) {
600         return false;
601       }
602     }
603   }
604
605   // Dump threads.
606   for (auto& thread : thread_comms) {
607     if (thread.pid == thread.tid) {
608       continue;
609     }
610     if (!all_threads && dump_threads.find(thread.tid) == dump_threads.end()) {
611       continue;
612     }
613     ForkRecord fork_record = CreateForkRecord(*attr, thread.pid, thread.tid, thread.pid, thread.pid);
614     if (!ProcessRecord(&fork_record)) {
615       return false;
616     }
617     CommRecord comm_record = CreateCommRecord(*attr, thread.pid, thread.tid, thread.comm);
618     if (!ProcessRecord(&comm_record)) {
619       return false;
620     }
621   }
622   return true;
623 }
624
625 bool RecordCommand::CollectRecordsFromKernel(const char* data, size_t size) {
626   record_cache_->Push(data, size);
627   while (true) {
628     std::unique_ptr<Record> r = record_cache_->Pop();
629     if (r == nullptr) {
630       break;
631     }
632     if (!ProcessRecord(r.get())) {
633       return false;
634     }
635   }
636   return true;
637 }
638
639 bool RecordCommand::ProcessRecord(Record* record) {
640   UpdateRecordForEmbeddedElfPath(record);
641   BuildThreadTree(*record, &thread_tree_);
642   CollectHitFileInfo(record);
643   if (unwind_dwarf_callchain_ && !post_unwind_) {
644     UnwindRecord(record);
645   }
646   if (record->type() == PERF_RECORD_SAMPLE) {
647     sample_record_count_++;
648   }
649   bool result = record_file_writer_->WriteData(record->BinaryFormat());
650   return result;
651 }
652
653 template<class RecordType>
654 void UpdateMmapRecordForEmbeddedElfPath(RecordType* record) {
655   RecordType& r = *record;
656   bool in_kernel = ((r.header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_KERNEL);
657   if (!in_kernel && r.data.pgoff != 0) {
658     // For the case of a shared library "foobar.so" embedded
659     // inside an APK, we rewrite the original MMAP from
660     // ["path.apk" offset=X] to ["path.apk!/foobar.so" offset=W]
661     // so as to make the library name explicit. This update is
662     // done here (as part of the record operation) as opposed to
663     // on the host during the report, since we want to report
664     // the correct library name even if the the APK in question
665     // is not present on the host. The new offset W is
666     // calculated to be with respect to the start of foobar.so,
667     // not to the start of path.apk.
668     EmbeddedElf* ee = ApkInspector::FindElfInApkByOffset(r.filename, r.data.pgoff);
669     if (ee != nullptr) {
670       // Compute new offset relative to start of elf in APK.
671       r.data.pgoff -= ee->entry_offset();
672       r.filename = GetUrlInApk(r.filename, ee->entry_name());
673       r.AdjustSizeBasedOnData();
674     }
675   }
676 }
677
678 void RecordCommand::UpdateRecordForEmbeddedElfPath(Record* record) {
679   if (record->type() == PERF_RECORD_MMAP) {
680     UpdateMmapRecordForEmbeddedElfPath(static_cast<MmapRecord*>(record));
681   } else if (record->type() == PERF_RECORD_MMAP2) {
682     UpdateMmapRecordForEmbeddedElfPath(static_cast<Mmap2Record*>(record));
683   }
684 }
685
686 void RecordCommand::UnwindRecord(Record* record) {
687   if (record->type() == PERF_RECORD_SAMPLE) {
688     SampleRecord& r = *static_cast<SampleRecord*>(record);
689     if ((r.sample_type & PERF_SAMPLE_CALLCHAIN) && (r.sample_type & PERF_SAMPLE_REGS_USER) &&
690         (r.regs_user_data.reg_mask != 0) && (r.sample_type & PERF_SAMPLE_STACK_USER) &&
691         (!r.stack_user_data.data.empty())) {
692       ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
693       RegSet regs = CreateRegSet(r.regs_user_data.reg_mask, r.regs_user_data.regs);
694       std::vector<char>& stack = r.stack_user_data.data;
695       std::vector<uint64_t> unwind_ips = UnwindCallChain(GetBuildArch(), *thread, regs, stack);
696       r.callchain_data.ips.push_back(PERF_CONTEXT_USER);
697       r.callchain_data.ips.insert(r.callchain_data.ips.end(), unwind_ips.begin(), unwind_ips.end());
698       r.regs_user_data.abi = 0;
699       r.regs_user_data.reg_mask = 0;
700       r.regs_user_data.regs.clear();
701       r.stack_user_data.data.clear();
702       r.stack_user_data.dyn_size = 0;
703       r.AdjustSizeBasedOnData();
704     }
705   }
706 }
707
708 bool RecordCommand::PostUnwind(const std::vector<std::string>& args) {
709   thread_tree_.Clear();
710   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(record_filename_);
711   if (reader == nullptr) {
712     return false;
713   }
714   std::string tmp_filename = record_filename_ + ".tmp";
715   record_file_writer_ = CreateRecordFile(tmp_filename);
716   if (record_file_writer_ == nullptr) {
717     return false;
718   }
719   bool result = reader->ReadDataSection(
720       [this](std::unique_ptr<Record> record) {
721         BuildThreadTree(*record, &thread_tree_);
722         UnwindRecord(record.get());
723         return record_file_writer_->WriteData(record->BinaryFormat());
724       },
725       false);
726   if (!result) {
727     return false;
728   }
729   if (!DumpAdditionalFeatures(args)) {
730     return false;
731   }
732   if (!record_file_writer_->Close()) {
733     return false;
734   }
735
736   if (unlink(record_filename_.c_str()) != 0) {
737     PLOG(ERROR) << "failed to remove " << record_filename_;
738     return false;
739   }
740   if (rename(tmp_filename.c_str(), record_filename_.c_str()) != 0) {
741     PLOG(ERROR) << "failed to rename " << tmp_filename << " to " << record_filename_;
742     return false;
743   }
744   return true;
745 }
746
747 bool RecordCommand::DumpAdditionalFeatures(const std::vector<std::string>& args) {
748   size_t feature_count = (branch_sampling_ != 0 ? 5 : 4);
749   if (!record_file_writer_->WriteFeatureHeader(feature_count)) {
750     return false;
751   }
752   if (!DumpBuildIdFeature()) {
753     return false;
754   }
755   utsname uname_buf;
756   if (TEMP_FAILURE_RETRY(uname(&uname_buf)) != 0) {
757     PLOG(ERROR) << "uname() failed";
758     return false;
759   }
760   if (!record_file_writer_->WriteFeatureString(PerfFileFormat::FEAT_OSRELEASE, uname_buf.release)) {
761     return false;
762   }
763   if (!record_file_writer_->WriteFeatureString(PerfFileFormat::FEAT_ARCH, uname_buf.machine)) {
764     return false;
765   }
766
767   std::string exec_path = "simpleperf";
768   GetExecPath(&exec_path);
769   std::vector<std::string> cmdline;
770   cmdline.push_back(exec_path);
771   cmdline.push_back("record");
772   cmdline.insert(cmdline.end(), args.begin(), args.end());
773   if (!record_file_writer_->WriteCmdlineFeature(cmdline)) {
774     return false;
775   }
776   if (branch_sampling_ != 0 && !record_file_writer_->WriteBranchStackFeature()) {
777     return false;
778   }
779   return true;
780 }
781
782 bool RecordCommand::DumpBuildIdFeature() {
783   std::vector<BuildIdRecord> build_id_records;
784   BuildId build_id;
785   // Add build_ids for kernel/modules.
786   for (const auto& filename : hit_kernel_modules_) {
787     if (filename == DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID) {
788       if (!GetKernelBuildId(&build_id)) {
789         LOG(DEBUG) << "can't read build_id for kernel";
790         continue;
791       }
792       build_id_records.push_back(
793           CreateBuildIdRecord(true, UINT_MAX, build_id, DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID));
794     } else {
795       std::string path = filename;
796       std::string module_name = basename(&path[0]);
797       if (android::base::EndsWith(module_name, ".ko")) {
798         module_name = module_name.substr(0, module_name.size() - 3);
799       }
800       if (!GetModuleBuildId(module_name, &build_id)) {
801         LOG(DEBUG) << "can't read build_id for module " << module_name;
802         continue;
803       }
804       build_id_records.push_back(CreateBuildIdRecord(true, UINT_MAX, build_id, filename));
805     }
806   }
807   // Add build_ids for user elf files.
808   for (const auto& filename : hit_user_files_) {
809     if (filename == DEFAULT_EXECNAME_FOR_THREAD_MMAP) {
810       continue;
811     }
812     auto tuple = SplitUrlInApk(filename);
813     if (std::get<0>(tuple)) {
814       if (!GetBuildIdFromApkFile(std::get<1>(tuple), std::get<2>(tuple), &build_id)) {
815         LOG(DEBUG) << "can't read build_id from file " << filename;
816         continue;
817       }
818     } else {
819       if (!GetBuildIdFromElfFile(filename, &build_id)) {
820         LOG(DEBUG) << "can't read build_id from file " << filename;
821         continue;
822       }
823     }
824     build_id_records.push_back(CreateBuildIdRecord(false, UINT_MAX, build_id, filename));
825   }
826   if (!record_file_writer_->WriteBuildIdFeature(build_id_records)) {
827     return false;
828   }
829   return true;
830 }
831
832 void RecordCommand::CollectHitFileInfo(Record* record) {
833   if (record->type() == PERF_RECORD_SAMPLE) {
834     auto r = *static_cast<SampleRecord*>(record);
835     bool in_kernel = ((r.header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_KERNEL);
836     const ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
837     const MapEntry* map = thread_tree_.FindMap(thread, r.ip_data.ip, in_kernel);
838     if (in_kernel) {
839       hit_kernel_modules_.insert(map->dso->Path());
840     } else {
841       hit_user_files_.insert(map->dso->Path());
842     }
843   }
844 }
845
846 void RegisterRecordCommand() {
847   RegisterCommand("record", [] { return std::unique_ptr<Command>(new RecordCommand()); });
848 }