OSDN Git Service

Merge "Perfprofd: Factor out threaded handler" into pi-dev
[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 <inttypes.h>
18 #include <libgen.h>
19 #include <signal.h>
20 #include <sys/prctl.h>
21 #include <sys/utsname.h>
22 #include <time.h>
23 #include <unistd.h>
24 #include <set>
25 #include <string>
26 #include <unordered_map>
27 #include <vector>
28
29 #include <android-base/logging.h>
30 #include <android-base/file.h>
31 #include <android-base/parsedouble.h>
32 #include <android-base/parseint.h>
33 #include <android-base/strings.h>
34 #include <android-base/test_utils.h>
35 #if defined(__ANDROID__)
36 #include <android-base/properties.h>
37 #endif
38
39 #include "CallChainJoiner.h"
40 #include "command.h"
41 #include "environment.h"
42 #include "event_selection_set.h"
43 #include "event_type.h"
44 #include "IOEventLoop.h"
45 #include "OfflineUnwinder.h"
46 #include "perf_clock.h"
47 #include "read_apk.h"
48 #include "read_elf.h"
49 #include "record.h"
50 #include "record_file.h"
51 #include "thread_tree.h"
52 #include "tracing.h"
53 #include "utils.h"
54 #include "workload.h"
55
56 using namespace simpleperf;
57
58 static std::string default_measured_event_type = "cpu-cycles";
59
60 static std::unordered_map<std::string, uint64_t> branch_sampling_type_map = {
61     {"u", PERF_SAMPLE_BRANCH_USER},
62     {"k", PERF_SAMPLE_BRANCH_KERNEL},
63     {"any", PERF_SAMPLE_BRANCH_ANY},
64     {"any_call", PERF_SAMPLE_BRANCH_ANY_CALL},
65     {"any_ret", PERF_SAMPLE_BRANCH_ANY_RETURN},
66     {"ind_call", PERF_SAMPLE_BRANCH_IND_CALL},
67 };
68
69 static std::unordered_map<std::string, int> clockid_map = {
70     {"realtime", CLOCK_REALTIME},
71     {"monotonic", CLOCK_MONOTONIC},
72     {"monotonic_raw", CLOCK_MONOTONIC_RAW},
73     {"boottime", CLOCK_BOOTTIME},
74 };
75
76 // The max size of records dumped by kernel is 65535, and dump stack size
77 // should be a multiply of 8, so MAX_DUMP_STACK_SIZE is 65528.
78 constexpr uint32_t MAX_DUMP_STACK_SIZE = 65528;
79
80 // The max allowed pages in mapped buffer is decided by rlimit(RLIMIT_MEMLOCK).
81 // Here 1024 is a desired value for pages in mapped buffer. If mapped
82 // successfully, the buffer size = 1024 * 4K (page size) = 4M.
83 constexpr size_t DESIRED_PAGES_IN_MAPPED_BUFFER = 1024;
84
85 // Cache size used by CallChainJoiner to cache call chains in memory.
86 constexpr size_t DEFAULT_CALL_CHAIN_JOINER_CACHE_SIZE = 8 * 1024 * 1024;
87
88 class RecordCommand : public Command {
89  public:
90   RecordCommand()
91       : Command(
92             "record", "record sampling info in perf.data",
93             // clang-format off
94 "Usage: simpleperf record [options] [--] [command [command-args]]\n"
95 "       Gather sampling information of running [command]. And -a/-p/-t option\n"
96 "       can be used to change target of sampling information.\n"
97 "       The default options are: -e cpu-cycles -f 4000 -o perf.data.\n"
98 "Select monitored threads:\n"
99 "-a     System-wide collection.\n"
100 #if defined(__ANDROID__)
101 "--app package_name    Profile the process of an Android application.\n"
102 "                      On non-rooted devices, the app must be debuggable,\n"
103 "                      because we use run-as to switch to the app's context.\n"
104 #endif
105 "-p pid1,pid2,...       Record events on existing processes. Mutually exclusive\n"
106 "                       with -a.\n"
107 "-t tid1,tid2,... Record events on existing threads. Mutually exclusive with -a.\n"
108 "\n"
109 "Select monitored event types:\n"
110 "-e event1[:modifier1],event2[:modifier2],...\n"
111 "             Select the event list to sample. Use `simpleperf list` to find\n"
112 "             all possible event names. Modifiers can be added to define how\n"
113 "             the event should be monitored.\n"
114 "             Possible modifiers are:\n"
115 "                u - monitor user space events only\n"
116 "                k - monitor kernel space events only\n"
117 "--group event1[:modifier],event2[:modifier2],...\n"
118 "             Similar to -e option. But events specified in the same --group\n"
119 "             option are monitored as a group, and scheduled in and out at the\n"
120 "             same time.\n"
121 "--trace-offcpu   Generate samples when threads are scheduled off cpu.\n"
122 "                 Similar to \"-c 1 -e sched:sched_switch\".\n"
123 "\n"
124 "Select monitoring options:\n"
125 "-f freq      Set event sample frequency. It means recording at most [freq]\n"
126 "             samples every second. For non-tracepoint events, the default\n"
127 "             option is -f 4000. A -f/-c option affects all event types\n"
128 "             following it until meeting another -f/-c option. For example,\n"
129 "             for \"-f 1000 cpu-cycles -c 1 -e sched:sched_switch\", cpu-cycles\n"
130 "             has sample freq 1000, sched:sched_switch event has sample period 1.\n"
131 "-c count     Set event sample period. It means recording one sample when\n"
132 "             [count] events happen. For tracepoint events, the default option\n"
133 "             is -c 1.\n"
134 "--call-graph fp | dwarf[,<dump_stack_size>]\n"
135 "             Enable call graph recording. Use frame pointer or dwarf debug\n"
136 "             frame as the method to parse call graph in stack.\n"
137 "             Default is dwarf,65528.\n"
138 "-g           Same as '--call-graph dwarf'.\n"
139 "--clockid clock_id      Generate timestamps of samples using selected clock.\n"
140 "                        Possible values are: realtime, monotonic,\n"
141 "                        monotonic_raw, boottime, perf. Default is perf.\n"
142 "--cpu cpu_item1,cpu_item2,...\n"
143 "             Collect samples only on the selected cpus. cpu_item can be cpu\n"
144 "             number like 1, or cpu range like 0-3.\n"
145 "--duration time_in_sec  Monitor for time_in_sec seconds instead of running\n"
146 "                        [command]. Here time_in_sec may be any positive\n"
147 "                        floating point number.\n"
148 "-j branch_filter1,branch_filter2,...\n"
149 "             Enable taken branch stack sampling. Each sample captures a series\n"
150 "             of consecutive taken branches.\n"
151 "             The following filters are defined:\n"
152 "                any: any type of branch\n"
153 "                any_call: any function call or system call\n"
154 "                any_ret: any function return or system call return\n"
155 "                ind_call: any indirect branch\n"
156 "                u: only when the branch target is at the user level\n"
157 "                k: only when the branch target is in the kernel\n"
158 "             This option requires at least one branch type among any, any_call,\n"
159 "             any_ret, ind_call.\n"
160 "-b           Enable taken branch stack sampling. Same as '-j any'.\n"
161 "-m mmap_pages   Set the size of the buffer used to receiving sample data from\n"
162 "                the kernel. It should be a power of 2. If not set, the max\n"
163 "                possible value <= 1024 will be used.\n"
164 "--no-inherit  Don't record created child threads/processes.\n"
165 "\n"
166 "Dwarf unwinding options:\n"
167 "--no-post-unwind   If `--call-graph dwarf` option is used, then the user's stack\n"
168 "                   will be recorded in perf.data and unwound after recording.\n"
169 "                   However, this takes a lot of disk space. Use this option to\n"
170 "                   unwind while recording.\n"
171 "--no-unwind   If `--call-graph dwarf` option is used, then the user's stack\n"
172 "              will be unwound by default. Use this option to disable the\n"
173 "              unwinding of the user's stack.\n"
174 "--no-callchain-joiner  If `--call-graph dwarf` option is used, then by default\n"
175 "                       callchain joiner is used to break the 64k stack limit\n"
176 "                       and build more complete call graphs. However, the built\n"
177 "                       call graphs may not be correct in all cases.\n"
178 "--callchain-joiner-min-matching-nodes count\n"
179 "               When callchain joiner is used, set the matched nodes needed to join\n"
180 "               callchains. The count should be >= 1. By default it is 1.\n"
181 "\n"
182 "Recording file options:\n"
183 "--no-dump-kernel-symbols  Don't dump kernel symbols in perf.data. By default\n"
184 "                          kernel symbols will be dumped when needed.\n"
185 "--no-dump-symbols       Don't dump symbols in perf.data. By default symbols are\n"
186 "                        dumped in perf.data, to support reporting in another\n"
187 "                        environment.\n"
188 "-o record_file_name    Set record file name, default is perf.data.\n"
189 "--exit-with-parent            Stop recording when the process starting\n"
190 "                              simpleperf dies.\n"
191 "--start_profiling_fd fd_no    After starting profiling, write \"STARTED\" to\n"
192 "                              <fd_no>, then close <fd_no>.\n"
193 "--symfs <dir>    Look for files with symbols relative to this directory.\n"
194 "                 This option is used to provide files with symbol table and\n"
195 "                 debug information, which are used for unwinding and dumping symbols.\n"
196 #if 0
197 // Below options are only used internally and shouldn't be visible to the public.
198 "--in-app         We are already running in the app's context.\n"
199 "--tracepoint-events file_name   Read tracepoint events from [file_name] instead of tracefs.\n"
200 #endif
201             // clang-format on
202             ),
203         system_wide_collection_(false),
204         branch_sampling_(0),
205         fp_callchain_sampling_(false),
206         dwarf_callchain_sampling_(false),
207         dump_stack_size_in_dwarf_sampling_(MAX_DUMP_STACK_SIZE),
208         unwind_dwarf_callchain_(true),
209         post_unwind_(true),
210         child_inherit_(true),
211         duration_in_sec_(0),
212         can_dump_kernel_symbols_(true),
213         dump_symbols_(true),
214         clockid_("perf"),
215         event_selection_set_(false),
216         mmap_page_range_(std::make_pair(1, DESIRED_PAGES_IN_MAPPED_BUFFER)),
217         record_filename_("perf.data"),
218         start_sampling_time_in_ns_(0),
219         sample_record_count_(0),
220         lost_record_count_(0),
221         start_profiling_fd_(-1),
222         in_app_context_(false),
223         trace_offcpu_(false),
224         exclude_kernel_callchain_(false),
225         allow_callchain_joiner_(true),
226         callchain_joiner_min_matching_nodes_(1u) {
227     // If we run `adb shell simpleperf record xxx` and stop profiling by ctrl-c, adb closes
228     // sockets connecting simpleperf. After that, simpleperf will receive SIGPIPE when writing
229     // to stdout/stderr, which is a problem when we use '--app' option. So ignore SIGPIPE to
230     // finish properly.
231     signal(SIGPIPE, SIG_IGN);
232     app_package_name_ = GetDefaultAppPackageName();
233   }
234
235   bool Run(const std::vector<std::string>& args);
236
237  private:
238   bool ParseOptions(const std::vector<std::string>& args,
239                     std::vector<std::string>* non_option_args);
240   bool PrepareRecording(Workload* workload);
241   bool DoRecording(Workload* workload);
242   bool PostProcessRecording(const std::vector<std::string>& args);
243   bool TraceOffCpu();
244   bool SetEventSelectionFlags();
245   bool CreateAndInitRecordFile();
246   std::unique_ptr<RecordFileWriter> CreateRecordFile(
247       const std::string& filename);
248   bool DumpKernelSymbol();
249   bool DumpTracingData();
250   bool DumpKernelAndModuleMmaps(const perf_event_attr& attr, uint64_t event_id);
251   bool DumpThreadCommAndMmaps(const perf_event_attr& attr, uint64_t event_id);
252   bool ProcessRecord(Record* record);
253   bool SaveRecordForPostUnwinding(Record* record);
254   bool SaveRecordAfterUnwinding(Record* record);
255   bool SaveRecordWithoutUnwinding(Record* record);
256
257   void UpdateRecordForEmbeddedElfPath(Record* record);
258   bool UnwindRecord(SampleRecord& r);
259   bool PostUnwindRecords();
260   bool JoinCallChains();
261   bool DumpAdditionalFeatures(const std::vector<std::string>& args);
262   bool DumpBuildIdFeature();
263   bool DumpFileFeature();
264   bool DumpMetaInfoFeature();
265   void CollectHitFileInfo(const SampleRecord& r);
266
267   std::unique_ptr<SampleSpeed> sample_speed_;
268   bool system_wide_collection_;
269   uint64_t branch_sampling_;
270   bool fp_callchain_sampling_;
271   bool dwarf_callchain_sampling_;
272   uint32_t dump_stack_size_in_dwarf_sampling_;
273   bool unwind_dwarf_callchain_;
274   bool post_unwind_;
275   std::unique_ptr<OfflineUnwinder> offline_unwinder_;
276   bool child_inherit_;
277   double duration_in_sec_;
278   bool can_dump_kernel_symbols_;
279   bool dump_symbols_;
280   std::string clockid_;
281   std::vector<int> cpus_;
282   EventSelectionSet event_selection_set_;
283
284   std::pair<size_t, size_t> mmap_page_range_;
285
286   ThreadTree thread_tree_;
287   std::string record_filename_;
288   std::unique_ptr<RecordFileWriter> record_file_writer_;
289
290   uint64_t start_sampling_time_in_ns_;  // nanoseconds from machine starting
291
292   uint64_t sample_record_count_;
293   uint64_t lost_record_count_;
294   int start_profiling_fd_;
295   std::string app_package_name_;
296   bool in_app_context_;
297   bool trace_offcpu_;
298   bool exclude_kernel_callchain_;
299
300   // For CallChainJoiner
301   bool allow_callchain_joiner_;
302   size_t callchain_joiner_min_matching_nodes_;
303   std::unique_ptr<CallChainJoiner> callchain_joiner_;
304 };
305
306 bool RecordCommand::Run(const std::vector<std::string>& args) {
307   ScopedCurrentArch scoped_arch(GetMachineArch());
308   if (!CheckPerfEventLimit()) {
309     return false;
310   }
311   AllowMoreOpenedFiles();
312
313   std::vector<std::string> workload_args;
314   if (!ParseOptions(args, &workload_args)) {
315     return false;
316   }
317   if (!app_package_name_.empty() && !in_app_context_) {
318     // Some users want to profile non debuggable apps on rooted devices. If we use run-as,
319     // it will be impossible when using --app. So don't switch to app's context when we are
320     // root.
321     if (!IsRoot()) {
322       return RunInAppContext(app_package_name_, "record", args, workload_args.size(),
323                              record_filename_, true);
324     }
325   }
326   std::unique_ptr<Workload> workload;
327   if (!workload_args.empty()) {
328     workload = Workload::CreateWorkload(workload_args);
329     if (workload == nullptr) {
330       return false;
331     }
332   }
333   if (!PrepareRecording(workload.get())) {
334     return false;
335   }
336   if (!DoRecording(workload.get())) {
337     return false;
338   }
339   return PostProcessRecording(args);
340 }
341
342 bool RecordCommand::PrepareRecording(Workload* workload) {
343   // 1. Prepare in other modules.
344   if (!InitPerfClock()) {
345     return false;
346   }
347   PrepareVdsoFile();
348
349   // 2. Add default event type.
350   if (event_selection_set_.empty()) {
351     size_t group_id;
352     if (!event_selection_set_.AddEventType(default_measured_event_type, &group_id)) {
353       return false;
354     }
355     if (sample_speed_) {
356       event_selection_set_.SetSampleSpeed(group_id, *sample_speed_);
357     }
358   }
359
360   // 3. Process options before opening perf event files.
361   exclude_kernel_callchain_ = event_selection_set_.ExcludeKernel();
362   if (trace_offcpu_ && !TraceOffCpu()) {
363     return false;
364   }
365   if (!SetEventSelectionFlags()) {
366     return false;
367   }
368   if (unwind_dwarf_callchain_) {
369     offline_unwinder_.reset(new OfflineUnwinder(false));
370   }
371   if (unwind_dwarf_callchain_ && allow_callchain_joiner_) {
372     callchain_joiner_.reset(new CallChainJoiner(DEFAULT_CALL_CHAIN_JOINER_CACHE_SIZE,
373                                                 callchain_joiner_min_matching_nodes_,
374                                                 false));
375   }
376
377   // 4. Add monitored targets.
378   bool need_to_check_targets = false;
379   if (system_wide_collection_) {
380     event_selection_set_.AddMonitoredThreads({-1});
381   } else if (!event_selection_set_.HasMonitoredTarget()) {
382     if (workload != nullptr) {
383       event_selection_set_.AddMonitoredProcesses({workload->GetPid()});
384       event_selection_set_.SetEnableOnExec(true);
385       if (event_selection_set_.HasInplaceSampler()) {
386         // Start worker early, because the worker process has to setup inplace-sampler server
387         // before we try to connect it.
388         if (!workload->Start()) {
389           return false;
390         }
391       }
392     } else if (!app_package_name_.empty()) {
393       // If app process is not created, wait for it. This allows simpleperf starts before
394       // app process. In this way, we can have a better support of app start-up time profiling.
395       std::set<pid_t> pids = WaitForAppProcesses(app_package_name_);
396       event_selection_set_.AddMonitoredProcesses(pids);
397       need_to_check_targets = true;
398     } else {
399       LOG(ERROR)
400           << "No threads to monitor. Try `simpleperf help record` for help";
401       return false;
402     }
403   } else {
404     need_to_check_targets = true;
405   }
406
407   // 5. Open perf event files and create mapped buffers.
408   if (!event_selection_set_.OpenEventFiles(cpus_)) {
409     return false;
410   }
411   if (!event_selection_set_.MmapEventFiles(mmap_page_range_.first,
412                                            mmap_page_range_.second)) {
413     return false;
414   }
415
416   // 6. Create perf.data.
417   if (!CreateAndInitRecordFile()) {
418     return false;
419   }
420
421   // 7. Add read/signal/periodic Events.
422   auto callback =
423       std::bind(&RecordCommand::ProcessRecord, this, std::placeholders::_1);
424   if (!event_selection_set_.PrepareToReadMmapEventData(callback)) {
425     return false;
426   }
427   if (need_to_check_targets && !event_selection_set_.StopWhenNoMoreTargets()) {
428     return false;
429   }
430   IOEventLoop* loop = event_selection_set_.GetIOEventLoop();
431   if (!loop->AddSignalEvents({SIGCHLD, SIGINT, SIGTERM},
432                              [loop]() { return loop->ExitLoop(); })) {
433     return false;
434   }
435
436   // Only add an event for SIGHUP if we didn't inherit SIG_IGN (e.g. from nohup).
437   if (!SignalIsIgnored(SIGHUP)) {
438     if (!loop->AddSignalEvent(SIGHUP, [loop]() { return loop->ExitLoop(); })) {
439       return false;
440     }
441   }
442
443   if (duration_in_sec_ != 0) {
444     if (!loop->AddPeriodicEvent(SecondToTimeval(duration_in_sec_),
445                                 [loop]() { return loop->ExitLoop(); })) {
446       return false;
447     }
448   }
449   return true;
450 }
451
452 bool RecordCommand::DoRecording(Workload* workload) {
453   // Write records in mapped buffers of perf_event_files to output file while workload is running.
454   start_sampling_time_in_ns_ = GetPerfClock();
455   LOG(VERBOSE) << "start_sampling_time is " << start_sampling_time_in_ns_ << " ns";
456   if (workload != nullptr && !workload->IsStarted() && !workload->Start()) {
457     return false;
458   }
459   if (start_profiling_fd_ != -1) {
460     if (!android::base::WriteStringToFd("STARTED", start_profiling_fd_)) {
461       PLOG(ERROR) << "failed to write to start_profiling_fd_";
462     }
463     close(start_profiling_fd_);
464   }
465   if (!event_selection_set_.GetIOEventLoop()->RunLoop()) {
466     return false;
467   }
468   if (!event_selection_set_.FinishReadMmapEventData()) {
469     return false;
470   }
471   return true;
472 }
473
474 bool RecordCommand::PostProcessRecording(const std::vector<std::string>& args) {
475   // 1. Post unwind dwarf callchain.
476   if (unwind_dwarf_callchain_ && post_unwind_) {
477     if (!PostUnwindRecords()) {
478       return false;
479     }
480   }
481
482   // 2. Optionally join Callchains.
483   if (callchain_joiner_) {
484     JoinCallChains();
485   }
486
487   // 3. Dump additional features, and close record file.
488   if (!DumpAdditionalFeatures(args)) {
489     return false;
490   }
491   if (!record_file_writer_->Close()) {
492     return false;
493   }
494
495   // 4. Show brief record result.
496   LOG(INFO) << "Samples recorded: " << sample_record_count_
497             << ". Samples lost: " << lost_record_count_ << ".";
498   if (sample_record_count_ + lost_record_count_ != 0) {
499     double lost_percent = static_cast<double>(lost_record_count_) /
500                           (lost_record_count_ + sample_record_count_);
501     constexpr double LOST_PERCENT_WARNING_BAR = 0.1;
502     if (lost_percent >= LOST_PERCENT_WARNING_BAR) {
503       LOG(WARNING) << "Lost " << (lost_percent * 100) << "% of samples, "
504                    << "consider increasing mmap_pages(-m), "
505                    << "or decreasing sample frequency(-f), "
506                    << "or increasing sample period(-c).";
507     }
508   }
509   if (callchain_joiner_) {
510     callchain_joiner_->DumpStat();
511   }
512   return true;
513 }
514
515 bool RecordCommand::ParseOptions(const std::vector<std::string>& args,
516                                  std::vector<std::string>* non_option_args) {
517   std::vector<size_t> wait_setting_speed_event_groups_;
518   size_t i;
519   for (i = 0; i < args.size() && !args[i].empty() && args[i][0] == '-'; ++i) {
520     if (args[i] == "-a") {
521       system_wide_collection_ = true;
522     } else if (args[i] == "--app") {
523       if (!NextArgumentOrError(args, &i)) {
524         return false;
525       }
526       app_package_name_ = args[i];
527     } else if (args[i] == "-b") {
528       branch_sampling_ = branch_sampling_type_map["any"];
529     } else if (args[i] == "-c" || args[i] == "-f") {
530       if (!NextArgumentOrError(args, &i)) {
531         return false;
532       }
533       char* endptr;
534       uint64_t value = strtoull(args[i].c_str(), &endptr, 0);
535       if (*endptr != '\0' || value == 0) {
536         LOG(ERROR) << "Invalid option for " << args[i-1] << ": '" << args[i] << "'";
537         return false;
538       }
539       if (args[i-1] == "-c") {
540         sample_speed_.reset(new SampleSpeed(0, value));
541       } else {
542         sample_speed_.reset(new SampleSpeed(value, 0));
543       }
544       for (auto group_id : wait_setting_speed_event_groups_) {
545         event_selection_set_.SetSampleSpeed(group_id, *sample_speed_);
546       }
547       wait_setting_speed_event_groups_.clear();
548
549     } else if (args[i] == "--call-graph") {
550       if (!NextArgumentOrError(args, &i)) {
551         return false;
552       }
553       std::vector<std::string> strs = android::base::Split(args[i], ",");
554       if (strs[0] == "fp") {
555         fp_callchain_sampling_ = true;
556         dwarf_callchain_sampling_ = false;
557       } else if (strs[0] == "dwarf") {
558         fp_callchain_sampling_ = false;
559         dwarf_callchain_sampling_ = true;
560         if (strs.size() > 1) {
561           char* endptr;
562           uint64_t size = strtoull(strs[1].c_str(), &endptr, 0);
563           if (*endptr != '\0' || size > UINT_MAX) {
564             LOG(ERROR) << "invalid dump stack size in --call-graph option: "
565                        << strs[1];
566             return false;
567           }
568           if ((size & 7) != 0) {
569             LOG(ERROR) << "dump stack size " << size
570                        << " is not 8-byte aligned.";
571             return false;
572           }
573           if (size >= MAX_DUMP_STACK_SIZE) {
574             LOG(ERROR) << "dump stack size " << size
575                        << " is bigger than max allowed size "
576                        << MAX_DUMP_STACK_SIZE << ".";
577             return false;
578           }
579           dump_stack_size_in_dwarf_sampling_ = static_cast<uint32_t>(size);
580         }
581       } else {
582         LOG(ERROR) << "unexpected argument for --call-graph option: "
583                    << args[i];
584         return false;
585       }
586     } else if (args[i] == "--clockid") {
587       if (!NextArgumentOrError(args, &i)) {
588         return false;
589       }
590       if (args[i] != "perf") {
591         if (!IsSettingClockIdSupported()) {
592           LOG(ERROR) << "Setting clockid is not supported by the kernel.";
593           return false;
594         }
595         if (clockid_map.find(args[i]) == clockid_map.end()) {
596           LOG(ERROR) << "Invalid clockid: " << args[i];
597           return false;
598         }
599       }
600       clockid_ = args[i];
601     } else if (args[i] == "--cpu") {
602       if (!NextArgumentOrError(args, &i)) {
603         return false;
604       }
605       cpus_ = GetCpusFromString(args[i]);
606     } else if (args[i] == "--duration") {
607       if (!NextArgumentOrError(args, &i)) {
608         return false;
609       }
610       if (!android::base::ParseDouble(args[i].c_str(), &duration_in_sec_,
611                                       1e-9)) {
612         LOG(ERROR) << "Invalid duration: " << args[i].c_str();
613         return false;
614       }
615     } else if (args[i] == "-e") {
616       if (!NextArgumentOrError(args, &i)) {
617         return false;
618       }
619       std::vector<std::string> event_types = android::base::Split(args[i], ",");
620       for (auto& event_type : event_types) {
621         size_t group_id;
622         if (!event_selection_set_.AddEventType(event_type, &group_id)) {
623           return false;
624         }
625         if (sample_speed_) {
626           event_selection_set_.SetSampleSpeed(group_id, *sample_speed_);
627         } else {
628           wait_setting_speed_event_groups_.push_back(group_id);
629         }
630       }
631     } else if (args[i] == "--exit-with-parent") {
632       prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
633     } else if (args[i] == "-g") {
634       fp_callchain_sampling_ = false;
635       dwarf_callchain_sampling_ = true;
636     } else if (args[i] == "--group") {
637       if (!NextArgumentOrError(args, &i)) {
638         return false;
639       }
640       std::vector<std::string> event_types = android::base::Split(args[i], ",");
641       size_t group_id;
642       if (!event_selection_set_.AddEventGroup(event_types, &group_id)) {
643         return false;
644       }
645       if (sample_speed_) {
646         event_selection_set_.SetSampleSpeed(group_id, *sample_speed_);
647       } else {
648         wait_setting_speed_event_groups_.push_back(group_id);
649       }
650     } else if (args[i] == "--in-app") {
651       in_app_context_ = true;
652     } else if (args[i] == "-j") {
653       if (!NextArgumentOrError(args, &i)) {
654         return false;
655       }
656       std::vector<std::string> branch_sampling_types =
657           android::base::Split(args[i], ",");
658       for (auto& type : branch_sampling_types) {
659         auto it = branch_sampling_type_map.find(type);
660         if (it == branch_sampling_type_map.end()) {
661           LOG(ERROR) << "unrecognized branch sampling filter: " << type;
662           return false;
663         }
664         branch_sampling_ |= it->second;
665       }
666     } else if (args[i] == "-m") {
667       if (!NextArgumentOrError(args, &i)) {
668         return false;
669       }
670       char* endptr;
671       uint64_t pages = strtoull(args[i].c_str(), &endptr, 0);
672       if (*endptr != '\0' || !IsPowerOfTwo(pages)) {
673         LOG(ERROR) << "Invalid mmap_pages: '" << args[i] << "'";
674         return false;
675       }
676       mmap_page_range_.first = mmap_page_range_.second = pages;
677     } else if (args[i] == "--no-dump-kernel-symbols") {
678       can_dump_kernel_symbols_ = false;
679     } else if (args[i] == "--no-dump-symbols") {
680       dump_symbols_ = false;
681     } else if (args[i] == "--no-inherit") {
682       child_inherit_ = false;
683     } else if (args[i] == "--no-unwind") {
684       unwind_dwarf_callchain_ = false;
685     } else if (args[i] == "--no-callchain-joiner") {
686       allow_callchain_joiner_ = false;
687     } else if (args[i] == "--callchain-joiner-min-matching-nodes") {
688       if (!NextArgumentOrError(args, &i)) {
689         return false;
690       }
691       if (!android::base::ParseUint(args[i].c_str(), &callchain_joiner_min_matching_nodes_) ||
692           callchain_joiner_min_matching_nodes_ < 1u) {
693         LOG(ERROR) << "unexpected argument for " << args[i - 1] << " option";
694         return false;
695       }
696     } else if (args[i] == "-o") {
697       if (!NextArgumentOrError(args, &i)) {
698         return false;
699       }
700       record_filename_ = args[i];
701     } else if (args[i] == "-p") {
702       if (!NextArgumentOrError(args, &i)) {
703         return false;
704       }
705       std::set<pid_t> pids;
706       if (!GetValidThreadsFromThreadString(args[i], &pids)) {
707         return false;
708       }
709       event_selection_set_.AddMonitoredProcesses(pids);
710     } else if (args[i] == "--no-post-unwind") {
711       post_unwind_ = false;
712     } else if (args[i] == "--start_profiling_fd") {
713       if (!NextArgumentOrError(args, &i)) {
714         return false;
715       }
716       if (!android::base::ParseInt(args[i].c_str(), &start_profiling_fd_, 0)) {
717         LOG(ERROR) << "Invalid start_profiling_fd: " << args[i];
718         return false;
719       }
720     } else if (args[i] == "--symfs") {
721       if (!NextArgumentOrError(args, &i)) {
722         return false;
723       }
724       if (!Dso::SetSymFsDir(args[i])) {
725         return false;
726       }
727     } else if (args[i] == "-t") {
728       if (!NextArgumentOrError(args, &i)) {
729         return false;
730       }
731       std::set<pid_t> tids;
732       if (!GetValidThreadsFromThreadString(args[i], &tids)) {
733         return false;
734       }
735       event_selection_set_.AddMonitoredThreads(tids);
736     } else if (args[i] == "--trace-offcpu") {
737       trace_offcpu_ = true;
738     } else if (args[i] == "--tracepoint-events") {
739       if (!NextArgumentOrError(args, &i)) {
740         return false;
741       }
742       if (!SetTracepointEventsFilePath(args[i])) {
743         return false;
744       }
745     } else if (args[i] == "--") {
746       i++;
747       break;
748     } else {
749       ReportUnknownOption(args, i);
750       return false;
751     }
752   }
753
754   if (!dwarf_callchain_sampling_) {
755     if (!unwind_dwarf_callchain_) {
756       LOG(ERROR)
757           << "--no-unwind is only used with `--call-graph dwarf` option.";
758       return false;
759     }
760     unwind_dwarf_callchain_ = false;
761   }
762   if (post_unwind_) {
763     if (!dwarf_callchain_sampling_ || !unwind_dwarf_callchain_) {
764       post_unwind_ = false;
765     }
766   } else {
767     if (!dwarf_callchain_sampling_) {
768       LOG(ERROR)
769           << "--no-post-unwind is only used with `--call-graph dwarf` option.";
770       return false;
771     }
772     if (!unwind_dwarf_callchain_) {
773       LOG(ERROR) << "--no-post-unwind can't be used with `--no-unwind` option.";
774       return false;
775     }
776   }
777
778   if (fp_callchain_sampling_) {
779     if (GetBuildArch() == ARCH_ARM) {
780       LOG(WARNING) << "`--callgraph fp` option doesn't work well on arm architecture, "
781                    << "consider using `-g` option or profiling on aarch64 architecture.";
782     }
783   }
784
785   if (system_wide_collection_ && event_selection_set_.HasMonitoredTarget()) {
786     LOG(ERROR) << "Record system wide and existing processes/threads can't be "
787                   "used at the same time.";
788     return false;
789   }
790
791   if (system_wide_collection_ && !IsRoot()) {
792     LOG(ERROR) << "System wide profiling needs root privilege.";
793     return false;
794   }
795
796   if (dump_symbols_ && can_dump_kernel_symbols_) {
797     // No need to dump kernel symbols as we will dump all required symbols.
798     can_dump_kernel_symbols_ = false;
799   }
800
801   non_option_args->clear();
802   for (; i < args.size(); ++i) {
803     non_option_args->push_back(args[i]);
804   }
805
806   SetTempDirectoryUsedInRecording(android::base::Dirname(record_filename_));
807   return true;
808 }
809
810 bool RecordCommand::TraceOffCpu() {
811   if (FindEventTypeByName("sched:sched_switch") == nullptr) {
812     LOG(ERROR) << "Can't trace off cpu because sched:sched_switch event is not available";
813     return false;
814   }
815   for (auto& event_type : event_selection_set_.GetTracepointEvents()) {
816     if (event_type->name == "sched:sched_switch") {
817       LOG(ERROR) << "Trace offcpu can't be used together with sched:sched_switch event";
818       return false;
819     }
820   }
821   if (!IsDumpingRegsForTracepointEventsSupported()) {
822     LOG(ERROR) << "Dumping regs for tracepoint events is not supported by the kernel";
823     return false;
824   }
825   return event_selection_set_.AddEventType("sched:sched_switch");
826 }
827
828 bool RecordCommand::SetEventSelectionFlags() {
829   event_selection_set_.SampleIdAll();
830   if (!event_selection_set_.SetBranchSampling(branch_sampling_)) {
831     return false;
832   }
833   if (fp_callchain_sampling_) {
834     event_selection_set_.EnableFpCallChainSampling();
835   } else if (dwarf_callchain_sampling_) {
836     if (!event_selection_set_.EnableDwarfCallChainSampling(
837             dump_stack_size_in_dwarf_sampling_)) {
838       return false;
839     }
840   }
841   event_selection_set_.SetInherit(child_inherit_);
842   if (clockid_ != "perf") {
843     event_selection_set_.SetClockId(clockid_map[clockid_]);
844   }
845   return true;
846 }
847
848 bool RecordCommand::CreateAndInitRecordFile() {
849   record_file_writer_ = CreateRecordFile(record_filename_);
850   if (record_file_writer_ == nullptr) {
851     return false;
852   }
853   // Use first perf_event_attr and first event id to dump mmap and comm records.
854   EventAttrWithId attr_id = event_selection_set_.GetEventAttrWithId()[0];
855   if (!DumpKernelSymbol()) {
856     return false;
857   }
858   if (!DumpTracingData()) {
859     return false;
860   }
861   if (!DumpKernelAndModuleMmaps(*attr_id.attr, attr_id.ids[0])) {
862     return false;
863   }
864   if (!DumpThreadCommAndMmaps(*attr_id.attr, attr_id.ids[0])) {
865     return false;
866   }
867   return true;
868 }
869
870 std::unique_ptr<RecordFileWriter> RecordCommand::CreateRecordFile(
871     const std::string& filename) {
872   std::unique_ptr<RecordFileWriter> writer =
873       RecordFileWriter::CreateInstance(filename);
874   if (writer == nullptr) {
875     return nullptr;
876   }
877
878   if (!writer->WriteAttrSection(event_selection_set_.GetEventAttrWithId())) {
879     return nullptr;
880   }
881   return writer;
882 }
883
884 bool RecordCommand::DumpKernelSymbol() {
885   if (can_dump_kernel_symbols_) {
886     std::string kallsyms;
887     if (event_selection_set_.NeedKernelSymbol() &&
888         CheckKernelSymbolAddresses()) {
889       if (!android::base::ReadFileToString("/proc/kallsyms", &kallsyms)) {
890         PLOG(ERROR) << "failed to read /proc/kallsyms";
891         return false;
892       }
893       KernelSymbolRecord r(kallsyms);
894       if (!ProcessRecord(&r)) {
895         return false;
896       }
897     }
898   }
899   return true;
900 }
901
902 bool RecordCommand::DumpTracingData() {
903   std::vector<const EventType*> tracepoint_event_types =
904       event_selection_set_.GetTracepointEvents();
905   if (tracepoint_event_types.empty() || !CanRecordRawData()) {
906     return true;  // No need to dump tracing data, or can't do it.
907   }
908   std::vector<char> tracing_data;
909   if (!GetTracingData(tracepoint_event_types, &tracing_data)) {
910     return false;
911   }
912   TracingDataRecord record(tracing_data);
913   if (!ProcessRecord(&record)) {
914     return false;
915   }
916   return true;
917 }
918
919 bool RecordCommand::DumpKernelAndModuleMmaps(const perf_event_attr& attr,
920                                              uint64_t event_id) {
921   KernelMmap kernel_mmap;
922   std::vector<KernelMmap> module_mmaps;
923   GetKernelAndModuleMmaps(&kernel_mmap, &module_mmaps);
924
925   MmapRecord mmap_record(attr, true, UINT_MAX, 0, kernel_mmap.start_addr,
926                          kernel_mmap.len, 0, kernel_mmap.filepath, event_id);
927   if (!ProcessRecord(&mmap_record)) {
928     return false;
929   }
930   for (auto& module_mmap : module_mmaps) {
931     MmapRecord mmap_record(attr, true, UINT_MAX, 0, module_mmap.start_addr,
932                            module_mmap.len, 0, module_mmap.filepath, event_id);
933     if (!ProcessRecord(&mmap_record)) {
934       return false;
935     }
936   }
937   return true;
938 }
939
940 bool RecordCommand::DumpThreadCommAndMmaps(const perf_event_attr& attr,
941                                            uint64_t event_id) {
942   // Decide which processes and threads to dump.
943   // For system_wide profiling, dump all threads.
944   // For non system wide profiling, build dump_threads.
945   bool all_threads = system_wide_collection_;
946   std::set<pid_t> dump_threads = event_selection_set_.GetMonitoredThreads();
947   for (const auto& pid : event_selection_set_.GetMonitoredProcesses()) {
948     std::vector<pid_t> tids = GetThreadsInProcess(pid);
949     dump_threads.insert(tids.begin(), tids.end());
950   }
951
952   // Collect processes to dump.
953   std::vector<pid_t> processes;
954   if (all_threads) {
955     processes = GetAllProcesses();
956   } else {
957     std::set<pid_t> process_set;
958     for (const auto& tid : dump_threads) {
959       pid_t pid;
960       if (!GetProcessForThread(tid, &pid)) {
961         continue;
962       }
963       process_set.insert(pid);
964     }
965     processes.insert(processes.end(), process_set.begin(), process_set.end());
966   }
967
968   // Dump each process and its threads.
969   for (auto& pid : processes) {
970     // Dump mmap records.
971     std::vector<ThreadMmap> thread_mmaps;
972     if (!GetThreadMmapsInProcess(pid, &thread_mmaps)) {
973       // The process may exit before we get its info.
974       continue;
975     }
976     for (const auto& map : thread_mmaps) {
977       if (map.executable == 0) {
978         continue;  // No need to dump non-executable mmap info.
979       }
980       MmapRecord record(attr, false, pid, pid, map.start_addr, map.len,
981                         map.pgoff, map.name, event_id);
982       if (!ProcessRecord(&record)) {
983         return false;
984       }
985     }
986     // Dump process name.
987     std::string name;
988     if (GetThreadName(pid, &name)) {
989       CommRecord record(attr, pid, pid, name, event_id, 0);
990       if (!ProcessRecord(&record)) {
991         return false;
992       }
993     }
994     // Dump thread info.
995     std::vector<pid_t> threads = GetThreadsInProcess(pid);
996     for (const auto& tid : threads) {
997       if (tid == pid) {
998         continue;
999       }
1000       if (all_threads || dump_threads.find(tid) != dump_threads.end()) {
1001         ForkRecord fork_record(attr, pid, tid, pid, pid, event_id);
1002         if (!ProcessRecord(&fork_record)) {
1003           return false;
1004         }
1005         if (GetThreadName(tid, &name)) {
1006           CommRecord comm_record(attr, pid, tid, name, event_id, 0);
1007           if (!ProcessRecord(&comm_record)) {
1008             return false;
1009           }
1010         }
1011       }
1012     }
1013   }
1014   return true;
1015 }
1016
1017 bool RecordCommand::ProcessRecord(Record* record) {
1018   if (unwind_dwarf_callchain_) {
1019     if (post_unwind_) {
1020       return SaveRecordForPostUnwinding(record);
1021     }
1022     return SaveRecordAfterUnwinding(record);
1023   }
1024   return SaveRecordWithoutUnwinding(record);
1025 }
1026
1027 bool RecordCommand::SaveRecordForPostUnwinding(Record* record) {
1028   if (record->type() == PERF_RECORD_SAMPLE) {
1029     static_cast<SampleRecord*>(record)->RemoveInvalidStackData();
1030   }
1031   if (!record_file_writer_->WriteRecord(*record)) {
1032     LOG(ERROR) << "If there isn't enough space for storing profiling data, consider using "
1033                << "--no-post-unwind option.";
1034     return false;
1035   }
1036   return true;
1037 }
1038
1039 bool RecordCommand::SaveRecordAfterUnwinding(Record* record) {
1040   if (record->type() == PERF_RECORD_SAMPLE) {
1041     auto& r = *static_cast<SampleRecord*>(record);
1042     // AdjustCallChainGeneratedByKernel() should go before UnwindRecord(). Because we don't want
1043     // to adjust callchains generated by dwarf unwinder.
1044     r.AdjustCallChainGeneratedByKernel();
1045     if (!UnwindRecord(r)) {
1046       return false;
1047     }
1048     // ExcludeKernelCallChain() should go after UnwindRecord() to notice the generated user call
1049     // chain.
1050     if (r.InKernel() && exclude_kernel_callchain_ && r.ExcludeKernelCallChain() == 0u) {
1051       // If current record contains no user callchain, skip it.
1052       return true;
1053     }
1054     sample_record_count_++;
1055   } else if (record->type() == PERF_RECORD_LOST) {
1056     lost_record_count_ += static_cast<LostRecord*>(record)->lost;
1057   } else {
1058     UpdateRecordForEmbeddedElfPath(record);
1059     thread_tree_.Update(*record);
1060   }
1061   return record_file_writer_->WriteRecord(*record);
1062 }
1063
1064 bool RecordCommand::SaveRecordWithoutUnwinding(Record* record) {
1065   if (record->type() == PERF_RECORD_SAMPLE) {
1066     auto& r = *static_cast<SampleRecord*>(record);
1067     if (fp_callchain_sampling_ || dwarf_callchain_sampling_) {
1068       r.AdjustCallChainGeneratedByKernel();
1069     }
1070     if (r.InKernel() && exclude_kernel_callchain_ && r.ExcludeKernelCallChain() == 0u) {
1071       // If current record contains no user callchain, skip it.
1072       return true;
1073     }
1074     sample_record_count_++;
1075   } else if (record->type() == PERF_RECORD_LOST) {
1076     lost_record_count_ += static_cast<LostRecord*>(record)->lost;
1077   }
1078   return record_file_writer_->WriteRecord(*record);
1079 }
1080
1081 template <class RecordType>
1082 void UpdateMmapRecordForEmbeddedElfPath(RecordType* record) {
1083   RecordType& r = *record;
1084   if (!r.InKernel() && r.data->pgoff != 0) {
1085     // For the case of a shared library "foobar.so" embedded
1086     // inside an APK, we rewrite the original MMAP from
1087     // ["path.apk" offset=X] to ["path.apk!/foobar.so" offset=W]
1088     // so as to make the library name explicit. This update is
1089     // done here (as part of the record operation) as opposed to
1090     // on the host during the report, since we want to report
1091     // the correct library name even if the the APK in question
1092     // is not present on the host. The new offset W is
1093     // calculated to be with respect to the start of foobar.so,
1094     // not to the start of path.apk.
1095     EmbeddedElf* ee =
1096         ApkInspector::FindElfInApkByOffset(r.filename, r.data->pgoff);
1097     if (ee != nullptr) {
1098       // Compute new offset relative to start of elf in APK.
1099       auto data = *r.data;
1100       data.pgoff -= ee->entry_offset();
1101       r.SetDataAndFilename(data, GetUrlInApk(r.filename, ee->entry_name()));
1102     }
1103   }
1104 }
1105
1106 void RecordCommand::UpdateRecordForEmbeddedElfPath(Record* record) {
1107   if (record->type() == PERF_RECORD_MMAP) {
1108     UpdateMmapRecordForEmbeddedElfPath(static_cast<MmapRecord*>(record));
1109   } else if (record->type() == PERF_RECORD_MMAP2) {
1110     UpdateMmapRecordForEmbeddedElfPath(static_cast<Mmap2Record*>(record));
1111   }
1112 }
1113
1114 bool RecordCommand::UnwindRecord(SampleRecord& r) {
1115   if ((r.sample_type & PERF_SAMPLE_CALLCHAIN) &&
1116       (r.sample_type & PERF_SAMPLE_REGS_USER) &&
1117       (r.regs_user_data.reg_mask != 0) &&
1118       (r.sample_type & PERF_SAMPLE_STACK_USER) &&
1119       (r.GetValidStackSize() > 0)) {
1120     ThreadEntry* thread =
1121         thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
1122     RegSet regs(r.regs_user_data.abi, r.regs_user_data.reg_mask, r.regs_user_data.regs);
1123     std::vector<uint64_t> ips;
1124     std::vector<uint64_t> sps;
1125     if (!offline_unwinder_->UnwindCallChain(*thread, regs, r.stack_user_data.data,
1126                                             r.GetValidStackSize(), &ips, &sps)) {
1127       return false;
1128     }
1129     r.ReplaceRegAndStackWithCallChain(ips);
1130     if (callchain_joiner_) {
1131       return callchain_joiner_->AddCallChain(r.tid_data.pid, r.tid_data.tid,
1132                                              CallChainJoiner::ORIGINAL_OFFLINE, ips, sps);
1133     }
1134   }
1135   return true;
1136 }
1137
1138 bool RecordCommand::PostUnwindRecords() {
1139   // 1. Move records from record_filename_ to a temporary file.
1140   if (!record_file_writer_->Close()) {
1141     return false;
1142   }
1143   record_file_writer_.reset();
1144   std::unique_ptr<TemporaryFile> tmpfile = CreateTempFileUsedInRecording();
1145   if (!Workload::RunCmd({"mv", record_filename_, tmpfile->path})) {
1146     return false;
1147   }
1148   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile->path);
1149   if (!reader) {
1150     return false;
1151   }
1152
1153   // 2. Read records from the temporary file, and write unwound records back to record_filename_.
1154   record_file_writer_ = CreateRecordFile(record_filename_);
1155   if (!record_file_writer_) {
1156     return false;
1157   }
1158   sample_record_count_ = 0;
1159   lost_record_count_ = 0;
1160   auto callback = [this](std::unique_ptr<Record> record) {
1161     return SaveRecordAfterUnwinding(record.get());
1162   };
1163   return reader->ReadDataSection(callback, false);
1164 }
1165
1166 bool RecordCommand::JoinCallChains() {
1167   // 1. Prepare joined callchains.
1168   if (!callchain_joiner_->JoinCallChains()) {
1169     return false;
1170   }
1171   // 2. Move records from record_filename_ to a temporary file.
1172   if (!record_file_writer_->Close()) {
1173     return false;
1174   }
1175   record_file_writer_.reset();
1176   std::unique_ptr<TemporaryFile> tmpfile = CreateTempFileUsedInRecording();
1177   if (!Workload::RunCmd({"mv", record_filename_, tmpfile->path})) {
1178     return false;
1179   }
1180
1181   // 3. Read records from the temporary file, and write record with joined call chains back
1182   // to record_filename_.
1183   std::unique_ptr<RecordFileReader> reader = RecordFileReader::CreateInstance(tmpfile->path);
1184   record_file_writer_ = CreateRecordFile(record_filename_);
1185   if (!reader || !record_file_writer_) {
1186     return false;
1187   }
1188
1189   auto record_callback = [&](std::unique_ptr<Record> r) {
1190     if (r->type() != PERF_RECORD_SAMPLE) {
1191       return record_file_writer_->WriteRecord(*r);
1192     }
1193     SampleRecord& sr = *static_cast<SampleRecord*>(r.get());
1194     if (!sr.HasUserCallChain()) {
1195       return record_file_writer_->WriteRecord(sr);
1196     }
1197     pid_t pid;
1198     pid_t tid;
1199     CallChainJoiner::ChainType type;
1200     std::vector<uint64_t> ips;
1201     std::vector<uint64_t> sps;
1202     if (!callchain_joiner_->GetNextCallChain(pid, tid, type, ips, sps)) {
1203       return false;
1204     }
1205     CHECK_EQ(type, CallChainJoiner::JOINED_OFFLINE);
1206     CHECK_EQ(pid, static_cast<pid_t>(sr.tid_data.pid));
1207     CHECK_EQ(tid, static_cast<pid_t>(sr.tid_data.tid));
1208     sr.UpdateUserCallChain(ips);
1209     return record_file_writer_->WriteRecord(sr);
1210   };
1211   return reader->ReadDataSection(record_callback, false);
1212 }
1213
1214 bool RecordCommand::DumpAdditionalFeatures(
1215     const std::vector<std::string>& args) {
1216   // Read data section of perf.data to collect hit file information.
1217   thread_tree_.ClearThreadAndMap();
1218   if (CheckKernelSymbolAddresses()) {
1219     Dso::ReadKernelSymbolsFromProc();
1220   }
1221   auto callback = [&](const Record* r) {
1222     thread_tree_.Update(*r);
1223     if (r->type() == PERF_RECORD_SAMPLE) {
1224       CollectHitFileInfo(*reinterpret_cast<const SampleRecord*>(r));
1225     }
1226   };
1227   if (!record_file_writer_->ReadDataSection(callback)) {
1228     return false;
1229   }
1230
1231   size_t feature_count = 5;
1232   if (branch_sampling_) {
1233     feature_count++;
1234   }
1235   if (dump_symbols_) {
1236     feature_count++;
1237   }
1238   if (!record_file_writer_->BeginWriteFeatures(feature_count)) {
1239     return false;
1240   }
1241   if (!DumpBuildIdFeature()) {
1242     return false;
1243   }
1244   if (dump_symbols_ && !DumpFileFeature()) {
1245     return false;
1246   }
1247   utsname uname_buf;
1248   if (TEMP_FAILURE_RETRY(uname(&uname_buf)) != 0) {
1249     PLOG(ERROR) << "uname() failed";
1250     return false;
1251   }
1252   if (!record_file_writer_->WriteFeatureString(PerfFileFormat::FEAT_OSRELEASE,
1253                                                uname_buf.release)) {
1254     return false;
1255   }
1256   if (!record_file_writer_->WriteFeatureString(PerfFileFormat::FEAT_ARCH,
1257                                                uname_buf.machine)) {
1258     return false;
1259   }
1260
1261   std::string exec_path = android::base::GetExecutablePath();
1262   if (exec_path.empty()) exec_path = "simpleperf";
1263   std::vector<std::string> cmdline;
1264   cmdline.push_back(exec_path);
1265   cmdline.push_back("record");
1266   cmdline.insert(cmdline.end(), args.begin(), args.end());
1267   if (!record_file_writer_->WriteCmdlineFeature(cmdline)) {
1268     return false;
1269   }
1270   if (branch_sampling_ != 0 &&
1271       !record_file_writer_->WriteBranchStackFeature()) {
1272     return false;
1273   }
1274   if (!DumpMetaInfoFeature()) {
1275     return false;
1276   }
1277
1278   if (!record_file_writer_->EndWriteFeatures()) {
1279     return false;
1280   }
1281   return true;
1282 }
1283
1284 bool RecordCommand::DumpBuildIdFeature() {
1285   std::vector<BuildIdRecord> build_id_records;
1286   BuildId build_id;
1287   std::vector<Dso*> dso_v = thread_tree_.GetAllDsos();
1288   for (Dso* dso : dso_v) {
1289     if (!dso->HasDumpId()) {
1290       continue;
1291     }
1292     if (dso->type() == DSO_KERNEL) {
1293       if (!GetKernelBuildId(&build_id)) {
1294         continue;
1295       }
1296       build_id_records.push_back(
1297           BuildIdRecord(true, UINT_MAX, build_id, dso->Path()));
1298     } else if (dso->type() == DSO_KERNEL_MODULE) {
1299       std::string path = dso->Path();
1300       std::string module_name = basename(&path[0]);
1301       if (android::base::EndsWith(module_name, ".ko")) {
1302         module_name = module_name.substr(0, module_name.size() - 3);
1303       }
1304       if (!GetModuleBuildId(module_name, &build_id)) {
1305         LOG(DEBUG) << "can't read build_id for module " << module_name;
1306         continue;
1307       }
1308       build_id_records.push_back(BuildIdRecord(true, UINT_MAX, build_id, path));
1309     } else {
1310       if (dso->Path() == DEFAULT_EXECNAME_FOR_THREAD_MMAP) {
1311         continue;
1312       }
1313       auto tuple = SplitUrlInApk(dso->Path());
1314       if (std::get<0>(tuple)) {
1315         ElfStatus result = GetBuildIdFromApkFile(std::get<1>(tuple),
1316                                                  std::get<2>(tuple), &build_id);
1317         if (result != ElfStatus::NO_ERROR) {
1318           LOG(DEBUG) << "can't read build_id from file " << dso->Path() << ": "
1319                      << result;
1320           continue;
1321         }
1322       } else {
1323         ElfStatus result = GetBuildIdFromElfFile(dso->Path(), &build_id);
1324         if (result != ElfStatus::NO_ERROR) {
1325           LOG(DEBUG) << "can't read build_id from file " << dso->Path() << ": "
1326                      << result;
1327           continue;
1328         }
1329       }
1330       build_id_records.push_back(
1331           BuildIdRecord(false, UINT_MAX, build_id, dso->Path()));
1332     }
1333   }
1334   if (!record_file_writer_->WriteBuildIdFeature(build_id_records)) {
1335     return false;
1336   }
1337   return true;
1338 }
1339
1340 bool RecordCommand::DumpFileFeature() {
1341   std::vector<Dso*> dso_v = thread_tree_.GetAllDsos();
1342   return record_file_writer_->WriteFileFeatures(thread_tree_.GetAllDsos());
1343 }
1344
1345 bool RecordCommand::DumpMetaInfoFeature() {
1346   std::unordered_map<std::string, std::string> info_map;
1347   info_map["simpleperf_version"] = GetSimpleperfVersion();
1348   info_map["system_wide_collection"] = system_wide_collection_ ? "true" : "false";
1349   info_map["trace_offcpu"] = trace_offcpu_ ? "true" : "false";
1350   // By storing event types information in perf.data, the readers of perf.data have the same
1351   // understanding of event types, even if they are on another machine.
1352   info_map["event_type_info"] = ScopedEventTypes::BuildString(event_selection_set_.GetEvents());
1353 #if defined(__ANDROID__)
1354   info_map["product_props"] = android::base::StringPrintf("%s:%s:%s",
1355                                   android::base::GetProperty("ro.product.manufacturer", "").c_str(),
1356                                   android::base::GetProperty("ro.product.model", "").c_str(),
1357                                   android::base::GetProperty("ro.product.name", "").c_str());
1358   info_map["android_version"] = android::base::GetProperty("ro.build.version.release", "");
1359 #endif
1360   info_map["clockid"] = clockid_;
1361   info_map["timestamp"] = std::to_string(time(nullptr));
1362   return record_file_writer_->WriteMetaInfoFeature(info_map);
1363 }
1364
1365 void RecordCommand::CollectHitFileInfo(const SampleRecord& r) {
1366   const ThreadEntry* thread =
1367       thread_tree_.FindThreadOrNew(r.tid_data.pid, r.tid_data.tid);
1368   const MapEntry* map =
1369       thread_tree_.FindMap(thread, r.ip_data.ip, r.InKernel());
1370   Dso* dso = map->dso;
1371   const Symbol* symbol;
1372   if (dump_symbols_) {
1373     symbol = thread_tree_.FindSymbol(map, r.ip_data.ip, nullptr, &dso);
1374     if (!symbol->HasDumpId()) {
1375       dso->CreateSymbolDumpId(symbol);
1376     }
1377   }
1378   if (!dso->HasDumpId()) {
1379     dso->CreateDumpId();
1380   }
1381   if (r.sample_type & PERF_SAMPLE_CALLCHAIN) {
1382     bool in_kernel = r.InKernel();
1383     bool first_ip = true;
1384     for (uint64_t i = 0; i < r.callchain_data.ip_nr; ++i) {
1385       uint64_t ip = r.callchain_data.ips[i];
1386       if (ip >= PERF_CONTEXT_MAX) {
1387         switch (ip) {
1388           case PERF_CONTEXT_KERNEL:
1389             in_kernel = true;
1390             break;
1391           case PERF_CONTEXT_USER:
1392             in_kernel = false;
1393             break;
1394           default:
1395             LOG(DEBUG) << "Unexpected perf_context in callchain: " << std::hex
1396                        << ip;
1397         }
1398       } else {
1399         if (first_ip) {
1400           first_ip = false;
1401           // Remove duplication with sample ip.
1402           if (ip == r.ip_data.ip) {
1403             continue;
1404           }
1405         }
1406         map = thread_tree_.FindMap(thread, ip, in_kernel);
1407         dso = map->dso;
1408         if (dump_symbols_) {
1409           symbol = thread_tree_.FindSymbol(map, ip, nullptr, &dso);
1410           if (!symbol->HasDumpId()) {
1411             dso->CreateSymbolDumpId(symbol);
1412           }
1413         }
1414         if (!dso->HasDumpId()) {
1415           dso->CreateDumpId();
1416         }
1417       }
1418     }
1419   }
1420 }
1421
1422 void RegisterRecordCommand() {
1423   RegisterCommand("record",
1424                   [] { return std::unique_ptr<Command>(new RecordCommand()); });
1425 }