• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright (C) 2022 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//      http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15import m from 'mithril';
16
17import {MeminfoCounters, VmstatCounters} from '../../common/protos';
18import {globals} from '../globals';
19import {
20  Dropdown,
21  DropdownAttrs,
22  Probe,
23  ProbeAttrs,
24  Slider,
25  SliderAttrs,
26  Textarea,
27  TextareaAttrs,
28  Toggle,
29  ToggleAttrs,
30} from '../record_widgets';
31
32import {POLL_INTERVAL_MS, RecordingSectionAttrs} from './recording_sections';
33
34class HeapSettings implements m.ClassComponent<RecordingSectionAttrs> {
35  view({attrs}: m.CVnode<RecordingSectionAttrs>) {
36    const valuesForMS = [
37      0,
38      1000,
39      10 * 1000,
40      30 * 1000,
41      60 * 1000,
42      5 * 60 * 1000,
43      10 * 60 * 1000,
44      30 * 60 * 1000,
45      60 * 60 * 1000,
46    ];
47    const valuesForShMemBuff = [
48      0,
49      512,
50      1024,
51      2 * 1024,
52      4 * 1024,
53      8 * 1024,
54      16 * 1024,
55      32 * 1024,
56      64 * 1024,
57      128 * 1024,
58      256 * 1024,
59      512 * 1024,
60      1024 * 1024,
61      64 * 1024 * 1024,
62      128 * 1024 * 1024,
63      256 * 1024 * 1024,
64      512 * 1024 * 1024,
65    ];
66
67    return m(
68        `.${attrs.cssClass}`,
69        m(Textarea, {
70          title: 'Names or pids of the processes to track (required)',
71          docsLink:
72              'https://perfetto.dev/docs/data-sources/native-heap-profiler#heapprofd-targets',
73          placeholder: 'One per line, e.g.:\n' +
74              'system_server\n' +
75              'com.google.android.apps.photos\n' +
76              '1503',
77          set: (cfg, val) => cfg.hpProcesses = val,
78          get: (cfg) => cfg.hpProcesses,
79        } as TextareaAttrs),
80        m(Slider, {
81          title: 'Sampling interval',
82          cssClass: '.thin',
83          values: [
84            /* eslint-disable no-multi-spaces */
85            0,     1,     2,      4,      8,      16,      32,   64,
86            128,   256,   512,    1024,   2048,   4096,    8192, 16384,
87            32768, 65536, 131072, 262144, 524288, 1048576,
88            /* eslint-enable no-multi-spaces */
89          ],
90          unit: 'B',
91          min: 0,
92          set: (cfg, val) => cfg.hpSamplingIntervalBytes = val,
93          get: (cfg) => cfg.hpSamplingIntervalBytes,
94        } as SliderAttrs),
95        m(Slider, {
96          title: 'Continuous dumps interval ',
97          description: 'Time between following dumps (0 = disabled)',
98          cssClass: '.thin',
99          values: valuesForMS,
100          unit: 'ms',
101          min: 0,
102          set: (cfg, val) => {
103            cfg.hpContinuousDumpsInterval = val;
104          },
105          get: (cfg) => cfg.hpContinuousDumpsInterval,
106        } as SliderAttrs),
107        m(Slider, {
108          title: 'Continuous dumps phase',
109          description: 'Time before first dump',
110          cssClass: `.thin${
111              globals.state.recordConfig.hpContinuousDumpsInterval === 0 ?
112                  '.greyed-out' :
113                  ''}`,
114          values: valuesForMS,
115          unit: 'ms',
116          min: 0,
117          disabled: globals.state.recordConfig.hpContinuousDumpsInterval === 0,
118          set: (cfg, val) => cfg.hpContinuousDumpsPhase = val,
119          get: (cfg) => cfg.hpContinuousDumpsPhase,
120        } as SliderAttrs),
121        m(Slider, {
122          title: `Shared memory buffer`,
123          cssClass: '.thin',
124          values: valuesForShMemBuff.filter(
125              (value) => value === 0 || value >= 8192 && value % 4096 === 0),
126          unit: 'B',
127          min: 0,
128          set: (cfg, val) => cfg.hpSharedMemoryBuffer = val,
129          get: (cfg) => cfg.hpSharedMemoryBuffer,
130        } as SliderAttrs),
131        m(Toggle, {
132          title: 'Block client',
133          cssClass: '.thin',
134          descr: `Slow down target application if profiler cannot keep up.`,
135          setEnabled: (cfg, val) => cfg.hpBlockClient = val,
136          isEnabled: (cfg) => cfg.hpBlockClient,
137        } as ToggleAttrs),
138        m(Toggle, {
139          title: 'All custom allocators (Q+)',
140          cssClass: '.thin',
141          descr: `If the target application exposes custom allocators, also
142sample from those.`,
143          setEnabled: (cfg, val) => cfg.hpAllHeaps = val,
144          isEnabled: (cfg) => cfg.hpAllHeaps,
145        } as ToggleAttrs),
146        // TODO(hjd): Add advanced options.
147    );
148  }
149}
150
151class JavaHeapDumpSettings implements m.ClassComponent<RecordingSectionAttrs> {
152  view({attrs}: m.CVnode<RecordingSectionAttrs>) {
153    const valuesForMS = [
154      0,
155      1000,
156      10 * 1000,
157      30 * 1000,
158      60 * 1000,
159      5 * 60 * 1000,
160      10 * 60 * 1000,
161      30 * 60 * 1000,
162      60 * 60 * 1000,
163    ];
164
165    return m(
166        `.${attrs.cssClass}`,
167        m(Textarea, {
168          title: 'Names or pids of the processes to track (required)',
169          placeholder: 'One per line, e.g.:\n' +
170              'com.android.vending\n' +
171              '1503',
172          set: (cfg, val) => cfg.jpProcesses = val,
173          get: (cfg) => cfg.jpProcesses,
174        } as TextareaAttrs),
175        m(Slider, {
176          title: 'Continuous dumps interval ',
177          description: 'Time between following dumps (0 = disabled)',
178          cssClass: '.thin',
179          values: valuesForMS,
180          unit: 'ms',
181          min: 0,
182          set: (cfg, val) => {
183            cfg.jpContinuousDumpsInterval = val;
184          },
185          get: (cfg) => cfg.jpContinuousDumpsInterval,
186        } as SliderAttrs),
187        m(Slider, {
188          title: 'Continuous dumps phase',
189          description: 'Time before first dump',
190          cssClass: `.thin${
191              globals.state.recordConfig.jpContinuousDumpsInterval === 0 ?
192                  '.greyed-out' :
193                  ''}`,
194          values: valuesForMS,
195          unit: 'ms',
196          min: 0,
197          disabled: globals.state.recordConfig.jpContinuousDumpsInterval === 0,
198          set: (cfg, val) => cfg.jpContinuousDumpsPhase = val,
199          get: (cfg) => cfg.jpContinuousDumpsPhase,
200        } as SliderAttrs),
201    );
202  }
203}
204
205export class MemorySettings implements m.ClassComponent<RecordingSectionAttrs> {
206  view({attrs}: m.CVnode<RecordingSectionAttrs>) {
207    const meminfoOpts = new Map<string, string>();
208    for (const x in MeminfoCounters) {
209      if (typeof MeminfoCounters[x] === 'number' &&
210          !`${x}`.endsWith('_UNSPECIFIED')) {
211        meminfoOpts.set(x, x.replace('MEMINFO_', '').toLowerCase());
212      }
213    }
214    const vmstatOpts = new Map<string, string>();
215    for (const x in VmstatCounters) {
216      if (typeof VmstatCounters[x] === 'number' &&
217          !`${x}`.endsWith('_UNSPECIFIED')) {
218        vmstatOpts.set(x, x.replace('VMSTAT_', '').toLowerCase());
219      }
220    }
221    return m(
222        `.record-section${attrs.cssClass}`,
223        m(Probe,
224          {
225            title: 'Native heap profiling',
226            img: 'rec_native_heap_profiler.png',
227            descr: `Track native heap allocations & deallocations of an Android
228               process. (Available on Android 10+)`,
229            setEnabled: (cfg, val) => cfg.heapProfiling = val,
230            isEnabled: (cfg) => cfg.heapProfiling,
231          } as ProbeAttrs,
232          m(HeapSettings, attrs)),
233        m(Probe,
234          {
235            title: 'Java heap dumps',
236            img: 'rec_java_heap_dump.png',
237            descr: `Dump information about the Java object graph of an
238          Android app. (Available on Android 11+)`,
239            setEnabled: (cfg, val) => cfg.javaHeapDump = val,
240            isEnabled: (cfg) => cfg.javaHeapDump,
241          } as ProbeAttrs,
242          m(JavaHeapDumpSettings, attrs)),
243        m(Probe,
244          {
245            title: 'Kernel meminfo',
246            img: 'rec_meminfo.png',
247            descr: 'Polling of /proc/meminfo',
248            setEnabled: (cfg, val) => cfg.meminfo = val,
249            isEnabled: (cfg) => cfg.meminfo,
250          } as ProbeAttrs,
251          m(Slider, {
252            title: 'Poll interval',
253            cssClass: '.thin',
254            values: POLL_INTERVAL_MS,
255            unit: 'ms',
256            set: (cfg, val) => cfg.meminfoPeriodMs = val,
257            get: (cfg) => cfg.meminfoPeriodMs,
258          } as SliderAttrs),
259          m(Dropdown, {
260            title: 'Select counters',
261            cssClass: '.multicolumn',
262            options: meminfoOpts,
263            set: (cfg, val) => cfg.meminfoCounters = val,
264            get: (cfg) => cfg.meminfoCounters,
265          } as DropdownAttrs)),
266        m(Probe, {
267          title: 'High-frequency memory events',
268          img: 'rec_mem_hifreq.png',
269          descr: `Allows to track short memory spikes and transitories through
270                ftrace's mm_event, rss_stat and ion events. Available only
271                on recent Android Q+ kernels`,
272          setEnabled: (cfg, val) => cfg.memHiFreq = val,
273          isEnabled: (cfg) => cfg.memHiFreq,
274        } as ProbeAttrs),
275        m(Probe, {
276          title: 'Low memory killer',
277          img: 'rec_lmk.png',
278          descr: `Record LMK events. Works both with the old in-kernel LMK
279                and the newer userspace lmkd. It also tracks OOM score
280                adjustments.`,
281          setEnabled: (cfg, val) => cfg.memLmk = val,
282          isEnabled: (cfg) => cfg.memLmk,
283        } as ProbeAttrs),
284        m(Probe,
285          {
286            title: 'Per process stats',
287            img: 'rec_ps_stats.png',
288            descr: `Periodically samples all processes in the system tracking:
289                    their thread list, memory counters (RSS, swap and other
290                    /proc/status counters) and oom_score_adj.`,
291            setEnabled: (cfg, val) => cfg.procStats = val,
292            isEnabled: (cfg) => cfg.procStats,
293          } as ProbeAttrs,
294          m(Slider, {
295            title: 'Poll interval',
296            cssClass: '.thin',
297            values: POLL_INTERVAL_MS,
298            unit: 'ms',
299            set: (cfg, val) => cfg.procStatsPeriodMs = val,
300            get: (cfg) => cfg.procStatsPeriodMs,
301          } as SliderAttrs)),
302        m(Probe,
303          {
304            title: 'Virtual memory stats',
305            img: 'rec_vmstat.png',
306            descr: `Periodically polls virtual memory stats from /proc/vmstat.
307                    Allows to gather statistics about swap, eviction,
308                    compression and pagecache efficiency`,
309            setEnabled: (cfg, val) => cfg.vmstat = val,
310            isEnabled: (cfg) => cfg.vmstat,
311          } as ProbeAttrs,
312          m(Slider, {
313            title: 'Poll interval',
314            cssClass: '.thin',
315            values: POLL_INTERVAL_MS,
316            unit: 'ms',
317            set: (cfg, val) => cfg.vmstatPeriodMs = val,
318            get: (cfg) => cfg.vmstatPeriodMs,
319          } as SliderAttrs),
320          m(Dropdown, {
321            title: 'Select counters',
322            cssClass: '.multicolumn',
323            options: vmstatOpts,
324            set: (cfg, val) => cfg.vmstatCounters = val,
325            get: (cfg) => cfg.vmstatCounters,
326          } as DropdownAttrs)));
327  }
328}
329