1# SPDX-License-Identifier: Apache-2.0 2# 3# Copyright (C) 2017, ARM Limited and contributors. 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); you may 6# 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, WITHOUT 13# 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# Parser for dumpsys gfxinfo output 18 19import ast, re 20 21def get_value(token): 22 try: 23 v = ast.literal_eval(token) 24 except: 25 return token 26 return v 27 28class GfxInfo(object): 29 """ 30 Class for parsing and accessing GfxInfo output 31 """ 32 __properties = {} 33 34 def __init__(self, path): 35 """ 36 Initialize gfxinfo parser object 37 38 :param path: Path to file containing output of gfxinfo 39 """ 40 self.path = path 41 self.parse_gfxinfo() 42 43 def parse_gfxinfo(self): 44 """ 45 Parser for gfxinfo output, creates a name/value pair 46 """ 47 with open(self.path) as f: 48 content = f.readlines() 49 50 parsing_histogram = False 51 52 # gfxinfo has several statistics of the format 53 # <string>: <value> 54 for line in content: 55 line = line.rstrip() 56 # Ignore any lines that aren't of this format 57 if not ':' in line or line.endswith(':'): 58 continue 59 60 tokens = line.split(':') 61 # convert <string> into a key by replacing spaces with '_' 62 tokens = [t.strip() for t in tokens] 63 tokens[0] = tokens[0].replace(' ', '_').lower() 64 65 # Parse janky_frames. Ex: "Janky frames: 44 (26.99%)" 66 if tokens[0] == 'janky_frames': 67 (frames, pc) = tokens[1].split(' ') 68 self.__properties["janky_frames"] = get_value(frames) 69 pc = re.sub('[\(\)\%]', '', pc) 70 self.__properties["janky_frames_pc"] = get_value(pc) 71 continue 72 # Parse 'nth_percentile: <int>ms' into nth_percentile_ms=<int> 73 if tokens[1].endswith('ms'): 74 tokens[0] = tokens[0] + '_ms' 75 tokens[1] = tokens[1][:-2] 76 # Begin parsing the histogram of frame times 77 if tokens[0] == 'histogram': 78 parsing_histogram = True 79 self.__properties['histogram'] = [] 80 line = line[11:] 81 # Extracts the frame time data into an array of tuples 82 # Ex: 5ms=50 6ms=60 7ms=70 ... -> [(5, 50), (6, 60), (7, 70), ...] 83 if parsing_histogram: 84 h_tokens = [x.rstrip() for x in line.split(' ')] 85 if 'ms=' in line: 86 for h_value in [x.split('=') for x in h_tokens]: 87 self.__properties['histogram'].append((int(h_value[0][:-2]), int(h_value[1]))) 88 else: 89 parsing_histogram = False 90 continue 91 92 # Regular parsing 93 self.__properties[tokens[0]] = get_value(tokens[1]) 94 95 def __dir__(self): 96 """ 97 List all available attributes including ones parsed from 98 gfxinfo output 99 """ 100 return self.__properties.keys() 101 102 def __getattr__(self, name): 103 """ 104 Get the gfxinfo property using the period operator 105 Ex: obj.number_missed_vsync 106 """ 107 return self.__properties[name] 108 109 def __getitem__(self, name): 110 """ 111 Get the gfxinfo property using the [] opertator 112 Useful for attributes like "50th_percentile" that can't 113 be fetched with the period operator 114 """ 115 return self.__properties[name] 116