• 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 '../../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:
74          'One per line, e.g.:\n' +
75          'system_server\n' +
76          'com.google.android.apps.photos\n' +
77          '1503',
78        set: (cfg, val) => (cfg.hpProcesses = val),
79        get: (cfg) => cfg.hpProcesses,
80      } as TextareaAttrs),
81      m(Slider, {
82        title: 'Sampling interval',
83        cssClass: '.thin',
84        values: [
85          /* eslint-disable no-multi-spaces */
86          0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192,
87          16384, 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        }`,
115        values: valuesForMS,
116        unit: 'ms',
117        min: 0,
118        disabled: globals.state.recordConfig.hpContinuousDumpsInterval === 0,
119        set: (cfg, val) => (cfg.hpContinuousDumpsPhase = val),
120        get: (cfg) => cfg.hpContinuousDumpsPhase,
121      } as SliderAttrs),
122      m(Slider, {
123        title: `Shared memory buffer`,
124        cssClass: '.thin',
125        values: valuesForShMemBuff.filter(
126          (value) => value === 0 || (value >= 8192 && value % 4096 === 0),
127        ),
128        unit: 'B',
129        min: 0,
130        set: (cfg, val) => (cfg.hpSharedMemoryBuffer = val),
131        get: (cfg) => cfg.hpSharedMemoryBuffer,
132      } as SliderAttrs),
133      m(Toggle, {
134        title: 'Block client',
135        cssClass: '.thin',
136        descr: `Slow down target application if profiler cannot keep up.`,
137        setEnabled: (cfg, val) => (cfg.hpBlockClient = val),
138        isEnabled: (cfg) => cfg.hpBlockClient,
139      } as ToggleAttrs),
140      m(Toggle, {
141        title: 'All custom allocators (Q+)',
142        cssClass: '.thin',
143        descr: `If the target application exposes custom allocators, also
144sample from those.`,
145        setEnabled: (cfg, val) => (cfg.hpAllHeaps = val),
146        isEnabled: (cfg) => cfg.hpAllHeaps,
147      } as ToggleAttrs),
148      // TODO(hjd): Add advanced options.
149    );
150  }
151}
152
153class JavaHeapDumpSettings implements m.ClassComponent<RecordingSectionAttrs> {
154  view({attrs}: m.CVnode<RecordingSectionAttrs>) {
155    const valuesForMS = [
156      0,
157      1000,
158      10 * 1000,
159      30 * 1000,
160      60 * 1000,
161      5 * 60 * 1000,
162      10 * 60 * 1000,
163      30 * 60 * 1000,
164      60 * 60 * 1000,
165    ];
166
167    return m(
168      `.${attrs.cssClass}`,
169      m(Textarea, {
170        title: 'Names or pids of the processes to track (required)',
171        placeholder: 'One per line, e.g.:\n' + 'com.android.vending\n' + '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        }`,
195        values: valuesForMS,
196        unit: 'ms',
197        min: 0,
198        disabled: globals.state.recordConfig.jpContinuousDumpsInterval === 0,
199        set: (cfg, val) => (cfg.jpContinuousDumpsPhase = val),
200        get: (cfg) => cfg.jpContinuousDumpsPhase,
201      } as SliderAttrs),
202    );
203  }
204}
205
206export class MemorySettings implements m.ClassComponent<RecordingSectionAttrs> {
207  view({attrs}: m.CVnode<RecordingSectionAttrs>) {
208    const meminfoOpts = new Map<string, string>();
209    for (const x in MeminfoCounters) {
210      if (
211        typeof MeminfoCounters[x] === 'number' &&
212        !`${x}`.endsWith('_UNSPECIFIED')
213      ) {
214        meminfoOpts.set(x, x.replace('MEMINFO_', '').toLowerCase());
215      }
216    }
217    const vmstatOpts = new Map<string, string>();
218    for (const x in VmstatCounters) {
219      if (
220        typeof VmstatCounters[x] === 'number' &&
221        !`${x}`.endsWith('_UNSPECIFIED')
222      ) {
223        vmstatOpts.set(x, x.replace('VMSTAT_', '').toLowerCase());
224      }
225    }
226    return m(
227      `.record-section${attrs.cssClass}`,
228      m(
229        Probe,
230        {
231          title: 'Native heap profiling',
232          img: 'rec_native_heap_profiler.png',
233          descr: `Track native heap allocations & deallocations of an Android
234               process. (Available on Android 10+)`,
235          setEnabled: (cfg, val) => (cfg.heapProfiling = val),
236          isEnabled: (cfg) => cfg.heapProfiling,
237        } as ProbeAttrs,
238        m(HeapSettings, attrs),
239      ),
240      m(
241        Probe,
242        {
243          title: 'Java heap dumps',
244          img: 'rec_java_heap_dump.png',
245          descr: `Dump information about the Java object graph of an
246          Android app. (Available on Android 11+)`,
247          setEnabled: (cfg, val) => (cfg.javaHeapDump = val),
248          isEnabled: (cfg) => cfg.javaHeapDump,
249        } as ProbeAttrs,
250        m(JavaHeapDumpSettings, attrs),
251      ),
252      m(
253        Probe,
254        {
255          title: 'Kernel meminfo',
256          img: 'rec_meminfo.png',
257          descr: 'Polling of /proc/meminfo',
258          setEnabled: (cfg, val) => (cfg.meminfo = val),
259          isEnabled: (cfg) => cfg.meminfo,
260        } as ProbeAttrs,
261        m(Slider, {
262          title: 'Poll interval',
263          cssClass: '.thin',
264          values: POLL_INTERVAL_MS,
265          unit: 'ms',
266          set: (cfg, val) => (cfg.meminfoPeriodMs = val),
267          get: (cfg) => cfg.meminfoPeriodMs,
268        } as SliderAttrs),
269        m(Dropdown, {
270          title: 'Select counters',
271          cssClass: '.multicolumn',
272          options: meminfoOpts,
273          set: (cfg, val) => (cfg.meminfoCounters = val),
274          get: (cfg) => cfg.meminfoCounters,
275        } as DropdownAttrs),
276      ),
277      m(Probe, {
278        title: 'High-frequency memory events',
279        img: 'rec_mem_hifreq.png',
280        descr: `Allows to track short memory spikes and transitories through
281                ftrace's mm_event, rss_stat and ion events. Available only
282                on recent Android Q+ kernels`,
283        setEnabled: (cfg, val) => (cfg.memHiFreq = val),
284        isEnabled: (cfg) => cfg.memHiFreq,
285      } as ProbeAttrs),
286      m(Probe, {
287        title: 'Low memory killer',
288        img: 'rec_lmk.png',
289        descr: `Record LMK events. Works both with the old in-kernel LMK
290                and the newer userspace lmkd. It also tracks OOM score
291                adjustments.`,
292        setEnabled: (cfg, val) => (cfg.memLmk = val),
293        isEnabled: (cfg) => cfg.memLmk,
294      } as ProbeAttrs),
295      m(
296        Probe,
297        {
298          title: 'Per process stats',
299          img: 'rec_ps_stats.png',
300          descr: `Periodically samples all processes in the system tracking:
301                    their thread list, memory counters (RSS, swap and other
302                    /proc/status counters) and oom_score_adj.`,
303          setEnabled: (cfg, val) => (cfg.procStats = val),
304          isEnabled: (cfg) => cfg.procStats,
305        } as ProbeAttrs,
306        m(Slider, {
307          title: 'Poll interval',
308          cssClass: '.thin',
309          values: POLL_INTERVAL_MS,
310          unit: 'ms',
311          set: (cfg, val) => (cfg.procStatsPeriodMs = val),
312          get: (cfg) => cfg.procStatsPeriodMs,
313        } as SliderAttrs),
314      ),
315      m(
316        Probe,
317        {
318          title: 'Virtual memory stats',
319          img: 'rec_vmstat.png',
320          descr: `Periodically polls virtual memory stats from /proc/vmstat.
321                    Allows to gather statistics about swap, eviction,
322                    compression and pagecache efficiency`,
323          setEnabled: (cfg, val) => (cfg.vmstat = val),
324          isEnabled: (cfg) => cfg.vmstat,
325        } as ProbeAttrs,
326        m(Slider, {
327          title: 'Poll interval',
328          cssClass: '.thin',
329          values: POLL_INTERVAL_MS,
330          unit: 'ms',
331          set: (cfg, val) => (cfg.vmstatPeriodMs = val),
332          get: (cfg) => cfg.vmstatPeriodMs,
333        } as SliderAttrs),
334        m(Dropdown, {
335          title: 'Select counters',
336          cssClass: '.multicolumn',
337          options: vmstatOpts,
338          set: (cfg, val) => (cfg.vmstatCounters = val),
339          get: (cfg) => cfg.vmstatCounters,
340        } as DropdownAttrs),
341      ),
342    );
343  }
344}
345