3 Copyright (C) 2015 The Android Open Source Project
5 Licensed under the Apache License, Version 2.0 (the "License");
6 you may not use this file except in compliance with the License.
7 You may obtain a copy of the License at
9 http://www.apache.org/licenses/LICENSE-2.0
11 Unless required by applicable law or agreed to in writing, software
12 distributed under the License is distributed on an "AS IS" BASIS,
13 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 See the License for the specific language governing permissions and
15 limitations under the License.
17 <link rel="import" href="/tracing/base/base.html">
18 <link rel="import" href="/tracing/extras/importer/linux_perf/ftrace_importer.html">
19 <link rel="import" href="/tracing/extras/importer/android/event_log_importer.html">
20 <link rel="import" href="/tracing/extras/android/android_auditor.html">
21 <link rel="import" href="/tracing/importer/import.html">
22 <link rel="import" href="/tracing/model/model.html">
27 var FRAME_PERF_CLASS = tr.model.FRAME_PERF_CLASS;
30 throw new Error('Can only run in headless mode.');
33 function printFrameStats(process, range) {
36 var neutralFrames = 0;
37 var terribleFrames = 0;
39 process.frames.forEach(function(frame) {
40 // Check if frame belongs to any activity
41 if (frame.start >= range.min && (frame.end <= range.max)) {
42 if (frame.perfClass == FRAME_PERF_CLASS.NEUTRAL) neutralFrames++;
43 if (frame.perfClass == FRAME_PERF_CLASS.GOOD) goodFrames++;
44 if (frame.perfClass == FRAME_PERF_CLASS.BAD) badFrames++;
45 if (frame.perfClass == FRAME_PERF_CLASS.TERRIBLE) terribleFrames++;
49 var totalFrames = goodFrames + badFrames + neutralFrames;
50 if (totalFrames > 0) {
51 console.log(" Frame stats:");
52 console.log(" # Total frames: " + totalFrames);
53 console.log(" # Terrible frames: " + terribleFrames);
54 console.log(" # Bad frames: " + badFrames);
55 console.log(" # Neutral frames: " + neutralFrames);
56 console.log(" # Good frames: " + goodFrames);
60 function printMemoryStats(process, range) {
61 var numDirectReclaim = 0;
62 for (var tid in process.threads) {
63 if (!process.threads[tid].timeSlices) continue;
64 process.threads[tid].sliceGroup.slices.forEach(function(slice) {
65 if (slice.title.startsWith('direct reclaim')) {
66 if (slice.start >= range.min &&
67 slice.start + slice.duration <= range.max) {
73 console.log(" Memory stats:");
74 console.log(" # of direct reclaims: " + numDirectReclaim);
77 function printCpuStatsForThread(thread, range) {
78 var stats = thread.getCpuStatsForRange(range);
79 // Sum total CPU duration
80 console.log(' ' + thread.name + ' CPU allocation: ');
81 for (var cpu in stats) {
82 var percentage = (stats[cpu] / stats.total * 100).toFixed(2);
84 console.log(" CPU " + cpu + ": " + percentage + "% (" +
85 stats[cpu].toFixed(2) + " ms.)");
89 function printCpuStatsForProcess(process, range) {
90 var total_runtime = 0;
91 for (var tid in process.threads) {
92 var stats = process.threads[tid].getCpuStatsForRange(range);
93 total_runtime += stats.total;
95 console.log(" CPU stats:");
96 console.log(" Total CPU runtime: " + total_runtime.toFixed(2) + " ms.");
97 var uiThread = process.getThread(process.pid);
98 var renderThreads = process.findAllThreadsNamed('RenderThread');
99 var renderThread = renderThreads.length == 1 ? renderThreads[0] : undefined;
101 printCpuStatsForThread(uiThread, range);
103 printCpuStatsForThread(renderThread, range);
104 printCpuFreqStats(range);
107 function printCpuFreqStats(range) {
108 for (var i = 0; i < 8; i++) {
109 var cpu = model.kernel.getOrCreateCpu(i);
110 if (cpu !== undefined) {
111 var stats = cpu.getFreqStatsForRange(range);
113 console.log(' CPU ' + i + ' frequency distribution:');
114 for (var freq in stats) {
115 var percentage = (stats[freq] / range.duration * 100).toFixed(2);
116 console.log(' ' + freq + ' ' + percentage + "% (" +
117 stats[freq].toFixed(2) + ' ms.)');
123 function printBinderStats(process, range) {
124 var outgoing_transactions = 0;
125 var incoming_transactions = 0;
126 for (var tid in process.threads) {
127 var outgoing_slices = process.threads[tid].sliceGroup.getSlicesOfName('binder transaction');
128 var outgoing_async_slices = process.threads[tid].sliceGroup.getSlicesOfName('binder transaction async');
129 var incoming_slices = process.threads[tid].sliceGroup.getSlicesOfName('binder reply');
130 var incoming_async_slices = process.threads[tid].sliceGroup.getSlicesOfName('binder Async recv');
131 outgoing_transactions += outgoing_slices.length + outgoing_async_slices.length;
132 incoming_transactions += incoming_slices.length + incoming_async_slices.length;
134 console.log(' Binder transaction stats:');
135 console.log(' # Outgoing binder transactions: ' + outgoing_transactions);
136 console.log(' # Incoming binder transactions: ' + incoming_transactions);
139 function pagesInMBString(pages) {
141 return '0 (0.00 MB)';
142 return pages + ' (' + (pages * 4096 / 1024 / 1024).toFixed(2) + ' MB)';
145 function printPageCacheStats(process) {
146 console.log(' Page cache stats:');
150 for (var file in process.pageCacheAccesses) {
151 totalAccess += process.pageCacheAccesses[file];
152 totalMiss += process.pageCacheMisses[file];
153 totalAdd += process.pageCacheAdd[file];
154 console.log(' File: ' + file);
155 console.log(' # of pages accessed: ' + pagesInMBString(process.pageCacheAccesses[file]));
156 console.log(' # of pages missed: ' + pagesInMBString(process.pageCacheMisses[file]));
157 console.log(' # of pages added to cache: ' + pagesInMBString(process.pageCacheAdd[file]));
159 console.log(' TOTALS:');
160 console.log(' # of pages accessed: ' + pagesInMBString(totalAccess));
161 console.log(' # of pages missed: ' + pagesInMBString(totalMiss));
162 console.log(' # of pages added to cache: ' + pagesInMBString(totalAdd));
165 function printProcessStats(process, opt_range) {
166 var range = opt_range;
167 if (range === undefined) {
168 // Use the process range
169 range = process.bounds;
171 printCpuStatsForProcess(process, range);
172 printPageCacheStats(process);
173 printMemoryStats(process, range);
174 printBinderStats(process, range);
175 printFrameStats(process, range);
178 if (sys.argv.length < 2)
179 console.log('First argument needs to be a systrace file.');
182 var systrace = read(sys.argv[1]);
183 var traces = [systrace];
184 if (sys.argv.length >= 3) {
185 // Add event log file if we got it
186 var events = read(sys.argv[2]);
189 var model = new tr.Model();
190 var i = new tr.importer.Import(model);
191 console.log("Starting import...");
192 i.importTraces(traces);
193 console.log("Done.");
194 model.getAllProcesses().forEach(function(process) {
195 if (process.name === undefined) return;
196 console.log('Stats for process ' + process.name + ' (' + process.pid + ')');
197 // Check if process has activity starts
198 if (process.activities && process.activities.length > 0) {
199 process.activities.forEach(function(activity) {
200 console.log('Activity ' + activity.name + ' foreground from ' +
201 activity.start + ' until ' + activity.end);
202 var activityRange = tr.b.Range.fromExplicitRange(activity.start,
203 activity.start + activity.duration);
204 printProcessStats(process, activityRange);
207 printProcessStats(process);