def __init__(self, library, trace, state): self.library = library self.trace = trace self.state = state self.stateModifiers = [] self.verdict = True self.comments = [] self.constants = Collections.DictProxy(self.library.constants) self.constantNames = Collections.inverseDict(self.library.constants)
def createEventFrequencyPlot(self, title, events, id=0): # Count the number of each event eventFrequency = Collections.DefaultDict(lambda: 0) for event in events: eventFrequency[event.name] += 1 items = eventFrequency.items() items.sort(key=lambda f: -f[1]) funcNames = [f[0] for f in items] funcFreq = [f[1] for f in items] # Create a bar charts and add a text describing the event to each bar pylab.figure() pylab.yticks([]) pylab.ylim(len(funcNames), 0) rects = pylab.barh(range(len(funcNames)), funcFreq, color=self.primaryColor) for name, rect in zip(funcNames, rects): pylab.text(rect.get_x() + rect.get_width(), rect.get_y() + rect.get_height(), " " + name, fontsize=8) fn = os.path.join(self.path, title.lower().replace(" ", "_") + "%03d.png" % id) pylab.savefig(fn) pylab.close() section = Report.Section(title) section.create(Report.Image, fn) return section
def interactivePythonMode(self, fileName=None, *args, **kwargs): """ Run an interactive Python interpreter that can be used to manipulate the loaded traces. @param fileName: Optional Python source file to run @param args: Optional arguments for the source file @param kwargs: Optional keyword arguments for the source file """ # Refresh the analyzer environment module import AnalyzerEnvironment as env env.analyzer = self.analyzer env.project = self.analyzer.project env.args = args env.kwargs = kwargs env.cmd = Collections.DictProxy(self.analyzer.commands) env.traces = Collections.DictProxy(self.analyzer.traces) try: env.library = self.analyzer.project.targets["code"].library env.constants = Collections.DictProxy(env.library.constants) except KeyError: env.library = None env.constants = None try: if fileName: path = os.path.dirname(fileName) moduleName = os.path.splitext(os.path.basename(fileName))[0] if not path in sys.path: sys.path.append(path) if not moduleName in sys.modules: __import__(moduleName) else: reload(sys.modules[moduleName]) else: console = code.InteractiveConsole(locals=env.__dict__) console.interact(banner="Entering Python mode.") except SystemExit: pass
def testInverseDict(self): d1 = {"hip": "hei"} d2 = Collections.inverseDict(d1) assert d2["hei"] == "hip"
def testDictProxy(self): d1 = {"hip": "hei"} d2 = Collections.DictProxy(d1) assert d2.hip == "hei"
def testDefaultDict(self): d = Collections.DefaultDict(lambda: 1) assert d["foo"] == 1 d["foo"] = 2 assert d["foo"] == 2
def getImageLoaders(project, trace): """ Return a list of (event, func) pairs, where event is a image upload event and func is a function that returns an Image containing the image data when called. """ library = project.targets["code"].library constants = Collections.DictProxy(library.constants) loaders = [] formats = { constants.VG_sRGBX_8888: ("b", 4, False, False, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000), constants.VG_sRGBA_8888: ("b", 4, False, False, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000), constants.VG_sRGBA_8888_PRE: ("b", 4, False, True, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000), constants.VG_sRGB_565: ("h", 3, False, False, 0x001f, 0x07e0, 0xf800, 0x0), constants.VG_sRGBA_5551: ("h", 4, False, False, 0x001f, 0x03e0, 0x7c00, 0x8000), constants.VG_sRGBA_4444: ("h", 4, False, False, 0x000f, 0x00f0, 0x0f00, 0xf000), constants.VG_sL_8: ("b", 1, False, False, 0xff, 0x0, 0x0, 0x0), constants.VG_lRGBX_8888: ("b", 4, True, False, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000), constants.VG_lRGBA_8888: ("b", 4, True, False, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000), constants.VG_lRGBA_8888_PRE: ("b", 4, True, True, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000), constants.VG_lL_8: ("b", 1, True, False, 0xff, 0x0, 0x0, 0x0), constants.VG_A_8: ("b", 1, True, False, 0xff, 0x0, 0x0, 0x0), constants.VG_BW_1: ("b", 1, True, False, 0x1, 0x0, 0x0, 0x0), } task = Task.startTask("prepare-images", "Looking for images", len(trace.events)) for event in trace.events: task.step() if event.name == "vgImageSubData" and event.values.get("data"): width = event.values["width"] height = event.values["height"] stride = event.values["dataStride"] format = event.values["dataFormat"] if format in formats: unit, components, isLinear, isPremultiplied, redMask, greenMask, blueMask, alphaMask = formats[ format] else: continue data = event.values["data"] data = struct.pack("<%d%s" % (len(data), unit), *data) size = (width, height) # Construct copies of the passed variables to make sure the proper data goes into the lambda when called func = lambda d=data, s=size, st=stride, rb=redMask, gb=greenMask, bb=blueMask, ab=alphaMask, il=isLinear, ip=isPremultiplied: \ Graphics.decodeImageData(d, s, st, rb, gb, bb, ab, isLinear = il, isPremultiplied = ip) loaders.append((event, func)) return loaders
def calculateStatistics(project, trace): """ Calculate derived OpenVG statistics instrumentation sensor data and trace events. """ if not "code" in project.targets: raise ValueError("No code information in project file") task = Task.startTask("vg-stats", "Calculating OpenVG statistics", len(trace.events)) library = project.targets["code"].library constants = Collections.DictProxy(library.constants) # Create the derived sensors trace.sensors["average_path_size"] = Trace.InstrumentationSensor( "Average path size", isAverage=True) trace.sensors["image_uploads"] = Trace.InstrumentationSensor( "Image uploads") trace.sensors["render_calls"] = Trace.InstrumentationSensor( "Rendering calls") trace.sensors["draw_ratio"] = Trace.InstrumentationSensor("Draw ratio") trace.sensors["path_segments"] = Trace.InstrumentationSensor( "Path segments") trace.sensors["gradient_stops"] = Trace.InstrumentationSensor( "Number of gradient stops defined") prevRenderEvent = None for event in trace.events: task.step() func = library.functions[event.name] if func.isRenderCall: event.sensorData["render_calls"] = 1 if event.name in ["vgSetParameterfv", "vgSetParameteriv"]: if event.values[ "paramType"] == constants.VG_PAINT_COLOR_RAMP_STOPS: event.sensorData["gradient_stops"] = event.values["count"] / 5 fragments = event.sensorData.get("rasterized_pixels", 0) renderCalls = event.sensorData.get("render_calls", 0) if fragments and renderCalls: event.sensorData["average_path_size"] = fragments / float( renderCalls) if event.name == "vgImageSubData" and "width" in event.values and "height" in event.values: event.sensorData["image_uploads"] = int(event.values["width"] * event.values["height"]) if event.name == "vgAppendPathData": event.sensorData["path_segments"] = int( event.values["numSegments"]) width = event.sensorData.get("render_surface_width", 0) height = event.sensorData.get("render_surface_height", 0) if fragments and width and height: event.sensorData["draw_ratio"] = fragments / float(width * height)
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. from AnalyzerEnvironment import * import Common from common import Collections import glob if not args or len(args) < 2: Log.notice("Usage: batch filemask1 [filemask2 ...] command") Log.notice("Repeat the same command sequence for a number of trace files.") Log.notice("") Log.notice("The following variables can be used in the command sequence:") Log.notice(" $t The current trace file name") exit() masks = args[:-1] commands = args[-1] files = Collections.flatten(map(glob.glob, masks)) for i, traceFile in enumerate(files): Log.notice("Processing trace file %d of %d: %s." % (i + 1, len(files), traceFile)) # FIXME: quoting c = commands.replace("$t", "%s" % traceFile) analyzer.execute(c)
def __init__(self, items=None): self.freq = Collections.DefaultDict(lambda: 0) if items: for item in items: self.add(item)
def getTextureLoaders(project, trace): """ Return a list of (event, func) pairs, where event is a texture upload event and func is a function that returns an Image containing the texture data when called. """ library = project.targets["code"].library constants = Collections.DictProxy(library.constants) loaders = [] componentCount = { constants.GL_ALPHA: 1, constants.GL_RGB: 3, constants.GL_RGBA: 4, constants.GL_LUMINANCE: 1, constants.GL_LUMINANCE_ALPHA: 2, } task = Task.startTask("prepare-textures", "Looking for textures", len(trace.events)) for event in trace.events: task.step() # We don't handle compressed texture formats if event.name in ["glTexImage2D", "glTexSubImage2D"] and event.values.get("pixels"): width = event.values["width"] height = event.values["height"] format = event.values["format"] type = event.values["type"] if format in componentCount: components = componentCount[format] else: continue if type == constants.GL_UNSIGNED_BYTE: bytesPerPixel = components format = "b" redMask = 0x00ff0000 greenMask = 0x0000ff00 blueMask = 0x000000ff alphaMask = 0xff000000 elif type == constants.GL_UNSIGNED_SHORT_5_6_5: bytesPerPixel = 2 format = "h" redMask = 0x001f greenMask = 0x07e0 blueMask = 0xf800 alphaMask = 0x0000 elif type == constants.GL_UNSIGNED_SHORT_5_5_5_1: bytesPerPixel = 2 format = "h" redMask = 0x001f greenMask = 0x03e0 blueMask = 0x7c00 alphaMask = 0x8000 elif type == constants.GL_UNSIGNED_SHORT_4_4_4_4: bytesPerPixel = 2 format = "h" redMask = 0x000f greenMask = 0x00f0 blueMask = 0x0f00 alphaMask = 0xf000 else: continue pixels = event.values["pixels"] data = struct.pack("<%d%s" % (len(pixels), format), *pixels) if components < 4: alphaMask = 0 if components < 3: blueMask = 0 if components < 2: greenMask = 0 size = (width, height) stride = width * bytesPerPixel # Construct copies of the passed variables to make sure the proper data goes into the lambda when called func = lambda d=data, s=size, st=stride, rb=redMask, gb=greenMask, bb=blueMask, ab=alphaMask: \ Graphics.decodeImageData(d, s, st, rb, gb, bb, ab) loaders.append((event, func)) return loaders
def calculateStatistics(project, trace): """ Calculate derived OpenGL ES statistics instrumentation sensor data and trace events. """ if not "code" in project.targets: raise ValueError("No code information in project file") task = Task.startTask("gles-stats", "Calculating OpenGL ES statistics", len(trace.events)) library = project.targets["code"].library constants = Collections.DictProxy(library.constants) # Create the derived sensors trace.sensors["average_triangle_size"] = Trace.InstrumentationSensor("Average triangle size", isAverage = True) trace.sensors["texel_fetches_per_pixel"] = Trace.InstrumentationSensor("Texel fetches per pixel", isAverage = True) trace.sensors["texel_uploads"] = Trace.InstrumentationSensor("Texel uploads") trace.sensors["vertices_in"] = Trace.InstrumentationSensor("Vertices in") trace.sensors["triangles_in"] = Trace.InstrumentationSensor("Triangles in") trace.sensors["render_calls"] = Trace.InstrumentationSensor("Rendering calls") trace.sensors["rasterizer_discarded_pixels"] = Trace.InstrumentationSensor("Rasterizer discarded pixels") trace.sensors["draw_ratio"] = Trace.InstrumentationSensor("Draw ratio") prevRenderEvent = None depthMask = 1 for event in trace.events: task.step() func = library.functions[event.name] if func.isRenderCall: event.sensorData["render_calls"] = 1 if func.isRenderCall and "count" in event.values and "mode" in event.values: m = event.values["mode"] if m == constants.GL_TRIANGLES: event.sensorData["triangles_in"] = int(event.values["count"] / 3) elif m == constants.GL_TRIANGLE_STRIP: event.sensorData["triangles_in"] = int(event.values["count"] - 2) elif m == constants.GL_TRIANGLE_FAN: event.sensorData["triangles_in"] = int(event.values["count"] - 2) elif m == constants.GL_POINTS: event.sensorData["triangles_in"] = int(event.values["count"] * 2) elif m == constants.GL_LINES: event.sensorData["triangles_in"] = int(event.values["count"]) elif m == constants.GL_LINE_STRIP: event.sensorData["triangles_in"] = int(event.values["count"] * 2) elif m == constants.GL_LINE_LOOP: event.sensorData["triangles_in"] = int(event.values["count"] * 2 + 2) fragments = event.sensorData.get("rasterizer_pixels", 0) triangles = event.sensorData.get("triangles_in", 0) texFetches = event.sensorData.get("rasterizer_texel_fetches", 0) if triangles and fragments: event.sensorData["average_triangle_size"] = fragments / float(triangles) if fragments and texFetches: event.sensorData["texel_fetches_per_pixel"] = fragments / float(texFetches) if event.name in ["glTexImage2D", "glTexSubImage2D"]: event.sensorData["texel_uploads"] = int(event.values["width"] * event.values["height"]) if func.isRenderCall and "count" in event.values: event.sensorData["vertices_in"] = int(event.values["count"]) if event.name == "glDepthMask": depthMask = event.values["flag"] # If we have the depth buffers for this event and the previous draw event, see how many pixels # actually changed and use that value to estimate overdraw if func.isRenderCall and not "rasterizer_discarded_pixels" in event.sensorData: if depthMask and prevRenderEvent and "depth_stride" in event.sensorData and "depth_mask" in event.sensorData: f1 = player.Instrumentation.getBufferFileName(prevRenderEvent, "depth") f2 = player.Instrumentation.getBufferFileName(event, "depth") if f1 and f2: diff = Graphics.compareDepthBuffers(f1, f2, event.sensorData["depth_stride"], event.sensorData["depth_mask"]) event.sensorData["rasterizer_discarded_pixels"] = fragments - diff prevRenderEvent = event discFragments = event.sensorData.get("rasterizer_discarded_pixels", 0) width = event.sensorData.get("render_surface_width", 0) height = event.sensorData.get("render_surface_height", 0) if fragments and width and height: event.sensorData["draw_ratio"] = (fragments - discFragments) / float(width * height)
def __init__(self, project, trace, title, path, reportFormat): self.project = project self.trace = trace self.path = path self.reportFormat = reportFormat self.library = project.targets["code"].library self.constants = Collections.DictProxy(self.library.constants) self.report = Report.Report(title) self.frames = [] self.interestingFrames = [] # Lazy loading of charting support global pylab, Charting import Charting from Charting import pylab try: self.compiler = Report.createCompiler(reportFormat, self.report) except KeyError: raise RuntimeError("Unsupported format: %s" % format) if not trace.events: raise RuntimeError("Trace is empty.") # Make sure the output directory exists Report.makePath(self.path) # Report appearance self.primaryColor = "orange" self.secondaryColor = "lightgrey" self.highlightColor = "red" self.thumbnailSize = (64, 64) # Chart appearance if pylab: pylab.subplots_adjust(hspace=.5) pylab.rc("font", size=7) pylab.rc("xtick", labelsize=7) pylab.rc("ytick", labelsize=7) pylab.rc("axes", labelsize=7) pylab.rc("legend", fontsize=9) # HTML report appearance if reportFormat == "html": self.compiler.setStyle("h1,h2,h3,h4,h5,h6", "clear: both;") self.compiler.setStyle("a", "color: %s;" % self.primaryColor, "text-decoration: none;") self.compiler.setStyle("a:hover", "color: %s;" % self.highlightColor, "text-decoration: underline;") self.compiler.setStyle("a img", "border: none;") self.compiler.setStyle("p.code", "background-color: #eee;", "border: solid 1px #ddd;", "width: 66%;", "padding: 1em;", "margin-left: 4em;") self.compiler.setStyle("p.checkpass", "float: right;", "padding: 1em;", "border: solid 1px black;", "background-color: %s;" % self.primaryColor) self.compiler.setStyle( "p.checkfail", "float: right;", "padding: 1em;", "border: solid 1px black;", "background-color: %s;" % self.highlightColor) self.compiler.setStyle("div.toc li", "list-style-type: none") self.compiler.setStyle("div.toc a", "color: black;") self.compiler.setStyle("table", "border: solid thin #aaa;", "margin: 1em;", "border-collapse: collapse;", "margin-left: 4em;") self.compiler.setStyle( "table th", "text-align: left;", "padding: .1em 1em .1em 1em;", "background-color: %s;" % (self.primaryColor)) self.compiler.setStyle("tr.odd", "background-color: #eee;") self.compiler.setStyle("table td", "padding: .1em 1em .1em 1em;") self.compiler.setStyle("img.screenshot", "float: right;")