Пример #1
0
 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)
Пример #2
0
    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
Пример #3
0
 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)
Пример #4
0
    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
Пример #5
0
 def testInverseDict(self):
   d1 = {"hip": "hei"}
   d2 = Collections.inverseDict(d1)
   assert d2["hei"] == "hip"
Пример #6
0
 def testInverseDict(self):
     d1 = {"hip": "hei"}
     d2 = Collections.inverseDict(d1)
     assert d2["hei"] == "hip"
Пример #7
0
 def testDictProxy(self):
     d1 = {"hip": "hei"}
     d2 = Collections.DictProxy(d1)
     assert d2.hip == "hei"
Пример #8
0
 def testDefaultDict(self):
     d = Collections.DefaultDict(lambda: 1)
     assert d["foo"] == 1
     d["foo"] = 2
     assert d["foo"] == 2
Пример #9
0
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
Пример #10
0
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)
Пример #11
0
# 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)
Пример #12
0
 def __init__(self, items=None):
     self.freq = Collections.DefaultDict(lambda: 0)
     if items:
         for item in items:
             self.add(item)
Пример #13
0
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
Пример #14
0
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)
Пример #15
0
    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;")