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