def createEventSection(self, event): func = self.library.functions[event.name] if func.isRenderCall: title = "Render call %s (#%d)" % (event.name, event.seq) elif func.isFrameMarker: title = "Frame swap %s (#%d)" % (event.name, event.seq) else: title = "Event %s (#%d)" % (event.name, event.seq) section = Report.Section(title) # Add a framebuffer snapshot if we have one colorBuffer = player.Instrumentation.getBufferFileName(event) if func.isRenderCall and colorBuffer: section.create(Report.Image, colorBuffer, elementClass="screenshot") # Describe the event section.create(Report.Paragraph, self.getEventDescription(event), elementClass="code") # Insert sensor measurements statsTable = section.create(Report.Table, ["Sensor", "Value"]) for name in sorted(event.sensorData.keys()): if name in self.trace.sensors and name in event.sensorData and event.sensorData[ name]: statsTable.addRow(self.trace.sensors[name].description, event.sensorData[name]) return section
def createFrameSection(self, frame): frameSection = Report.Section("Frame #%d" % (frame.number + 1)) frameSection.create(Report.LinkTarget, "frame%d" % (frame.number + 1)) # Add a framebuffer snapshot if we have one colorBuffer = player.Instrumentation.getBufferFileName(frame.swapEvent) if colorBuffer: frameSection.create(Report.Image, colorBuffer, elementClass="screenshot") table = frameSection.create(Report.Table, ["Property", "Value"]) table.addRow("API calls", len(frame.events)) table.addRow("Render calls", len(frame.renderEvents)) table.addRow("FPS", "%.02f" % (1.0 / frame.duration)) # Add some frame-level graphs frameSection.add( self.createEventPlot("Event distribution", frame.events, sliceStart=frame.startTime, sliceLength=frame.duration, id=frame.number + 1)) frameSection.add( self.createEventFrequencyPlot("Operation distribution", frame.events, id=frame.number + 1)) return frameSection
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 createChecklistSection(self, title, checklistItems): checklistSection = Report.Section(title) checklistItems = Checklist.compileChecklist(self.project, self.trace, checklistItems) for item in checklistItems: title = "%s [%s]" % (item.name, item.verdict and "PASS" or "FAIL") itemSection = checklistSection.create(Report.Section, title) itemSection.create(Report.Paragraph, item.verdict and "PASS" or "FAIL", elementClass=item.verdict and "checkpass" or "checkfail") itemSection.create(Report.Paragraph, item.description) commentList = itemSection.create(Report.UnorderedList) # List unique comments only comments = sorted(item.comments, key=lambda c: c[1]) lastComment = None repeatedEvents = [] for event, comment in comments + [(None, None)]: if comment != lastComment: if lastComment and repeatedEvents: if len(repeatedEvents) < 100: commentList.addItem( "Previous comment repeated for %s." % ", ".join([ "%s (%d)" % (e.name, e.seq) for e in repeatedEvents ])) else: commentList.addItem( "Previous comment repeated for %d events." % len(repeatedEvents)) if comment: if event: commentList.addItem( "%s (%d): %s" % (self.getEventDescription(event), event.seq, comment)) else: commentList.addItem(comment) lastComment = comment repeatedEvents = [] elif event: repeatedEvents.append(event) return checklistSection
def createPlot(self, title, xAxis, yAxis, id=0, style="line"): # See if there's anything to plot for value in yAxis: if value: break else: return pylab.clf() Charting.slicePlot(xAxis, yAxis, color=self.primaryColor, style=style) 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 createEventPlot(self, title, events, sliceStart=0.0, sliceLength=10.0, id=0): # See if there's anything to plot if not len(events) >= 2: return segmentDuration = (events[-1].time - events[0].time) / 1e6 if segmentDuration < sliceLength: sliceLength = events[0].time / 1e6 + segmentDuration segmentStart = sliceStart slices = int(segmentDuration / sliceLength) + 2 pylab.figure(figsize=(8, slices * 1)) pylab.subplot(slices, 1, 1) pylab.xlim(sliceStart, sliceStart + sliceLength) pylab.yticks([]) legends = {} for event in events: time = event.time / 1e6 duration = event.duration / 1e6 if time + duration > sliceStart + sliceLength: pylab.subplot(slices, 1, int((time - segmentStart) / sliceLength) + 1) pylab.xticks(size=7) pylab.yticks([]) sliceStart += sliceLength pylab.xlim(sliceStart, sliceStart + sliceLength) func = self.library.functions[event.name] if func.isFrameMarker: color = self.highlightColor label = "frameswap" elif func.isRenderCall: color = self.primaryColor label = "render" else: continue legends[label] = pylab.axvspan(time, time + max(sliceLength / 100.0, duration), facecolor=color, linewidth=.1, label=label) # Describe the chart elements l1 = [] l2 = [] if "render" in legends: l1.append(legends["render"]) l2.append("Render call") if "frameswap" in legends: l1.append(legends["frameswap"]) l2.append("Frame swap") pylab.legend(l1, l2) 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