From 1679719e7ca8ce433c5714474a32c926161dc5b8 Mon Sep 17 00:00:00 2001 From: rcoh Date: Tue, 4 Jan 2011 17:23:30 -0500 Subject: Some performance improvements -- we also synchronize all the frames, giving us a meaning that even if things slow down, rendering doesn't look weird. --- LightInstallation.py | 8 ++++---- TestProfile.py | 32 ++++++++++++++++++++++++-------- behaviors/Accelerate.xml | 2 +- behaviors/DebugBehavior.py | 2 +- config/Outdoor.xml | 4 ++++ ga | 1 + inputs/MouseFollower.xml | 2 +- layouts/50PixelStrip.xml | 2 +- operationscore/SmootCoreObject.py | 3 +++ pixelcore/Pixel.py | 25 +++++++++++++------------ pixelcore/Screen.py | 5 +++-- pixelmappers/GaussianMapper.py | 10 +++++----- pixelmappers/SimpleMapper.py | 3 ++- renderers/IndoorRenderer.py | 6 +++--- renderers/PygameRenderer.py | 8 ++++---- util/PacketComposition.py | 9 +++++---- 16 files changed, 75 insertions(+), 47 deletions(-) create mode 100755 ga diff --git a/LightInstallation.py b/LightInstallation.py index db7b808..6e3c093 100644 --- a/LightInstallation.py +++ b/LightInstallation.py @@ -99,9 +99,9 @@ class LightInstallation: exec('from ' + module+'.'+className + ' import *') main_log.debug(module +'.' +className + 'imported') except Exception as inst: - pdb.set_trace() main_log.error('Error importing ' + module+'.'+'.className. Component not\ initialized.') + main_log.error(str(inst)) #TODO: exception logging continue #TODO: verify functions as expected args = configGetter.pullArgsFromItem(configItem) args['parentScope'] = self #TODO: we shouldn't give away scope @@ -112,7 +112,7 @@ class LightInstallation: #right except Exception as inst: main_log.error('Failure while initializing ' + className + ' with ' + str(args)) - #main_log.error(inst) TODO: exception logging + main_log.error(str(inst)) #TODO: exception logging return components def alive(self): @@ -121,7 +121,7 @@ class LightInstallation: #self.screen.allOn() lastLoopTime = clock.time() refreshInterval = 30 - runCount = 3000 + runCount = 2000 while runCount > 0: runCount -= 1 loopStart = clock.time() @@ -131,7 +131,7 @@ class LightInstallation: [self.screen.respond(response) for response in responses if response != []] self.screen.timeStep() - [r.render(self.screen) for r in self.renderers] + [r.render(self.screen, loopStart) for r in self.renderers] loopElapsed = clock.time()-loopStart sleepTime = max(0,refreshInterval-loopElapsed) self.timer.stop() diff --git a/TestProfile.py b/TestProfile.py index eccb884..342def6 100644 --- a/TestProfile.py +++ b/TestProfile.py @@ -1,5 +1,7 @@ -import cProfile -from LightInstallation import main +#import cProfile +import struct +import random +#from LightInstallation import main numiter = 10000000 def main1(): for i in xrange(0,numiter): @@ -18,17 +20,31 @@ def main2(): x = [1,2,3] a = [] def abc1(): - for i in xrange(0,numiter): + for i in range(0,numiter): a = min(4, 255) b = min(257, 255) def abc2(): - for i in xrange(0,numiter): + for i in range(0,numiter): a = 4 if 4 < 255 else 255 b = 257 if 257 < 255 else 255 -command = """abc1()""" -cProfile.runctx(command, globals(), locals()) +def strucpack(): + for i in xrange(0,numiter): + b = struct.pack('B', random.randint(0,255)) +def dictlookup(): + lookup = {} + for i in xrange(0,256): + lookup[i] = struct.pack('B', random.randint(0,255)) + for i in xrange(0,numiter): + b = lookup[random.randint(0,255)] +print('starting') +abc1() +print('starting') +abc2() +print('done') +#command = """abc1()""" +#cProfile.runctx(command, globals(), locals()) -command = """abc2()""" -cProfile.runctx(command, globals(), locals()) +#command = """abc2()""" +#cProfile.runctx(command, globals(), locals()) diff --git a/behaviors/Accelerate.xml b/behaviors/Accelerate.xml index 2a3d7ac..c78195b 100644 --- a/behaviors/Accelerate.xml +++ b/behaviors/Accelerate.xml @@ -3,6 +3,6 @@ Sensor StepSize - {val}*1.05 + {val}*1.01 diff --git a/behaviors/DebugBehavior.py b/behaviors/DebugBehavior.py index 2f8db80..8e9bbdb 100644 --- a/behaviors/DebugBehavior.py +++ b/behaviors/DebugBehavior.py @@ -4,5 +4,5 @@ import pdb class DebugBehavior(Behavior): def processResponse(self, sensorInputs, recursiveInputs): if sensorInputs != []: - main_log.debug('Sensor Inputs: ', sensorInputs) + main_log.debug('Sensor Inputs: ', str(sensorInputs)) return [] diff --git a/config/Outdoor.xml b/config/Outdoor.xml index 9ca33e9..c2a2c3c 100644 --- a/config/Outdoor.xml +++ b/config/Outdoor.xml @@ -13,6 +13,7 @@ pixelmappers.SimpleMapper simplemap + 20 @@ -85,6 +86,9 @@ behaviors/LoopAndDie.xml + + 2000 + behaviors.BehaviorChain diff --git a/ga b/ga new file mode 100755 index 0000000..7bed4ad --- /dev/null +++ b/ga @@ -0,0 +1 @@ +git add *.py */*.py *.xml */*.xml tests/*.py tests/testdata/* diff --git a/inputs/MouseFollower.xml b/inputs/MouseFollower.xml index 7d7963d..bf3a36a 100644 --- a/inputs/MouseFollower.xml +++ b/inputs/MouseFollower.xml @@ -2,7 +2,7 @@ inputs.PygameInput followmouse - 50 + 20 True diff --git a/layouts/50PixelStrip.xml b/layouts/50PixelStrip.xml index beabb97..11fa5e1 100644 --- a/layouts/50PixelStrip.xml +++ b/layouts/50PixelStrip.xml @@ -3,6 +3,6 @@ 4 4 - 50 + 500 diff --git a/operationscore/SmootCoreObject.py b/operationscore/SmootCoreObject.py index 291519a..c481776 100644 --- a/operationscore/SmootCoreObject.py +++ b/operationscore/SmootCoreObject.py @@ -8,6 +8,9 @@ class SmootCoreObject(object): self.validateArgs(self.className()+'.params') self.lock = thread.allocate_lock() self.init() #call init of inheriting class + #put everything into attributes for speed + for key in argDict: + setattr(self, key, argDict[key]) # self.__setitem__ = self.argDict.__setitem__ # self.__getitem__ = self.argDict.__getitem__ def init(self): diff --git a/pixelcore/Pixel.py b/pixelcore/Pixel.py index 9f5cc85..b9fc07f 100644 --- a/pixelcore/Pixel.py +++ b/pixelcore/Pixel.py @@ -14,7 +14,8 @@ class Pixel: def __init__(self, location): self.location = location self.events = {} - self.memState = None + self.lastRenderTime = timeops.time() + self.lastRender = (0,0,0) def turnOn(self): self.turnOnFor(-1) @@ -28,24 +29,23 @@ class Pixel: #arg #Add a pixelEvent to the list of active events - def processInput(self,pixelEvent,zindex): #consider migrating arg to dict - self.events[timeops.time()] = (zindex, pixelEvent) + def processInput(self,pixelEvent,zindex, currentTime=None): #consider migrating arg to dict + if currentTime == None: + currentTime = timeops.time() + self.events[currentTime] = (zindex, pixelEvent) def clearAllEvents(self): self.events = {} #Combines all PixelEvents currently active and computes the current color of #the pixel. - def invalidateState(self): - self.memState = None - - def state(self): - if self.memState != None: - return self.memState - if self.events == []: + def state(self, currentTime=timeops.time()): #TODO: this only evaluates at import time, I think + if currentTime-self.lastRenderTime < 5: + return self.lastRender + if self.events == {}: + self.lastRenderTime = currentTime return (0,0,0) deadEvents = [] - currentTime = timeops.time() resultingColor = (0,0,0) colors = [] for eventTime in self.events: #TODO: right color weighting code @@ -59,7 +59,8 @@ class Pixel: resultingColor = color.combineColors(colors) [self.events.pop(event) for event in deadEvents] resultingColor = [int(round(c)) for c in resultingColor] - self.memState = tuple(resultingColor) + self.lastRender = tuple(resultingColor) + self.lastRenderTime = currentTime return tuple(resultingColor) def __str__(self): diff --git a/pixelcore/Screen.py b/pixelcore/Screen.py index b002896..198bd3f 100644 --- a/pixelcore/Screen.py +++ b/pixelcore/Screen.py @@ -5,6 +5,7 @@ from operationscore.PixelMapper import * import util.Search as Search import util.ComponentRegistry as compReg import util.Strings as Strings +import util.TimeOps as timeops import itertools import sys from logger import main_log @@ -54,7 +55,6 @@ class Screen: self.responseQueue = [] for response in tempQueue: self.processResponse(response) - [p.invalidateState() for p in self] #public def respond(self, responseInfo): @@ -92,6 +92,7 @@ class Screen: main_log.debug(str(len(pixelWeightList))) main_log.debug(pixelWeightList) PixelEvent.addPixelEventIfMissing(responseInfo) + currentTime = timeops.time() for (pixel, weight) in pixelWeightList: - pixel.processInput(responseInfo['PixelEvent'].scale(weight), 0) #TODO: z-index + pixel.processInput(responseInfo['PixelEvent'].scale(weight), 0, currentTime) #TODO: z-index diff --git a/pixelmappers/GaussianMapper.py b/pixelmappers/GaussianMapper.py index 8fdf16b..686ebcd 100644 --- a/pixelmappers/GaussianMapper.py +++ b/pixelmappers/GaussianMapper.py @@ -4,11 +4,11 @@ class GaussianMapper(PixelMapper): def mappingFunction(self, eventLocation, screen): returnPixels = [] #TODO: consider preallocation and trimming [x,y] = eventLocation - for (x,pixel) in screen.pixelsInRange(x-self['CutoffDist'], \ - x+self['CutoffDist']): + for (x,pixel) in screen.pixelsInRange(x-self.CutoffDist, \ + x+self.CutoffDist): pixelDist = Geo.dist(pixel.location, eventLocation) - if pixelDist < self['CutoffDist']: - w = Geo.gaussian(pixelDist, self['Height'], 0, self['Width']) - if w > self['MinWeight']: + if pixelDist < self.CutoffDist: + w = Geo.gaussian(pixelDist, self.Height, 0, self.Width) + if w > self.MinWeight: returnPixels.append((pixel, w)) return returnPixels diff --git a/pixelmappers/SimpleMapper.py b/pixelmappers/SimpleMapper.py index 5df1032..4d12fe4 100644 --- a/pixelmappers/SimpleMapper.py +++ b/pixelmappers/SimpleMapper.py @@ -22,7 +22,8 @@ class SimpleMapper(PixelMapper): eventLocation = eventLocation.replace('{y}', 'pixel.location[1]') for pixel in screen: try: - pixelValid = sum(eval(eventLocation)) == len(eval(eventLocation)) #TODO: some + preValid = eval(eventLocation) + pixelValid = sum(preValid) == len(preValid) #TODO: some #optimizations possible. This might be slow in the long run if pixelValid: ret.append((pixel, 1)) diff --git a/renderers/IndoorRenderer.py b/renderers/IndoorRenderer.py index 0ee566a..5f8546a 100644 --- a/renderers/IndoorRenderer.py +++ b/renderers/IndoorRenderer.py @@ -1,6 +1,7 @@ from operationscore.Renderer import * import util.PacketComposition as composer import util.NetworkOps as network +import util.TimeOps as timeops import socket,pdb sock_port = 6038 #Renderer for a Specific Light System. @@ -19,7 +20,7 @@ class IndoorRenderer(Renderer): for stripId in stripsInPowerSupply: self.stripLocations[stripId] = (ip, \ stripsInPowerSupply[stripId]) - def render(self, lightSystem): + def render(self, lightSystem, currentTime=timeops.time()): try: for pixelStrip in lightSystem.pixelStrips: stripId = pixelStrip.argDict['Id'] @@ -27,9 +28,8 @@ class IndoorRenderer(Renderer): if not ip in self.sockets: #do we have a socket to this #strip? if not, spin off a new one self.sockets[ip] = network.getConnectedSocket(ip,sock_port) - packet = composer.composePixelStripPacket(pixelStrip, port) + packet = composer.composePixelStripPacket(pixelStrip, port, currentTime) self.sockets[ip].send(packet, 0x00) - #pdb.set_trace() except Exception as inst: print inst diff --git a/renderers/PygameRenderer.py b/renderers/PygameRenderer.py index a10700b..24b2d08 100644 --- a/renderers/PygameRenderer.py +++ b/renderers/PygameRenderer.py @@ -1,5 +1,5 @@ from operationscore.Renderer import * -import util.TimeOps as clock +import util.TimeOps as timeops import pygame from pygame.locals import * import pdb @@ -10,13 +10,13 @@ class PygameRenderer(Renderer): self.background = pygame.Surface(self.screen.get_size()) self.background = self.background.convert() self.background.fill(Color('Black')) - self.stopwatch = clock.Stopwatch() + self.stopwatch = timeops.Stopwatch() self.stopwatch.start() - def render(self, lightSystem): + def render(self, lightSystem, currentTime=timeops.time()): self.background.fill(Color('Black')) #print 'drawing color:',light.color for light in lightSystem: - pygame.draw.circle(self.background, light.state(), light.location, \ + pygame.draw.circle(self.background, light.state(currentTime), light.location, \ light.radius) self.screen.blit(self.background, (0,0)) diff --git a/util/PacketComposition.py b/util/PacketComposition.py index 73eefff..b323d54 100644 --- a/util/PacketComposition.py +++ b/util/PacketComposition.py @@ -7,11 +7,12 @@ MAGICHASH = 0x69000420 PORTOUT = 0x0108 UNI = 0 import pdb +import util.TimeOps as timeops kinetDict = {'flags': 0, 'startcode': 0, 'pad':0} -def composePixelStripData(pixelStrip): +def composePixelStripData(pixelStrip,currentTime=timeops.time()): packet = bytearray() for light in pixelStrip: - color = light.state() + color = light.state(currentTime) for channel in color: #skip the last value, its an #alpha value packet.append(struct.pack('B', channel)) @@ -21,9 +22,9 @@ def composePixelStripData(pixelStrip): #color = pixelStrip.pixels[i].state() #packet[i:i+2] = color # return bytearray(packet) -def composePixelStripPacket(pixelStrip,port): +def composePixelStripPacket(pixelStrip,port, currentTime): packet = bytearray() - data = composePixelStripData(pixelStrip) + data = composePixelStripData(pixelStrip, currentTime) subDict = dict(kinetDict) subDict['len'] = 38000 #I have no idea why this works. subDict['port'] = port -- cgit v1.2.3