changeset 903:bca2e8d754aa

tripleFilter optimization on currentState. optimize how often curvecalc rebuilds Subterm objs Ignore-this: 7402387bd9f4f99c2e7ef27b8dcfc4db
author Drew Perttula <drewp@bigasterisk.com>
date Mon, 10 Jun 2013 06:00:48 +0000
parents f376e7605e25
children 86c6700d1d63
files bin/curvecalc light9/curvecalc/output.py light9/curvecalc/subterm.py light9/rdfdb/currentstategraphapi.py
diffstat 4 files changed, 60 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/bin/curvecalc	Mon Jun 10 04:22:07 2013 +0000
+++ b/bin/curvecalc	Mon Jun 10 06:00:48 2013 +0000
@@ -46,6 +46,7 @@
         self.graph, self.opts, self.session = graph, opts, session
         self.curveset, self.music = curveset, music
         self.lastSeenInputTime = 0
+        self.currentSubterms = [] # Subterm objects that are synced to the graph
 
         wtree = self.wtree = gtk.Builder()
         wtree.add_from_file("light9/curvecalc/curvecalc.glade")
@@ -211,17 +212,23 @@
         return uri
                          
     def set_subterms_from_graph(self):
+        """rebuild all the gtktable 'subterms' widgets and the
+        self.currentSubterms list"""
+        song = self.graph.value(self.session, L9['currentSong'])
+
+        newList = []
+        for st in set(self.graph.objects(song, L9['subterm'])):
+            log.info("song %s has subterm %s", song, st)
+            term = Subterm(self.graph, st, self.songSubtermsContext(),
+                               self.curveset)
+            newList.append(term)
+        self.currentSubterms[:] = newList
+
         master = self.wtree.get_object("subterms")
         log.info("removing subterm widgets")
         [master.remove(c) for c in master.get_children()]
-
-        song = self.graph.value(self.session, L9['currentSong'])
-        
-        for st in set(self.graph.objects(song, L9['subterm'])):
-            log.info("song %s has subterm %s", song, st)
-            term = Subterm(self.graph, st, self.songSubtermsContext(), self.curveset)
+        for term in self.currentSubterms:
             add_one_subterm(term, self.curveset, master)
-
         master.show_all()
         log.info("%s table children showing" % len(master.get_children()))
         
@@ -396,12 +403,12 @@
     graph.addHandler(curvesetReload)
         
     log.debug("startup: output %s", time.time() - startTime)
-    out = Output(graph, session, music, curveset)
 
     mt = MaxTime(graph, session)
     dispatcher.connect(lambda: mt.get(), "get max time", weak=False)
 
     start = Main(graph, opts, session, curveset, music)
+    out = Output(graph, session, music, curveset, start.currentSubterms)
 
     dispatcher.send("show all")
         
--- a/light9/curvecalc/output.py	Mon Jun 10 04:22:07 2013 +0000
+++ b/light9/curvecalc/output.py	Mon Jun 10 06:00:48 2013 +0000
@@ -10,8 +10,9 @@
 class Output(object):
     lastsendtime=0
     lastsendlevs=None
-    def __init__(self, graph, session, music, curveset):
+    def __init__(self, graph, session, music, curveset, currentSubterms):
         self.graph, self.session, self.music = graph, session, music
+        self.currentSubterms = currentSubterms
         self.curveset = curveset
 
         self.recent_t=[]
@@ -52,14 +53,9 @@
         dispatcher.send("curves to sliders", t=t)
         scaledsubs=[]
 
-        with self.graph.currentState() as current:
-            song = current.value(self.session, L9['currentSong'])
-            for st in current.objects(song, L9['subterm']):
-                # this is getting especially broken to have Output
-                # being able to remake the Subterm on each frame. Some
-                # object should maintain all the subterms for us.
-                scl = Subterm(self.graph, st, None, self.curveset).scaled(current, t)
-                scaledsubs.append(scl)
+        for st in self.currentSubterms:
+            scl = st.scaled(t)
+            scaledsubs.append(scl)
                 
         out = Submaster.sub_maxes(*scaledsubs)
         levs = out.get_levels()
--- a/light9/curvecalc/subterm.py	Mon Jun 10 04:22:07 2013 +0000
+++ b/light9/curvecalc/subterm.py	Mon Jun 10 06:00:48 2013 +0000
@@ -83,37 +83,39 @@
         self.submasters = Submaster.get_global_submasters(self.graph)
         
     def ensureExpression(self, saveCtx):
-        with self.graph.currentState() as current:
+        with self.graph.currentState(tripleFilter=(self.uri, None, None)) as current:
             if current.value(self.uri, L9['expression']) is None:
                 self.graph.patch(Patch(addQuads=[
                     (self.uri, L9['expression'], Literal("..."), saveCtx),
                     ]))
 
-    def scaled(self, current, t):
-        subexpr_eval = self.eval(current, t)
-        # we prevent any exceptions from escaping, since they cause us to
-        # stop sending levels
-        try:
-            if isinstance(subexpr_eval, Submaster.Submaster):
-                # if the expression returns a submaster, just return it
-                return subexpr_eval
-            else:
-                # otherwise, return our submaster multiplied by the value 
-                # returned
-                if subexpr_eval == 0:
-                    return Submaster.Submaster("zero", {})
-                subUri = current.value(self.uri, L9['sub'])
-                sub = self.submasters.get_sub_by_uri(subUri)
-                return sub * subexpr_eval
-        except Exception, e:
-            dispatcher.send("expr_error", sender=self.uri, exc=repr(e))
-            return Submaster.Submaster(name='Error: %s' % str(e), levels={})
-    
+    def scaled(self, t):
+        with self.graph.currentState(tripleFilter=(self.uri, None, None)) as current:
+            subexpr_eval = self.eval(current, t)
+            # we prevent any exceptions from escaping, since they cause us to
+            # stop sending levels
+            try:
+                if isinstance(subexpr_eval, Submaster.Submaster):
+                    # if the expression returns a submaster, just return it
+                    return subexpr_eval
+                else:
+                    # otherwise, return our submaster multiplied by the value 
+                    # returned
+                    if subexpr_eval == 0:
+                        return Submaster.Submaster("zero", {})
+                    subUri = current.value(self.uri, L9['sub'])
+                    sub = self.submasters.get_sub_by_uri(subUri)
+                    return sub * subexpr_eval
+            except Exception, e:
+                dispatcher.send("expr_error", sender=self.uri, exc=repr(e))
+                return Submaster.Submaster(name='Error: %s' % str(e), levels={})
+
+
     def eval(self, current, t):
         """current graph is being passed as an optimization. It should be
         equivalent to use self.graph in here."""
 
-        objs = list(current.objects(self.uri, L9.expression))
+        objs = list(current.objects(self.uri, L9['expression']))
         if len(objs) > 1:
             raise ValueError("found multiple expressions for %s: %s" %
                              (self.uri, objs))
--- a/light9/rdfdb/currentstategraphapi.py	Mon Jun 10 04:22:07 2013 +0000
+++ b/light9/rdfdb/currentstategraphapi.py	Mon Jun 10 06:00:48 2013 +0000
@@ -1,14 +1,18 @@
+import logging, traceback
 from rdflib import ConjunctiveGraph
 from light9.rdfdb.rdflibpatch import contextsForStatement as rp_contextsForStatement
+log = logging.getLogger("currentstate")
 
 class CurrentStateGraphApi(object):
     """
     mixin for SyncedGraph, separated here because these methods work together
     """
 
-    def currentState(self, context=None):
+    def currentState(self, context=None, tripleFilter=(None, None, None)):
         """
         a graph you can read without being in an addHandler
+
+        you can save some time by passing a triple filter, and we'll only give you the matching triples
         """
         if context is not None:
             raise NotImplementedError("currentState with context arg")
@@ -22,11 +26,21 @@
                 # before moving on to writes.
 
                 g = ConjunctiveGraph()
-                for s,p,o,c in self._graph.quads((None,None,None)):
+                for s,p,o,c in self._graph.quads(tripleFilter):
                     g.store.add((s,p,o), c)
+
+                if tripleFilter == (None, None, None):
+                    self2.logThisCopy(g)
+                    
                 g.contextsForStatement = lambda t: contextsForStatementNoWildcards(g, t)
                 return g
 
+            def logThisCopy(self, g):
+                log.info("copied graph %s statements because of this:" % len(g))
+                for frame in traceback.format_stack(limit=4)[:-2]:
+                    for line in frame.splitlines():
+                        log.info("  "+line)
+
             def __exit__(self, type, val, tb):
                 return