OSDN Git Service

am ba6c98db: am 82943ecf: am d40c93f6: Merge "Add dependency generation to Aapt for...
[android-x86/frameworks-base.git] / tools / velocityplot / velocityplot.py
1 #!/usr/bin/env python2.6
2 #
3 # Copyright (C) 2011 The Android Open Source Project
4 #
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
8 #
9 #      http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16 #
17
18 #
19 # Plots debug log output from VelocityTracker.
20 # Enable DEBUG_VELOCITY to print the output.
21 #
22 # This code supports side-by-side comparison of two algorithms.
23 # The old algorithm should be modified to emit debug log messages containing
24 # the word "OLD".
25 #
26
27 import numpy as np
28 import matplotlib.pyplot as plot
29 import subprocess
30 import re
31 import fcntl
32 import os
33 import errno
34 import bisect
35 from datetime import datetime, timedelta
36
37 # Parameters.
38 timespan = 15 # seconds total span shown
39 scrolljump = 5 # seconds jump when scrolling
40 timeticks = 1 # seconds between each time tick
41
42 # Non-blocking stream wrapper.
43 class NonBlockingStream:
44   def __init__(self, stream):
45     fcntl.fcntl(stream, fcntl.F_SETFL, os.O_NONBLOCK)
46     self.stream = stream
47     self.buffer = ''
48     self.pos = 0
49
50   def readline(self):
51     while True:
52       index = self.buffer.find('\n', self.pos)
53       if index != -1:
54         result = self.buffer[self.pos:index]
55         self.pos = index + 1
56         return result
57
58       self.buffer = self.buffer[self.pos:]
59       self.pos = 0
60       try:
61         chunk = os.read(self.stream.fileno(), 4096)
62       except OSError, e:
63         if e.errno == errno.EAGAIN:
64           return None
65         raise e
66       if len(chunk) == 0:
67         if len(self.buffer) == 0:
68           raise(EOFError)
69         else:
70           result = self.buffer
71           self.buffer = ''
72           self.pos = 0
73           return result
74       self.buffer += chunk
75
76 # Plotter
77 class Plotter:
78   def __init__(self, adbout):
79     self.adbout = adbout
80
81     self.fig = plot.figure(1)
82     self.fig.suptitle('Velocity Tracker', fontsize=12)
83     self.fig.set_dpi(96)
84     self.fig.set_size_inches(16, 12, forward=True)
85
86     self.velocity_x = self._make_timeseries()
87     self.velocity_y = self._make_timeseries()
88     self.velocity_magnitude = self._make_timeseries()
89     self.velocity_axes = self._add_timeseries_axes(
90         1, 'Velocity', 'px/s', [-5000, 5000],
91         yticks=range(-5000, 5000, 1000))
92     self.velocity_line_x = self._add_timeseries_line(
93         self.velocity_axes, 'vx', 'red')
94     self.velocity_line_y = self._add_timeseries_line(
95         self.velocity_axes, 'vy', 'green')
96     self.velocity_line_magnitude = self._add_timeseries_line(
97         self.velocity_axes, 'magnitude', 'blue')
98     self._add_timeseries_legend(self.velocity_axes)
99
100     shared_axis = self.velocity_axes
101
102     self.old_velocity_x = self._make_timeseries()
103     self.old_velocity_y = self._make_timeseries()
104     self.old_velocity_magnitude = self._make_timeseries()
105     self.old_velocity_axes = self._add_timeseries_axes(
106         2, 'Old Algorithm Velocity', 'px/s', [-5000, 5000],
107         sharex=shared_axis,
108         yticks=range(-5000, 5000, 1000))
109     self.old_velocity_line_x = self._add_timeseries_line(
110         self.old_velocity_axes, 'vx', 'red')
111     self.old_velocity_line_y = self._add_timeseries_line(
112         self.old_velocity_axes, 'vy', 'green')
113     self.old_velocity_line_magnitude = self._add_timeseries_line(
114         self.old_velocity_axes, 'magnitude', 'blue')
115     self._add_timeseries_legend(self.old_velocity_axes)
116
117     self.timer = self.fig.canvas.new_timer(interval=100)
118     self.timer.add_callback(lambda: self.update())
119     self.timer.start()
120
121     self.timebase = None
122     self._reset_parse_state()
123
124   # Initialize a time series.
125   def _make_timeseries(self):
126     return [[], []]
127
128   # Add a subplot to the figure for a time series.
129   def _add_timeseries_axes(self, index, title, ylabel, ylim, yticks, sharex=None):
130     num_graphs = 2
131     height = 0.9 / num_graphs
132     top = 0.95 - height * index
133     axes = self.fig.add_axes([0.1, top, 0.8, height],
134         xscale='linear',
135         xlim=[0, timespan],
136         ylabel=ylabel,
137         yscale='linear',
138         ylim=ylim,
139         sharex=sharex)
140     axes.text(0.02, 0.02, title, transform=axes.transAxes, fontsize=10, fontweight='bold')
141     axes.set_xlabel('time (s)', fontsize=10, fontweight='bold')
142     axes.set_ylabel(ylabel, fontsize=10, fontweight='bold')
143     axes.set_xticks(range(0, timespan + 1, timeticks))
144     axes.set_yticks(yticks)
145     axes.grid(True)
146
147     for label in axes.get_xticklabels():
148       label.set_fontsize(9)
149     for label in axes.get_yticklabels():
150       label.set_fontsize(9)
151
152     return axes
153
154   # Add a line to the axes for a time series.
155   def _add_timeseries_line(self, axes, label, color, linewidth=1):
156     return axes.plot([], label=label, color=color, linewidth=linewidth)[0]
157
158   # Add a legend to a time series.
159   def _add_timeseries_legend(self, axes):
160     axes.legend(
161         loc='upper left',
162         bbox_to_anchor=(1.01, 1),
163         borderpad=0.1,
164         borderaxespad=0.1,
165         prop={'size': 10})
166
167   # Resets the parse state.
168   def _reset_parse_state(self):
169     self.parse_velocity_x = None
170     self.parse_velocity_y = None
171     self.parse_velocity_magnitude = None
172     self.parse_old_velocity_x = None
173     self.parse_old_velocity_y = None
174     self.parse_old_velocity_magnitude = None
175
176   # Update samples.
177   def update(self):
178     timeindex = 0
179     while True:
180       try:
181         line = self.adbout.readline()
182       except EOFError:
183         plot.close()
184         return
185       if line is None:
186         break
187       print line
188
189       try:
190         timestamp = self._parse_timestamp(line)
191       except ValueError, e:
192         continue
193       if self.timebase is None:
194         self.timebase = timestamp
195       delta = timestamp - self.timebase
196       timeindex = delta.seconds + delta.microseconds * 0.000001
197
198       if line.find(': position') != -1:
199         self.parse_velocity_x = self._get_following_number(line, 'vx=')
200         self.parse_velocity_y = self._get_following_number(line, 'vy=')
201         self.parse_velocity_magnitude = self._get_following_number(line, 'speed=')
202         self._append(self.velocity_x, timeindex, self.parse_velocity_x)
203         self._append(self.velocity_y, timeindex, self.parse_velocity_y)
204         self._append(self.velocity_magnitude, timeindex, self.parse_velocity_magnitude)
205
206       if line.find(': OLD') != -1:
207         self.parse_old_velocity_x = self._get_following_number(line, 'vx=')
208         self.parse_old_velocity_y = self._get_following_number(line, 'vy=')
209         self.parse_old_velocity_magnitude = self._get_following_number(line, 'speed=')
210         self._append(self.old_velocity_x, timeindex, self.parse_old_velocity_x)
211         self._append(self.old_velocity_y, timeindex, self.parse_old_velocity_y)
212         self._append(self.old_velocity_magnitude, timeindex, self.parse_old_velocity_magnitude)
213
214     # Scroll the plots.
215     if timeindex > timespan:
216       bottom = int(timeindex) - timespan + scrolljump
217       self.timebase += timedelta(seconds=bottom)
218       self._scroll(self.velocity_x, bottom)
219       self._scroll(self.velocity_y, bottom)
220       self._scroll(self.velocity_magnitude, bottom)
221       self._scroll(self.old_velocity_x, bottom)
222       self._scroll(self.old_velocity_y, bottom)
223       self._scroll(self.old_velocity_magnitude, bottom)
224
225     # Redraw the plots.
226     self.velocity_line_x.set_data(self.velocity_x)
227     self.velocity_line_y.set_data(self.velocity_y)
228     self.velocity_line_magnitude.set_data(self.velocity_magnitude)
229     self.old_velocity_line_x.set_data(self.old_velocity_x)
230     self.old_velocity_line_y.set_data(self.old_velocity_y)
231     self.old_velocity_line_magnitude.set_data(self.old_velocity_magnitude)
232
233     self.fig.canvas.draw_idle()
234
235   # Scroll a time series.
236   def _scroll(self, timeseries, bottom):
237     bottom_index = bisect.bisect_left(timeseries[0], bottom)
238     del timeseries[0][:bottom_index]
239     del timeseries[1][:bottom_index]
240     for i, timeindex in enumerate(timeseries[0]):
241       timeseries[0][i] = timeindex - bottom
242
243   # Extract a word following the specified prefix.
244   def _get_following_word(self, line, prefix):
245     prefix_index = line.find(prefix)
246     if prefix_index == -1:
247       return None
248     start_index = prefix_index + len(prefix)
249     delim_index = line.find(',', start_index)
250     if delim_index == -1:
251       return line[start_index:]
252     else:
253       return line[start_index:delim_index]
254
255   # Extract a number following the specified prefix.
256   def _get_following_number(self, line, prefix):
257     word = self._get_following_word(line, prefix)
258     if word is None:
259       return None
260     return float(word)
261
262   # Add a value to a time series.
263   def _append(self, timeseries, timeindex, number):
264     timeseries[0].append(timeindex)
265     timeseries[1].append(number)
266
267   # Parse the logcat timestamp.
268   # Timestamp has the form '01-21 20:42:42.930'
269   def _parse_timestamp(self, line):
270     return datetime.strptime(line[0:18], '%m-%d %H:%M:%S.%f')
271
272 # Notice
273 print "Velocity Tracker plotting tool"
274 print "-----------------------------------------\n"
275 print "Please enable debug logging and recompile the code."
276
277 # Start adb.
278 print "Starting adb logcat.\n"
279
280 adb = subprocess.Popen(['adb', 'logcat', '-s', '-v', 'time', 'Input:*', 'VelocityTracker:*'],
281     stdout=subprocess.PIPE)
282 adbout = NonBlockingStream(adb.stdout)
283
284 # Prepare plotter.
285 plotter = Plotter(adbout)
286 plotter.update()
287
288 # Main loop.
289 plot.show()