OSDN Git Service

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