OSDN Git Service

d37c2a848a70dc86388232277aef2dc7093833ce
[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 <signal.h>
19 #include <sys/prctl.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/file.h>
29 #include <android-base/parsedouble.h>
30 #include <android-base/parseint.h>
31 #include <android-base/strings.h>
32 #include <android-base/test_utils.h>
33
34 #include "command.h"
35 #include "dwarf_unwind.h"
36 #include "environment.h"
37 #include "event_selection_set.h"
38 #include "event_type.h"
39 #include "IOEventLoop.h"
40 #include "perf_clock.h"
41 #include "read_apk.h"
42 #include "read_elf.h"
43 #include "record.h"
44 #include "record_file.h"
45 #include "thread_tree.h"
46 #include "tracing.h"
47 #include "utils.h"
48 #include "workload.h"
49
50 static std::string default_measured_event_type = "cpu-cycles";
51
52 static std::unordered_map<std::string, uint64_t> branch_sampling_type_map = {
53     {"u", PERF_SAMPLE_BRANCH_USER},
54     {"k", PERF_SAMPLE_BRANCH_KERNEL},
55     {"any", PERF_SAMPLE_BRANCH_ANY},
56     {"any_call", PERF_SAMPLE_BRANCH_ANY_CALL},
57     {"any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN},
58     {"ind_call", PERF_SAMPLE_BRANCH_IND_CALL},
59 };
60
61 // The max size of records dumped by kernel is 65535, and dump stack size
62 // should be a multiply of 8, so MAX_DUMP_STACK_SIZE is 65528.
63 constexpr uint32_t MAX_DUMP_STACK_SIZE = 65528;
64
65 // The max allowed pages in mapped buffer is decided by rlimit(RLIMIT_MEMLOCK).
66 // Here 1024 is a desired value for pages in mapped buffer. If mapped
67 // successfully, the buffer size = 1024 * 4K (page size) = 4M.
68 constexpr size_t DESIRED_PAGES_IN_MAPPED_BUFFER = 1024;
69
70 class RecordCommand : public Command {
71  public:
72   RecordCommand()
73       : Command(
74             "record", "record sampling info in perf.data",
75             // clang-format off
76 "Usage: simpleperf record [options] [command [command-args]]\n"
77 "       Gather sampling information of running [command]. And -a/-p/-t option\n"
78 "       can be used to change target of sampling information.\n"
79 "       The default options are: -e cpu-cycles -f 4000 -o perf.data.\n"
80 "-a     System-wide collection.\n"
81 #if defined(__ANDROID__)
82 "--app package_name    Profile the process of an Android application.\n"
83 "                      On non-rooted devices, the app must be debuggable,\n"
84 "                      because we use run-as to switch to the app's context.\n"
85 #endif
86 "-b     Enable take branch stack sampling. Same as '-j any'\n"
87 "-c count     Set event sample period. It means recording one sample when\n"
88 "             [count] events happen. Can't be used with -f/-F option.\n"
89 "             For tracepoint events, the default option is -c 1.\n"
90 "--call-graph fp | dwarf[,<dump_stack_size>]\n"
91 "             Enable call graph recording. Use frame pointer or dwarf debug\n"
92 "             frame as the method to parse call graph in stack.\n"
93 "             Default is dwarf,65528.\n"
94 "--cpu cpu_item1,cpu_item2,...\n"
95 "             Collect samples only on the selected cpus. cpu_item can be cpu\n"
96 "             number like 1, or cpu range like 0-3.\n"
97 "--duration time_in_sec  Monitor for time_in_sec seconds instead of running\n"
98 "                        [command]. Here time_in_sec may be any positive\n"
99 "                        floating point number.\n"
100 "-e event1[:modifier1],event2[:modifier2],...\n"
101 "             Select the event list to sample. Use `simpleperf list` to find\n"
102 "             all possible event names. Modifiers can be added to define how\n"
103 "             the event should be monitored.\n"
104 "             Possible modifiers are:\n"
105 "                u - monitor user space events only\n"
106 "                k - monitor kernel space events only\n"
107 "-f freq      Set event sample frequency. It means recording at most [freq]\n"
108 "             samples every second. For non-tracepoint events, the default\n"
109 "             option is -f 4000.\n"
110 "-F freq      Same as '-f freq'.\n"
111 "-g           Same as '--call-graph dwarf'.\n"
112 "--group event1[:modifier],event2[:modifier2],...\n"
113 "             Similar to -e option. But events specified in the same --group\n"
114 "             option are monitored as a group, and scheduled in and out at the\n"
115 "             same time.\n"
116 "-j branch_filter1,branch_filter2,...\n"
117 "             Enable taken branch stack sampling. Each sample captures a series\n"
118 "             of consecutive taken branches.\n"
119 "             The following filters are defined:\n"
120 "                any: any type of branch\n"
121 "                any_call: any function call or system call\n"
122 "                any_ret: any function return or system call return\n"
123 "                ind_call: any indirect branch\n"
124 "                u: only when the branch target is at the user level\n"
125 "                k: only when the branch target is in the kernel\n"
126 "             This option requires at least one branch type among any, any_call,\n"
127 "             any_ret, ind_call.\n"
128 "-m mmap_pages   Set the size of the buffer used to receiving sample data from\n"
129 "                the kernel. It should be a power of 2. If not set, the max\n"
130 "                possible value <= 1024 will be used.\n"
131 "--no-dump-kernel-symbols  Don't dump kernel symbols in perf.data. By default\n"
132 "                          kernel symbols will be dumped when needed.\n"
133 "--no-dump-symbols       Don't dump symbols in perf.data. By default symbols are\n"
134 "                        dumped in perf.data, to support reporting in another\n"
135 "                        environment.\n"
136 "--no-inherit  Don't record created child threads/processes.\n"
137 "--no-unwind   If `--call-graph dwarf` option is used, then the user's stack\n"
138 "              will be unwound by default. Use this option to disable the\n"
139 "              unwinding of the user's stack.\n"
140 "-o record_file_name    Set record file name, default is perf.data.\n"
141 "-p pid1,pid2,...       Record events on existing processes. Mutually exclusive\n"
142 "                       with -a.\n"
143 "--post-unwind  If `--call-graph dwarf` option is used, then the user's stack\n"
144 "               will be unwound while recording by default. But it may lose\n"
145 "               records as stacking unwinding can be time consuming. Use this\n"
146 "               option to unwind the user's stack after recording.\n"
147 "--start_profiling_fd fd_no    After starting profiling, write \"STARTED\" to\n"
148 "                              <fd_no>, then close <fd_no>.\n"
149 "--symfs <dir>    Look for files with symbols relative to this directory.\n"
150 "                 This option is used to provide files with symbol table and\n"
151 "                 debug information, which are used for unwinding and dumping symbols.\n"
152 "-t tid1,tid2,... Record events on existing threads. Mutually exclusive with -a.\n"
153 #if 0
154 // Below options are only used internally and shouldn't be visible to the public.
155 "--in-app         We are already running in the app's context.\n"
156 #endif
157             // clang-format on
158             ),
159         use_sample_freq_(false),
160         sample_freq_(0),
161         use_sample_period_(false),
162         sample_period_(0),
163         system_wide_collection_(false),
164         branch_sampling_(0),
165         fp_callchain_sampling_(false),
166         dwarf_callchain_sampling_(false),
167         dump_stack_size_in_dwarf_sampling_(MAX_DUMP_STACK_SIZE),
168         unwind_dwarf_callchain_(true),
169         post_unwind_(false),
170         child_inherit_(true),
171         duration_in_sec_(0),
172         can_dump_kernel_symbols_(true),
173         dump_symbols_(true),
174         event_selection_set_(false),
175         mmap_page_range_(std::make_pair(1, DESIRED_PAGES_IN_MAPPED_BUFFER)),
176         record_filename_("perf.data"),
177         start_sampling_time_in_ns_(0),
178         sample_record_count_(0),
179         lost_record_count_(0),
180         start_profiling_fd_(-1),
181         in_app_context_(false) {
182     // Stop profiling if parent exits.
183     prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
184     app_package_name_ = GetDefaultAppPackageName();
185   }
186
187   bool Run(const std::vector<std::string>& args);
188
189  private:
190   bool ParseOptions(const std::vector<std::string>& args,
191                     std::vector<std::string>* non_option_args);
192   bool SetEventSelectionFlags();
193   bool CreateAndInitRecordFile();
194   std::unique_ptr<RecordFileWriter> CreateRecordFile(
195       const std::string& filename);
196   bool DumpKernelSymbol();
197   bool DumpTracingData();
198   bool DumpKernelAndModuleMmaps(const perf_event_attr& attr, uint64_t event_id);
199   bool DumpThreadCommAndMmaps(const perf_event_attr& attr, uint64_t event_id);
200   bool ProcessRecord(Record* record);
201   void UpdateRecordForEmbeddedElfPath(Record* record);
202   bool UnwindRecord(Record* record);
203   bool PostUnwind(const std::vector<std::string>& args);
204   bool DumpAdditionalFeatures(const std::vector<std::string>& args);
205   bool DumpBuildIdFeature();
206   bool DumpFileFeature();
207   void CollectHitFileInfo(const SampleRecord& r);
208
209   bool use_sample_freq_;
210   uint64_t sample_freq_;  // Sample 'sample_freq_' times per second.
211   bool use_sample_period_;
212   uint64_t sample_period_;  // Sample once when 'sample_period_' events occur.
213
214   bool system_wide_collection_;
215   uint64_t branch_sampling_;
216   bool fp_callchain_sampling_;
217   bool dwarf_callchain_sampling_;
218   uint32_t dump_stack_size_in_dwarf_sampling_;
219   bool unwind_dwarf_callchain_;
220   bool post_unwind_;
221   bool child_inherit_;
222   double duration_in_sec_;
223   bool can_dump_kernel_symbols_;
224   bool dump_symbols_;
225   std::vector<int> cpus_;
226   EventSelectionSet event_selection_set_;
227
228   std::pair<size_t, size_t> mmap_page_range_;
229
230   ThreadTree thread_tree_;
231   std::string record_filename_;
232   std::unique_ptr<RecordFileWriter> record_file_writer_;
233
234   uint64_t start_sampling_time_in_ns_;  // nanoseconds from machine starting
235
236   uint64_t sample_record_count_;
237   uint64_t lost_record_count_;
238   int start_profiling_fd_;
239   std::string app_package_name_;
240   bool in_app_context_;
241 };
242
243 bool RecordCommand::Run(const std::vector<std::string>& args) {
244   // 0. Do some environment preparation.
245   if (!CheckPerfEventLimit()) {
246     return false;
247   }
248   if (!InitPerfClock()) {
249     return false;
250   }
251   PrepareVdsoFile();
252
253   // 1. Parse options, and use default measured event type if not given.
254   std::vector<std::string> workload_args;
255   if (!ParseOptions(args, &workload_args)) {
256     return false;
257   }
258   if (!app_package_name_.empty() && !in_app_context_) {
259     // Some users want to profile non debuggable apps on rooted devices. If we use run-as,
260     // it will be impossible when using --app. So don't switch to app's context when we are
261     // root.
262     if (!IsRoot()) {
263       return RunInAppContext(app_package_name_, "record", args, workload_args.size(),
264                              record_filename_);
265     }
266   }
267   if (event_selection_set_.empty()) {
268     if (!event_selection_set_.AddEventType(default_measured_event_type)) {
269       return false;
270     }
271   }
272   if (!SetEventSelectionFlags()) {
273     return false;
274   }
275   ScopedCurrentArch scoped_arch(GetMachineArch());
276
277   // 2. Create workload.
278   std::unique_ptr<Workload> workload;
279   if (!workload_args.empty()) {
280     workload = Workload::CreateWorkload(workload_args);
281     if (workload == nullptr) {
282       return false;
283     }
284   }
285   bool need_to_check_targets = false;
286   if (system_wide_collection_) {
287     event_selection_set_.AddMonitoredThreads({-1});
288   } else if (!event_selection_set_.HasMonitoredTarget()) {
289     if (workload != nullptr) {
290       event_selection_set_.AddMonitoredProcesses({workload->GetPid()});
291       event_selection_set_.SetEnableOnExec(true);
292       if (event_selection_set_.HasInplaceSampler()) {
293         // Start worker early, because the worker process has to setup inplace-sampler server
294         // before we try to connect it.
295         if (!workload->Start()) {
296           return false;
297         }
298       }
299     } else if (!app_package_name_.empty()) {
300       // If app process is not created, wait for it. This allows simpleperf starts before
301       // app process. In this way, we can have a better support of app start-up time profiling.
302       int pid = WaitForAppProcess(app_package_name_);
303       event_selection_set_.AddMonitoredProcesses({pid});
304     } else {
305       LOG(ERROR)
306           << "No threads to monitor. Try `simpleperf help record` for help";
307       return false;
308     }
309   } else {
310     need_to_check_targets = true;
311   }
312
313   // 3. Open perf_event_files, create mapped buffers for perf_event_files.
314   if (!event_selection_set_.OpenEventFiles(cpus_)) {
315     return false;
316   }
317   if (!event_selection_set_.MmapEventFiles(mmap_page_range_.first,
318                                            mmap_page_range_.second)) {
319     return false;
320   }
321
322   // 4. Create perf.data.
323   if (!CreateAndInitRecordFile()) {
324     return false;
325   }
326
327   // 5. Add read/signal/periodic Events.
328   auto callback =
329       std::bind(&RecordCommand::ProcessRecord, this, std::placeholders::_1);
330   if (!event_selection_set_.PrepareToReadMmapEventData(callback)) {
331     return false;
332   }
333   if (!event_selection_set_.HandleCpuHotplugEvents(cpus_)) {
334     return false;
335   }
336   if (need_to_check_targets && !event_selection_set_.StopWhenNoMoreTargets()) {
337     return false;
338   }
339   IOEventLoop* loop = event_selection_set_.GetIOEventLoop();
340   if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM, SIGHUP},
341                              [&]() { return loop->ExitLoop(); })) {
342     return false;
343   }
344   if (duration_in_sec_ != 0) {
345     if (!loop->AddPeriodicEvent(SecondToTimeval(duration_in_sec_),
346                                 [&]() { return loop->ExitLoop(); })) {
347       return false;
348     }
349   }
350
351   // 6. Write records in mapped buffers of perf_event_files to output file while
352   //    workload is running.
353   start_sampling_time_in_ns_ = GetPerfClock();
354   LOG(VERBOSE) << "start_sampling_time is " << start_sampling_time_in_ns_
355                << " ns";
356   if (workload != nullptr && !workload->IsStarted() && !workload->Start()) {
357     return false;
358   }
359   if (start_profiling_fd_ != -1) {
360     if (!android::base::WriteStringToFd("STARTED", start_profiling_fd_)) {
361       PLOG(ERROR) << "failed to write to start_profiling_fd_";
362     }
363     close(start_profiling_fd_);
364   }
365   if (!loop->RunLoop()) {
366     return false;
367   }
368   if (!event_selection_set_.FinishReadMmapEventData()) {
369     return false;
370   }
371
372   // 7. Dump additional features, and close record file.
373   if (!DumpAdditionalFeatures(args)) {
374     return false;
375   }
376   if (!record_file_writer_->Close()) {
377     return false;
378   }
379
380   // 8. Unwind dwarf callchain.
381   if (post_unwind_) {
382     if (!PostUnwind(args)) {
383       return false;
384     }
385   }
386
387   // 9. Show brief record result.
388   LOG(INFO) << "Samples recorded: " << sample_record_count_
389             << ". Samples lost: " << lost_record_count_ << ".";
390   if (sample_record_count_ + lost_record_count_ != 0) {
391     double lost_percent = static_cast<double>(lost_record_count_) /
392                           (lost_record_count_ + sample_record_count_);
393     constexpr double LOST_PERCENT_WARNING_BAR = 0.1;
394     if (lost_percent >= LOST_PERCENT_WARNING_BAR) {
395       LOG(WARNING) << "Lost " << (lost_percent * 100) << "% of samples, "
396                    << "consider increasing mmap_pages(-m), "
397                    << "or decreasing sample frequency(-f), "
398                    << "or increasing sample period(-c).";
399     }
400   }
401   return true;
402 }
403
404 bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
405                                  std::vector<std::string>* non_option_args) {
406   size_t i;
407   for (i = 0; i < args.size() && !args[i].empty() && args[i][0] == '-'; ++i) {
408     if (args[i] == "-a") {
409       system_wide_collection_ = true;
410     } else if (args[i] == "--app") {
411       if (!NextArgumentOrError(args, &i)) {
412         return false;
413       }
414       app_package_name_ = args[i];
415     } else if (args[i] == "-b") {
416       branch_sampling_ = branch_sampling_type_map["any"];
417     } else if (args[i] == "-c") {
418       if (!NextArgumentOrError(args, &i)) {
419         return false;
420       }
421       char* endptr;
422       sample_period_ = strtoull(args[i].c_str(), &endptr, 0);
423       if (*endptr != '\0' || sample_period_ == 0) {
424         LOG(ERROR) << "Invalid sample period: '" << args[i] << "'";
425         return false;
426       }
427       use_sample_period_ = true;
428     } else if (args[i] == "--call-graph") {
429       if (!NextArgumentOrError(args, &i)) {
430         return false;
431       }
432       std::vector<std::string> strs = android::base::Split(args[i], ",");
433       if (strs[0] == "fp") {
434         fp_callchain_sampling_ = true;
435         dwarf_callchain_sampling_ = false;
436       } else if (strs[0] == "dwarf") {
437         fp_callchain_sampling_ = false;
438         dwarf_callchain_sampling_ = true;
439         if (strs.size() > 1) {
440           char* endptr;
441           uint64_t size = strtoull(strs[1].c_str(), &endptr, 0);
442           if (*endptr != '\0' || size > UINT_MAX) {
443             LOG(ERROR) << "invalid dump stack size in --call-graph option: "
444                        << strs[1];
445             return false;
446           }
447           if ((size & 7) != 0) {
448             LOG(ERROR) << "dump stack size " << size
449                        << " is not 8-byte aligned.";
450             return false;
451           }
452           if (size >= MAX_DUMP_STACK_SIZE) {
453             LOG(ERROR) << "dump stack size " << size
454                        << " is bigger than max allowed size "
455                        << MAX_DUMP_STACK_SIZE << ".";
456             return false;
457           }
458           dump_stack_size_in_dwarf_sampling_ = static_cast<uint32_t>(size);
459         }
460       } else {
461         LOG(ERROR) << "unexpected argument for --call-graph option: "
462                    << args[i];
463         return false;
464       }
465     } else if (args[i] == "--cpu") {
466       if (!NextArgumentOrError(args, &i)) {
467         return false;
468       }
469       cpus_ = GetCpusFromString(args[i]);
470     } else if (args[i] == "--duration") {
471       if (!NextArgumentOrError(args, &i)) {
472         return false;
473       }
474       if (!android::base::ParseDouble(args[i].c_str(), &duration_in_sec_,
475                                       1e-9)) {
476         LOG(ERROR) << "Invalid duration: " << args[i].c_str();
477         return false;
478       }
479     } else if (args[i] == "-e") {
480       if (!NextArgumentOrError(args, &i)) {
481         return false;
482       }
483       std::vector<std::string> event_types = android::base::Split(args[i], ",");
484       for (auto& event_type : event_types) {
485         if (!event_selection_set_.AddEventType(event_type)) {
486           return false;
487         }
488       }
489     } else if (args[i] == "-f" || args[i] == "-F") {
490       if (!NextArgumentOrError(args, &i)) {
491         return false;
492       }
493       if (!android::base::ParseUint(args[i].c_str(), &sample_freq_)) {
494         LOG(ERROR) << "Invalid sample frequency: " << args[i];
495         return false;
496       }
497       if (!CheckSampleFrequency(sample_freq_)) {
498         return false;
499       }
500       use_sample_freq_ = true;
501     } else if (args[i] == "-g") {
502       fp_callchain_sampling_ = false;
503       dwarf_callchain_sampling_ = true;
504     } else if (args[i] == "--group") {
505       if (!NextArgumentOrError(args, &i)) {
506         return false;
507       }
508       std::vector<std::string> event_types = android::base::Split(args[i], ",");
509       if (!event_selection_set_.AddEventGroup(event_types)) {
510         return false;
511       }
512     } else if (args[i] == "--in-app") {
513       in_app_context_ = true;
514     } else if (args[i] == "-j") {
515       if (!NextArgumentOrError(args, &i)) {
516         return false;
517       }
518       std::vector<std::string> branch_sampling_types =
519           android::base::Split(args[i], ",");
520       for (auto& type : branch_sampling_types) {
521         auto it = branch_sampling_type_map.find(type);
522         if (it == branch_sampling_type_map.end()) {
523           LOG(ERROR) << "unrecognized branch sampling filter: " << type;
524           return false;
525         }
526         branch_sampling_ |= it->second;
527       }
528     } else if (args[i] == "-m") {
529       if (!NextArgumentOrError(args, &i)) {
530         return false;
531       }
532       char* endptr;
533       uint64_t pages = strtoull(args[i].c_str(), &endptr, 0);
534       if (*endptr != '\0' || !IsPowerOfTwo(pages)) {
535         LOG(ERROR) << "Invalid mmap_pages: '" << args[i] << "'";
536         return false;
537       }
538       mmap_page_range_.first = mmap_page_range_.second = pages;
539     } else if (args[i] == "--no-dump-kernel-symbols") {
540       can_dump_kernel_symbols_ = false;
541     } else if (args[i] == "--no-dump-symbols") {
542       dump_symbols_ = false;
543     } else if (args[i] == "--no-inherit") {
544       child_inherit_ = false;
545     } else if (args[i] == "--no-unwind") {
546       unwind_dwarf_callchain_ = false;
547     } else if (args[i] == "-o") {
548       if (!NextArgumentOrError(args, &i)) {
549         return false;
550       }
551       record_filename_ = args[i];
552     } else if (args[i] == "-p") {
553       if (!NextArgumentOrError(args, &i)) {
554         return false;
555       }
556       std::set<pid_t> pids;
557       if (!GetValidThreadsFromThreadString(args[i], &pids)) {
558         return false;
559       }
560       event_selection_set_.AddMonitoredProcesses(pids);
561     } else if (args[i] == "--post-unwind") {
562       post_unwind_ = true;
563     } else if (args[i] == "--start_profiling_fd") {
564       if (!NextArgumentOrError(args, &i)) {
565         return false;
566       }
567       if (!android::base::ParseInt(args[i].c_str(), &start_profiling_fd_, 0)) {
568         LOG(ERROR) << "Invalid start_profiling_fd: " << args[i];
569         return false;
570       }
571     } else if (args[i] == "--symfs") {
572       if (!NextArgumentOrError(args, &i)) {
573         return false;
574       }
575       if (!Dso::SetSymFsDir(args[i])) {
576         return false;
577       }
578     } else if (args[i] == "-t") {
579       if (!NextArgumentOrError(args, &i)) {
580         return false;
581       }
582       std::set<pid_t> tids;
583       if (!GetValidThreadsFromThreadString(args[i], &tids)) {
584         return false;
585       }
586       event_selection_set_.AddMonitoredThreads(tids);
587     } else {
588       ReportUnknownOption(args, i);
589       return false;
590     }
591   }
592
593   if (use_sample_freq_ && use_sample_period_) {
594     LOG(ERROR) << "-f option can't be used with -c option.";
595     return false;
596   }
597
598   if (!dwarf_callchain_sampling_) {
599     if (!unwind_dwarf_callchain_) {
600       LOG(ERROR)
601           << "--no-unwind is only used with `--call-graph dwarf` option.";
602       return false;
603     }
604     unwind_dwarf_callchain_ = false;
605   }
606   if (post_unwind_) {
607     if (!dwarf_callchain_sampling_) {
608       LOG(ERROR)
609           << "--post-unwind is only used with `--call-graph dwarf` option.";
610       return false;
611     }
612     if (!unwind_dwarf_callchain_) {
613       LOG(ERROR) << "--post-unwind can't be used with `--no-unwind` option.";
614       return false;
615     }
616   }
617
618   if (fp_callchain_sampling_) {
619     if (GetBuildArch() == ARCH_ARM) {
620       LOG(WARNING) << "`--callgraph fp` option doesn't work well on arm architecture, "
621                    << "consider using `-g` option or profiling on aarch64 architecture.";
622     }
623   }
624
625   if (system_wide_collection_ && event_selection_set_.HasMonitoredTarget()) {
626     LOG(ERROR) << "Record system wide and existing processes/threads can't be "
627                   "used at the same time.";
628     return false;
629   }
630
631   if (system_wide_collection_ && !IsRoot()) {
632     LOG(ERROR) << "System wide profiling needs root privilege.";
633     return false;
634   }
635
636   if (dump_symbols_ && can_dump_kernel_symbols_) {
637     // No need to dump kernel symbols as we will dump all required symbols.
638     can_dump_kernel_symbols_ = false;
639   }
640
641   non_option_args->clear();
642   for (; i < args.size(); ++i) {
643     non_option_args->push_back(args[i]);
644   }
645   return true;
646 }
647
648 bool RecordCommand::SetEventSelectionFlags() {
649   if (use_sample_freq_) {
650     event_selection_set_.SetSampleFreq(sample_freq_);
651   } else if (use_sample_period_) {
652     event_selection_set_.SetSamplePeriod(sample_period_);
653   } else {
654     event_selection_set_.UseDefaultSampleFreq();
655   }
656   event_selection_set_.SampleIdAll();
657   if (!event_selection_set_.SetBranchSampling(branch_sampling_)) {
658     return false;
659   }
660   if (fp_callchain_sampling_) {
661     event_selection_set_.EnableFpCallChainSampling();
662   } else if (dwarf_callchain_sampling_) {
663     if (!event_selection_set_.EnableDwarfCallChainSampling(
664             dump_stack_size_in_dwarf_sampling_)) {
665       return false;
666     }
667   }
668   event_selection_set_.SetInherit(child_inherit_);
669   return true;
670 }
671
672 bool RecordCommand::CreateAndInitRecordFile() {
673   record_file_writer_ = CreateRecordFile(record_filename_);
674   if (record_file_writer_ == nullptr) {
675     return false;
676   }
677   // Use first perf_event_attr and first event id to dump mmap and comm records.
678   EventAttrWithId attr_id = event_selection_set_.GetEventAttrWithId()[0];
679   if (!DumpKernelSymbol()) {
680     return false;
681   }
682   if (!DumpTracingData()) {
683     return false;
684   }
685   if (!DumpKernelAndModuleMmaps(*attr_id.attr, attr_id.ids[0])) {
686     return false;
687   }
688   if (!DumpThreadCommAndMmaps(*attr_id.attr, attr_id.ids[0])) {
689     return false;
690   }
691   return true;
692 }
693
694 std::unique_ptr<RecordFileWriter> RecordCommand::CreateRecordFile(
695     const std::string& filename) {
696   std::unique_ptr<RecordFileWriter> writer =
697       RecordFileWriter::CreateInstance(filename);
698   if (writer == nullptr) {
699     return nullptr;
700   }
701
702   if (!writer->WriteAttrSection(event_selection_set_.GetEventAttrWithId())) {
703     return nullptr;
704   }
705   return writer;
706 }
707
708 bool RecordCommand::DumpKernelSymbol() {
709   if (can_dump_kernel_symbols_) {
710     std::string kallsyms;
711     if (event_selection_set_.NeedKernelSymbol() &&
712         CheckKernelSymbolAddresses()) {
713       if (!android::base::ReadFileToString("/proc/kallsyms", &kallsyms)) {
714         PLOG(ERROR) << "failed to read /proc/kallsyms";
715         return false;
716       }
717       KernelSymbolRecord r(kallsyms);
718       if (!ProcessRecord(&r)) {
719         return false;
720       }
721     }
722   }
723   return true;
724 }
725
726 bool RecordCommand::DumpTracingData() {
727   std::vector<const EventType*> tracepoint_event_types =
728       event_selection_set_.GetTracepointEvents();
729   if (tracepoint_event_types.empty()) {
730     return true;  // No need to dump tracing data.
731   }
732   std::vector<char> tracing_data;
733   if (!GetTracingData(tracepoint_event_types, &tracing_data)) {
734     return false;
735   }
736   TracingDataRecord record(tracing_data);
737   if (!ProcessRecord(&record)) {
738     return false;
739   }
740   return true;
741 }
742
743 bool RecordCommand::DumpKernelAndModuleMmaps(const perf_event_attr& attr,
744                                              uint64_t event_id) {
745   KernelMmap kernel_mmap;
746   std::vector<KernelMmap> module_mmaps;
747   GetKernelAndModuleMmaps(&kernel_mmap, &module_mmaps);
748
749   MmapRecord mmap_record(attr, true, UINT_MAX, 0, kernel_mmap.start_addr,
750                          kernel_mmap.len, 0, kernel_mmap.filepath, event_id);
751   if (!ProcessRecord(&mmap_record)) {
752     return false;
753   }
754   for (auto& module_mmap : module_mmaps) {
755     MmapRecord mmap_record(attr, true, UINT_MAX, 0, module_mmap.start_addr,
756                            module_mmap.len, 0, module_mmap.filepath, event_id);
757     if (!ProcessRecord(&mmap_record)) {
758       return false;
759     }
760   }
761   return true;
762 }
763
764 bool RecordCommand::DumpThreadCommAndMmaps(const perf_event_attr& attr,
765                                            uint64_t event_id) {
766   // Decide which processes and threads to dump.
767   // For system_wide profiling, dump all threads.
768   // For non system wide profiling, build dump_threads.
769   bool all_threads = system_wide_collection_;
770   std::set<pid_t> dump_threads = event_selection_set_.GetMonitoredThreads();
771   for (const auto& pid : event_selection_set_.GetMonitoredProcesses()) {
772     std::vector<pid_t> tids = GetThreadsInProcess(pid);
773     dump_threads.insert(tids.begin(), tids.end());
774   }
775
776   // Collect processes to dump.
777   std::vector<pid_t> processes;
778   if (all_threads) {
779     processes = GetAllProcesses();
780   } else {
781     std::set<pid_t> process_set;
782     for (const auto& tid : dump_threads) {
783       pid_t pid;
784       if (!GetProcessForThread(tid, &pid)) {
785         continue;
786       }
787       process_set.insert(pid);
788     }
789     processes.insert(processes.end(), process_set.begin(), process_set.end());
790   }
791
792   // Dump each process and its threads.
793   for (auto& pid : processes) {
794     // Dump mmap records.
795     std::vector<ThreadMmap> thread_mmaps;
796     if (!GetThreadMmapsInProcess(pid, &thread_mmaps)) {
797       // The process may exit before we get its info.
798       continue;
799     }
800     for (const auto& map : thread_mmaps) {
801       if (map.executable == 0) {
802         continue;  // No need to dump non-executable mmap info.
803       }
804       MmapRecord record(attr, false, pid, pid, map.start_addr, map.len,
805                         map.pgoff, map.name, event_id);
806       if (!ProcessRecord(&record)) {
807         return false;
808       }
809     }
810     // Dump process name.
811     std::string name;
812     if (GetThreadName(pid, &name)) {
813       CommRecord record(attr, pid, pid, name, event_id, 0);
814       if (!ProcessRecord(&record)) {
815         return false;
816       }
817     }
818     // Dump thread info.
819     std::vector<pid_t> threads = GetThreadsInProcess(pid);
820     for (const auto& tid : threads) {
821       if (tid == pid) {
822         continue;
823       }
824       if (all_threads || dump_threads.find(tid) != dump_threads.end()) {
825         ForkRecord fork_record(attr, pid, tid, pid, pid, event_id);
826         if (!ProcessRecord(&fork_record)) {
827           return false;
828         }
829         if (GetThreadName(tid, &name)) {
830           CommRecord comm_record(attr, pid, tid, name, event_id, 0);
831           if (!ProcessRecord(&comm_record)) {
832             return false;
833           }
834         }
835       }
836     }
837   }
838   return true;
839 }
840
841 bool RecordCommand::ProcessRecord(Record* record) {
842   if (system_wide_collection_ && record->type() == PERF_RECORD_SAMPLE) {
843     auto& r = *static_cast<SampleRecord*>(record);
844     // Omit samples get before start sampling time.
845     if (r.time_data.time < start_sampling_time_in_ns_) {
846       return true;
847     }
848   }
849   UpdateRecordForEmbeddedElfPath(record);
850   if (unwind_dwarf_callchain_ && !post_unwind_) {
851     thread_tree_.Update(*record);
852     if (!UnwindRecord(record)) {
853       return false;
854     }
855   }
856   if (record->type() == PERF_RECORD_SAMPLE) {
857     sample_record_count_++;
858   } else if (record->type() == PERF_RECORD_LOST) {
859     lost_record_count_ += static_cast<LostRecord*>(record)->lost;
860   }
861   bool result = record_file_writer_->WriteRecord(*record);
862   return result;
863 }
864
865 template <class RecordType>
866 void UpdateMmapRecordForEmbeddedElfPath(RecordType* record) {
867   RecordType& r = *record;
868   if (!r.InKernel() && r.data->pgoff != 0) {
869     // For the case of a shared library "foobar.so" embedded
870     // inside an APK, we rewrite the original MMAP from
871     // ["path.apk" offset=X] to ["path.apk!/foobar.so" offset=W]
872     // so as to make the library name explicit. This update is
873     // done here (as part of the record operation) as opposed to
874     // on the host during the report, since we want to report
875     // the correct library name even if the the APK in question
876     // is not present on the host. The new offset W is
877     // calculated to be with respect to the start of foobar.so,
878     // not to the start of path.apk.
879     EmbeddedElf* ee =
880         ApkInspector::FindElfInApkByOffset(r.filename, r.data->pgoff);
881     if (ee != nullptr) {
882       // Compute new offset relative to start of elf in APK.
883       auto data = *r.data;
884       data.pgoff -= ee->entry_offset();
885       r.SetDataAndFilename(data, GetUrlInApk(r.filename, ee->entry_name()));
886     }
887   }
888 }
889
890 void RecordCommand::UpdateRecordForEmbeddedElfPath(Record* record) {
891   if (record->type() == PERF_RECORD_MMAP) {
892     UpdateMmapRecordForEmbeddedElfPath(static_cast<MmapRecord*>(record));
893   } else if (record->type() == PERF_RECORD_MMAP2) {
894     UpdateMmapRecordForEmbeddedElfPath(static_cast<Mmap2Record*>(record));
895   }
896 }
897
898 bool RecordCommand::UnwindRecord(Record* record) {
899   if (record->type() == PERF_RECORD_SAMPLE) {
900     SampleRecord& r = *static_cast<SampleRecord*>(record);
901     if ((r.sample_type & PERF_SAMPLE_CALLCHAIN) &&
902         (r.sample_type & PERF_SAMPLE_REGS_USER) &&
903         (r.regs_user_data.reg_mask != 0) &&
904         (r.sample_type & PERF_SAMPLE_STACK_USER) &&
905         (r.GetValidStackSize() > 0)) {
906       ThreadEntry* thread =
907           thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
908       RegSet regs = CreateRegSet(r.regs_user_data.abi,
909                                  r.regs_user_data.reg_mask,
910                                  r.regs_user_data.regs);
911       // Normally do strict arch check when unwinding stack. But allow unwinding
912       // 32-bit processes on 64-bit devices for system wide profiling.
913       bool strict_arch_check = !system_wide_collection_;
914       std::vector<uint64_t> unwind_ips =
915           UnwindCallChain(r.regs_user_data.abi, *thread, regs,
916                           r.stack_user_data.data,
917                           r.GetValidStackSize(), strict_arch_check);
918       r.ReplaceRegAndStackWithCallChain(unwind_ips);
919     }
920   }
921   return true;
922 }
923
924 bool RecordCommand::PostUnwind(const std::vector<std::string>& args) {
925   thread_tree_.ClearThreadAndMap();
926   std::unique_ptr<RecordFileReader> reader =
927       RecordFileReader::CreateInstance(record_filename_);
928   if (reader == nullptr) {
929     return false;
930   }
931   std::string tmp_filename = record_filename_ + ".tmp";
932   record_file_writer_ = CreateRecordFile(tmp_filename);
933   if (record_file_writer_ == nullptr) {
934     return false;
935   }
936   bool result = reader->ReadDataSection(
937       [this](std::unique_ptr<Record> record) {
938         thread_tree_.Update(*record);
939         if (!UnwindRecord(record.get())) {
940           return false;
941         }
942         return record_file_writer_->WriteRecord(*record);
943       },
944       false);
945   if (!result) {
946     return false;
947   }
948   if (!DumpAdditionalFeatures(args)) {
949     return false;
950   }
951   if (!record_file_writer_->Close()) {
952     return false;
953   }
954
955   if (unlink(record_filename_.c_str()) != 0) {
956     PLOG(ERROR) << "failed to remove " << record_filename_;
957     return false;
958   }
959   if (rename(tmp_filename.c_str(), record_filename_.c_str()) != 0) {
960     PLOG(ERROR) << "failed to rename " << tmp_filename << " to "
961                 << record_filename_;
962     return false;
963   }
964   return true;
965 }
966
967 bool RecordCommand::DumpAdditionalFeatures(
968     const std::vector<std::string>& args) {
969   // Read data section of perf.data to collect hit file information.
970   thread_tree_.ClearThreadAndMap();
971   if (CheckKernelSymbolAddresses()) {
972     Dso::ReadKernelSymbolsFromProc();
973   }
974   auto callback = [&](const Record* r) {
975     thread_tree_.Update(*r);
976     if (r->type() == PERF_RECORD_SAMPLE) {
977       CollectHitFileInfo(*reinterpret_cast<const SampleRecord*>(r));
978     }
979   };
980   if (!record_file_writer_->ReadDataSection(callback)) {
981     return false;
982   }
983
984   size_t feature_count = 5;
985   if (branch_sampling_) {
986     feature_count++;
987   }
988   if (dump_symbols_) {
989     feature_count++;
990   }
991   if (!record_file_writer_->BeginWriteFeatures(feature_count)) {
992     return false;
993   }
994   if (!DumpBuildIdFeature()) {
995     return false;
996   }
997   if (dump_symbols_ && !DumpFileFeature()) {
998     return false;
999   }
1000   utsname uname_buf;
1001   if (TEMP_FAILURE_RETRY(uname(&uname_buf)) != 0) {
1002     PLOG(ERROR) << "uname() failed";
1003     return false;
1004   }
1005   if (!record_file_writer_->WriteFeatureString(PerfFileFormat::FEAT_OSRELEASE,
1006                                                uname_buf.release)) {
1007     return false;
1008   }
1009   if (!record_file_writer_->WriteFeatureString(PerfFileFormat::FEAT_ARCH,
1010                                                uname_buf.machine)) {
1011     return false;
1012   }
1013
1014   std::string exec_path = android::base::GetExecutablePath();
1015   if (exec_path.empty()) exec_path = "simpleperf";
1016   std::vector<std::string> cmdline;
1017   cmdline.push_back(exec_path);
1018   cmdline.push_back("record");
1019   cmdline.insert(cmdline.end(), args.begin(), args.end());
1020   if (!record_file_writer_->WriteCmdlineFeature(cmdline)) {
1021     return false;
1022   }
1023   if (branch_sampling_ != 0 &&
1024       !record_file_writer_->WriteBranchStackFeature()) {
1025     return false;
1026   }
1027
1028   std::unordered_map<std::string, std::string> info_map;
1029   info_map["simpleperf_version"] = GetSimpleperfVersion();
1030   if (!record_file_writer_->WriteMetaInfoFeature(info_map)) {
1031     return false;
1032   }
1033
1034   if (!record_file_writer_->EndWriteFeatures()) {
1035     return false;
1036   }
1037   return true;
1038 }
1039
1040 bool RecordCommand::DumpBuildIdFeature() {
1041   std::vector<BuildIdRecord> build_id_records;
1042   BuildId build_id;
1043   std::vector<Dso*> dso_v = thread_tree_.GetAllDsos();
1044   for (Dso* dso : dso_v) {
1045     if (!dso->HasDumpId()) {
1046       continue;
1047     }
1048     if (dso->type() == DSO_KERNEL) {
1049       if (!GetKernelBuildId(&build_id)) {
1050         continue;
1051       }
1052       build_id_records.push_back(
1053           BuildIdRecord(true, UINT_MAX, build_id, dso->Path()));
1054     } else if (dso->type() == DSO_KERNEL_MODULE) {
1055       std::string path = dso->Path();
1056       std::string module_name = basename(&path[0]);
1057       if (android::base::EndsWith(module_name, ".ko")) {
1058         module_name = module_name.substr(0, module_name.size() - 3);
1059       }
1060       if (!GetModuleBuildId(module_name, &build_id)) {
1061         LOG(DEBUG) << "can't read build_id for module " << module_name;
1062         continue;
1063       }
1064       build_id_records.push_back(BuildIdRecord(true, UINT_MAX, build_id, path));
1065     } else {
1066       if (dso->Path() == DEFAULT_EXECNAME_FOR_THREAD_MMAP) {
1067         continue;
1068       }
1069       auto tuple = SplitUrlInApk(dso->Path());
1070       if (std::get<0>(tuple)) {
1071         ElfStatus result = GetBuildIdFromApkFile(std::get<1>(tuple),
1072                                                  std::get<2>(tuple), &build_id);
1073         if (result != ElfStatus::NO_ERROR) {
1074           LOG(DEBUG) << "can't read build_id from file " << dso->Path() << ": "
1075                      << result;
1076           continue;
1077         }
1078       } else {
1079         ElfStatus result = GetBuildIdFromElfFile(dso->Path(), &build_id);
1080         if (result != ElfStatus::NO_ERROR) {
1081           LOG(DEBUG) << "can't read build_id from file " << dso->Path() << ": "
1082                      << result;
1083           continue;
1084         }
1085       }
1086       build_id_records.push_back(
1087           BuildIdRecord(false, UINT_MAX, build_id, dso->Path()));
1088     }
1089   }
1090   if (!record_file_writer_->WriteBuildIdFeature(build_id_records)) {
1091     return false;
1092   }
1093   return true;
1094 }
1095
1096 bool RecordCommand::DumpFileFeature() {
1097   std::vector<Dso*> dso_v = thread_tree_.GetAllDsos();
1098   for (Dso* dso : dso_v) {
1099     if (!dso->HasDumpId()) {
1100       continue;
1101     }
1102     uint32_t dso_type = dso->type();
1103     uint64_t min_vaddr = dso->MinVirtualAddress();
1104
1105     // Dumping all symbols in hit files takes too much space, so only dump
1106     // needed symbols.
1107     const std::vector<Symbol>& symbols = dso->GetSymbols();
1108     std::vector<const Symbol*> dump_symbols;
1109     for (const auto& sym : symbols) {
1110       if (sym.HasDumpId()) {
1111         dump_symbols.push_back(&sym);
1112       }
1113     }
1114     std::sort(dump_symbols.begin(), dump_symbols.end(), Symbol::CompareByAddr);
1115
1116     if (!record_file_writer_->WriteFileFeature(dso->Path(), dso_type, min_vaddr,
1117                                                dump_symbols)) {
1118       return false;
1119     }
1120   }
1121   return true;
1122 }
1123
1124 void RecordCommand::CollectHitFileInfo(const SampleRecord& r) {
1125   const ThreadEntry* thread =
1126       thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
1127   const MapEntry* map =
1128       thread_tree_.FindMap(thread, r.ip_data.ip, r.InKernel());
1129   Dso* dso = map->dso;
1130   const Symbol* symbol;
1131   if (dump_symbols_) {
1132     symbol = thread_tree_.FindSymbol(map, r.ip_data.ip, nullptr, &dso);
1133     if (!symbol->HasDumpId()) {
1134       dso->CreateSymbolDumpId(symbol);
1135     }
1136   }
1137   if (!dso->HasDumpId()) {
1138     dso->CreateDumpId();
1139   }
1140   if (r.sample_type & PERF_SAMPLE_CALLCHAIN) {
1141     bool in_kernel = r.InKernel();
1142     bool first_ip = true;
1143     for (uint64_t i = 0; i < r.callchain_data.ip_nr; ++i) {
1144       uint64_t ip = r.callchain_data.ips[i];
1145       if (ip >= PERF_CONTEXT_MAX) {
1146         switch (ip) {
1147           case PERF_CONTEXT_KERNEL:
1148             in_kernel = true;
1149             break;
1150           case PERF_CONTEXT_USER:
1151             in_kernel = false;
1152             break;
1153           default:
1154             LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex
1155                        << ip;
1156         }
1157       } else {
1158         if (first_ip) {
1159           first_ip = false;
1160           // Remove duplication with sample ip.
1161           if (ip == r.ip_data.ip) {
1162             continue;
1163           }
1164         }
1165         map = thread_tree_.FindMap(thread, ip, in_kernel);
1166         dso = map->dso;
1167         if (dump_symbols_) {
1168           symbol = thread_tree_.FindSymbol(map, ip, nullptr, &dso);
1169           if (!symbol->HasDumpId()) {
1170             dso->CreateSymbolDumpId(symbol);
1171           }
1172         }
1173         if (!dso->HasDumpId()) {
1174           dso->CreateDumpId();
1175         }
1176       }
1177     }
1178   }
1179 }
1180
1181 void RegisterRecordCommand() {
1182   RegisterCommand("record",
1183                   [] { return std::unique_ptr<Command>(new RecordCommand()); });
1184 }