示例#1
0
文件: Trace.py 项目: se210/tracy
 def __init__(self):
     self.name = None
     self.seq = 0
     self.time = 0
     self.duration = 0
     self.apiId = 0
     self.values = OrderedDict()
     self.modifiedArrays = []
     self.modifiedObjects = []
     self.sensorData = {}
示例#2
0
    def saveTrace(self,
                  trace,
                  traceFile,
                  dataFileName=None,
                  dataFileFormat="rvct",
                  frameMarkers=[],
                  initFuncName="init",
                  uninitFuncName="uninit",
                  playFuncName="play",
                  playFrameFuncName="playFrame",
                  frameFuncName="frame",
                  arrayPrefix="array",
                  playerArgument="context",
                  insertCopyright=True):
        try:
            library = self.analyzer.project.targets["code"].library
            config = self.analyzer.project.config
        except (AttributeError, KeyError):
            raise RuntimeError("API configuration not found.")

        def arrayId(array):
            assert isinstance(array, Trace.Array)
            return (array.__class__, array.id)

        def objectId(obj):
            assert isinstance(obj, Trace.Object)
            return "%s_%x_%x" % (obj.cls.name.lower(), obj.ns, obj.id)

        task = Task.startTask("c-export", "Formatting source",
                              len(trace.events))
        indent = " " * 3

        # Collect all values for all events
        task = Task.startTask("c-export", "Collecting data", len(trace.events))
        values = []
        [values.extend(e.values.values()) for e in trace.events]

        # Collect arrays
        arrays = OrderedDict([(arrayId(v), v) for v in reversed(values)
                              if isinstance(v, Trace.Array)])

        # Check that the external data format is supported
        if dataFileName:
            assert dataFileName.endswith(
                ".s"), "Unsupported external data file type. Use one of: s"
            assert dataFileFormat in (
                "gcc", "rvct"
            ), "Unsupported external data format. Use one of: gcc, rvct"
            dataFile = open(dataFileName, "w")
        else:
            dataFile = None

        # Calculate maximum sizes of arrays
        arraySizes = dict([(a, 0) for a in arrays.keys()])
        for value in values:
            if isinstance(value, Trace.Array):
                a = arrayId(value)
                arraySizes[a] = max(len(value), arraySizes[a])

        # Figure out the C types of arrays and objects
        classes = {}
        objectTypes = {}
        arrayTypes = {}
        outValueObjects = set()  # Objects that are acquired through a function
        arrayVariants = DefaultDict(list)
        usePersistentArrays = False  # Use arrays whose contents must be kept up to date

        # even after passing them to the API

        def registerObject(event, name, value):
            if not value.cls in classes:
                classes[value.cls] = {}
            function = self.analyzer.lookupFunction(event)
            # Object has already been registered
            if not name or function.parameters[name].isOut:
                outValueObjects.add(value)
            if objectId(value) in classes[value.cls]:
                return
            classes[value.cls][objectId(value)] = value
            for cType, nativeTypeName in library.typeMap.items():
                if cType.name == value.cls.name:
                    objectTypes[value] = cType
                    break
            else:
                self.analyzer.reportWarning("Unknown class: <%s>" %
                                            value.cls.name)
                # Create a fake type name for this class
                objectTypes[value] = value.cls.name

        def registerArray(event, name, value):
            function = self.analyzer.lookupFunction(event)

            if name:
                cType = function.parameters[name].type
            else:
                cType = function.type

            # Extract an essential type for the array discarding all qualifiers and modifiers
            cType = Library.Type(cType.name)

            # Get the real, non-typedef'd type as well
            realType = library.resolveType(cType)

            # If this is a void type, use the original type instead
            if realType.name == "void":
                cType = arrayTypeMap[value.__class__]

            arrayTypes[arrayId(value)] = cType

            # If this is an object array, register the objects too
            if isinstance(value, Trace.ObjectArrayValue):
                for obj in value:
                    registerObject(event, name, obj)

        for event in trace.events:
            # OpenGL needs persistent arrays
            if event.name.startswith("gl"):
                usePersistentArrays = True

            for name, value in event.values.items():
                if isinstance(value, Trace.Object):
                    registerObject(event, name, value)
                elif isinstance(value, Trace.Array):
                    registerArray(event, name, value)

            # Collect the modified arrays for this event
            for array in event.modifiedArrays:
                a = arrayId(array)
                # Only consider the arrays we know about
                if a in arrayTypes:
                    arrayVariants[a].append(array)
            task.step()

        # Count the number of frames
        if frameMarkers:
            frameCount = len(frameMarkers) + 3
        else:
            frameCount = len([
                1 for event in trace.events
                if self.analyzer.lookupFunction(event).isFrameMarker
            ]) + 3

        # Add the header
        print >> traceFile, "/**"
        print >> traceFile, " *  C source generated from %d events (%d frames). " % (
            len(trace.events), frameCount)
        if insertCopyright:
            print >> traceFile, copyrightText
        print >> traceFile, " */"
        print >> traceFile, ""
        print >> traceFile, "/** A macro for copying data into an array */"
        print >> traceFile, "#define LOAD_ARRAY(TO, FROM, LENGTH) \\"
        print >> traceFile, indent, "{ \\"
        print >> traceFile, indent * 2, "int i; \\"
        print >> traceFile, indent * 2, "for (i = 0; i < (LENGTH); i++) \\"
        print >> traceFile, indent * 3, "(TO)[i] = (FROM)[i]; \\"
        print >> traceFile, indent, "}"
        print >> traceFile, ""

        # Insert any additional code specified in the configuration
        if "c_player_code" in config:
            for fileName in config["c_player_code"]:
                f = open(config.getRelativePath(fileName))
                print >> traceFile, f.read()
                f.close()

        # Add the header to the data file if we have one
        if dataFile:
            if dataFileFormat == "gcc":
                print >> dataFile, "#"
                print >> dataFile, "# GNU Assembler data file generated from %d events (%d frames). " % (
                    len(trace.events), frameCount)
                print >> dataFile, "#"
                print >> dataFile, ""
                print >> dataFile, ".section .data"
            else:  # rvct
                print >> dataFile, ";"
                print >> dataFile, "; RVCT Assembler data file generated from %d events (%d frames). " % (
                    len(trace.events), frameCount)
                print >> dataFile, ";"
                print >> dataFile, ""
                print >> dataFile, "    AREA ||.constdata||, DATA, READONLY, ALIGN=2"

        # Introduce objects
        print >> traceFile, "/* Objects */ "
        for objects in classes.values():
            for obj in objects.values():
                print >> traceFile, "static %s %s = (%s)0x%x;" % (
                    objectTypes[obj], objectId(obj), objectTypes[obj], obj.id)
        print >> traceFile, ""
        task.step()

        # Introduce arrays
        print >> traceFile, "/* %d arrays */ " % len(arrays)
        for i, array in enumerate(arrays.values()):
            a = arrayId(array)
            if usePersistentArrays:
                l = arraySizes[a]
                if not l:
                    self.analyzer.reportWarning("Empty array %s" % str(a))
                    l = 1
                print >> traceFile, "static %s %s_%s%d[%d];" % (
                    arrayTypes[a], str(
                        arrayTypes[a]).lower(), arrayPrefix, i, l)
            else:
                print >> traceFile, "static %s* %s_%s%d;" % (
                    arrayTypes[a], str(arrayTypes[a]).lower(), arrayPrefix, i)
        print >> traceFile, ""

        # Introduce unique array data
        print >> traceFile, "/* Array data */ "
        arrayData = []
        arrayMap = {}
        for variants in arrayVariants.values():
            for array in variants:
                # See if an equivalent array is already created
                for j, existingArray in enumerate(arrayData):
                    if existingArray == array and \
                       existingArray.__class__ == array.__class__:
                        arrayMap[id(array)] = j
                        break
                else:
                    arrayMap[id(array)] = len(arrayData)
                    arrayData.append(array)

        if not dataFile:
            # Inline data
            for i, array in enumerate(arrayData):
                if not len(array):
                    continue
                # Object arrays can't be initialized inline
                if isinstance(array, Trace.ObjectArrayValue):
                    print >> traceFile, "static %s %sData%d[%d];" % (
                        arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
                    print >> traceFile, ""
                    continue
                elif usePersistentArrays:
                    print >> traceFile, "static const %s %sData%d[%d] = {" % (
                        arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
                else:
                    print >> traceFile, "static %s %sData%d[%d] = {" % (
                        arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
                print >> traceFile, indent,

                # Figure out the proper qualifier for the array elements
                qualifier = ""
                format = "s"
                if len(array):
                    if isinstance(array, Trace.FloatArrayValue):
                        format = qualifier = "f"
                    elif isinstance(array, Trace.DoubleArrayValue):
                        format = qualifier = "d"
                    elif isinstance(array, Trace.LongArrayValue):
                        format = qualifier = "l"

                for k, value in enumerate(array):
                    value = ("%%%s%s" % (format, qualifier)) % value
                    if k != len(array) - 1:
                        print >> traceFile, "%s," % value,
                        if not (k + 1) % 8:
                            print >> traceFile, ""
                            print >> traceFile, indent,
                    else:
                        print >> traceFile, value
                print >> traceFile, "};"
                print >> traceFile, ""
        else:  # External data
            for i, array in enumerate(arrayData):
                if not len(array):
                    continue
                if usePersistentArrays and not isinstance(
                        array, Trace.ObjectArrayValue):
                    print >> traceFile, "extern const %s %sData%d[%d];" % (
                        arrayTypes[arrayId(array)], arrayPrefix, i, len(array))
                else:
                    print >> traceFile, "extern %s %sData%d[%d];" % (
                        arrayTypes[arrayId(array)], arrayPrefix, i, len(array))

                # Object arrays can't be initialized inline
                if isinstance(array, Trace.ObjectArrayValue):
                    continue

                # Figure out the proper type code for the array elements
                if dataFileFormat == "gcc":
                    print >> dataFile, ".global %sData%d" % (arrayPrefix, i)
                    print >> dataFile, "%sData%d:" % (arrayPrefix, i)
                    if isinstance(array, Trace.FloatArrayValue):
                        typeCode = ".float"
                    elif isinstance(array, Trace.DoubleArrayValue):
                        typeCode = ".double"
                    elif isinstance(array, Trace.LongArrayValue):
                        typeCode = ".quad"
                    elif isinstance(array, Trace.ShortArrayValue):
                        typeCode = ".short"
                    elif isinstance(array, Trace.ByteArrayValue):
                        typeCode = ".byte"
                    elif isinstance(array, Trace.IntegerArrayValue):
                        typeCode = ".int"
                    else:
                        raise RuntimeError("Unknown array type")

                    # Write out the data
                    print >> dataFile, "%s %s" % (typeCode, ", ".join(
                        map(str, array)))
                else:  # rvct
                    print >> dataFile, "GLOBAL %sData%d" % (arrayPrefix, i)
                    print >> dataFile, "%sData%d" % (arrayPrefix, i)
                    if isinstance(array, Trace.FloatArrayValue):
                        typeCode = "DCFS"
                    elif isinstance(array, Trace.DoubleArrayValue):
                        typeCode = "DCFD"
                    elif isinstance(array, Trace.LongArrayValue):
                        typeCode = "DCQ"
                    elif isinstance(array, Trace.ShortArrayValue):
                        typeCode = "DCW"
                    elif isinstance(array, Trace.ByteArrayValue):
                        typeCode = "DCB"
                    elif isinstance(array, Trace.IntegerArrayValue):
                        typeCode = "DCD"
                    else:
                        raise RuntimeError("Unknown array type")

                    # Write out the data
                    prefix = "    %s " % typeCode
                    for j in xrange(0, len(array), 8):
                        values = array[j:j + 8]
                        print >> dataFile, prefix, ",".join(map(str, values))

        # Initialize the objects
        print >> traceFile, "static void %s(void* %s)" % (initFuncName,
                                                          playerArgument)
        print >> traceFile, "{"

        def getObjectAttributeValue(attr):
            if isinstance(attr, Trace.Array):
                # Only strings are supported so far
                assert isinstance(attr, Trace.ByteArrayValue)
                s = "".join((chr(c) for c in attr))
                s = s.replace("\r", "\\r")
                s = s.replace("\t", "\\t")
                s = s.rstrip("\x00")
                lines = s.split("\n")
                return "\n".join(('"%s\\n"' % l for l in lines))
            return str(attr)

        for objects in classes.values():
            for obj in objects.values():
                # If the object has attributes or it wasn't created from a return value, ask the user to create it
                cClass = library.classes.get(obj.cls.name)
                if obj.attrs or (not obj in outValueObjects and cClass
                                 and cClass.overridable):
                    print >> traceFile, indent, "/* %s attributes: %s */" % (
                        obj.cls.name, ", ".join(obj.attrs.keys()))
                    if obj.attrs:
                        attrs = ", ".join(
                            map(getObjectAttributeValue, obj.attrs.values()))
                        print >> traceFile, indent, "%s = create%s%d(%s, %s);" % (
                            objectId(obj), obj.cls.name, len(obj.attrs) + 1,
                            playerArgument, attrs)
                    else:
                        print >> traceFile, indent, "%s = create%s1(%s);" % (
                            objectId(obj), obj.cls.name, playerArgument)
        print >> traceFile, "}"
        print >> traceFile, ""

        # Uninitialize the objects
        print >> traceFile, "static void %s(void* %s)" % (uninitFuncName,
                                                          playerArgument)
        print >> traceFile, "{"
        for objects in classes.values():
            for obj in objects.values():
                # If the object has attributes or it wasn't created from a return value, ask the user to destroy it
                cClass = library.classes.get(obj.cls.name)
                if obj.attrs or (not obj in outValueObjects and cClass
                                 and cClass.overridable):
                    print >> traceFile, indent, "destroy%s2(%s, %s);" % (
                        obj.cls.name, playerArgument, objectId(obj))
        print >> traceFile, "}"
        print >> traceFile, ""

        # Add the events
        task.finish()
        task = Task.startTask("c-export", "Generating source",
                              len(trace.events))
        frameNumber = 0
        frameFunctions = ["%s0" % frameFuncName]
        activeArrays = dict([(a, None) for a in arrays.keys()])

        # Open the frame function
        print >> traceFile, "static void %s0(void* %s)" % (frameFuncName,
                                                           playerArgument)
        print >> traceFile, "{"

        for event in trace.events:
            function = self.analyzer.lookupFunction(event)

            # Modify objects
            for obj in event.modifiedObjects:
                # Check the the object was really modified
                if obj.attrs and obj.attrs != classes[obj.cls][objectId(
                        obj)].attrs:
                    attrs = ", ".join(
                        map(getObjectAttributeValue, obj.attrs.values()))
                    print >> traceFile, indent, "/* %s attributes: %s */" % (
                        obj.cls.name, ", ".join(obj.attrs.keys()))
                    print >>traceFile, indent, "%s = modify%s%d(%s, %s, %s);" % \
                      (objectId(obj), obj.cls.name, len(obj.attrs) + 2, playerArgument, objectId(obj), attrs)
                    classes[obj.cls][objectId(obj)].attrs = obj.attrs

            # Modify arrays
            for array in event.modifiedArrays:
                # Load the correct data into the array
                a = arrayId(array)

                # If this array is not used anywhere, skip it
                if not id(array) in arrayMap:
                    continue

                toArray = arrays.index(a)
                fromArray = arrayMap[id(array)]

                # Don't reload the same data
                if activeArrays[a] == fromArray:
                    continue

                # Ignore empty arrays
                if not len(array):
                    continue

                activeArrays[a] = fromArray
                # Insert new objects directly into the array
                if isinstance(array, Trace.ObjectArrayValue):
                    for i, obj in enumerate(array):
                        print >>traceFile, indent, "%s_%s%d[%d] = %s;" % \
                        (str(arrayTypes[a]).lower(), arrayPrefix, toArray, i, objectId(obj))
                elif usePersistentArrays:
                    print >>traceFile, indent, "LOAD_ARRAY(%s_%s%d, %sData%d, %d);" % \
                      (str(arrayTypes[a]).lower(), arrayPrefix, toArray, arrayPrefix, fromArray, len(array))
                else:
                    print >>traceFile, indent, "%s_%s%d = %sData%d;" % \
                      (str(arrayTypes[a]).lower(), arrayPrefix, toArray, arrayPrefix, fromArray)

            # Collect the arguments
            args = []
            returnValue = None
            for name, value in event.values.items():
                valueType = name and function.parameters[
                    name].type or function.type
                if value is None:
                    value = "(%s)0" % valueType
                elif isinstance(value, Trace.Array):
                    # If this array can be modified by the function, mark it as lost
                    if not valueType.isConstant(
                    ) and value in event.modifiedArrays:
                        a = arrayId(value)
                        activeArrays[a] = None
                    if not value.id:
                        value = "(%s)0" % valueType
                    else:
                        a = arrayId(value)
                        value = "(%s)%s_%s%d" % (valueType, str(
                            arrayTypes[a]).lower(), arrayPrefix,
                                                 arrays.index(a))
                elif isinstance(value, Trace.Object):
                    value = str(objectId(value))
                elif isinstance(value, Trace.UnknownPhrase):
                    value = "(%s)NULL" % valueType
                else:
                    value = StringUtils.decorateValue(library, function, name,
                                                      value)
                    if isinstance(value, Trace.FloatValue):
                        value = str(value) + "f"
                    elif isinstance(value, Trace.DoubleValue):
                        value = str(value) + "d"
                    elif isinstance(value, Trace.LongValue):
                        value = str(value) + "l"

                    # Do a cast if this is actually a pointer parameter (e.g. 'ptr' in glVertexAttribPointer)
                    if name and library.isPointerType(
                            function.parameters[name].type):
                        value = "(%s)%s" % (valueType, value)

                    # If the real C type is unsigned and we have a negative value, do a cast
                    try:
                        if name and "unsigned" in str(
                                library.resolveType(function.parameters[name].
                                                    type)) and int(value) < 0:
                            value = "(%s)%s" % (function.parameters[name].type,
                                                value)
                    except ValueError:
                        # Not an integer
                        pass

                # HACK: eglGetDisplay(0) -> eglGetDisplay(EGL_DEFAULT_DISPLAY)
                if event.name == "eglGetDisplay" and name and str(
                        value) == "0":
                    value = "EGL_DEFAULT_DISPLAY"

                # Make sure we have a meaningful parameter value
                assert len(str(value))

                if name:
                    args.append(str(value))
                else:
                    returnValue = value

            # Truncated event stream?
            if not len(args) == len(function.parameters):
                self.analyzer.reportWarning("Truncated call to %s(%s)" %
                                            (event.name, ", ".join(args)))
                print >> traceFile, indent, "/* truncated call to %s(%s) */" % (
                    event.name, ", ".join(args))
                continue

            # Save the return value if needed
            returnObject = event.values.get(None, None)
            if isinstance(returnObject, Trace.Object):
                print >> traceFile, indent, "%s =" % objectId(returnObject),
            else:
                print >> traceFile, indent,

            args = ", ".join(args)
            print >> traceFile, "%s(%s);" % (event.name, args)

            # Apply modifications to object arrays
            for array in event.modifiedArrays:
                if isinstance(array, Trace.ObjectArrayValue):
                    for i, obj in enumerate(array):
                        a = arrayId(array)
                        fromArray = arrays.index(a)
                        print >>traceFile, indent, "%s = %s_%s%d[%d];" % \
                        (objectId(obj), str(arrayTypes[a]).lower(), arrayPrefix, fromArray, i)

            if (not frameMarkers
                    and function.isFrameMarker) or event in frameMarkers:
                frameNumber += 1
                name = "%s%d" % (frameFuncName, frameNumber)
                print >> traceFile, "}"
                print >> traceFile, ""
                print >> traceFile, "/**"
                print >> traceFile, " *  Frame #%d" % frameNumber
                print >> traceFile, " */"
                print >> traceFile, "static void %s(void* %s)" % (
                    name, playerArgument)
                print >> traceFile, "{"
                frameFunctions.append(name)

            task.step()
        print >> traceFile, "}"
        print >> traceFile, ""

        # Create the playback function
        print >> traceFile, "/**"
        print >> traceFile, " *  Play back all trace frames."
        print >> traceFile, " *  @param %s Optional user data pointer" % (
            playerArgument)
        print >> traceFile, " */"
        print >> traceFile, "static void %s(void* %s)" % (playFuncName,
                                                          playerArgument)
        print >> traceFile, "{"
        print >> traceFile, indent, "%s(%s);" % (initFuncName, playerArgument)
        for name in frameFunctions:
            print >> traceFile, indent, "%s(%s);" % (name, playerArgument)
        print >> traceFile, indent, "%s(%s);" % (uninitFuncName,
                                                 playerArgument)
        print >> traceFile, "}"
        print >> traceFile, ""

        # Create the playback function for single frame playback
        print >> traceFile, "/**"
        print >> traceFile, " *  Play back a single frame of the trace."
        print >> traceFile, " *  @param %s Optional user data pointer" % (
            playerArgument)
        print >> traceFile, " *  @param frame Zero-based number of frame to play"
        print >> traceFile, " *  @returns 1 if the frame number was valid, 0 otherwise"
        print >> traceFile, " */"
        print >> traceFile, "static int %s(void* %s, int frame)" % (
            playFrameFuncName, playerArgument)
        print >> traceFile, "{"
        print >> traceFile, indent, "switch (frame)"
        print >> traceFile, indent, "{"
        print >> traceFile, indent * 2, "case %6d: %s(%s); break;" % (
            0, initFuncName, playerArgument)
        for i, name in enumerate(frameFunctions):
            print >> traceFile, indent * 2, "case %6d: %s(%s); break;" % (
                i + 1, name, playerArgument)
        print >> traceFile, indent * 2, "case %6d: %s(%s); break;" % (
            len(frameFunctions) + 1, uninitFuncName, playerArgument)
        print >> traceFile, indent * 2, "default: return 0;"
        print >> traceFile, indent, "}"
        print >> traceFile, indent, "return 1;"
        print >> traceFile, "}"

        # Close the data file
        if dataFile:
            dataFile.close()

        # All done
        task.finish()
示例#3
0
文件: Trace.py 项目: se210/tracy
 def __init__(self, id, ns, cls):
     self.id = id
     self.ns = ns
     self.cls = cls
     self.attrs = OrderedDict()