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 = {}
class Object(object): __slots__ = ["id", "ns", "cls", "attrs"] def __init__(self, id, ns, cls): self.id = id self.ns = ns self.cls = cls self.attrs = OrderedDict() def __repr__(self): attrs = ", ".join(["%s=%s" % (k, v) for k, v in self.attrs.items()]) return "<%s instance at %s%x %s>" % (self.cls.name, ("%x:" % self.ns if self.ns else ""), self.id, attrs) def __eq__(self, o): try: return self.id == o.id and self.cls == o.cls and self.attrs == o.attrs except AttributeError: return False def __hash__(self): return hash(self.id) ^ hash(self.ns) ^ hash(self.cls) ^ hash(str(self.attrs.items()))
class Object(object): __slots__ = ["id", "ns", "cls", "attrs"] def __init__(self, id, ns, cls): self.id = id self.ns = ns self.cls = cls self.attrs = OrderedDict() def __repr__(self): attrs = ", ".join(["%s=%s" % (k, v) for k, v in self.attrs.items()]) return "<%s instance at %s%x %s>" % (self.cls.name, ("%x:" % self.ns if self.ns else ""), self.id, attrs) def __eq__(self, o): try: return self.id == o.id and self.cls == o.cls and self.attrs == o.attrs except AttributeError: return False def __hash__(self): return hash(self.id) ^ hash(self.ns) ^ hash(self.cls) ^ hash( str(self.attrs.items()))
def __init__(self, id, ns, cls): self.id = id self.ns = ns self.cls = cls self.attrs = OrderedDict()
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()
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()