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