mirror of
https://github.com/ARM-software/devlib.git
synced 2025-02-07 13:40:48 +00:00
rendering: Add surfaceflinger frame collector
Add a FrameCollector implementation that utilizes the output from surfaceflinger (the Android compositor). This is is the only method for accessing rendering data on older Android devices.
This commit is contained in:
parent
4adefecb55
commit
2b3cee6a7e
@ -15,6 +15,9 @@ from devlib.exception import WorkerThreadError, TargetNotRespondingError, Timeo
|
|||||||
|
|
||||||
logger = logging.getLogger('rendering')
|
logger = logging.getLogger('rendering')
|
||||||
|
|
||||||
|
SurfaceFlingerFrame = namedtuple('SurfaceFlingerFrame',
|
||||||
|
'desired_present_time actual_present_time frame_ready_time')
|
||||||
|
|
||||||
|
|
||||||
class FrameCollector(threading.Thread):
|
class FrameCollector(threading.Thread):
|
||||||
|
|
||||||
@ -99,6 +102,57 @@ class FrameCollector(threading.Thread):
|
|||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
class SurfaceFlingerFrameCollector(FrameCollector):
|
||||||
|
|
||||||
|
def __init__(self, target, period, view, header=None):
|
||||||
|
super(SurfaceFlingerFrameCollector, self).__init__(target, period)
|
||||||
|
self.view = view
|
||||||
|
self.header = header or SurfaceFlingerFrame._fields
|
||||||
|
|
||||||
|
def collect_frames(self, wfh):
|
||||||
|
for activity in self.list():
|
||||||
|
if activity == self.view:
|
||||||
|
wfh.write(self.get_latencies(activity))
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.target.execute('dumpsys SurfaceFlinger --latency-clear ')
|
||||||
|
|
||||||
|
def get_latencies(self, activity):
|
||||||
|
cmd = 'dumpsys SurfaceFlinger --latency "{}"'
|
||||||
|
return self.target.execute(cmd.format(activity))
|
||||||
|
|
||||||
|
def list(self):
|
||||||
|
return self.target.execute('dumpsys SurfaceFlinger --list').split('\r\n')
|
||||||
|
|
||||||
|
def _process_raw_file(self, fh):
|
||||||
|
text = fh.read().replace('\r\n', '\n').replace('\r', '\n')
|
||||||
|
for line in text.split('\n'):
|
||||||
|
line = line.strip()
|
||||||
|
if line:
|
||||||
|
self._process_trace_line(line)
|
||||||
|
|
||||||
|
def _process_trace_line(self, line):
|
||||||
|
parts = line.split()
|
||||||
|
if len(parts) == 3:
|
||||||
|
frame = SurfaceFlingerFrame(*map(int, parts))
|
||||||
|
if not frame.frame_ready_time:
|
||||||
|
return # "null" frame
|
||||||
|
if frame.frame_ready_time <= self.last_ready_time:
|
||||||
|
return # duplicate frame
|
||||||
|
if (frame.frame_ready_time - frame.desired_present_time) > self.drop_threshold:
|
||||||
|
logger.debug('Dropping bogus frame {}.'.format(line))
|
||||||
|
return # bogus data
|
||||||
|
self.last_ready_time = frame.frame_ready_time
|
||||||
|
self.frames.append(frame)
|
||||||
|
elif len(parts) == 1:
|
||||||
|
self.refresh_period = int(parts[0])
|
||||||
|
self.drop_threshold = self.refresh_period * 1000
|
||||||
|
elif 'SurfaceFlinger appears to be unresponsive, dumping anyways' in line:
|
||||||
|
self.unresponsive_count += 1
|
||||||
|
else:
|
||||||
|
logger.warning('Unexpected SurfaceFlinger dump output: {}'.format(line))
|
||||||
|
|
||||||
|
|
||||||
def read_gfxinfo_columns(target):
|
def read_gfxinfo_columns(target):
|
||||||
output = target.execute('dumpsys gfxinfo --list framestats')
|
output = target.execute('dumpsys gfxinfo --list framestats')
|
||||||
lines = iter(output.split('\n'))
|
lines = iter(output.split('\n'))
|
||||||
|
Loading…
x
Reference in New Issue
Block a user