From bb1d982669c44a990ffc926f4666b6aa72237619 Mon Sep 17 00:00:00 2001 From: Thomas B Thompson Date: Mon, 10 Jan 2011 22:23:49 -0500 Subject: Worked on getting the threading stuff consolidated in ThreadedSmootCoreObject. Also set up a decent system for SmootCoreObjects to kill the whole application in a managed fashion. --- LightInstallation.py | 64 +++++++++++++++++++++++-------- TestProfile.py | 51 ++++++++++++++++++------ behaviors/DebugBehavior.py | 2 +- inputs/PygameInput.py | 4 +- operationscore/Input.py | 14 ++++--- operationscore/Renderer.py | 1 - operationscore/SmootCoreObject.py | 27 ++++++++++++- operationscore/ThreadedSmootCoreObject.py | 8 +--- pixelcore/Screen.py | 3 +- 9 files changed, 126 insertions(+), 48 deletions(-) diff --git a/LightInstallation.py b/LightInstallation.py index 6e3c093..e594602 100644 --- a/LightInstallation.py +++ b/LightInstallation.py @@ -9,7 +9,7 @@ import util.ComponentRegistry as compReg from logger import main_log #Python class to instantiate and drive a Screen through different patterns, #and effects. -class LightInstallation: +class LightInstallation(object): def __init__(self, configFileName): main_log.info("System Initialization began based on: " + str(configFileName)) self.timer = clock.Stopwatch() @@ -21,36 +21,50 @@ class LightInstallation: self.behaviorInputs = {} self.componentDict = {} self.inputBehaviorRegistry = {} #inputid -> behaviors listening to that + self.dieNow = False #input self.screen = Screen() compReg.initRegistry() compReg.registerComponent(self.screen, 'Screen') #TODO: move to constants file - config = configGetter.loadConfigFile(configFileName) + #read configs from xml + config = configGetter.loadConfigFile(configFileName) + rendererConfig = config.find('RendererConfiguration') + self.initializeRenderers(rendererConfig) + pixelConfig = config.find('PixelConfiguration') + self.initializeScreen(pixelConfig) + inputConfig = config.find('InputConfiguration') + self.initializeInputs(inputConfig) + behaviorConfig = config.find('BehaviorConfiguration') + self.initializeBehaviors(behaviorConfig) + mapperConfig = config.find('PixelMapperConfiguration') + self.initializeMapper(mapperConfig) - installationConfig = config.find('InstallationConfiguration') #inits - self.initializeScreen(pixelConfig) - self.initializeRenderers(rendererConfig) - self.initializeInputs(inputConfig) - self.initializeBehaviors(behaviorConfig) - self.initializeMapper(mapperConfig) main_log.info('All components initialized') - #registration in dict - self.registerComponents(self.renderers) - self.registerComponents(self.inputs) - self.registerComponents(self.behaviors) - self.registerComponents(self.mappers) + # + self.registerAllComponents() + + installationConfig = config.find('InstallationConfiguration') self.configureInstallation(installationConfig) #Done initializing. Lets start this thing! self.timer.stop() #main_log.info('Initialization done. Time: ', self.timer.elapsed(), 'ms') self.mainLoop() + + def registerAllComponents(self): + #registration in dict + self.registerComponents(self.renderers) + self.registerComponents(self.inputs) + self.registerComponents(self.behaviors) + self.registerComponents(self.mappers) + + def configureInstallation(self, installationConfig): defaults = configGetter.generateArgDict(installationConfig.find('Defaults')) for defaultSelection in defaults: @@ -62,12 +76,15 @@ class LightInstallation: def initializeMapper(self, mapperConfig): self.mappers = self.initializeComponent(mapperConfig) + def initializeScreen(self, layoutConfig): pixelAssemblers = self.initializeComponent(layoutConfig) [self.addPixelStrip(l) for l in pixelAssemblers] + def addPixelStrip(self, layoutEngine): pixelStrip = PixelStrip(layoutEngine) self.screen.addStrip(pixelStrip) + def initializeInputs(self, inputConfig): inputs = self.initializeComponent(inputConfig) self.inputs = inputs @@ -75,8 +92,10 @@ class LightInstallation: inputClass.start() self.inputBehaviorRegistry[inputClass['Id']] = [] #empty list is list of bound behaviors + def initializeRenderers(self, rendererConfig): self.renderers = self.initializeComponent(rendererConfig) + def registerComponents(self, components): for component in components: cid = component['Id'] @@ -85,6 +104,7 @@ class LightInstallation: else: compReg.registerComponent(component) main_log.debug(cid + ' registered') + def initializeComponent(self, config): components = [] if config != None: @@ -107,7 +127,9 @@ class LightInstallation: args['parentScope'] = self #TODO: we shouldn't give away scope #like this, find another way. try: - components.append(eval(className+'(args)')) #TODO: doesn't error + new_component = eval(className+'(args)') + new_component.addDieListener(self) + components.append(new_component) #TODO: doesn't error main_log.debug(className + 'initialized with args ' + str(args)) #right except Exception as inst: @@ -115,14 +137,16 @@ class LightInstallation: main_log.error(str(inst)) #TODO: exception logging return components + def alive(self): return True + def mainLoop(self): #self.screen.allOn() lastLoopTime = clock.time() refreshInterval = 30 runCount = 2000 - while runCount > 0: + while runCount > 0 and not self.dieNow: runCount -= 1 loopStart = clock.time() responses = self.evaluateBehaviors() #inputs are all queued when they @@ -138,6 +162,7 @@ class LightInstallation: #print self.timer.elapsed() if sleepTime > 0: time.sleep(sleepTime/1000) + #evaluates all the behaviors (including inter-dependencies) and returns a #list of responses to go to the screen. def evaluateBehaviors(self): @@ -154,12 +179,14 @@ class LightInstallation: self.behaviors = self.initializeComponent(behaviorConfig) for behavior in self.behaviors: self.addBehavior(behavior) + #Does work needed to add a behavior: currently -- maps behavior inputs into #the input behavior registry. def addBehavior(self, behavior): for inputId in behavior.argDict['Inputs']: if inputId in self.inputBehaviorRegistry: #it could be a behavior self.inputBehaviorRegistry[inputId].append(behavior['Id']) + def processResponse(self,inputDict, responseDict): inputId = inputDict['Id'] boundBehaviorIds = self.inputBehaviorRegistry[inputId] @@ -168,12 +195,17 @@ class LightInstallation: [compReg.getComponent(b).addInput(responseDict) for b in boundBehaviorIds] except: pass - #print 'Behaviors not initialized yet. WAIT!' + #print 'Behaviors not initialized yet. WAIT!' + + def handleDie(self, caller): + self.dieNow = True + def main(argv): if len(argv) == 1: l = LightInstallation('LightInstallationConfig.xml') else: l = LightInstallation(argv[1]) + if __name__ == "__main__": try: main(sys.argv) diff --git a/TestProfile.py b/TestProfile.py index 342def6..d6f24c1 100644 --- a/TestProfile.py +++ b/TestProfile.py @@ -1,8 +1,10 @@ -#import cProfile +import cProfile import struct import random +import scipy.weave as weave +import math #from LightInstallation import main -numiter = 10000000 +numiter = 1000000 def main1(): for i in xrange(0,numiter): if 'abc' == 'def': @@ -37,14 +39,39 @@ def dictlookup(): 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()) +#print('starting') +#abc1() +#print('starting') +#abc2() +#print('done') + +def normal_python(): + for i in xrange(0,numiter): + a = math.sqrt(3 + 4 + 5) + +def weave_outloop(): + code = """ + float x = 0; + for (int i = 0;i < numiter;i++) { + x = sqrt(3 + 4 + 5); + } + """ + weave.inline(code, ['numiter']) + +def weave_inloop(): + code = """ + x = sqrt(3 + 4 + 5); + """ + x = 0.0 + for i in xrange(0,numiter): + weave.inline(code, ['x']) + +command = """normal_python()""" +cProfile.runctx(command, globals(), locals()) + +command = """weave_outloop()""" +cProfile.runctx(command, globals(), locals()) + +command = """weave_inloop()""" +cProfile.runctx(command, globals(), locals()) diff --git a/behaviors/DebugBehavior.py b/behaviors/DebugBehavior.py index 8e9bbdb..9bf3ea8 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: ', str(sensorInputs)) + main_log.debug('Sensor Inputs: ' + str(sensorInputs)) return [] diff --git a/inputs/PygameInput.py b/inputs/PygameInput.py index a39c089..27b82b0 100644 --- a/inputs/PygameInput.py +++ b/inputs/PygameInput.py @@ -13,8 +13,8 @@ class PygameInput(Input): return for event in pygame.event.get(): if event.type is KEYDOWN: - if event.key == 301: - exit() + if event.key == 27: + self.die() self.respond({Strings.LOCATION: (5,5),'Key': event.key}) if event.type is MOUSEBUTTONDOWN: self.respond({Strings.LOCATION: pygame.mouse.get_pos()}) diff --git a/operationscore/Input.py b/operationscore/Input.py index 3dd74cf..2ee3c3c 100644 --- a/operationscore/Input.py +++ b/operationscore/Input.py @@ -11,28 +11,28 @@ import pdb class Input(ThreadedSmootCoreObject): #Event scope is a function pointer the function that will get called when #an Parent is raised. - def __init__(self, argDict): + def init(self): self.eventQueue = [] - self.parentScope = argDict['parentScope'] - self.argDict = argDict - if not 'RefreshInterval' in argDict: + if not 'RefreshInterval' in self.argDict: print 'RefreshInterval not defined. Defaulting to .5s.' self.argDict['RefreshInterval'] = 500 + self.parentScope = self.argDict['parentScope'] self.inputInit() - threading.Thread.__init__(self) - self.daemon = True #This kills this thread when the main thread stops + def respond(self, eventDict): #if eventDict != []: self.parentScope.lock.acquire() self.parentScope.processResponse(self.argDict, eventDict) self.parentScope.lock.release() time.sleep(.001) + def parentAlive(self): try: parentAlive = self.parentScope.alive() return parentAlive except: return False + def run(self): while 1: try: @@ -43,8 +43,10 @@ class Input(ThreadedSmootCoreObject): self.acquireLock() self.sensingLoop() self.releaseLock() + def sensingLoop(self): pass + def inputInit(self): pass diff --git a/operationscore/Renderer.py b/operationscore/Renderer.py index 88da606..ed88a8c 100644 --- a/operationscore/Renderer.py +++ b/operationscore/Renderer.py @@ -7,7 +7,6 @@ from operationscore.ThreadedSmootCoreObject import * class Renderer(ThreadedSmootCoreObject): def init(self): self.initRenderer() - threading.Thread.__init__(self) def render(lightSystem): pass def initRenderer(self): diff --git a/operationscore/SmootCoreObject.py b/operationscore/SmootCoreObject.py index c481776..8b36f4d 100644 --- a/operationscore/SmootCoreObject.py +++ b/operationscore/SmootCoreObject.py @@ -2,39 +2,62 @@ import pdb import threading import thread import util.Config as configGetter + class SmootCoreObject(object): def __init__(self, argDict, skipValidation = False): + self.dieListeners = [] self.argDict = argDict 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.init() #call init of inheriting class # self.__setitem__ = self.argDict.__setitem__ # self.__getitem__ = self.argDict.__getitem__ + def init(self): pass + def acquireLock(self): - self.lock = thread.allocate_lock() #TODO: fix. + self.lock = thread.allocate_lock() #TODO: fix. -- investigate this, it should only have to be run once in the initialization. self.lock.acquire() + def releaseLock(self): self.lock.release() + def className(self): return self.__class__.__name__ + def __setitem__(self,k, item): self.argDict[k] = item + def __getitem__(self, item): if item in self.argDict: return self.argDict[item] else: return None + def __getiter__(self): return self.argDict.__getiter__() + def validateArgs(self, argFileName): self.validateArgDict(configGetter.loadParamRequirementDict(argFileName))#util #caches for us, woo! + def validateArgDict(self, validationDict): for item in validationDict: if not item in self.argDict: raise Exception(validationDict[item]) + + def addDieListener(self, listener): + if listener not in self.dieListeners: + self.dieListeners.append(listener) + + def removeDieListener(self, listener): + if listener in self.dieListeners: + self.dieListeners.remove(listener) + + def die(self): + for listener in self.dieListeners: + listener.handleDie(self) diff --git a/operationscore/ThreadedSmootCoreObject.py b/operationscore/ThreadedSmootCoreObject.py index 90611bc..967ee35 100644 --- a/operationscore/ThreadedSmootCoreObject.py +++ b/operationscore/ThreadedSmootCoreObject.py @@ -5,10 +5,6 @@ import util.Config as configGetter from operationscore.SmootCoreObject import SmootCoreObject class ThreadedSmootCoreObject(SmootCoreObject, threading.Thread): def __init__(self, argDict, skipValidation = False): - self.argDict = argDict - self.validateArgs(self.className()+'.params') - self.lock = thread.allocate_lock() + SmootCoreObject.__init__(self, argDict, skipValidation) threading.Thread.__init__(self) - self.init() #call init of inheriting class - # self.__setitem__ = self.argDict.__setitem__ - # self.__getitem__ = self.argDict.__getitem__ + self.daemon = True #This kills this thread when the main thread stops diff --git a/pixelcore/Screen.py b/pixelcore/Screen.py index 198bd3f..22cfdb0 100644 --- a/pixelcore/Screen.py +++ b/pixelcore/Screen.py @@ -89,8 +89,7 @@ class Screen: #if type(mapper) != type(PixelMapper): # raise Exception('No default mapper specified.') pixelWeightList = mapper.mapEvent(responseInfo['Location'], self) - main_log.debug(str(len(pixelWeightList))) - main_log.debug(pixelWeightList) + PixelEvent.addPixelEventIfMissing(responseInfo) currentTime = timeops.time() for (pixel, weight) in pixelWeightList: -- cgit v1.2.3