Changeset - 5e905ff44e84
[Not reviewed]
default
0 2 0
drewp@bigasterisk.com - 11 years ago 2014-06-15 03:09:48
drewp@bigasterisk.com
CC now suports statprof profiling, and every other profile() call is now broken
Ignore-this: bc7c31af6598e7c132d2f847afe8de68
2 files changed with 17 insertions and 8 deletions:
0 comments (0 inline, 0 general)
bin/curvecalc
Show inline comments
 
@@ -109,405 +109,405 @@ class Main(object):
 
        ec.show()
 
        
 
        wtree.get_object("subterms").connect("add", self.onSubtermChildAdded)
 
        
 
        self.refreshCurveView()       
 
        
 
        self.makeStatusLines(wtree.get_object("status"))
 
        self.setupNewSubZone()
 
        self.acceptDragsOnCurveViews()
 
                
 
        # may not work
 
        wtree.get_object("paned1").set_position(600)
 

	
 
    def setupNewSubZone(self):
 
        self.wtree.get_object("newSubZone").drag_dest_set(
 
            flags=Gtk.DestDefaults.ALL,
 
            targets=[Gtk.TargetEntry('text/uri-list', 0, 0)],
 
            actions=Gdk.DragAction.COPY)
 
        
 
    def acceptDragsOnCurveViews(self):
 
        w = self.wtree.get_object("curves")
 
        w.drag_dest_set(flags=Gtk.DestDefaults.ALL,
 
                        targets=[Gtk.TargetEntry('text/uri-list', 0, 0)],
 
                        actions=Gdk.DragAction.COPY)
 
        def recv(widget, context, x, y, selection,
 
                       targetType, time):
 
            subUri = URIRef(selection.data.strip())
 
            print "into curves", subUri
 
            with self.graph.currentState(
 
                    tripleFilter=(subUri, RDFS.label, None)) as current:
 
                subName = current.label(subUri)
 

	
 
            if '?' in subUri:
 
                subName = self.handleSubtermDrop(subUri)
 
            else:
 
                try:
 
                    self.makeSubterm(subName, withCurve=True,
 
                                     sub=subUri,
 
                                     expr="%s(t)" % subName)
 
                except SubtermExists:
 
                    # we're not making sure the expression/etc are
 
                    # correct-- user mihgt need to fix things
 
                    pass
 
            curveView = self.curvesetView.row(subName).curveView
 
            t = self.lastSeenInputTime # curveView.current_time() # new curve hasn't heard the time yet. this has gotten too messy- everyone just needs to be able to reach the time source
 
            print "time", t
 
            curveView.add_points([(t - .5, 0),
 
                                  (t, 1)])
 
        w.connect("drag-data-received", recv)
 
        
 
    def onDragDataInNewSubZone(self, widget, context, x, y, selection,
 
                       targetType, time):
 
        data = URIRef(selection.data.strip())
 
        if '?' in data:
 
            self.handleSubtermDrop(data)
 
            return
 
        with self.graph.currentState(tripleFilter=(data, None, None)) as current:
 
            subName = current.label(data)
 
        self.makeSubterm(newname=subName, withCurve=True, sub=data,
 
                         expr="%s(t)" % subName)
 
        
 
    def handleSubtermDrop(self, data):
 
        params = parse_qsl(data.split('?')[1])
 
        flattened = dict(params)
 
        self.makeSubterm(Literal(flattened['subtermName']),
 
                         expr=flattened['subtermExpr'])
 

	
 
        for cmd, name in params:
 
            if cmd == 'curve':
 
                self.curveset.new_curve(name)
 
        return name
 

	
 
    def onNewCurve(self, *args):
 
        dialog = self.wtree.get_object("newCurve")
 
        entry = self.wtree.get_object("newCurveName")
 
        # if you don't have songx, that should be the suggested name
 
        entry.set_text("")
 
        if dialog.run() == 1:
 
            self.curveset.new_curve(entry.get_text())
 
        dialog.hide()
 

	
 
    def onRedrawCurves(self, *args):
 
        dispatcher.send("all curves rebuild")
 
        
 
    def onSubtermsMap(self, *args):
 
        # if this was called too soon, like in __init__, the gtktable
 
        # would get its children but it wouldn't lay anything out that
 
        # I can see, and I'm not sure why. Waiting for map event is
 
        # just a wild guess.
 
        self.graph.addHandler(self.set_subterms_from_graph)
 
        
 
    def onNewSubterm(self, *args):
 
        self.makeSubterm(Literal(""), withCurve=False)
 
        return
 

	
 
        # pretty sure i don't want this back, but not completely sure
 
        # what the UX should be to get the new curve.
 
        
 
        dialog = self.wtree.get_object("newSubterm")
 
        # the plan is to autocomplete this on existing subterm names
 
        # (but let you make one up, too)
 
        entry = self.wtree.get_object("newSubtermName").get_children()[0]
 
        entry.set_text("")
 
        entry.grab_focus()
 
        if dialog.run() == 1:
 
            newname = entry.get_text()
 
            wc = self.wtree.get_object("newSubtermMakeCurve").get_active()
 
            self.makeSubterm(newname, withCurve=wc)
 
        dialog.hide()
 

	
 
    def currentSong(self):
 

	
 
        with self.graph.currentState(
 
                tripleFilter=(self.session, L9['currentSong'], None)
 
        ) as current:
 
            return current.value(self.session, L9['currentSong'])
 

	
 
    def songSubtermsContext(self):
 
        return self.currentSong()
 

	
 
    def makeSubterm(self, newname, withCurve=False, expr=None, sub=None):
 
        """
 
        raises SubtermExists if we had a subterm with a sub with the given
 
        name. what about a no-sub term with the same label? who knows
 
        """
 
        assert isinstance(newname, Literal), repr(newname)
 
        if withCurve:
 
            self.curveset.new_curve(newname)
 
        if newname in self.all_subterm_labels():
 
            raise SubtermExists("have a subterm who sub is named %r" % newname)
 
        with self.graph.currentState() as current:
 
            song = self.currentSong()
 
            for i in range(1000):
 
                uri = song + "/subterm/%d" % i
 
                if (uri, None, None) not in current:
 
                    break
 
            else:
 
                raise ValueError("can't pick a name for the new subterm")
 

	
 
        ctx = self.songSubtermsContext()
 
        quads = [
 
            (uri, RDF.type, L9.Subterm, ctx),
 
            (uri, RDFS.label, Literal(newname), ctx),
 
            (self.currentSong(), L9['subterm'], uri, ctx),
 
            ]
 
        if sub is not None:
 
            quads.append((uri, L9['sub'], sub, ctx))
 
        if expr is not None:
 
            quads.append((uri, L9['expression'], Literal(expr), ctx))
 
        self.graph.patch(Patch(addQuads=quads))
 
            
 
        return uri
 

	
 
    def all_subterm_labels(self):
 
        """
 
        Literal labels of subs in subterms. doesn't currently include labels of the
 
        subterm resources. I'm not sure what I'm going to do with
 
        those.
 
        """
 
        labels = []
 
        with self.graph.currentState() as current:
 
            for st in current.objects(
 
                    current.value(self.session, L9['currentSong']),
 
                    L9['subterm']):
 
                sub = current.value(st, L9['sub'])
 
                if sub is not None:
 
                    labels.append(current.label(sub))
 
        return labels
 
        
 
    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.debug("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.debug("removing subterm widgets")
 
        [master.remove(c) for c in master.get_children()]
 
        for term in self.currentSubterms:
 
            add_one_subterm(term, self.curveset, master)
 
        master.show_all()
 
        log.debug("%s table children showing" % len(master.get_children()))
 
        
 
    def refreshTheme(self):
 
        Gtk.rc_reparse_all()
 
        reactor.callLater(1, self.refreshTheme)
 

	
 
    def onSubtermChildAdded(self, subtermsTable, *args):
 
        # this would probably work, but isn't getting called
 
        log.info("onSubtermChildAdded")
 
        v = subtermsTable.get_parent().props.vadjustment
 
        v.props.value = v.props.upper
 

	
 
    def onQuit(self, *args):
 
        reactor.crash()
 
        # there's a hang after this, maybe in sem_wait in two
 
        # threads. I don't know whose they are.
 
        # This fix affects profilers who want to write output at the end.
 
        os.kill(os.getpid(), signal.SIGKILL)
 

	
 
    def onCollapseAll(self, *args):
 
        self.curvesetView.collapseAll()
 

	
 
    def onCollapseNone(self, *args):
 
        self.curvesetView.collapseNone()
 

	
 
    def onDelete(self, *args):
 
        self.curvesetView.onDelete()
 

	
 
    def onPythonConsole(self, item):
 
        ns = dict()
 
        ns.update(globals())
 
        ns.update(self.__dict__)
 
        togglePyConsole(self, item, ns)
 
        
 
    def onSeeCurrentTime(self, item):
 
        dispatcher.send("see time")
 

	
 
    def onSeeTimeUntilEnd(self, item):
 
        dispatcher.send("see time until end")
 

	
 
    def onZoomAll(self, item):
 
        dispatcher.send("show all")
 

	
 
    def onPlayPause(self, item):
 
        # since the X coord in a curveview affects the handling, one
 
        # of them may be able to pick this up
 
        results = dispatcher.send("onPlayPause")
 
        times = [t for listener, t in results if t is not None]
 
        self.music.playOrPause(t=times[0] if times else None)
 

	
 
    def onSave(self, *args):
 
        # only doing curves still. I hope to eliminate all this.
 
        log.info("saving curves")
 
        self.curveset.save()
 
        log.info("saved")
 

	
 
    def makeStatusLines(self, master):
 
        """various labels that listen for dispatcher signals"""
 
        for row, (signame, textfilter) in enumerate([
 
            ('input time', lambda t: "%.2fs"%t),
 
            ('output levels',
 
             lambda levels: textwrap.fill("; ".join(["%s:%.2f"%(n,v)
 
                                                     for n,v in
 
                                                     levels.items()[:2]
 
                                                     if v>0]),70)),
 
            ('update period', lambda t: "%.1fms"%(t*1000)),
 
            ('update status', lambda x: str(x)),
 
            ]):
 
            key = Gtk.Label("%s:" % signame)
 
            value = Gtk.Label("")
 
            master.resize(row + 1, 2)
 
            master.attach(key, 0, 1, row, row + 1)
 
            master.attach(value, 1, 2, row, row + 1)
 
            key.set_alignment(1, 0)
 
            value.set_alignment(0, 0)
 

	
 
            dispatcher.connect(lambda val, value=value, tf=textfilter:
 
                               value.set_text(tf(val)),
 
                               signame, weak=False)
 
        dispatcher.connect(lambda val: setattr(self, 'lastSeenInputTime', val),
 
                           'input time', weak=False)
 
        master.show_all()
 

	
 
    def refreshCurveView(self):
 
        wtree = self.wtree
 
        mtimes = [os.path.getmtime(f) for f in [
 
            'light9/curvecalc/curveview.py',
 
            'light9/curvecalc/zoomcontrol.py',
 
            ]]
 

	
 
        if (not hasattr(self, 'curvesetView') or
 
            self.curvesetView._mtimes != mtimes):
 
            print "reload curveview.py"
 
            curvesVBox = wtree.get_object("curves")
 
            zoomControlBox = wtree.get_object("zoomControlBox")
 
            [curvesVBox.remove(c) for c in curvesVBox.get_children()]
 
            [zoomControlBox.remove(c) for c in
 
             zoomControlBox.get_children()]
 
            try:
 
                linecache.clearcache()
 
                reload(curveview)
 

	
 
                # old ones are not getting deleted right
 
                if hasattr(self, 'curvesetView'):
 
                    self.curvesetView.live = False
 

	
 
                # mem problem somewhere; need to hold a ref to this
 
                self.curvesetView = curveview.Curvesetview(self.graph, 
 
                    curvesVBox, zoomControlBox, self.curveset)
 
                self.curvesetView._mtimes = mtimes
 

	
 
                # this is scheduled after some tk shuffling, to
 
                # try to minimize the number of times we redraw
 
                # the curve at startup. If tk is very slow, it's
 
                # ok. You'll just get some wasted redraws.
 
                self.curvesetView.goLive()
 
            except Exception:
 
                print "reload failed:"
 
                traceback.print_exc()
 
        if self.opts.reload:
 
            reactor.callLater(1, self.refreshCurveView)
 

	
 

	
 
class MaxTime(object):
 
    """
 
    looks up the time in seconds for the session's current song
 
    """
 
    def __init__(self, graph, session):
 
        self.graph, self.session = graph, session
 
        graph.addHandler(self.update)
 

	
 
    def update(self):
 
        song = self.graph.value(self.session, L9['currentSong'])
 
        if song is None:
 
            self.maxtime = 0
 
            return
 
        musicfilename = showconfig.songOnDisk(song)
 
        self.maxtime = wavelength(musicfilename)
 
        log.info("new max time %r", self.maxtime)
 
        dispatcher.send("max time", maxtime=self.maxtime)
 

	
 
    def get(self):
 
        return self.maxtime
 

	
 
def launch(args, graph, session, opts, startTime, music):
 

	
 
    try:
 
        song = URIRef(args[0])
 
        graph.patchObject(context=session,
 
                          subject=session,
 
                          predicate=L9['currentSong'],
 
                          newObject=song)
 
    except IndexError:
 
        pass
 

	
 
    curveset = Curveset(graph=graph, session=session)
 
        
 
    log.debug("startup: output %s", time.time() - startTime)
 

	
 
    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")
 
        
 
    if opts.startup_only:
 
        log.debug("quitting now because of --startup-only")
 
        return
 

	
 
    def hoverTimeResponse(requestHandler):
 
        results = dispatcher.send("onPlayPause")
 
        times = [t for listener, t in results if t is not None]
 
        if not times:
 
            requestHandler.set_status(404)
 
            requestHandler.write("not hovering over any time")
 
            return
 
        with graph.currentState(
 
                tripleFilter=(session, L9['currentSong'], None)) as g:
 
            song = g.value(session, L9['currentSong'])
 
            json.dump({"song": song, "hoverTime" : times[0]}, requestHandler)
 
        
 
    serveCurveEdit(networking.curveCalc.port, hoverTimeResponse, start.curveset)
 

	
 
def main():
 
    startTime = time.time()
 
    parser = optparse.OptionParser()
 
    parser.set_usage("%prog [opts] [songURI]")
 
    parser.add_option("--debug", action="store_true",
 
                      help="log at DEBUG")
 
    parser.add_option("--reload", action="store_true",
 
                      help="live reload of themes and code")
 
    parser.add_option("--startup-only", action='store_true',
 
                      help="quit after loading everything (for timing tests)")
 
    parser.add_option("--profile", action='store_true', help='profile')
 
    parser.add_option("--profile", help='"hotshot" or "stat"')
 
    clientsession.add_option(parser)
 
    opts, args = parser.parse_args()
 

	
 
    log.setLevel(logging.DEBUG if opts.debug else logging.INFO)
 

	
 
    log.debug("startup: music %s", time.time() - startTime)
 

	
 

	
 
    session = clientsession.getUri('curvecalc', opts)
 

	
 
    music = Music()
 
    graph = SyncedGraph(networking.rdfdb.url, "curvecalc")
 

	
 
    graph.initiallySynced.addCallback(
 
        lambda _: launch(args, graph, session, opts, startTime, music))
 
    from light9 import prof
 
    prof.run(reactor.run, profile=opts.profile)
 

	
 
main()
 

	
light9/prof.py
Show inline comments
 
import sys, traceback, time, logging
 
log = logging.getLogger()
 

	
 
def run(main, profile=False):
 
def run(main, profile=None):
 
    if not profile:
 
        main()
 
        return
 
    
 
    import hotshot, hotshot.stats
 
    p = hotshot.Profile("/tmp/pro")
 
    p.runcall(main)
 
    p.close()
 
    hotshot.stats.load("/tmp/pro").sort_stats('cumulative').print_stats()
 

	
 
    if profile == 'hotshot':
 
        import hotshot, hotshot.stats
 
        p = hotshot.Profile("/tmp/pro")
 
        p.runcall(main)
 
        p.close()
 
        hotshot.stats.load("/tmp/pro").sort_stats('cumulative').print_stats()
 
    elif profile == 'stat':
 
        import statprof
 
        statprof.start()
 
        try:
 
            main()
 
        finally:
 
            statprof.stop()
 
            statprof.display()
 
    
 
def watchPoint(filename, lineno, event="call"):
 
    """whenever we hit this line, print a stack trace. event='call'
 
    for lines that are function definitions, like what a profiler
 
    gives you.
 

	
 
    Switch to 'line' to match lines inside functions. Execution speed
 
    will be much slower."""
 
    seenTraces = {} # trace contents : count
 
    def trace(frame, ev, arg):
 
        if ev == event:
 
            if (frame.f_code.co_filename, frame.f_lineno) == (filename, lineno):
 
                stack = ''.join(traceback.format_stack(frame))
 
                if stack not in seenTraces:
 
                    print "watchPoint hit"
 
                    print stack
 
                    seenTraces[stack] = 1
 
                else:
 
                    seenTraces[stack] += 1
 

	
 
        return trace
 
    sys.settrace(trace)
 

	
 
    # atexit, print the frequencies?
 

	
 
def logTime(func):
 
    def inner(*args, **kw):
 
        t1 = time.time()
 
        try:
 
            ret = func(*args, **kw)
 
        finally:
 
            log.info("Call to %s took %.1f ms" % (
 
                func.__name__, 1000 * (time.time() - t1)))
 
        return ret
 
    return inner
0 comments (0 inline, 0 general)