xref: /aosp_15_r20/system/extras/simpleperf/cmd_kmem.cpp (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker /*
2*288bf522SAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*288bf522SAndroid Build Coastguard Worker  *
4*288bf522SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*288bf522SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*288bf522SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*288bf522SAndroid Build Coastguard Worker  *
8*288bf522SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*288bf522SAndroid Build Coastguard Worker  *
10*288bf522SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*288bf522SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*288bf522SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*288bf522SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*288bf522SAndroid Build Coastguard Worker  * limitations under the License.
15*288bf522SAndroid Build Coastguard Worker  */
16*288bf522SAndroid Build Coastguard Worker 
17*288bf522SAndroid Build Coastguard Worker #include "command.h"
18*288bf522SAndroid Build Coastguard Worker 
19*288bf522SAndroid Build Coastguard Worker #include <unordered_map>
20*288bf522SAndroid Build Coastguard Worker 
21*288bf522SAndroid Build Coastguard Worker #include <android-base/logging.h>
22*288bf522SAndroid Build Coastguard Worker #include <android-base/strings.h>
23*288bf522SAndroid Build Coastguard Worker 
24*288bf522SAndroid Build Coastguard Worker #include "callchain.h"
25*288bf522SAndroid Build Coastguard Worker #include "event_attr.h"
26*288bf522SAndroid Build Coastguard Worker #include "event_type.h"
27*288bf522SAndroid Build Coastguard Worker #include "record_file.h"
28*288bf522SAndroid Build Coastguard Worker #include "sample_tree.h"
29*288bf522SAndroid Build Coastguard Worker #include "tracing.h"
30*288bf522SAndroid Build Coastguard Worker #include "utils.h"
31*288bf522SAndroid Build Coastguard Worker 
32*288bf522SAndroid Build Coastguard Worker namespace simpleperf {
33*288bf522SAndroid Build Coastguard Worker namespace {
34*288bf522SAndroid Build Coastguard Worker 
35*288bf522SAndroid Build Coastguard Worker struct SlabSample {
36*288bf522SAndroid Build Coastguard Worker   const Symbol* symbol;                 // the function making allocation
37*288bf522SAndroid Build Coastguard Worker   uint64_t ptr;                         // the start address of the allocated space
38*288bf522SAndroid Build Coastguard Worker   uint64_t bytes_req;                   // requested space size
39*288bf522SAndroid Build Coastguard Worker   uint64_t bytes_alloc;                 // allocated space size
40*288bf522SAndroid Build Coastguard Worker   uint64_t sample_count;                // count of allocations
41*288bf522SAndroid Build Coastguard Worker   uint64_t gfp_flags;                   // flags used for allocation
42*288bf522SAndroid Build Coastguard Worker   uint64_t cross_cpu_allocations;       // count of allocations freed not on the
43*288bf522SAndroid Build Coastguard Worker                                         // cpu allocating them
44*288bf522SAndroid Build Coastguard Worker   CallChainRoot<SlabSample> callchain;  // a callchain tree representing all
45*288bf522SAndroid Build Coastguard Worker                                         // callchains in this sample
SlabSamplesimpleperf::__anon37f433630111::SlabSample46*288bf522SAndroid Build Coastguard Worker   SlabSample(const Symbol* symbol, uint64_t ptr, uint64_t bytes_req, uint64_t bytes_alloc,
47*288bf522SAndroid Build Coastguard Worker              uint64_t sample_count, uint64_t gfp_flags, uint64_t cross_cpu_allocations)
48*288bf522SAndroid Build Coastguard Worker       : symbol(symbol),
49*288bf522SAndroid Build Coastguard Worker         ptr(ptr),
50*288bf522SAndroid Build Coastguard Worker         bytes_req(bytes_req),
51*288bf522SAndroid Build Coastguard Worker         bytes_alloc(bytes_alloc),
52*288bf522SAndroid Build Coastguard Worker         sample_count(sample_count),
53*288bf522SAndroid Build Coastguard Worker         gfp_flags(gfp_flags),
54*288bf522SAndroid Build Coastguard Worker         cross_cpu_allocations(cross_cpu_allocations) {}
55*288bf522SAndroid Build Coastguard Worker 
GetPeriodsimpleperf::__anon37f433630111::SlabSample56*288bf522SAndroid Build Coastguard Worker   uint64_t GetPeriod() const { return sample_count; }
57*288bf522SAndroid Build Coastguard Worker };
58*288bf522SAndroid Build Coastguard Worker 
59*288bf522SAndroid Build Coastguard Worker struct SlabAccumulateInfo {
60*288bf522SAndroid Build Coastguard Worker   uint64_t bytes_req;
61*288bf522SAndroid Build Coastguard Worker   uint64_t bytes_alloc;
62*288bf522SAndroid Build Coastguard Worker };
63*288bf522SAndroid Build Coastguard Worker 
64*288bf522SAndroid Build Coastguard Worker BUILD_COMPARE_VALUE_FUNCTION(ComparePtr, ptr);
65*288bf522SAndroid Build Coastguard Worker BUILD_COMPARE_VALUE_FUNCTION_REVERSE(CompareBytesReq, bytes_req);
66*288bf522SAndroid Build Coastguard Worker BUILD_COMPARE_VALUE_FUNCTION_REVERSE(CompareBytesAlloc, bytes_alloc);
67*288bf522SAndroid Build Coastguard Worker BUILD_COMPARE_VALUE_FUNCTION(CompareGfpFlags, gfp_flags);
68*288bf522SAndroid Build Coastguard Worker BUILD_COMPARE_VALUE_FUNCTION_REVERSE(CompareCrossCpuAllocations, cross_cpu_allocations);
69*288bf522SAndroid Build Coastguard Worker 
70*288bf522SAndroid Build Coastguard Worker BUILD_DISPLAY_HEX64_FUNCTION(DisplayPtr, ptr);
71*288bf522SAndroid Build Coastguard Worker BUILD_DISPLAY_UINT64_FUNCTION(DisplayBytesReq, bytes_req);
72*288bf522SAndroid Build Coastguard Worker BUILD_DISPLAY_UINT64_FUNCTION(DisplayBytesAlloc, bytes_alloc);
73*288bf522SAndroid Build Coastguard Worker BUILD_DISPLAY_HEX64_FUNCTION(DisplayGfpFlags, gfp_flags);
74*288bf522SAndroid Build Coastguard Worker BUILD_DISPLAY_UINT64_FUNCTION(DisplayCrossCpuAllocations, cross_cpu_allocations);
75*288bf522SAndroid Build Coastguard Worker 
CompareFragment(const SlabSample * sample1,const SlabSample * sample2)76*288bf522SAndroid Build Coastguard Worker static int CompareFragment(const SlabSample* sample1, const SlabSample* sample2) {
77*288bf522SAndroid Build Coastguard Worker   uint64_t frag1 = sample1->bytes_alloc - sample1->bytes_req;
78*288bf522SAndroid Build Coastguard Worker   uint64_t frag2 = sample2->bytes_alloc - sample2->bytes_req;
79*288bf522SAndroid Build Coastguard Worker   return Compare(frag2, frag1);
80*288bf522SAndroid Build Coastguard Worker }
81*288bf522SAndroid Build Coastguard Worker 
DisplayFragment(const SlabSample * sample)82*288bf522SAndroid Build Coastguard Worker static std::string DisplayFragment(const SlabSample* sample) {
83*288bf522SAndroid Build Coastguard Worker   return android::base::StringPrintf("%" PRIu64, sample->bytes_alloc - sample->bytes_req);
84*288bf522SAndroid Build Coastguard Worker }
85*288bf522SAndroid Build Coastguard Worker 
86*288bf522SAndroid Build Coastguard Worker struct SlabSampleTree {
87*288bf522SAndroid Build Coastguard Worker   std::vector<SlabSample*> samples;
88*288bf522SAndroid Build Coastguard Worker   uint64_t total_requested_bytes;
89*288bf522SAndroid Build Coastguard Worker   uint64_t total_allocated_bytes;
90*288bf522SAndroid Build Coastguard Worker   uint64_t nr_allocations;
91*288bf522SAndroid Build Coastguard Worker   uint64_t nr_frees;
92*288bf522SAndroid Build Coastguard Worker   uint64_t nr_cross_cpu_allocations;
93*288bf522SAndroid Build Coastguard Worker };
94*288bf522SAndroid Build Coastguard Worker 
95*288bf522SAndroid Build Coastguard Worker struct SlabFormat {
96*288bf522SAndroid Build Coastguard Worker   enum {
97*288bf522SAndroid Build Coastguard Worker     KMEM_ALLOC,
98*288bf522SAndroid Build Coastguard Worker     KMEM_FREE,
99*288bf522SAndroid Build Coastguard Worker   } type;
100*288bf522SAndroid Build Coastguard Worker   TracingFieldPlace call_site;
101*288bf522SAndroid Build Coastguard Worker   TracingFieldPlace ptr;
102*288bf522SAndroid Build Coastguard Worker   TracingFieldPlace bytes_req;
103*288bf522SAndroid Build Coastguard Worker   TracingFieldPlace bytes_alloc;
104*288bf522SAndroid Build Coastguard Worker   TracingFieldPlace gfp_flags;
105*288bf522SAndroid Build Coastguard Worker };
106*288bf522SAndroid Build Coastguard Worker 
107*288bf522SAndroid Build Coastguard Worker class SlabSampleTreeBuilder : public SampleTreeBuilder<SlabSample, SlabAccumulateInfo> {
108*288bf522SAndroid Build Coastguard Worker  public:
SlabSampleTreeBuilder(const SampleComparator<SlabSample> & sample_comparator,ThreadTree * thread_tree)109*288bf522SAndroid Build Coastguard Worker   SlabSampleTreeBuilder(const SampleComparator<SlabSample>& sample_comparator,
110*288bf522SAndroid Build Coastguard Worker                         ThreadTree* thread_tree)
111*288bf522SAndroid Build Coastguard Worker       : SampleTreeBuilder(sample_comparator),
112*288bf522SAndroid Build Coastguard Worker         thread_tree_(thread_tree),
113*288bf522SAndroid Build Coastguard Worker         total_requested_bytes_(0),
114*288bf522SAndroid Build Coastguard Worker         total_allocated_bytes_(0),
115*288bf522SAndroid Build Coastguard Worker         nr_allocations_(0),
116*288bf522SAndroid Build Coastguard Worker         nr_cross_cpu_allocations_(0) {}
117*288bf522SAndroid Build Coastguard Worker 
GetSampleTree() const118*288bf522SAndroid Build Coastguard Worker   SlabSampleTree GetSampleTree() const {
119*288bf522SAndroid Build Coastguard Worker     SlabSampleTree sample_tree;
120*288bf522SAndroid Build Coastguard Worker     sample_tree.samples = GetSamples();
121*288bf522SAndroid Build Coastguard Worker     sample_tree.total_requested_bytes = total_requested_bytes_;
122*288bf522SAndroid Build Coastguard Worker     sample_tree.total_allocated_bytes = total_allocated_bytes_;
123*288bf522SAndroid Build Coastguard Worker     sample_tree.nr_allocations = nr_allocations_;
124*288bf522SAndroid Build Coastguard Worker     sample_tree.nr_frees = nr_frees_;
125*288bf522SAndroid Build Coastguard Worker     sample_tree.nr_cross_cpu_allocations = nr_cross_cpu_allocations_;
126*288bf522SAndroid Build Coastguard Worker     return sample_tree;
127*288bf522SAndroid Build Coastguard Worker   }
128*288bf522SAndroid Build Coastguard Worker 
AddSlabFormat(const std::vector<uint64_t> & event_ids,SlabFormat format)129*288bf522SAndroid Build Coastguard Worker   void AddSlabFormat(const std::vector<uint64_t>& event_ids, SlabFormat format) {
130*288bf522SAndroid Build Coastguard Worker     std::unique_ptr<SlabFormat> p(new SlabFormat(format));
131*288bf522SAndroid Build Coastguard Worker     for (auto id : event_ids) {
132*288bf522SAndroid Build Coastguard Worker       event_id_to_format_map_[id] = p.get();
133*288bf522SAndroid Build Coastguard Worker     }
134*288bf522SAndroid Build Coastguard Worker     formats_.push_back(std::move(p));
135*288bf522SAndroid Build Coastguard Worker   }
136*288bf522SAndroid Build Coastguard Worker 
137*288bf522SAndroid Build Coastguard Worker  protected:
CreateSample(const SampleRecord & r,bool in_kernel,SlabAccumulateInfo * acc_info)138*288bf522SAndroid Build Coastguard Worker   SlabSample* CreateSample(const SampleRecord& r, bool in_kernel,
139*288bf522SAndroid Build Coastguard Worker                            SlabAccumulateInfo* acc_info) override {
140*288bf522SAndroid Build Coastguard Worker     if (!in_kernel) {
141*288bf522SAndroid Build Coastguard Worker       // Normally we don't parse records in user space because tracepoint
142*288bf522SAndroid Build Coastguard Worker       // events all happen in kernel. But if r.ip_data.ip == 0, it may be
143*288bf522SAndroid Build Coastguard Worker       // a kernel record failed to dump ip register and is still useful.
144*288bf522SAndroid Build Coastguard Worker       if (r.ip_data.ip == 0) {
145*288bf522SAndroid Build Coastguard Worker         // It seems we are on a kernel can't dump regset for tracepoint events
146*288bf522SAndroid Build Coastguard Worker         // because of lacking perf_arch_fetch_caller_regs(). We can't get
147*288bf522SAndroid Build Coastguard Worker         // callchain, but we can still do a normal report.
148*288bf522SAndroid Build Coastguard Worker         static bool first = true;
149*288bf522SAndroid Build Coastguard Worker         if (first) {
150*288bf522SAndroid Build Coastguard Worker           first = false;
151*288bf522SAndroid Build Coastguard Worker           if (accumulate_callchain_) {
152*288bf522SAndroid Build Coastguard Worker             // The kernel doesn't seem to support dumping registers for
153*288bf522SAndroid Build Coastguard Worker             // tracepoint events because of lacking
154*288bf522SAndroid Build Coastguard Worker             // perf_arch_fetch_caller_regs().
155*288bf522SAndroid Build Coastguard Worker             LOG(WARNING) << "simpleperf may not get callchains for tracepoint"
156*288bf522SAndroid Build Coastguard Worker                          << " events because of lacking kernel support.";
157*288bf522SAndroid Build Coastguard Worker           }
158*288bf522SAndroid Build Coastguard Worker         }
159*288bf522SAndroid Build Coastguard Worker       } else {
160*288bf522SAndroid Build Coastguard Worker         return nullptr;
161*288bf522SAndroid Build Coastguard Worker       }
162*288bf522SAndroid Build Coastguard Worker     }
163*288bf522SAndroid Build Coastguard Worker     uint64_t id = r.id_data.id;
164*288bf522SAndroid Build Coastguard Worker     auto it = event_id_to_format_map_.find(id);
165*288bf522SAndroid Build Coastguard Worker     if (it == event_id_to_format_map_.end()) {
166*288bf522SAndroid Build Coastguard Worker       return nullptr;
167*288bf522SAndroid Build Coastguard Worker     }
168*288bf522SAndroid Build Coastguard Worker     const char* raw_data = r.raw_data.data;
169*288bf522SAndroid Build Coastguard Worker     SlabFormat* format = it->second;
170*288bf522SAndroid Build Coastguard Worker     if (format->type == SlabFormat::KMEM_ALLOC) {
171*288bf522SAndroid Build Coastguard Worker       uint64_t call_site = format->call_site.ReadFromData(raw_data);
172*288bf522SAndroid Build Coastguard Worker       const Symbol* symbol = thread_tree_->FindKernelSymbol(call_site);
173*288bf522SAndroid Build Coastguard Worker       uint64_t ptr = format->ptr.ReadFromData(raw_data);
174*288bf522SAndroid Build Coastguard Worker       uint64_t bytes_req = format->bytes_req.ReadFromData(raw_data);
175*288bf522SAndroid Build Coastguard Worker       uint64_t bytes_alloc = format->bytes_alloc.ReadFromData(raw_data);
176*288bf522SAndroid Build Coastguard Worker       uint64_t gfp_flags = format->gfp_flags.ReadFromData(raw_data);
177*288bf522SAndroid Build Coastguard Worker       SlabSample* sample = InsertSample(std::unique_ptr<SlabSample>(
178*288bf522SAndroid Build Coastguard Worker           new SlabSample(symbol, ptr, bytes_req, bytes_alloc, 1, gfp_flags, 0)));
179*288bf522SAndroid Build Coastguard Worker       alloc_cpu_record_map_.insert(std::make_pair(ptr, std::make_pair(r.cpu_data.cpu, sample)));
180*288bf522SAndroid Build Coastguard Worker       acc_info->bytes_req = bytes_req;
181*288bf522SAndroid Build Coastguard Worker       acc_info->bytes_alloc = bytes_alloc;
182*288bf522SAndroid Build Coastguard Worker       return sample;
183*288bf522SAndroid Build Coastguard Worker     } else if (format->type == SlabFormat::KMEM_FREE) {
184*288bf522SAndroid Build Coastguard Worker       uint64_t ptr = format->ptr.ReadFromData(raw_data);
185*288bf522SAndroid Build Coastguard Worker       auto it = alloc_cpu_record_map_.find(ptr);
186*288bf522SAndroid Build Coastguard Worker       if (it != alloc_cpu_record_map_.end()) {
187*288bf522SAndroid Build Coastguard Worker         SlabSample* sample = it->second.second;
188*288bf522SAndroid Build Coastguard Worker         if (r.cpu_data.cpu != it->second.first) {
189*288bf522SAndroid Build Coastguard Worker           sample->cross_cpu_allocations++;
190*288bf522SAndroid Build Coastguard Worker           nr_cross_cpu_allocations_++;
191*288bf522SAndroid Build Coastguard Worker         }
192*288bf522SAndroid Build Coastguard Worker         alloc_cpu_record_map_.erase(it);
193*288bf522SAndroid Build Coastguard Worker       }
194*288bf522SAndroid Build Coastguard Worker       nr_frees_++;
195*288bf522SAndroid Build Coastguard Worker     }
196*288bf522SAndroid Build Coastguard Worker     return nullptr;
197*288bf522SAndroid Build Coastguard Worker   }
198*288bf522SAndroid Build Coastguard Worker 
CreateBranchSample(const SampleRecord &,const BranchStackItemType &)199*288bf522SAndroid Build Coastguard Worker   SlabSample* CreateBranchSample(const SampleRecord&, const BranchStackItemType&) override {
200*288bf522SAndroid Build Coastguard Worker     return nullptr;
201*288bf522SAndroid Build Coastguard Worker   }
202*288bf522SAndroid Build Coastguard Worker 
CreateCallChainSample(const ThreadEntry *,const SlabSample * sample,uint64_t ip,bool in_kernel,const std::vector<SlabSample * > & callchain,const SlabAccumulateInfo & acc_info)203*288bf522SAndroid Build Coastguard Worker   SlabSample* CreateCallChainSample(const ThreadEntry*, const SlabSample* sample, uint64_t ip,
204*288bf522SAndroid Build Coastguard Worker                                     bool in_kernel, const std::vector<SlabSample*>& callchain,
205*288bf522SAndroid Build Coastguard Worker                                     const SlabAccumulateInfo& acc_info) override {
206*288bf522SAndroid Build Coastguard Worker     if (!in_kernel) {
207*288bf522SAndroid Build Coastguard Worker       return nullptr;
208*288bf522SAndroid Build Coastguard Worker     }
209*288bf522SAndroid Build Coastguard Worker     const Symbol* symbol = thread_tree_->FindKernelSymbol(ip);
210*288bf522SAndroid Build Coastguard Worker     return InsertCallChainSample(
211*288bf522SAndroid Build Coastguard Worker         std::unique_ptr<SlabSample>(new SlabSample(symbol, sample->ptr, acc_info.bytes_req,
212*288bf522SAndroid Build Coastguard Worker                                                    acc_info.bytes_alloc, 1, sample->gfp_flags, 0)),
213*288bf522SAndroid Build Coastguard Worker         callchain);
214*288bf522SAndroid Build Coastguard Worker   }
215*288bf522SAndroid Build Coastguard Worker 
GetThreadOfSample(SlabSample *)216*288bf522SAndroid Build Coastguard Worker   const ThreadEntry* GetThreadOfSample(SlabSample*) override { return nullptr; }
217*288bf522SAndroid Build Coastguard Worker 
GetPeriodForCallChain(const SlabAccumulateInfo &)218*288bf522SAndroid Build Coastguard Worker   uint64_t GetPeriodForCallChain(const SlabAccumulateInfo&) override {
219*288bf522SAndroid Build Coastguard Worker     // Decide the percentage of callchain by the sample_count, so use 1 as the
220*288bf522SAndroid Build Coastguard Worker     // period when calling AddCallChain().
221*288bf522SAndroid Build Coastguard Worker     return 1;
222*288bf522SAndroid Build Coastguard Worker   }
223*288bf522SAndroid Build Coastguard Worker 
UpdateSummary(const SlabSample * sample)224*288bf522SAndroid Build Coastguard Worker   void UpdateSummary(const SlabSample* sample) override {
225*288bf522SAndroid Build Coastguard Worker     total_requested_bytes_ += sample->bytes_req;
226*288bf522SAndroid Build Coastguard Worker     total_allocated_bytes_ += sample->bytes_alloc;
227*288bf522SAndroid Build Coastguard Worker     nr_allocations_++;
228*288bf522SAndroid Build Coastguard Worker   }
229*288bf522SAndroid Build Coastguard Worker 
MergeSample(SlabSample * sample1,SlabSample * sample2)230*288bf522SAndroid Build Coastguard Worker   void MergeSample(SlabSample* sample1, SlabSample* sample2) override {
231*288bf522SAndroid Build Coastguard Worker     sample1->bytes_req += sample2->bytes_req;
232*288bf522SAndroid Build Coastguard Worker     sample1->bytes_alloc += sample2->bytes_alloc;
233*288bf522SAndroid Build Coastguard Worker     sample1->sample_count += sample2->sample_count;
234*288bf522SAndroid Build Coastguard Worker   }
235*288bf522SAndroid Build Coastguard Worker 
236*288bf522SAndroid Build Coastguard Worker  private:
237*288bf522SAndroid Build Coastguard Worker   ThreadTree* thread_tree_;
238*288bf522SAndroid Build Coastguard Worker   uint64_t total_requested_bytes_;
239*288bf522SAndroid Build Coastguard Worker   uint64_t total_allocated_bytes_;
240*288bf522SAndroid Build Coastguard Worker   uint64_t nr_allocations_;
241*288bf522SAndroid Build Coastguard Worker   uint64_t nr_frees_;
242*288bf522SAndroid Build Coastguard Worker   uint64_t nr_cross_cpu_allocations_;
243*288bf522SAndroid Build Coastguard Worker 
244*288bf522SAndroid Build Coastguard Worker   std::unordered_map<uint64_t, SlabFormat*> event_id_to_format_map_;
245*288bf522SAndroid Build Coastguard Worker   std::vector<std::unique_ptr<SlabFormat>> formats_;
246*288bf522SAndroid Build Coastguard Worker   std::unordered_map<uint64_t, std::pair<uint32_t, SlabSample*>> alloc_cpu_record_map_;
247*288bf522SAndroid Build Coastguard Worker };
248*288bf522SAndroid Build Coastguard Worker 
249*288bf522SAndroid Build Coastguard Worker using SlabSampleTreeSorter = SampleTreeSorter<SlabSample>;
250*288bf522SAndroid Build Coastguard Worker using SlabSampleTreeDisplayer = SampleTreeDisplayer<SlabSample, SlabSampleTree>;
251*288bf522SAndroid Build Coastguard Worker using SlabSampleCallgraphDisplayer = CallgraphDisplayer<SlabSample, CallChainNode<SlabSample>>;
252*288bf522SAndroid Build Coastguard Worker 
253*288bf522SAndroid Build Coastguard Worker struct EventAttrWithName {
254*288bf522SAndroid Build Coastguard Worker   perf_event_attr attr;
255*288bf522SAndroid Build Coastguard Worker   std::string name;
256*288bf522SAndroid Build Coastguard Worker   std::vector<uint64_t> event_ids;
257*288bf522SAndroid Build Coastguard Worker };
258*288bf522SAndroid Build Coastguard Worker 
259*288bf522SAndroid Build Coastguard Worker class KmemCommand : public Command {
260*288bf522SAndroid Build Coastguard Worker  public:
KmemCommand()261*288bf522SAndroid Build Coastguard Worker   KmemCommand()
262*288bf522SAndroid Build Coastguard Worker       : Command("kmem", "collect kernel memory allocation information",
263*288bf522SAndroid Build Coastguard Worker                 // clang-format off
264*288bf522SAndroid Build Coastguard Worker "Usage: kmem (record [record options] | report [report options])\n"
265*288bf522SAndroid Build Coastguard Worker "kmem record\n"
266*288bf522SAndroid Build Coastguard Worker "-g        Enable call graph recording. Same as '--call-graph fp'.\n"
267*288bf522SAndroid Build Coastguard Worker "--slab    Collect slab allocation information. Default option.\n"
268*288bf522SAndroid Build Coastguard Worker "Other record options provided by simpleperf record command are also available.\n"
269*288bf522SAndroid Build Coastguard Worker "kmem report\n"
270*288bf522SAndroid Build Coastguard Worker "--children  Print the accumulated allocation info appeared in the callchain.\n"
271*288bf522SAndroid Build Coastguard Worker "            Can be used on perf.data recorded with `--call-graph fp` option.\n"
272*288bf522SAndroid Build Coastguard Worker "-g [callee|caller]  Print call graph for perf.data recorded with\n"
273*288bf522SAndroid Build Coastguard Worker "                    `--call-graph fp` option. If callee mode is used, the graph\n"
274*288bf522SAndroid Build Coastguard Worker "                     shows how functions are called from others. Otherwise, the\n"
275*288bf522SAndroid Build Coastguard Worker "                     graph shows how functions call others. Default is callee\n"
276*288bf522SAndroid Build Coastguard Worker "                     mode. The percentage shown in the graph is determined by\n"
277*288bf522SAndroid Build Coastguard Worker "                     the hit count of the callchain.\n"
278*288bf522SAndroid Build Coastguard Worker "-i          Specify path of record file, default is perf.data\n"
279*288bf522SAndroid Build Coastguard Worker "-o report_file_name  Set report file name, default is stdout.\n"
280*288bf522SAndroid Build Coastguard Worker "--slab      Report slab allocation information. Default option.\n"
281*288bf522SAndroid Build Coastguard Worker "--slab-sort key1,key2,...\n"
282*288bf522SAndroid Build Coastguard Worker "            Select the keys to sort and print slab allocation information.\n"
283*288bf522SAndroid Build Coastguard Worker "            Should be used with --slab option. Possible keys include:\n"
284*288bf522SAndroid Build Coastguard Worker "              hit         -- the allocation count.\n"
285*288bf522SAndroid Build Coastguard Worker "              caller      -- the function calling allocation.\n"
286*288bf522SAndroid Build Coastguard Worker "              ptr         -- the address of the allocated space.\n"
287*288bf522SAndroid Build Coastguard Worker "              bytes_req   -- the total requested space size.\n"
288*288bf522SAndroid Build Coastguard Worker "              bytes_alloc -- the total allocated space size.\n"
289*288bf522SAndroid Build Coastguard Worker "              fragment    -- the extra allocated space size\n"
290*288bf522SAndroid Build Coastguard Worker "                             (bytes_alloc - bytes_req).\n"
291*288bf522SAndroid Build Coastguard Worker "              gfp_flags   -- the flags used for allocation.\n"
292*288bf522SAndroid Build Coastguard Worker "              pingpong    -- the count of allocations that are freed not on\n"
293*288bf522SAndroid Build Coastguard Worker "                             the cpu allocating them.\n"
294*288bf522SAndroid Build Coastguard Worker "            The default slab sort keys are:\n"
295*288bf522SAndroid Build Coastguard Worker "              hit,caller,bytes_req,bytes_alloc,fragment,pingpong.\n"
296*288bf522SAndroid Build Coastguard Worker                 // clang-format on
297*288bf522SAndroid Build Coastguard Worker                 ),
298*288bf522SAndroid Build Coastguard Worker         is_record_(false),
299*288bf522SAndroid Build Coastguard Worker         use_slab_(false),
300*288bf522SAndroid Build Coastguard Worker         accumulate_callchain_(false),
301*288bf522SAndroid Build Coastguard Worker         print_callgraph_(false),
302*288bf522SAndroid Build Coastguard Worker         callgraph_show_callee_(false),
303*288bf522SAndroid Build Coastguard Worker         record_filename_("perf.data"),
304*288bf522SAndroid Build Coastguard Worker         record_file_arch_(GetTargetArch()) {}
305*288bf522SAndroid Build Coastguard Worker 
306*288bf522SAndroid Build Coastguard Worker   bool Run(const std::vector<std::string>& args);
307*288bf522SAndroid Build Coastguard Worker 
308*288bf522SAndroid Build Coastguard Worker  private:
309*288bf522SAndroid Build Coastguard Worker   bool ParseOptions(const std::vector<std::string>& args, std::vector<std::string>* left_args);
310*288bf522SAndroid Build Coastguard Worker   bool RecordKmemInfo(const std::vector<std::string>& record_args);
311*288bf522SAndroid Build Coastguard Worker   bool ReportKmemInfo();
312*288bf522SAndroid Build Coastguard Worker   bool PrepareToBuildSampleTree();
313*288bf522SAndroid Build Coastguard Worker   void ReadEventAttrsFromRecordFile();
314*288bf522SAndroid Build Coastguard Worker   bool ReadFeaturesFromRecordFile();
315*288bf522SAndroid Build Coastguard Worker   bool ReadSampleTreeFromRecordFile();
316*288bf522SAndroid Build Coastguard Worker   bool ProcessRecord(std::unique_ptr<Record> record);
317*288bf522SAndroid Build Coastguard Worker   bool ProcessTracingData(const std::vector<char>& data);
318*288bf522SAndroid Build Coastguard Worker   bool PrintReport();
319*288bf522SAndroid Build Coastguard Worker   void PrintReportContext(FILE* fp);
320*288bf522SAndroid Build Coastguard Worker   void PrintSlabReportContext(FILE* fp);
321*288bf522SAndroid Build Coastguard Worker 
322*288bf522SAndroid Build Coastguard Worker   bool is_record_;
323*288bf522SAndroid Build Coastguard Worker   bool use_slab_;
324*288bf522SAndroid Build Coastguard Worker   std::vector<std::string> slab_sort_keys_;
325*288bf522SAndroid Build Coastguard Worker   bool accumulate_callchain_;
326*288bf522SAndroid Build Coastguard Worker   bool print_callgraph_;
327*288bf522SAndroid Build Coastguard Worker   bool callgraph_show_callee_;
328*288bf522SAndroid Build Coastguard Worker 
329*288bf522SAndroid Build Coastguard Worker   std::string record_filename_;
330*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<RecordFileReader> record_file_reader_;
331*288bf522SAndroid Build Coastguard Worker   std::vector<EventAttrWithName> event_attrs_;
332*288bf522SAndroid Build Coastguard Worker   std::string record_cmdline_;
333*288bf522SAndroid Build Coastguard Worker   ArchType record_file_arch_;
334*288bf522SAndroid Build Coastguard Worker 
335*288bf522SAndroid Build Coastguard Worker   ThreadTree thread_tree_;
336*288bf522SAndroid Build Coastguard Worker   SlabSampleTree slab_sample_tree_;
337*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<SlabSampleTreeBuilder> slab_sample_tree_builder_;
338*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<SlabSampleTreeSorter> slab_sample_tree_sorter_;
339*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<SlabSampleTreeDisplayer> slab_sample_tree_displayer_;
340*288bf522SAndroid Build Coastguard Worker 
341*288bf522SAndroid Build Coastguard Worker   std::string report_filename_;
342*288bf522SAndroid Build Coastguard Worker };
343*288bf522SAndroid Build Coastguard Worker 
Run(const std::vector<std::string> & args)344*288bf522SAndroid Build Coastguard Worker bool KmemCommand::Run(const std::vector<std::string>& args) {
345*288bf522SAndroid Build Coastguard Worker   std::vector<std::string> left_args;
346*288bf522SAndroid Build Coastguard Worker   if (!ParseOptions(args, &left_args)) {
347*288bf522SAndroid Build Coastguard Worker     return false;
348*288bf522SAndroid Build Coastguard Worker   }
349*288bf522SAndroid Build Coastguard Worker   if (!use_slab_) {
350*288bf522SAndroid Build Coastguard Worker     use_slab_ = true;
351*288bf522SAndroid Build Coastguard Worker   }
352*288bf522SAndroid Build Coastguard Worker   if (is_record_) {
353*288bf522SAndroid Build Coastguard Worker     return RecordKmemInfo(left_args);
354*288bf522SAndroid Build Coastguard Worker   }
355*288bf522SAndroid Build Coastguard Worker   return ReportKmemInfo();
356*288bf522SAndroid Build Coastguard Worker }
357*288bf522SAndroid Build Coastguard Worker 
ParseOptions(const std::vector<std::string> & args,std::vector<std::string> * left_args)358*288bf522SAndroid Build Coastguard Worker bool KmemCommand::ParseOptions(const std::vector<std::string>& args,
359*288bf522SAndroid Build Coastguard Worker                                std::vector<std::string>* left_args) {
360*288bf522SAndroid Build Coastguard Worker   if (args.empty()) {
361*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "No subcommand specified";
362*288bf522SAndroid Build Coastguard Worker     return false;
363*288bf522SAndroid Build Coastguard Worker   }
364*288bf522SAndroid Build Coastguard Worker   if (args[0] == "record") {
365*288bf522SAndroid Build Coastguard Worker     if (!IsRoot()) {
366*288bf522SAndroid Build Coastguard Worker       LOG(ERROR) << "simpleperf kmem record command needs root privilege";
367*288bf522SAndroid Build Coastguard Worker       return false;
368*288bf522SAndroid Build Coastguard Worker     }
369*288bf522SAndroid Build Coastguard Worker     is_record_ = true;
370*288bf522SAndroid Build Coastguard Worker     size_t i;
371*288bf522SAndroid Build Coastguard Worker     for (i = 1; i < args.size() && !args[i].empty() && args[i][0] == '-'; ++i) {
372*288bf522SAndroid Build Coastguard Worker       if (args[i] == "-g") {
373*288bf522SAndroid Build Coastguard Worker         left_args->push_back("--call-graph");
374*288bf522SAndroid Build Coastguard Worker         left_args->push_back("fp");
375*288bf522SAndroid Build Coastguard Worker       } else if (args[i] == "--slab") {
376*288bf522SAndroid Build Coastguard Worker         use_slab_ = true;
377*288bf522SAndroid Build Coastguard Worker       } else {
378*288bf522SAndroid Build Coastguard Worker         left_args->push_back(args[i]);
379*288bf522SAndroid Build Coastguard Worker       }
380*288bf522SAndroid Build Coastguard Worker     }
381*288bf522SAndroid Build Coastguard Worker     left_args->insert(left_args->end(), args.begin() + i, args.end());
382*288bf522SAndroid Build Coastguard Worker   } else if (args[0] == "report") {
383*288bf522SAndroid Build Coastguard Worker     is_record_ = false;
384*288bf522SAndroid Build Coastguard Worker     for (size_t i = 1; i < args.size(); ++i) {
385*288bf522SAndroid Build Coastguard Worker       if (args[i] == "--children") {
386*288bf522SAndroid Build Coastguard Worker         accumulate_callchain_ = true;
387*288bf522SAndroid Build Coastguard Worker       } else if (args[i] == "-g") {
388*288bf522SAndroid Build Coastguard Worker         print_callgraph_ = true;
389*288bf522SAndroid Build Coastguard Worker         accumulate_callchain_ = true;
390*288bf522SAndroid Build Coastguard Worker         callgraph_show_callee_ = true;
391*288bf522SAndroid Build Coastguard Worker         if (i + 1 < args.size() && args[i + 1][0] != '-') {
392*288bf522SAndroid Build Coastguard Worker           ++i;
393*288bf522SAndroid Build Coastguard Worker           if (args[i] == "callee") {
394*288bf522SAndroid Build Coastguard Worker             callgraph_show_callee_ = true;
395*288bf522SAndroid Build Coastguard Worker           } else if (args[i] == "caller") {
396*288bf522SAndroid Build Coastguard Worker             callgraph_show_callee_ = false;
397*288bf522SAndroid Build Coastguard Worker           } else {
398*288bf522SAndroid Build Coastguard Worker             LOG(ERROR) << "Unknown argument with -g option: " << args[i];
399*288bf522SAndroid Build Coastguard Worker             return false;
400*288bf522SAndroid Build Coastguard Worker           }
401*288bf522SAndroid Build Coastguard Worker         }
402*288bf522SAndroid Build Coastguard Worker       } else if (args[i] == "-i") {
403*288bf522SAndroid Build Coastguard Worker         if (!NextArgumentOrError(args, &i)) {
404*288bf522SAndroid Build Coastguard Worker           return false;
405*288bf522SAndroid Build Coastguard Worker         }
406*288bf522SAndroid Build Coastguard Worker         record_filename_ = args[i];
407*288bf522SAndroid Build Coastguard Worker       } else if (args[i] == "-o") {
408*288bf522SAndroid Build Coastguard Worker         if (!NextArgumentOrError(args, &i)) {
409*288bf522SAndroid Build Coastguard Worker           return false;
410*288bf522SAndroid Build Coastguard Worker         }
411*288bf522SAndroid Build Coastguard Worker         report_filename_ = args[i];
412*288bf522SAndroid Build Coastguard Worker       } else if (args[i] == "--slab") {
413*288bf522SAndroid Build Coastguard Worker         use_slab_ = true;
414*288bf522SAndroid Build Coastguard Worker       } else if (args[i] == "--slab-sort") {
415*288bf522SAndroid Build Coastguard Worker         if (!NextArgumentOrError(args, &i)) {
416*288bf522SAndroid Build Coastguard Worker           return false;
417*288bf522SAndroid Build Coastguard Worker         }
418*288bf522SAndroid Build Coastguard Worker         slab_sort_keys_ = android::base::Split(args[i], ",");
419*288bf522SAndroid Build Coastguard Worker       } else {
420*288bf522SAndroid Build Coastguard Worker         ReportUnknownOption(args, i);
421*288bf522SAndroid Build Coastguard Worker         return false;
422*288bf522SAndroid Build Coastguard Worker       }
423*288bf522SAndroid Build Coastguard Worker     }
424*288bf522SAndroid Build Coastguard Worker   } else {
425*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Unknown subcommand for " << Name() << ": " << args[0]
426*288bf522SAndroid Build Coastguard Worker                << ". Try `simpleperf help " << Name() << "`";
427*288bf522SAndroid Build Coastguard Worker     return false;
428*288bf522SAndroid Build Coastguard Worker   }
429*288bf522SAndroid Build Coastguard Worker   return true;
430*288bf522SAndroid Build Coastguard Worker }
431*288bf522SAndroid Build Coastguard Worker 
RecordKmemInfo(const std::vector<std::string> & record_args)432*288bf522SAndroid Build Coastguard Worker bool KmemCommand::RecordKmemInfo(const std::vector<std::string>& record_args) {
433*288bf522SAndroid Build Coastguard Worker   std::vector<std::string> args;
434*288bf522SAndroid Build Coastguard Worker   if (use_slab_) {
435*288bf522SAndroid Build Coastguard Worker     std::vector<std::string> trace_events = {"kmem:kmalloc",      "kmem:kmem_cache_alloc",
436*288bf522SAndroid Build Coastguard Worker                                              "kmem:kmalloc_node", "kmem:kmem_cache_alloc_node",
437*288bf522SAndroid Build Coastguard Worker                                              "kmem:kfree",        "kmem:kmem_cache_free"};
438*288bf522SAndroid Build Coastguard Worker     for (const auto& name : trace_events) {
439*288bf522SAndroid Build Coastguard Worker       if (ParseEventType(name)) {
440*288bf522SAndroid Build Coastguard Worker         args.insert(args.end(), {"-e", name});
441*288bf522SAndroid Build Coastguard Worker       }
442*288bf522SAndroid Build Coastguard Worker     }
443*288bf522SAndroid Build Coastguard Worker   }
444*288bf522SAndroid Build Coastguard Worker   if (args.empty()) {
445*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "Kernel allocation related trace events are not supported.";
446*288bf522SAndroid Build Coastguard Worker     return false;
447*288bf522SAndroid Build Coastguard Worker   }
448*288bf522SAndroid Build Coastguard Worker   args.push_back("-a");
449*288bf522SAndroid Build Coastguard Worker   args.insert(args.end(), record_args.begin(), record_args.end());
450*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<Command> record_cmd = CreateCommandInstance("record");
451*288bf522SAndroid Build Coastguard Worker   if (record_cmd == nullptr) {
452*288bf522SAndroid Build Coastguard Worker     LOG(ERROR) << "record command isn't available";
453*288bf522SAndroid Build Coastguard Worker     return false;
454*288bf522SAndroid Build Coastguard Worker   }
455*288bf522SAndroid Build Coastguard Worker   return record_cmd->Run(args);
456*288bf522SAndroid Build Coastguard Worker }
457*288bf522SAndroid Build Coastguard Worker 
ReportKmemInfo()458*288bf522SAndroid Build Coastguard Worker bool KmemCommand::ReportKmemInfo() {
459*288bf522SAndroid Build Coastguard Worker   if (!PrepareToBuildSampleTree()) {
460*288bf522SAndroid Build Coastguard Worker     return false;
461*288bf522SAndroid Build Coastguard Worker   }
462*288bf522SAndroid Build Coastguard Worker   record_file_reader_ = RecordFileReader::CreateInstance(record_filename_);
463*288bf522SAndroid Build Coastguard Worker   if (record_file_reader_ == nullptr) {
464*288bf522SAndroid Build Coastguard Worker     return false;
465*288bf522SAndroid Build Coastguard Worker   }
466*288bf522SAndroid Build Coastguard Worker   ReadEventAttrsFromRecordFile();
467*288bf522SAndroid Build Coastguard Worker   if (!ReadFeaturesFromRecordFile()) {
468*288bf522SAndroid Build Coastguard Worker     return false;
469*288bf522SAndroid Build Coastguard Worker   }
470*288bf522SAndroid Build Coastguard Worker   if (!ReadSampleTreeFromRecordFile()) {
471*288bf522SAndroid Build Coastguard Worker     return false;
472*288bf522SAndroid Build Coastguard Worker   }
473*288bf522SAndroid Build Coastguard Worker   if (!PrintReport()) {
474*288bf522SAndroid Build Coastguard Worker     return false;
475*288bf522SAndroid Build Coastguard Worker   }
476*288bf522SAndroid Build Coastguard Worker   return true;
477*288bf522SAndroid Build Coastguard Worker }
478*288bf522SAndroid Build Coastguard Worker 
PrepareToBuildSampleTree()479*288bf522SAndroid Build Coastguard Worker bool KmemCommand::PrepareToBuildSampleTree() {
480*288bf522SAndroid Build Coastguard Worker   if (use_slab_) {
481*288bf522SAndroid Build Coastguard Worker     if (slab_sort_keys_.empty()) {
482*288bf522SAndroid Build Coastguard Worker       slab_sort_keys_ = {"hit", "caller", "bytes_req", "bytes_alloc", "fragment", "pingpong"};
483*288bf522SAndroid Build Coastguard Worker     }
484*288bf522SAndroid Build Coastguard Worker     SampleComparator<SlabSample> comparator;
485*288bf522SAndroid Build Coastguard Worker     SampleComparator<SlabSample> sort_comparator;
486*288bf522SAndroid Build Coastguard Worker     SampleDisplayer<SlabSample, SlabSampleTree> displayer;
487*288bf522SAndroid Build Coastguard Worker     std::string accumulated_name = accumulate_callchain_ ? "Accumulated_" : "";
488*288bf522SAndroid Build Coastguard Worker 
489*288bf522SAndroid Build Coastguard Worker     if (print_callgraph_) {
490*288bf522SAndroid Build Coastguard Worker       displayer.AddExclusiveDisplayFunction(SlabSampleCallgraphDisplayer());
491*288bf522SAndroid Build Coastguard Worker     }
492*288bf522SAndroid Build Coastguard Worker 
493*288bf522SAndroid Build Coastguard Worker     for (const auto& key : slab_sort_keys_) {
494*288bf522SAndroid Build Coastguard Worker       if (key == "hit") {
495*288bf522SAndroid Build Coastguard Worker         sort_comparator.AddCompareFunction(CompareSampleCount);
496*288bf522SAndroid Build Coastguard Worker         displayer.AddDisplayFunction(accumulated_name + "Hit", DisplaySampleCount<SlabSample>);
497*288bf522SAndroid Build Coastguard Worker       } else if (key == "caller") {
498*288bf522SAndroid Build Coastguard Worker         comparator.AddCompareFunction(CompareSymbol);
499*288bf522SAndroid Build Coastguard Worker         displayer.AddDisplayFunction("Caller", DisplaySymbol<SlabSample>);
500*288bf522SAndroid Build Coastguard Worker       } else if (key == "ptr") {
501*288bf522SAndroid Build Coastguard Worker         comparator.AddCompareFunction(ComparePtr);
502*288bf522SAndroid Build Coastguard Worker         displayer.AddDisplayFunction("Ptr", DisplayPtr<SlabSample>);
503*288bf522SAndroid Build Coastguard Worker       } else if (key == "bytes_req") {
504*288bf522SAndroid Build Coastguard Worker         sort_comparator.AddCompareFunction(CompareBytesReq);
505*288bf522SAndroid Build Coastguard Worker         displayer.AddDisplayFunction(accumulated_name + "BytesReq", DisplayBytesReq<SlabSample>);
506*288bf522SAndroid Build Coastguard Worker       } else if (key == "bytes_alloc") {
507*288bf522SAndroid Build Coastguard Worker         sort_comparator.AddCompareFunction(CompareBytesAlloc);
508*288bf522SAndroid Build Coastguard Worker         displayer.AddDisplayFunction(accumulated_name + "BytesAlloc",
509*288bf522SAndroid Build Coastguard Worker                                      DisplayBytesAlloc<SlabSample>);
510*288bf522SAndroid Build Coastguard Worker       } else if (key == "fragment") {
511*288bf522SAndroid Build Coastguard Worker         sort_comparator.AddCompareFunction(CompareFragment);
512*288bf522SAndroid Build Coastguard Worker         displayer.AddDisplayFunction(accumulated_name + "Fragment", DisplayFragment);
513*288bf522SAndroid Build Coastguard Worker       } else if (key == "gfp_flags") {
514*288bf522SAndroid Build Coastguard Worker         comparator.AddCompareFunction(CompareGfpFlags);
515*288bf522SAndroid Build Coastguard Worker         displayer.AddDisplayFunction("GfpFlags", DisplayGfpFlags<SlabSample>);
516*288bf522SAndroid Build Coastguard Worker       } else if (key == "pingpong") {
517*288bf522SAndroid Build Coastguard Worker         sort_comparator.AddCompareFunction(CompareCrossCpuAllocations);
518*288bf522SAndroid Build Coastguard Worker         displayer.AddDisplayFunction("Pingpong", DisplayCrossCpuAllocations<SlabSample>);
519*288bf522SAndroid Build Coastguard Worker       } else {
520*288bf522SAndroid Build Coastguard Worker         LOG(ERROR) << "Unknown sort key for slab allocation: " << key;
521*288bf522SAndroid Build Coastguard Worker         return false;
522*288bf522SAndroid Build Coastguard Worker       }
523*288bf522SAndroid Build Coastguard Worker       slab_sample_tree_builder_.reset(new SlabSampleTreeBuilder(comparator, &thread_tree_));
524*288bf522SAndroid Build Coastguard Worker       slab_sample_tree_builder_->SetCallChainSampleOptions(accumulate_callchain_, print_callgraph_,
525*288bf522SAndroid Build Coastguard Worker                                                            !callgraph_show_callee_);
526*288bf522SAndroid Build Coastguard Worker       sort_comparator.AddComparator(comparator);
527*288bf522SAndroid Build Coastguard Worker       slab_sample_tree_sorter_.reset(new SlabSampleTreeSorter(sort_comparator));
528*288bf522SAndroid Build Coastguard Worker       slab_sample_tree_displayer_.reset(new SlabSampleTreeDisplayer(displayer));
529*288bf522SAndroid Build Coastguard Worker     }
530*288bf522SAndroid Build Coastguard Worker   }
531*288bf522SAndroid Build Coastguard Worker   return true;
532*288bf522SAndroid Build Coastguard Worker }
533*288bf522SAndroid Build Coastguard Worker 
ReadEventAttrsFromRecordFile()534*288bf522SAndroid Build Coastguard Worker void KmemCommand::ReadEventAttrsFromRecordFile() {
535*288bf522SAndroid Build Coastguard Worker   for (const EventAttrWithId& attr_with_id : record_file_reader_->AttrSection()) {
536*288bf522SAndroid Build Coastguard Worker     EventAttrWithName attr;
537*288bf522SAndroid Build Coastguard Worker     attr.attr = attr_with_id.attr;
538*288bf522SAndroid Build Coastguard Worker     attr.event_ids = attr_with_id.ids;
539*288bf522SAndroid Build Coastguard Worker     attr.name = GetEventNameByAttr(attr.attr);
540*288bf522SAndroid Build Coastguard Worker     event_attrs_.push_back(attr);
541*288bf522SAndroid Build Coastguard Worker   }
542*288bf522SAndroid Build Coastguard Worker }
543*288bf522SAndroid Build Coastguard Worker 
ReadFeaturesFromRecordFile()544*288bf522SAndroid Build Coastguard Worker bool KmemCommand::ReadFeaturesFromRecordFile() {
545*288bf522SAndroid Build Coastguard Worker   if (!record_file_reader_->LoadBuildIdAndFileFeatures(thread_tree_)) {
546*288bf522SAndroid Build Coastguard Worker     return false;
547*288bf522SAndroid Build Coastguard Worker   }
548*288bf522SAndroid Build Coastguard Worker   std::string arch = record_file_reader_->ReadFeatureString(PerfFileFormat::FEAT_ARCH);
549*288bf522SAndroid Build Coastguard Worker   if (!arch.empty()) {
550*288bf522SAndroid Build Coastguard Worker     record_file_arch_ = GetArchType(arch);
551*288bf522SAndroid Build Coastguard Worker     if (record_file_arch_ == ARCH_UNSUPPORTED) {
552*288bf522SAndroid Build Coastguard Worker       return false;
553*288bf522SAndroid Build Coastguard Worker     }
554*288bf522SAndroid Build Coastguard Worker   }
555*288bf522SAndroid Build Coastguard Worker   std::vector<std::string> cmdline = record_file_reader_->ReadCmdlineFeature();
556*288bf522SAndroid Build Coastguard Worker   if (!cmdline.empty()) {
557*288bf522SAndroid Build Coastguard Worker     record_cmdline_ = android::base::Join(cmdline, ' ');
558*288bf522SAndroid Build Coastguard Worker   }
559*288bf522SAndroid Build Coastguard Worker   if (record_file_reader_->HasFeature(PerfFileFormat::FEAT_TRACING_DATA)) {
560*288bf522SAndroid Build Coastguard Worker     std::vector<char> tracing_data;
561*288bf522SAndroid Build Coastguard Worker     if (!record_file_reader_->ReadFeatureSection(PerfFileFormat::FEAT_TRACING_DATA,
562*288bf522SAndroid Build Coastguard Worker                                                  &tracing_data)) {
563*288bf522SAndroid Build Coastguard Worker       return false;
564*288bf522SAndroid Build Coastguard Worker     }
565*288bf522SAndroid Build Coastguard Worker     ProcessTracingData(tracing_data);
566*288bf522SAndroid Build Coastguard Worker   }
567*288bf522SAndroid Build Coastguard Worker   return true;
568*288bf522SAndroid Build Coastguard Worker }
569*288bf522SAndroid Build Coastguard Worker 
ReadSampleTreeFromRecordFile()570*288bf522SAndroid Build Coastguard Worker bool KmemCommand::ReadSampleTreeFromRecordFile() {
571*288bf522SAndroid Build Coastguard Worker   if (!record_file_reader_->ReadDataSection(
572*288bf522SAndroid Build Coastguard Worker           [this](std::unique_ptr<Record> record) { return ProcessRecord(std::move(record)); })) {
573*288bf522SAndroid Build Coastguard Worker     return false;
574*288bf522SAndroid Build Coastguard Worker   }
575*288bf522SAndroid Build Coastguard Worker   if (use_slab_) {
576*288bf522SAndroid Build Coastguard Worker     slab_sample_tree_ = slab_sample_tree_builder_->GetSampleTree();
577*288bf522SAndroid Build Coastguard Worker     slab_sample_tree_sorter_->Sort(slab_sample_tree_.samples, print_callgraph_);
578*288bf522SAndroid Build Coastguard Worker   }
579*288bf522SAndroid Build Coastguard Worker   return true;
580*288bf522SAndroid Build Coastguard Worker }
581*288bf522SAndroid Build Coastguard Worker 
ProcessRecord(std::unique_ptr<Record> record)582*288bf522SAndroid Build Coastguard Worker bool KmemCommand::ProcessRecord(std::unique_ptr<Record> record) {
583*288bf522SAndroid Build Coastguard Worker   thread_tree_.Update(*record);
584*288bf522SAndroid Build Coastguard Worker   if (record->type() == PERF_RECORD_SAMPLE) {
585*288bf522SAndroid Build Coastguard Worker     if (use_slab_) {
586*288bf522SAndroid Build Coastguard Worker       slab_sample_tree_builder_->ProcessSampleRecord(
587*288bf522SAndroid Build Coastguard Worker           *static_cast<const SampleRecord*>(record.get()));
588*288bf522SAndroid Build Coastguard Worker     }
589*288bf522SAndroid Build Coastguard Worker   } else if (record->type() == PERF_RECORD_TRACING_DATA ||
590*288bf522SAndroid Build Coastguard Worker              record->type() == SIMPLE_PERF_RECORD_TRACING_DATA) {
591*288bf522SAndroid Build Coastguard Worker     const auto& r = *static_cast<TracingDataRecord*>(record.get());
592*288bf522SAndroid Build Coastguard Worker     if (!ProcessTracingData(std::vector<char>(r.data, r.data + r.data_size))) {
593*288bf522SAndroid Build Coastguard Worker       return false;
594*288bf522SAndroid Build Coastguard Worker     }
595*288bf522SAndroid Build Coastguard Worker   }
596*288bf522SAndroid Build Coastguard Worker   return true;
597*288bf522SAndroid Build Coastguard Worker }
598*288bf522SAndroid Build Coastguard Worker 
ProcessTracingData(const std::vector<char> & data)599*288bf522SAndroid Build Coastguard Worker bool KmemCommand::ProcessTracingData(const std::vector<char>& data) {
600*288bf522SAndroid Build Coastguard Worker   auto tracing = Tracing::Create(data);
601*288bf522SAndroid Build Coastguard Worker   if (!tracing) {
602*288bf522SAndroid Build Coastguard Worker     return false;
603*288bf522SAndroid Build Coastguard Worker   }
604*288bf522SAndroid Build Coastguard Worker   for (auto& attr : event_attrs_) {
605*288bf522SAndroid Build Coastguard Worker     if (attr.attr.type == PERF_TYPE_TRACEPOINT) {
606*288bf522SAndroid Build Coastguard Worker       uint64_t trace_event_id = attr.attr.config;
607*288bf522SAndroid Build Coastguard Worker       attr.name = tracing->GetTracingEventNameHavingId(trace_event_id);
608*288bf522SAndroid Build Coastguard Worker       std::optional<TracingFormat> opt_format = tracing->GetTracingFormatHavingId(trace_event_id);
609*288bf522SAndroid Build Coastguard Worker       if (!opt_format.has_value()) {
610*288bf522SAndroid Build Coastguard Worker         return false;
611*288bf522SAndroid Build Coastguard Worker       }
612*288bf522SAndroid Build Coastguard Worker       const TracingFormat& format = opt_format.value();
613*288bf522SAndroid Build Coastguard Worker       if (use_slab_) {
614*288bf522SAndroid Build Coastguard Worker         if (format.name == "kmalloc" || format.name == "kmem_cache_alloc" ||
615*288bf522SAndroid Build Coastguard Worker             format.name == "kmalloc_node" || format.name == "kmem_cache_alloc_node") {
616*288bf522SAndroid Build Coastguard Worker           SlabFormat f;
617*288bf522SAndroid Build Coastguard Worker           f.type = SlabFormat::KMEM_ALLOC;
618*288bf522SAndroid Build Coastguard Worker           format.GetField("call_site", f.call_site);
619*288bf522SAndroid Build Coastguard Worker           format.GetField("ptr", f.ptr);
620*288bf522SAndroid Build Coastguard Worker           format.GetField("bytes_req", f.bytes_req);
621*288bf522SAndroid Build Coastguard Worker           format.GetField("bytes_alloc", f.bytes_alloc);
622*288bf522SAndroid Build Coastguard Worker           format.GetField("gfp_flags", f.gfp_flags);
623*288bf522SAndroid Build Coastguard Worker           slab_sample_tree_builder_->AddSlabFormat(attr.event_ids, f);
624*288bf522SAndroid Build Coastguard Worker         } else if (format.name == "kfree" || format.name == "kmem_cache_free") {
625*288bf522SAndroid Build Coastguard Worker           SlabFormat f;
626*288bf522SAndroid Build Coastguard Worker           f.type = SlabFormat::KMEM_FREE;
627*288bf522SAndroid Build Coastguard Worker           format.GetField("call_site", f.call_site);
628*288bf522SAndroid Build Coastguard Worker           format.GetField("ptr", f.ptr);
629*288bf522SAndroid Build Coastguard Worker           slab_sample_tree_builder_->AddSlabFormat(attr.event_ids, f);
630*288bf522SAndroid Build Coastguard Worker         }
631*288bf522SAndroid Build Coastguard Worker       }
632*288bf522SAndroid Build Coastguard Worker     }
633*288bf522SAndroid Build Coastguard Worker   }
634*288bf522SAndroid Build Coastguard Worker   return true;
635*288bf522SAndroid Build Coastguard Worker }
636*288bf522SAndroid Build Coastguard Worker 
PrintReport()637*288bf522SAndroid Build Coastguard Worker bool KmemCommand::PrintReport() {
638*288bf522SAndroid Build Coastguard Worker   std::unique_ptr<FILE, decltype(&fclose)> file_handler(nullptr, fclose);
639*288bf522SAndroid Build Coastguard Worker   FILE* report_fp = stdout;
640*288bf522SAndroid Build Coastguard Worker   if (!report_filename_.empty()) {
641*288bf522SAndroid Build Coastguard Worker     file_handler.reset(fopen(report_filename_.c_str(), "w"));
642*288bf522SAndroid Build Coastguard Worker     if (file_handler == nullptr) {
643*288bf522SAndroid Build Coastguard Worker       PLOG(ERROR) << "failed to open " << report_filename_;
644*288bf522SAndroid Build Coastguard Worker       return false;
645*288bf522SAndroid Build Coastguard Worker     }
646*288bf522SAndroid Build Coastguard Worker     report_fp = file_handler.get();
647*288bf522SAndroid Build Coastguard Worker   }
648*288bf522SAndroid Build Coastguard Worker   PrintReportContext(report_fp);
649*288bf522SAndroid Build Coastguard Worker   if (use_slab_) {
650*288bf522SAndroid Build Coastguard Worker     fprintf(report_fp, "\n\n");
651*288bf522SAndroid Build Coastguard Worker     PrintSlabReportContext(report_fp);
652*288bf522SAndroid Build Coastguard Worker     slab_sample_tree_displayer_->DisplaySamples(report_fp, slab_sample_tree_.samples,
653*288bf522SAndroid Build Coastguard Worker                                                 &slab_sample_tree_);
654*288bf522SAndroid Build Coastguard Worker   }
655*288bf522SAndroid Build Coastguard Worker   return true;
656*288bf522SAndroid Build Coastguard Worker }
657*288bf522SAndroid Build Coastguard Worker 
PrintReportContext(FILE * fp)658*288bf522SAndroid Build Coastguard Worker void KmemCommand::PrintReportContext(FILE* fp) {
659*288bf522SAndroid Build Coastguard Worker   if (!record_cmdline_.empty()) {
660*288bf522SAndroid Build Coastguard Worker     fprintf(fp, "Cmdline: %s\n", record_cmdline_.c_str());
661*288bf522SAndroid Build Coastguard Worker   }
662*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "Arch: %s\n", GetArchString(record_file_arch_).c_str());
663*288bf522SAndroid Build Coastguard Worker   for (const auto& attr : event_attrs_) {
664*288bf522SAndroid Build Coastguard Worker     fprintf(fp, "Event: %s (type %u, config %llu)\n", attr.name.c_str(), attr.attr.type,
665*288bf522SAndroid Build Coastguard Worker             attr.attr.config);
666*288bf522SAndroid Build Coastguard Worker   }
667*288bf522SAndroid Build Coastguard Worker }
668*288bf522SAndroid Build Coastguard Worker 
PrintSlabReportContext(FILE * fp)669*288bf522SAndroid Build Coastguard Worker void KmemCommand::PrintSlabReportContext(FILE* fp) {
670*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "Slab allocation information:\n");
671*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "Total requested bytes: %" PRIu64 "\n", slab_sample_tree_.total_requested_bytes);
672*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "Total allocated bytes: %" PRIu64 "\n", slab_sample_tree_.total_allocated_bytes);
673*288bf522SAndroid Build Coastguard Worker   uint64_t fragment =
674*288bf522SAndroid Build Coastguard Worker       slab_sample_tree_.total_allocated_bytes - slab_sample_tree_.total_requested_bytes;
675*288bf522SAndroid Build Coastguard Worker   double percentage = 0.0;
676*288bf522SAndroid Build Coastguard Worker   if (slab_sample_tree_.total_allocated_bytes != 0) {
677*288bf522SAndroid Build Coastguard Worker     percentage = 100.0 * fragment / slab_sample_tree_.total_allocated_bytes;
678*288bf522SAndroid Build Coastguard Worker   }
679*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "Total fragment: %" PRIu64 ", %f%%\n", fragment, percentage);
680*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "Total allocations: %" PRIu64 "\n", slab_sample_tree_.nr_allocations);
681*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "Total frees: %" PRIu64 "\n", slab_sample_tree_.nr_frees);
682*288bf522SAndroid Build Coastguard Worker   percentage = 0.0;
683*288bf522SAndroid Build Coastguard Worker   if (slab_sample_tree_.nr_allocations != 0) {
684*288bf522SAndroid Build Coastguard Worker     percentage =
685*288bf522SAndroid Build Coastguard Worker         100.0 * slab_sample_tree_.nr_cross_cpu_allocations / slab_sample_tree_.nr_allocations;
686*288bf522SAndroid Build Coastguard Worker   }
687*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "Total cross cpu allocation/free: %" PRIu64 ", %f%%\n",
688*288bf522SAndroid Build Coastguard Worker           slab_sample_tree_.nr_cross_cpu_allocations, percentage);
689*288bf522SAndroid Build Coastguard Worker   fprintf(fp, "\n");
690*288bf522SAndroid Build Coastguard Worker }
691*288bf522SAndroid Build Coastguard Worker 
692*288bf522SAndroid Build Coastguard Worker }  // namespace
693*288bf522SAndroid Build Coastguard Worker 
RegisterKmemCommand()694*288bf522SAndroid Build Coastguard Worker void RegisterKmemCommand() {
695*288bf522SAndroid Build Coastguard Worker   RegisterCommand("kmem", [] { return std::unique_ptr<Command>(new KmemCommand()); });
696*288bf522SAndroid Build Coastguard Worker }
697*288bf522SAndroid Build Coastguard Worker 
698*288bf522SAndroid Build Coastguard Worker }  // namespace simpleperf
699