xref: /aosp_15_r20/system/extras/systrace_analysis/analysis.html (revision 288bf5226967eb3dac5cce6c939ccc2a7f2b4fe5)
1*288bf522SAndroid Build Coastguard Worker<!DOCTYPE html>
2*288bf522SAndroid Build Coastguard Worker<!--
3*288bf522SAndroid Build Coastguard WorkerCopyright (C) 2015 The Android Open Source Project
4*288bf522SAndroid Build Coastguard Worker
5*288bf522SAndroid Build Coastguard WorkerLicensed under the Apache License, Version 2.0 (the "License");
6*288bf522SAndroid Build Coastguard Workeryou may not use this file except in compliance with the License.
7*288bf522SAndroid Build Coastguard WorkerYou may obtain a copy of the License at
8*288bf522SAndroid Build Coastguard Worker
9*288bf522SAndroid Build Coastguard Worker     http://www.apache.org/licenses/LICENSE-2.0
10*288bf522SAndroid Build Coastguard Worker
11*288bf522SAndroid Build Coastguard WorkerUnless required by applicable law or agreed to in writing, software
12*288bf522SAndroid Build Coastguard Workerdistributed under the License is distributed on an "AS IS" BASIS,
13*288bf522SAndroid Build Coastguard WorkerWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14*288bf522SAndroid Build Coastguard WorkerSee the License for the specific language governing permissions and
15*288bf522SAndroid Build Coastguard Workerlimitations under the License.
16*288bf522SAndroid Build Coastguard Worker-->
17*288bf522SAndroid Build Coastguard Worker<link rel="import" href="/tracing/base/base.html">
18*288bf522SAndroid Build Coastguard Worker<link rel="import" href="/tracing/extras/importer/linux_perf/ftrace_importer.html">
19*288bf522SAndroid Build Coastguard Worker<link rel="import" href="/tracing/extras/importer/android/event_log_importer.html">
20*288bf522SAndroid Build Coastguard Worker<link rel="import" href="/tracing/extras/android/android_auditor.html">
21*288bf522SAndroid Build Coastguard Worker<link rel="import" href="/tracing/importer/import.html">
22*288bf522SAndroid Build Coastguard Worker<link rel="import" href="/tracing/model/model.html">
23*288bf522SAndroid Build Coastguard Worker<script>
24*288bf522SAndroid Build Coastguard Worker'use strict';
25*288bf522SAndroid Build Coastguard Worker
26*288bf522SAndroid Build Coastguard Worker(function() {
27*288bf522SAndroid Build Coastguard Worker  var FRAME_PERF_CLASS = tr.model.FRAME_PERF_CLASS;
28*288bf522SAndroid Build Coastguard Worker
29*288bf522SAndroid Build Coastguard Worker  if (!tr.isHeadless) {
30*288bf522SAndroid Build Coastguard Worker    throw new Error('Can only run in headless mode.');
31*288bf522SAndroid Build Coastguard Worker  }
32*288bf522SAndroid Build Coastguard Worker
33*288bf522SAndroid Build Coastguard Worker  function printFrameStats(process, range) {
34*288bf522SAndroid Build Coastguard Worker    var goodFrames = 0;
35*288bf522SAndroid Build Coastguard Worker    var badFrames = 0;
36*288bf522SAndroid Build Coastguard Worker    var neutralFrames = 0;
37*288bf522SAndroid Build Coastguard Worker    var terribleFrames = 0;
38*288bf522SAndroid Build Coastguard Worker
39*288bf522SAndroid Build Coastguard Worker    process.frames.forEach(function(frame) {
40*288bf522SAndroid Build Coastguard Worker      // Check if frame belongs to any activity
41*288bf522SAndroid Build Coastguard Worker      if (frame.start >= range.min && (frame.end <= range.max)) {
42*288bf522SAndroid Build Coastguard Worker        if (frame.perfClass == FRAME_PERF_CLASS.NEUTRAL) neutralFrames++;
43*288bf522SAndroid Build Coastguard Worker        if (frame.perfClass == FRAME_PERF_CLASS.GOOD) goodFrames++;
44*288bf522SAndroid Build Coastguard Worker        if (frame.perfClass == FRAME_PERF_CLASS.BAD) badFrames++;
45*288bf522SAndroid Build Coastguard Worker        if (frame.perfClass == FRAME_PERF_CLASS.TERRIBLE) terribleFrames++;
46*288bf522SAndroid Build Coastguard Worker      }
47*288bf522SAndroid Build Coastguard Worker    });
48*288bf522SAndroid Build Coastguard Worker
49*288bf522SAndroid Build Coastguard Worker    var totalFrames = goodFrames + badFrames + neutralFrames;
50*288bf522SAndroid Build Coastguard Worker    if (totalFrames > 0) {
51*288bf522SAndroid Build Coastguard Worker      console.log("  Frame stats:");
52*288bf522SAndroid Build Coastguard Worker      console.log("    # Total frames: " + totalFrames);
53*288bf522SAndroid Build Coastguard Worker      console.log("    # Terrible frames: " + terribleFrames);
54*288bf522SAndroid Build Coastguard Worker      console.log("    # Bad frames: " + badFrames);
55*288bf522SAndroid Build Coastguard Worker      console.log("    # Neutral frames: " + neutralFrames);
56*288bf522SAndroid Build Coastguard Worker      console.log("    # Good frames: " + goodFrames);
57*288bf522SAndroid Build Coastguard Worker    }
58*288bf522SAndroid Build Coastguard Worker  };
59*288bf522SAndroid Build Coastguard Worker
60*288bf522SAndroid Build Coastguard Worker  function printMemoryStats(process, range) {
61*288bf522SAndroid Build Coastguard Worker    var numDirectReclaim = 0;
62*288bf522SAndroid Build Coastguard Worker    for (var tid in process.threads) {
63*288bf522SAndroid Build Coastguard Worker      if (!process.threads[tid].timeSlices) continue;
64*288bf522SAndroid Build Coastguard Worker      process.threads[tid].sliceGroup.slices.forEach(function(slice) {
65*288bf522SAndroid Build Coastguard Worker        if (slice.title.startsWith('direct reclaim')) {
66*288bf522SAndroid Build Coastguard Worker          if (slice.start >= range.min &&
67*288bf522SAndroid Build Coastguard Worker              slice.start + slice.duration <= range.max) {
68*288bf522SAndroid Build Coastguard Worker            numDirectReclaim++;
69*288bf522SAndroid Build Coastguard Worker          }
70*288bf522SAndroid Build Coastguard Worker        }
71*288bf522SAndroid Build Coastguard Worker      });
72*288bf522SAndroid Build Coastguard Worker    }
73*288bf522SAndroid Build Coastguard Worker    console.log("  Memory stats:");
74*288bf522SAndroid Build Coastguard Worker    console.log("    # of direct reclaims: " + numDirectReclaim);
75*288bf522SAndroid Build Coastguard Worker  };
76*288bf522SAndroid Build Coastguard Worker
77*288bf522SAndroid Build Coastguard Worker  function printCpuStatsForThread(thread, range) {
78*288bf522SAndroid Build Coastguard Worker    var stats = thread.getCpuStatsForRange(range);
79*288bf522SAndroid Build Coastguard Worker    // Sum total CPU duration
80*288bf522SAndroid Build Coastguard Worker    console.log('    ' + thread.name + ' CPU allocation: ');
81*288bf522SAndroid Build Coastguard Worker    for (var cpu in stats) {
82*288bf522SAndroid Build Coastguard Worker      var percentage = (stats[cpu] / stats.total * 100).toFixed(2);
83*288bf522SAndroid Build Coastguard Worker
84*288bf522SAndroid Build Coastguard Worker      console.log("      CPU " + cpu + ": " + percentage + "% (" +
85*288bf522SAndroid Build Coastguard Worker          stats[cpu].toFixed(2) + " ms.)");
86*288bf522SAndroid Build Coastguard Worker    }
87*288bf522SAndroid Build Coastguard Worker  };
88*288bf522SAndroid Build Coastguard Worker
89*288bf522SAndroid Build Coastguard Worker  function printCpuStatsForProcess(process, range) {
90*288bf522SAndroid Build Coastguard Worker    var total_runtime = 0;
91*288bf522SAndroid Build Coastguard Worker    for (var tid in process.threads) {
92*288bf522SAndroid Build Coastguard Worker      var stats = process.threads[tid].getCpuStatsForRange(range);
93*288bf522SAndroid Build Coastguard Worker      total_runtime += stats.total;
94*288bf522SAndroid Build Coastguard Worker    }
95*288bf522SAndroid Build Coastguard Worker    console.log("  CPU stats:");
96*288bf522SAndroid Build Coastguard Worker    console.log("    Total CPU runtime: " + total_runtime.toFixed(2) + " ms.");
97*288bf522SAndroid Build Coastguard Worker    var uiThread = process.getThread(process.pid);
98*288bf522SAndroid Build Coastguard Worker    var renderThreads = process.findAllThreadsNamed('RenderThread');
99*288bf522SAndroid Build Coastguard Worker    var renderThread = renderThreads.length == 1 ? renderThreads[0] : undefined;
100*288bf522SAndroid Build Coastguard Worker    if (uiThread)
101*288bf522SAndroid Build Coastguard Worker      printCpuStatsForThread(uiThread, range);
102*288bf522SAndroid Build Coastguard Worker    if (renderThread)
103*288bf522SAndroid Build Coastguard Worker      printCpuStatsForThread(renderThread, range);
104*288bf522SAndroid Build Coastguard Worker    printCpuFreqStats(range);
105*288bf522SAndroid Build Coastguard Worker  };
106*288bf522SAndroid Build Coastguard Worker
107*288bf522SAndroid Build Coastguard Worker  function printCpuFreqStats(range) {
108*288bf522SAndroid Build Coastguard Worker    for (var i = 0; i < 8; i++) {
109*288bf522SAndroid Build Coastguard Worker      var cpu = model.kernel.getOrCreateCpu(i);
110*288bf522SAndroid Build Coastguard Worker      if (cpu !== undefined) {
111*288bf522SAndroid Build Coastguard Worker        var stats = cpu.getFreqStatsForRange(range);
112*288bf522SAndroid Build Coastguard Worker
113*288bf522SAndroid Build Coastguard Worker        console.log('    CPU ' + i + ' frequency distribution:');
114*288bf522SAndroid Build Coastguard Worker        for (var freq in stats) {
115*288bf522SAndroid Build Coastguard Worker          var percentage = (stats[freq] / range.duration * 100).toFixed(2);
116*288bf522SAndroid Build Coastguard Worker          console.log('      ' + freq + ' ' + percentage + "% (" +
117*288bf522SAndroid Build Coastguard Worker              stats[freq].toFixed(2)  + ' ms.)');
118*288bf522SAndroid Build Coastguard Worker        }
119*288bf522SAndroid Build Coastguard Worker      }
120*288bf522SAndroid Build Coastguard Worker    }
121*288bf522SAndroid Build Coastguard Worker  };
122*288bf522SAndroid Build Coastguard Worker
123*288bf522SAndroid Build Coastguard Worker  function printBinderStats(process, range) {
124*288bf522SAndroid Build Coastguard Worker    var outgoing_transactions = 0;
125*288bf522SAndroid Build Coastguard Worker    var incoming_transactions = 0;
126*288bf522SAndroid Build Coastguard Worker    for (var tid in process.threads) {
127*288bf522SAndroid Build Coastguard Worker      var outgoing_slices = process.threads[tid].sliceGroup.getSlicesOfName('binder transaction');
128*288bf522SAndroid Build Coastguard Worker      var outgoing_async_slices = process.threads[tid].sliceGroup.getSlicesOfName('binder transaction async');
129*288bf522SAndroid Build Coastguard Worker      var incoming_slices = process.threads[tid].sliceGroup.getSlicesOfName('binder reply');
130*288bf522SAndroid Build Coastguard Worker      var incoming_async_slices = process.threads[tid].sliceGroup.getSlicesOfName('binder Async recv');
131*288bf522SAndroid Build Coastguard Worker      outgoing_transactions += outgoing_slices.length + outgoing_async_slices.length;
132*288bf522SAndroid Build Coastguard Worker      incoming_transactions += incoming_slices.length + incoming_async_slices.length;
133*288bf522SAndroid Build Coastguard Worker    }
134*288bf522SAndroid Build Coastguard Worker    console.log('  Binder transaction stats:');
135*288bf522SAndroid Build Coastguard Worker    console.log('    # Outgoing binder transactions: ' + outgoing_transactions);
136*288bf522SAndroid Build Coastguard Worker    console.log('    # Incoming binder transactions: ' + incoming_transactions);
137*288bf522SAndroid Build Coastguard Worker  };
138*288bf522SAndroid Build Coastguard Worker
139*288bf522SAndroid Build Coastguard Worker  function pagesInMBString(pages) {
140*288bf522SAndroid Build Coastguard Worker    if (isNaN(pages))
141*288bf522SAndroid Build Coastguard Worker      return '0 (0.00 MB)';
142*288bf522SAndroid Build Coastguard Worker    return pages + ' (' + (pages * 4096 / 1024 / 1024).toFixed(2) + ' MB)';
143*288bf522SAndroid Build Coastguard Worker  };
144*288bf522SAndroid Build Coastguard Worker
145*288bf522SAndroid Build Coastguard Worker  function printPageCacheStats(process) {
146*288bf522SAndroid Build Coastguard Worker    console.log('  Page cache stats:');
147*288bf522SAndroid Build Coastguard Worker    var totalAccess = 0;
148*288bf522SAndroid Build Coastguard Worker    var totalMiss = 0;
149*288bf522SAndroid Build Coastguard Worker    var totalAdd = 0;
150*288bf522SAndroid Build Coastguard Worker    for (var file in process.pageCacheAccesses) {
151*288bf522SAndroid Build Coastguard Worker      totalAccess += process.pageCacheAccesses[file];
152*288bf522SAndroid Build Coastguard Worker      totalMiss += process.pageCacheMisses[file];
153*288bf522SAndroid Build Coastguard Worker      totalAdd += process.pageCacheAdd[file];
154*288bf522SAndroid Build Coastguard Worker      console.log('    File: ' + file);
155*288bf522SAndroid Build Coastguard Worker      console.log('        # of pages accessed: ' + pagesInMBString(process.pageCacheAccesses[file]));
156*288bf522SAndroid Build Coastguard Worker      console.log('        # of pages missed: ' + pagesInMBString(process.pageCacheMisses[file]));
157*288bf522SAndroid Build Coastguard Worker      console.log('        # of pages added to cache: ' + pagesInMBString(process.pageCacheAdd[file]));
158*288bf522SAndroid Build Coastguard Worker    }
159*288bf522SAndroid Build Coastguard Worker    console.log('    TOTALS:');
160*288bf522SAndroid Build Coastguard Worker    console.log('        # of pages accessed: ' + pagesInMBString(totalAccess));
161*288bf522SAndroid Build Coastguard Worker    console.log('        # of pages missed: ' + pagesInMBString(totalMiss));
162*288bf522SAndroid Build Coastguard Worker    console.log('        # of pages added to cache: ' + pagesInMBString(totalAdd));
163*288bf522SAndroid Build Coastguard Worker  };
164*288bf522SAndroid Build Coastguard Worker
165*288bf522SAndroid Build Coastguard Worker  function printProcessStats(process, opt_range) {
166*288bf522SAndroid Build Coastguard Worker    var range = opt_range;
167*288bf522SAndroid Build Coastguard Worker    if (range === undefined) {
168*288bf522SAndroid Build Coastguard Worker      // Use the process range
169*288bf522SAndroid Build Coastguard Worker      range = process.bounds;
170*288bf522SAndroid Build Coastguard Worker    }
171*288bf522SAndroid Build Coastguard Worker    printCpuStatsForProcess(process, range);
172*288bf522SAndroid Build Coastguard Worker    printPageCacheStats(process);
173*288bf522SAndroid Build Coastguard Worker    printMemoryStats(process, range);
174*288bf522SAndroid Build Coastguard Worker    printBinderStats(process, range);
175*288bf522SAndroid Build Coastguard Worker    printFrameStats(process, range);
176*288bf522SAndroid Build Coastguard Worker  };
177*288bf522SAndroid Build Coastguard Worker
178*288bf522SAndroid Build Coastguard Worker  if (sys.argv.length < 2)
179*288bf522SAndroid Build Coastguard Worker    console.log('First argument needs to be a systrace file.');
180*288bf522SAndroid Build Coastguard Worker
181*288bf522SAndroid Build Coastguard Worker  // Import model
182*288bf522SAndroid Build Coastguard Worker  var systrace = read(sys.argv[1]);
183*288bf522SAndroid Build Coastguard Worker  var traces = [systrace];
184*288bf522SAndroid Build Coastguard Worker  if (sys.argv.length >= 3) {
185*288bf522SAndroid Build Coastguard Worker    // Add event log file if we got it
186*288bf522SAndroid Build Coastguard Worker    var events = read(sys.argv[2]);
187*288bf522SAndroid Build Coastguard Worker    traces.push(events);
188*288bf522SAndroid Build Coastguard Worker  }
189*288bf522SAndroid Build Coastguard Worker  var model = new tr.Model();
190*288bf522SAndroid Build Coastguard Worker  var i = new tr.importer.Import(model);
191*288bf522SAndroid Build Coastguard Worker  console.log("Starting import...");
192*288bf522SAndroid Build Coastguard Worker  i.importTraces(traces);
193*288bf522SAndroid Build Coastguard Worker  console.log("Done.");
194*288bf522SAndroid Build Coastguard Worker  model.getAllProcesses().forEach(function(process) {
195*288bf522SAndroid Build Coastguard Worker    if (process.name === undefined) return;
196*288bf522SAndroid Build Coastguard Worker    console.log('Stats for process ' + process.name + ' (' + process.pid + ')');
197*288bf522SAndroid Build Coastguard Worker    // Check if process has activity starts
198*288bf522SAndroid Build Coastguard Worker    if (process.activities && process.activities.length > 0) {
199*288bf522SAndroid Build Coastguard Worker      process.activities.forEach(function(activity) {
200*288bf522SAndroid Build Coastguard Worker        console.log('Activity ' + activity.name + ' foreground from ' +
201*288bf522SAndroid Build Coastguard Worker            activity.start + ' until ' + activity.end);
202*288bf522SAndroid Build Coastguard Worker        var activityRange = tr.b.Range.fromExplicitRange(activity.start,
203*288bf522SAndroid Build Coastguard Worker            activity.start + activity.duration);
204*288bf522SAndroid Build Coastguard Worker        printProcessStats(process, activityRange);
205*288bf522SAndroid Build Coastguard Worker      }, this);
206*288bf522SAndroid Build Coastguard Worker    } else {
207*288bf522SAndroid Build Coastguard Worker      printProcessStats(process);
208*288bf522SAndroid Build Coastguard Worker    }
209*288bf522SAndroid Build Coastguard Worker    console.log('');
210*288bf522SAndroid Build Coastguard Worker  });
211*288bf522SAndroid Build Coastguard Worker})();
212*288bf522SAndroid Build Coastguard Worker</script>
213