OSDN Git Service

simpleperf: don't looking for _text symbol in /proc/kallsyms.
[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   // 1. Parse options, and use default measured event type if not given.
192   std::vector<std::string> workload_args;
193   if (!ParseOptions(args, &workload_args)) {
194     return false;
195   }
196   if (measured_event_types_.empty()) {
197     if (!AddMeasuredEventType(default_measured_event_type)) {
198       return false;
199     }
200   }
201   if (!SetEventSelection()) {
202     return false;
203   }
204
205   // 2. Create workload.
206   std::unique_ptr<Workload> workload;
207   if (!workload_args.empty()) {
208     workload = Workload::CreateWorkload(workload_args);
209     if (workload == nullptr) {
210       return false;
211     }
212   }
213   if (!system_wide_collection_ && monitored_threads_.empty()) {
214     if (workload != nullptr) {
215       monitored_threads_.push_back(workload->GetPid());
216       event_selection_set_.SetEnableOnExec(true);
217     } else {
218       LOG(ERROR) << "No threads to monitor. Try `simpleperf help record` for help\n";
219       return false;
220     }
221   }
222
223   // 3. Open perf_event_files, create memory mapped buffers for perf_event_files, add prepare poll
224   //    for perf_event_files.
225   if (system_wide_collection_) {
226     if (!event_selection_set_.OpenEventFilesForCpus(cpus_)) {
227       system_wide_perf_event_open_failed = true;
228       return false;
229     }
230   } else {
231     if (!event_selection_set_.OpenEventFilesForThreadsOnCpus(monitored_threads_, cpus_)) {
232       return false;
233     }
234   }
235   if (!event_selection_set_.MmapEventFiles(perf_mmap_pages_)) {
236     return false;
237   }
238   std::vector<pollfd> pollfds;
239   event_selection_set_.PreparePollForEventFiles(&pollfds);
240
241   // 4. Create perf.data.
242   if (!CreateAndInitRecordFile()) {
243     return false;
244   }
245
246   // 5. Write records in mmap buffers of perf_event_files to output file while workload is running.
247   if (workload != nullptr && !workload->Start()) {
248     return false;
249   }
250   record_cache_.reset(
251       new RecordCache(*event_selection_set_.FindEventAttrByType(measured_event_types_[0])));
252   auto callback = std::bind(&RecordCommand::CollectRecordsFromKernel, this, std::placeholders::_1,
253                             std::placeholders::_2);
254   while (true) {
255     if (!event_selection_set_.ReadMmapEventData(callback)) {
256       return false;
257     }
258     if (signaled) {
259       break;
260     }
261     poll(&pollfds[0], pollfds.size(), -1);
262   }
263   std::vector<std::unique_ptr<Record>> records = record_cache_->PopAll();
264   for (auto& r : records) {
265     if (!ProcessRecord(r.get())) {
266       return false;
267     }
268   }
269
270   // 6. Dump additional features, and close record file.
271   if (!DumpAdditionalFeatures(args)) {
272     return false;
273   }
274   if (!record_file_writer_->Close()) {
275     return false;
276   }
277
278   // 7. Unwind dwarf callchain.
279   if (post_unwind_) {
280     if (!PostUnwind(args)) {
281       return false;
282     }
283   }
284   LOG(VERBOSE) << "Record " << sample_record_count_ << " samples.";
285   return true;
286 }
287
288 bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
289                                  std::vector<std::string>* non_option_args) {
290   std::set<pid_t> tid_set;
291   size_t i;
292   for (i = 0; i < args.size() && args[i].size() > 0 && args[i][0] == '-'; ++i) {
293     if (args[i] == "-a") {
294       system_wide_collection_ = true;
295     } else if (args[i] == "-b") {
296       branch_sampling_ = branch_sampling_type_map["any"];
297     } else if (args[i] == "-c") {
298       if (!NextArgumentOrError(args, &i)) {
299         return false;
300       }
301       char* endptr;
302       sample_period_ = strtoull(args[i].c_str(), &endptr, 0);
303       if (*endptr != '\0' || sample_period_ == 0) {
304         LOG(ERROR) << "Invalid sample period: '" << args[i] << "'";
305         return false;
306       }
307       use_sample_freq_ = false;
308     } else if (args[i] == "--call-graph") {
309       if (!NextArgumentOrError(args, &i)) {
310         return false;
311       }
312       std::vector<std::string> strs = android::base::Split(args[i], ",");
313       if (strs[0] == "fp") {
314         fp_callchain_sampling_ = true;
315         dwarf_callchain_sampling_ = false;
316       } else if (strs[0] == "dwarf") {
317         fp_callchain_sampling_ = false;
318         dwarf_callchain_sampling_ = true;
319         if (strs.size() > 1) {
320           char* endptr;
321           uint64_t size = strtoull(strs[1].c_str(), &endptr, 0);
322           if (*endptr != '\0' || size > UINT_MAX) {
323             LOG(ERROR) << "invalid dump stack size in --call-graph option: " << strs[1];
324             return false;
325           }
326           if ((size & 7) != 0) {
327             LOG(ERROR) << "dump stack size " << size << " is not 8-byte aligned.";
328             return false;
329           }
330           dump_stack_size_in_dwarf_sampling_ = static_cast<uint32_t>(size);
331         }
332       } else {
333         LOG(ERROR) << "unexpected argument for --call-graph option: " << args[i];
334         return false;
335       }
336     } else if (args[i] == "--cpu") {
337       if (!NextArgumentOrError(args, &i)) {
338         return false;
339       }
340       cpus_ = GetCpusFromString(args[i]);
341     } else if (args[i] == "-e") {
342       if (!NextArgumentOrError(args, &i)) {
343         return false;
344       }
345       std::vector<std::string> event_types = android::base::Split(args[i], ",");
346       for (auto& event_type : event_types) {
347         if (!AddMeasuredEventType(event_type)) {
348           return false;
349         }
350       }
351     } else if (args[i] == "-f" || args[i] == "-F") {
352       if (!NextArgumentOrError(args, &i)) {
353         return false;
354       }
355       char* endptr;
356       sample_freq_ = strtoull(args[i].c_str(), &endptr, 0);
357       if (*endptr != '\0' || sample_freq_ == 0) {
358         LOG(ERROR) << "Invalid sample frequency: '" << args[i] << "'";
359         return false;
360       }
361       use_sample_freq_ = true;
362     } else if (args[i] == "-g") {
363       fp_callchain_sampling_ = false;
364       dwarf_callchain_sampling_ = true;
365     } else if (args[i] == "-j") {
366       if (!NextArgumentOrError(args, &i)) {
367         return false;
368       }
369       std::vector<std::string> branch_sampling_types = android::base::Split(args[i], ",");
370       for (auto& type : branch_sampling_types) {
371         auto it = branch_sampling_type_map.find(type);
372         if (it == branch_sampling_type_map.end()) {
373           LOG(ERROR) << "unrecognized branch sampling filter: " << type;
374           return false;
375         }
376         branch_sampling_ |= it->second;
377       }
378     } else if (args[i] == "-m") {
379       if (!NextArgumentOrError(args, &i)) {
380         return false;
381       }
382       char* endptr;
383       uint64_t pages = strtoull(args[i].c_str(), &endptr, 0);
384       if (*endptr != '\0' || !IsPowerOfTwo(pages)) {
385         LOG(ERROR) << "Invalid mmap_pages: '" << args[i] << "'";
386         return false;
387       }
388       perf_mmap_pages_ = pages;
389     } else if (args[i] == "--no-inherit") {
390       child_inherit_ = false;
391     } else if (args[i] == "--no-unwind") {
392       unwind_dwarf_callchain_ = false;
393     } else if (args[i] == "-o") {
394       if (!NextArgumentOrError(args, &i)) {
395         return false;
396       }
397       record_filename_ = args[i];
398     } else if (args[i] == "-p") {
399       if (!NextArgumentOrError(args, &i)) {
400         return false;
401       }
402       if (!GetValidThreadsFromProcessString(args[i], &tid_set)) {
403         return false;
404       }
405     } else if (args[i] == "--post-unwind") {
406       post_unwind_ = true;
407     } else if (args[i] == "-t") {
408       if (!NextArgumentOrError(args, &i)) {
409         return false;
410       }
411       if (!GetValidThreadsFromThreadString(args[i], &tid_set)) {
412         return false;
413       }
414     } else {
415       ReportUnknownOption(args, i);
416       return false;
417     }
418   }
419
420   if (!dwarf_callchain_sampling_) {
421     if (!unwind_dwarf_callchain_) {
422       LOG(ERROR) << "--no-unwind is only used with `--call-graph dwarf` option.";
423       return false;
424     }
425     unwind_dwarf_callchain_ = false;
426   }
427   if (post_unwind_) {
428     if (!dwarf_callchain_sampling_) {
429       LOG(ERROR) << "--post-unwind is only used with `--call-graph dwarf` option.";
430       return false;
431     }
432     if (!unwind_dwarf_callchain_) {
433       LOG(ERROR) << "--post-unwind can't be used with `--no-unwind` option.";
434       return false;
435     }
436   }
437
438   monitored_threads_.insert(monitored_threads_.end(), tid_set.begin(), tid_set.end());
439   if (system_wide_collection_ && !monitored_threads_.empty()) {
440     LOG(ERROR)
441         << "Record system wide and existing processes/threads can't be used at the same time.";
442     return false;
443   }
444
445   if (non_option_args != nullptr) {
446     non_option_args->clear();
447     for (; i < args.size(); ++i) {
448       non_option_args->push_back(args[i]);
449     }
450   }
451   return true;
452 }
453
454 bool RecordCommand::AddMeasuredEventType(const std::string& event_type_name) {
455   std::unique_ptr<EventTypeAndModifier> event_type_modifier = ParseEventType(event_type_name);
456   if (event_type_modifier == nullptr) {
457     return false;
458   }
459   measured_event_types_.push_back(*event_type_modifier);
460   return true;
461 }
462
463 bool RecordCommand::SetEventSelection() {
464   for (auto& event_type : measured_event_types_) {
465     if (!event_selection_set_.AddEventType(event_type)) {
466       return false;
467     }
468   }
469   if (use_sample_freq_) {
470     event_selection_set_.SetSampleFreq(sample_freq_);
471   } else {
472     event_selection_set_.SetSamplePeriod(sample_period_);
473   }
474   event_selection_set_.SampleIdAll();
475   if (!event_selection_set_.SetBranchSampling(branch_sampling_)) {
476     return false;
477   }
478   if (fp_callchain_sampling_) {
479     event_selection_set_.EnableFpCallChainSampling();
480   } else if (dwarf_callchain_sampling_) {
481     if (!event_selection_set_.EnableDwarfCallChainSampling(dump_stack_size_in_dwarf_sampling_)) {
482       return false;
483     }
484   }
485   event_selection_set_.SetInherit(child_inherit_);
486   return true;
487 }
488
489 bool RecordCommand::CreateAndInitRecordFile() {
490   record_file_writer_ = CreateRecordFile(record_filename_);
491   if (record_file_writer_ == nullptr) {
492     return false;
493   }
494   if (!DumpKernelAndModuleMmaps()) {
495     return false;
496   }
497   if (!DumpThreadCommAndMmaps(system_wide_collection_, monitored_threads_)) {
498     return false;
499   }
500   return true;
501 }
502
503 std::unique_ptr<RecordFileWriter> RecordCommand::CreateRecordFile(const std::string& filename) {
504   std::unique_ptr<RecordFileWriter> writer = RecordFileWriter::CreateInstance(filename);
505   if (writer == nullptr) {
506     return nullptr;
507   }
508
509   std::vector<AttrWithId> attr_ids;
510   for (auto& event_type : measured_event_types_) {
511     AttrWithId attr_id;
512     attr_id.attr = event_selection_set_.FindEventAttrByType(event_type);
513     CHECK(attr_id.attr != nullptr);
514     const std::vector<std::unique_ptr<EventFd>>* fds =
515         event_selection_set_.FindEventFdsByType(event_type);
516     CHECK(fds != nullptr);
517     for (auto& fd : *fds) {
518       attr_id.ids.push_back(fd->Id());
519     }
520     attr_ids.push_back(attr_id);
521   }
522   if (!writer->WriteAttrSection(attr_ids)) {
523     return nullptr;
524   }
525   return writer;
526 }
527
528 bool RecordCommand::DumpKernelAndModuleMmaps() {
529   KernelMmap kernel_mmap;
530   std::vector<KernelMmap> module_mmaps;
531   GetKernelAndModuleMmaps(&kernel_mmap, &module_mmaps);
532
533   const perf_event_attr* attr = event_selection_set_.FindEventAttrByType(measured_event_types_[0]);
534   CHECK(attr != nullptr);
535   MmapRecord mmap_record = CreateMmapRecord(*attr, true, UINT_MAX, 0, kernel_mmap.start_addr,
536                                             kernel_mmap.len, 0, kernel_mmap.filepath);
537   if (!ProcessRecord(&mmap_record)) {
538     return false;
539   }
540   for (auto& module_mmap : module_mmaps) {
541     MmapRecord mmap_record = CreateMmapRecord(*attr, true, UINT_MAX, 0, module_mmap.start_addr,
542                                               module_mmap.len, 0, module_mmap.filepath);
543     if (!ProcessRecord(&mmap_record)) {
544       return false;
545     }
546   }
547   return true;
548 }
549
550 bool RecordCommand::DumpThreadCommAndMmaps(bool all_threads,
551                                            const std::vector<pid_t>& selected_threads) {
552   std::vector<ThreadComm> thread_comms;
553   if (!GetThreadComms(&thread_comms)) {
554     return false;
555   }
556   // Decide which processes and threads to dump.
557   std::set<pid_t> dump_processes;
558   std::set<pid_t> dump_threads;
559   for (auto& tid : selected_threads) {
560     dump_threads.insert(tid);
561   }
562   for (auto& thread : thread_comms) {
563     if (dump_threads.find(thread.tid) != dump_threads.end()) {
564       dump_processes.insert(thread.pid);
565     }
566   }
567
568   const perf_event_attr* attr = event_selection_set_.FindEventAttrByType(measured_event_types_[0]);
569   CHECK(attr != nullptr);
570
571   // Dump processes.
572   for (auto& thread : thread_comms) {
573     if (thread.pid != thread.tid) {
574       continue;
575     }
576     if (!all_threads && dump_processes.find(thread.pid) == dump_processes.end()) {
577       continue;
578     }
579     CommRecord record = CreateCommRecord(*attr, thread.pid, thread.tid, thread.comm);
580     if (!ProcessRecord(&record)) {
581       return false;
582     }
583     std::vector<ThreadMmap> thread_mmaps;
584     if (!GetThreadMmapsInProcess(thread.pid, &thread_mmaps)) {
585       // The thread may exit before we get its info.
586       continue;
587     }
588     for (auto& thread_mmap : thread_mmaps) {
589       if (thread_mmap.executable == 0) {
590         continue;  // No need to dump non-executable mmap info.
591       }
592       MmapRecord record =
593           CreateMmapRecord(*attr, false, thread.pid, thread.tid, thread_mmap.start_addr,
594                            thread_mmap.len, thread_mmap.pgoff, thread_mmap.name);
595       if (!ProcessRecord(&record)) {
596         return false;
597       }
598     }
599   }
600
601   // Dump threads.
602   for (auto& thread : thread_comms) {
603     if (thread.pid == thread.tid) {
604       continue;
605     }
606     if (!all_threads && dump_threads.find(thread.tid) == dump_threads.end()) {
607       continue;
608     }
609     ForkRecord fork_record = CreateForkRecord(*attr, thread.pid, thread.tid, thread.pid, thread.pid);
610     if (!ProcessRecord(&fork_record)) {
611       return false;
612     }
613     CommRecord comm_record = CreateCommRecord(*attr, thread.pid, thread.tid, thread.comm);
614     if (!ProcessRecord(&comm_record)) {
615       return false;
616     }
617   }
618   return true;
619 }
620
621 bool RecordCommand::CollectRecordsFromKernel(const char* data, size_t size) {
622   record_cache_->Push(data, size);
623   while (true) {
624     std::unique_ptr<Record> r = record_cache_->Pop();
625     if (r == nullptr) {
626       break;
627     }
628     if (!ProcessRecord(r.get())) {
629       return false;
630     }
631   }
632   return true;
633 }
634
635 bool RecordCommand::ProcessRecord(Record* record) {
636   UpdateRecordForEmbeddedElfPath(record);
637   BuildThreadTree(*record, &thread_tree_);
638   CollectHitFileInfo(record);
639   if (unwind_dwarf_callchain_ && !post_unwind_) {
640     UnwindRecord(record);
641   }
642   if (record->type() == PERF_RECORD_SAMPLE) {
643     sample_record_count_++;
644   }
645   bool result = record_file_writer_->WriteData(record->BinaryFormat());
646   return result;
647 }
648
649 template<class RecordType>
650 void UpdateMmapRecordForEmbeddedElfPath(RecordType* record) {
651   RecordType& r = *record;
652   bool in_kernel = ((r.header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_KERNEL);
653   if (!in_kernel && r.data.pgoff != 0) {
654     // For the case of a shared library "foobar.so" embedded
655     // inside an APK, we rewrite the original MMAP from
656     // ["path.apk" offset=X] to ["path.apk!/foobar.so" offset=W]
657     // so as to make the library name explicit. This update is
658     // done here (as part of the record operation) as opposed to
659     // on the host during the report, since we want to report
660     // the correct library name even if the the APK in question
661     // is not present on the host. The new offset W is
662     // calculated to be with respect to the start of foobar.so,
663     // not to the start of path.apk.
664     EmbeddedElf* ee = ApkInspector::FindElfInApkByOffset(r.filename, r.data.pgoff);
665     if (ee != nullptr) {
666       // Compute new offset relative to start of elf in APK.
667       r.data.pgoff -= ee->entry_offset();
668       r.filename = GetUrlInApk(r.filename, ee->entry_name());
669       r.AdjustSizeBasedOnData();
670     }
671   }
672 }
673
674 void RecordCommand::UpdateRecordForEmbeddedElfPath(Record* record) {
675   if (record->type() == PERF_RECORD_MMAP) {
676     UpdateMmapRecordForEmbeddedElfPath(static_cast<MmapRecord*>(record));
677   } else if (record->type() == PERF_RECORD_MMAP2) {
678     UpdateMmapRecordForEmbeddedElfPath(static_cast<Mmap2Record*>(record));
679   }
680 }
681
682 void RecordCommand::UnwindRecord(Record* record) {
683   if (record->type() == PERF_RECORD_SAMPLE) {
684     SampleRecord& r = *static_cast<SampleRecord*>(record);
685     if ((r.sample_type & PERF_SAMPLE_CALLCHAIN) && (r.sample_type & PERF_SAMPLE_REGS_USER) &&
686         (r.regs_user_data.reg_mask != 0) && (r.sample_type & PERF_SAMPLE_STACK_USER) &&
687         (!r.stack_user_data.data.empty())) {
688       ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
689       RegSet regs = CreateRegSet(r.regs_user_data.reg_mask, r.regs_user_data.regs);
690       std::vector<char>& stack = r.stack_user_data.data;
691       std::vector<uint64_t> unwind_ips = UnwindCallChain(*thread, regs, stack);
692       r.callchain_data.ips.push_back(PERF_CONTEXT_USER);
693       r.callchain_data.ips.insert(r.callchain_data.ips.end(), unwind_ips.begin(), unwind_ips.end());
694       r.regs_user_data.abi = 0;
695       r.regs_user_data.reg_mask = 0;
696       r.regs_user_data.regs.clear();
697       r.stack_user_data.data.clear();
698       r.stack_user_data.dyn_size = 0;
699       r.AdjustSizeBasedOnData();
700     }
701   }
702 }
703
704 bool RecordCommand::PostUnwind(const std::vector<std::string>& args) {
705   thread_tree_.Clear();
706   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(record_filename_);
707   if (reader == nullptr) {
708     return false;
709   }
710   std::string tmp_filename = record_filename_ + ".tmp";
711   record_file_writer_ = CreateRecordFile(tmp_filename);
712   if (record_file_writer_ == nullptr) {
713     return false;
714   }
715   bool result = reader->ReadDataSection(
716       [this](std::unique_ptr<Record> record) {
717         BuildThreadTree(*record, &thread_tree_);
718         UnwindRecord(record.get());
719         return record_file_writer_->WriteData(record->BinaryFormat());
720       },
721       false);
722   if (!result) {
723     return false;
724   }
725   if (!DumpAdditionalFeatures(args)) {
726     return false;
727   }
728   if (!record_file_writer_->Close()) {
729     return false;
730   }
731
732   if (unlink(record_filename_.c_str()) != 0) {
733     PLOG(ERROR) << "failed to remove " << record_filename_;
734     return false;
735   }
736   if (rename(tmp_filename.c_str(), record_filename_.c_str()) != 0) {
737     PLOG(ERROR) << "failed to rename " << tmp_filename << " to " << record_filename_;
738     return false;
739   }
740   return true;
741 }
742
743 bool RecordCommand::DumpAdditionalFeatures(const std::vector<std::string>& args) {
744   size_t feature_count = (branch_sampling_ != 0 ? 5 : 4);
745   if (!record_file_writer_->WriteFeatureHeader(feature_count)) {
746     return false;
747   }
748   if (!DumpBuildIdFeature()) {
749     return false;
750   }
751   utsname uname_buf;
752   if (TEMP_FAILURE_RETRY(uname(&uname_buf)) != 0) {
753     PLOG(ERROR) << "uname() failed";
754     return false;
755   }
756   if (!record_file_writer_->WriteFeatureString(PerfFileFormat::FEAT_OSRELEASE, uname_buf.release)) {
757     return false;
758   }
759   if (!record_file_writer_->WriteFeatureString(PerfFileFormat::FEAT_ARCH, uname_buf.machine)) {
760     return false;
761   }
762
763   std::string exec_path = "simpleperf";
764   GetExecPath(&exec_path);
765   std::vector<std::string> cmdline;
766   cmdline.push_back(exec_path);
767   cmdline.push_back("record");
768   cmdline.insert(cmdline.end(), args.begin(), args.end());
769   if (!record_file_writer_->WriteCmdlineFeature(cmdline)) {
770     return false;
771   }
772   if (branch_sampling_ != 0 && !record_file_writer_->WriteBranchStackFeature()) {
773     return false;
774   }
775   return true;
776 }
777
778 bool RecordCommand::DumpBuildIdFeature() {
779   std::vector<BuildIdRecord> build_id_records;
780   BuildId build_id;
781   // Add build_ids for kernel/modules.
782   for (const auto& filename : hit_kernel_modules_) {
783     if (filename == DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID) {
784       if (!GetKernelBuildId(&build_id)) {
785         LOG(DEBUG) << "can't read build_id for kernel";
786         continue;
787       }
788       build_id_records.push_back(
789           CreateBuildIdRecord(true, UINT_MAX, build_id, DEFAULT_KERNEL_FILENAME_FOR_BUILD_ID));
790     } else {
791       std::string path = filename;
792       std::string module_name = basename(&path[0]);
793       if (android::base::EndsWith(module_name, ".ko")) {
794         module_name = module_name.substr(0, module_name.size() - 3);
795       }
796       if (!GetModuleBuildId(module_name, &build_id)) {
797         LOG(DEBUG) << "can't read build_id for module " << module_name;
798         continue;
799       }
800       build_id_records.push_back(CreateBuildIdRecord(true, UINT_MAX, build_id, filename));
801     }
802   }
803   // Add build_ids for user elf files.
804   for (const auto& filename : hit_user_files_) {
805     if (filename == DEFAULT_EXECNAME_FOR_THREAD_MMAP) {
806       continue;
807     }
808     auto tuple = SplitUrlInApk(filename);
809     if (std::get<0>(tuple)) {
810       if (!GetBuildIdFromApkFile(std::get<1>(tuple), std::get<2>(tuple), &build_id)) {
811         LOG(DEBUG) << "can't read build_id from file " << filename;
812         continue;
813       }
814     } else {
815       if (!GetBuildIdFromElfFile(filename, &build_id)) {
816         LOG(DEBUG) << "can't read build_id from file " << filename;
817         continue;
818       }
819     }
820     build_id_records.push_back(CreateBuildIdRecord(false, UINT_MAX, build_id, filename));
821   }
822   if (!record_file_writer_->WriteBuildIdFeature(build_id_records)) {
823     return false;
824   }
825   return true;
826 }
827
828 void RecordCommand::CollectHitFileInfo(Record* record) {
829   if (record->type() == PERF_RECORD_SAMPLE) {
830     auto r = *static_cast<SampleRecord*>(record);
831     bool in_kernel = ((r.header.misc & PERF_RECORD_MISC_CPUMODE_MASK) == PERF_RECORD_MISC_KERNEL);
832     const ThreadEntry* thread = thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
833     const MapEntry* map = thread_tree_.FindMap(thread, r.ip_data.ip, in_kernel);
834     if (in_kernel) {
835       hit_kernel_modules_.insert(map->dso->Path());
836     } else {
837       hit_user_files_.insert(map->dso->Path());
838     }
839   }
840 }
841
842 void RegisterRecordCommand() {
843   RegisterCommand("record", [] { return std::unique_ptr<Command>(new RecordCommand()); });
844 }