Browse Source

fixed FrameProfiler/taskMgr synchronization problem

Darren Ranalli 17 years ago
parent
commit
3b2a2af619

+ 3 - 4
direct/src/showbase/ProfileSession.py

@@ -306,6 +306,8 @@ class ProfileSession:
         
         
         if statsChanged:
         if statsChanged:
             self._stats.strip_dirs()
             self._stats.strip_dirs()
+            # throw out any cached result strings
+            self._resultCache = {}
 
 
         return statsChanged
         return statsChanged
 
 
@@ -326,10 +328,7 @@ class ProfileSession:
             if totalTime is Default:
             if totalTime is Default:
                 totalTime = self._totalTime
                 totalTime = self._totalTime
             
             
-            statsChanged = self._compileStats()
-            if statsChanged:
-                # throw out any cached result strings
-                self._resultCache = {}
+            self._compileStats()
 
 
             if totalTime is None:
             if totalTime is None:
                 totalTime = self._stats.total_tt
                 totalTime = self._stats.total_tt

+ 46 - 23
direct/src/task/FrameProfiler.py

@@ -14,6 +14,8 @@ class FrameProfiler:
         Hour = FrameProfiler.Hour
         Hour = FrameProfiler.Hour
         # how long to wait between frame profiles
         # how long to wait between frame profiles
         self._period = 2 * FrameProfiler.Minute
         self._period = 2 * FrameProfiler.Minute
+        if config.GetBool('frame-profiler-debug', 0):
+            self._period = 1 * FrameProfiler.Minute
         # used to prevent profile from being taken exactly every 'period' seconds
         # used to prevent profile from being taken exactly every 'period' seconds
         self._jitterMagnitude = self._period * .75
         self._jitterMagnitude = self._period * .75
         # when to log output
         # when to log output
@@ -24,6 +26,12 @@ class FrameProfiler:
                              12 * FrameProfiler.Hour,
                              12 * FrameProfiler.Hour,
                               1 * FrameProfiler.Day,
                               1 * FrameProfiler.Day,
                               ] # day schedule proceeds as 1, 2, 4, 8 days, etc.
                               ] # day schedule proceeds as 1, 2, 4, 8 days, etc.
+        if config.GetBool('frame-profiler-debug', 0):
+            self._logSchedule = [ 1  * FrameProfiler.Minute,
+                                  4  * FrameProfiler.Minute,
+                                  12 * FrameProfiler.Minute,
+                                  24 * FrameProfiler.Minute,
+                                  ]
         for t in self._logSchedule:
         for t in self._logSchedule:
             assert isInteger(t)
             assert isInteger(t)
             # make sure the period is evenly divisible into each element of the log schedule
             # make sure the period is evenly divisible into each element of the log schedule
@@ -47,9 +55,10 @@ class FrameProfiler:
             self._profileCounter = 0
             self._profileCounter = 0
             self._jitter = None
             self._jitter = None
             self._period2aggregateProfile = {}
             self._period2aggregateProfile = {}
-            self._lastSession = None
+            self._id2session = {}
+            self._id2task = {}
             # don't profile process startup
             # don't profile process startup
-            self._task = taskMgr.doMethodLater(self._period, self._startProfiling,
+            self._task = taskMgr.doMethodLater(self._period, self._scheduleNextProfileDoLater,
                                                'FrameProfilerStart-%s' % serialNum())
                                                'FrameProfilerStart-%s' % serialNum())
         else:
         else:
             self._task.remove()
             self._task.remove()
@@ -57,12 +66,15 @@ class FrameProfiler:
             for session in self._period2aggregateProfile.itervalues:
             for session in self._period2aggregateProfile.itervalues:
                 session.release()
                 session.release()
             del self._period2aggregateProfile
             del self._period2aggregateProfile
-            if self._lastSession:
-                self._lastSession.release()
-            del self._lastSession
+            for task in self._id2task.itervalues():
+                task.remove()
+            del self._id2task
+            for session in self._id2session.itervalues():
+                session.release()
+            del self._id2session
             self.notify.info('frame profiler stopped')
             self.notify.info('frame profiler stopped')
 
 
-    def _startProfiling(self, task):
+    def _scheduleNextProfileDoLater(self, task):
         self._scheduleNextProfile()
         self._scheduleNextProfile()
         return task.done
         return task.done
 
 
@@ -83,30 +95,41 @@ class FrameProfiler:
             jitter = None
             jitter = None
         self._jitter = jitter
         self._jitter = jitter
             
             
-        self._lastSession = taskMgr.getProfileSession('FrameProfile-%s' % serialNum())
-        taskMgr.profileFrames(num=1, session=self._lastSession)
+        sessionId = serialNum()
+        session = taskMgr.getProfileSession('FrameProfile-%s' % sessionId)
+        self._id2session[sessionId] = session
+        taskMgr.profileFrames(num=1, session=session, callback=Functor(
+            self._analyzeResults, sessionId))
 
 
+        # schedule the next profile
         delay = max(time - globalClock.getFrameTime(), 0.)
         delay = max(time - globalClock.getFrameTime(), 0.)
-        self._task = taskMgr.doMethodLater(delay, self._frameProfileTask,
+        self._task = taskMgr.doMethodLater(delay, self._scheduleNextProfileDoLater,
                                            'FrameProfiler-%s' % serialNum())
                                            'FrameProfiler-%s' % serialNum())
 
 
-    def _frameProfileTask(self, task):
+    def _analyzeResults(self, sessionId):
+        # do the analysis in a task 1) to separate the processing from the profiled frame,
+        # and 2) to get the processing to show up in a named task instead of in the taskMgr
+        self._id2task[sessionId] = taskMgr.add(
+            Functor(self._doAnalysis, sessionId), 'FrameProfilerAnalysis-%s' % sessionId)
+
+    def _doAnalysis(self, sessionId, task):
         p2ap = self._period2aggregateProfile
         p2ap = self._period2aggregateProfile
 
 
-        if self._lastSession:
-            if self._lastSession.profileSucceeded():
-                # always add this profile to the first aggregated profile
-                period = self._logSchedule[0]
-                if period not in self._period2aggregateProfile:
-                    p2ap[period] = self._lastSession.getReference()
-                else:
-                    p2ap[period].aggregate(self._lastSession)
+        self._id2task.pop(sessionId)
+        session = self._id2session.pop(sessionId)
+
+        if session.profileSucceeded():
+            # always add this profile to the first aggregated profile
+            period = self._logSchedule[0]
+            if period not in self._period2aggregateProfile:
+                p2ap[period] = session.getReference()
             else:
             else:
-                self.notify.warning('frame profile did not succeed')
+                p2ap[period].aggregate(session)
+        else:
+            self.notify.warning('frame profile did not succeed')
 
 
-        # always release the last-recorded profile
-        self._lastSession.release()
-        self._lastSession = None
+        session.release()
+        session = None
 
 
         # log profiles when it's time, and aggregate them upwards into the
         # log profiles when it's time, and aggregate them upwards into the
         # next-longer profile
         # next-longer profile
@@ -138,5 +161,5 @@ class FrameProfiler:
                 # periods are multiples of this one
                 # periods are multiples of this one
                 break
                 break
 
 
-        self._scheduleNextProfile()
         return task.done
         return task.done
+    

+ 8 - 3
direct/src/task/TaskNew.py

@@ -456,12 +456,15 @@ class TaskManager:
             while self.running:
             while self.running:
                 try:
                 try:
                     if len(self._frameProfileQueue):
                     if len(self._frameProfileQueue):
-                        numFrames, session = self._frameProfileQueue.pop()
+                        numFrames, session, callback = self._frameProfileQueue.pop()
                         def _profileFunc(numFrames=numFrames):
                         def _profileFunc(numFrames=numFrames):
                             self._doProfiledFrames(numFrames)
                             self._doProfiledFrames(numFrames)
                         session.setFunc(_profileFunc)
                         session.setFunc(_profileFunc)
                         session.run()
                         session.run()
                         _profileFunc = None
                         _profileFunc = None
+                        if callback:
+                            callback()
+                        session.release()
                     else:
                     else:
                         self.step()
                         self.step()
                 except KeyboardInterrupt:
                 except KeyboardInterrupt:
@@ -546,12 +549,14 @@ class TaskManager:
             name = 'taskMgrFrameProfile'
             name = 'taskMgrFrameProfile'
         return ProfileSession(name)
         return ProfileSession(name)
 
 
-    def profileFrames(self, num=None, session=None):
+    def profileFrames(self, num=None, session=None, callback=None):
         if num is None:
         if num is None:
             num = 1
             num = 1
         if session is None:
         if session is None:
             session = self.getProfileSession()
             session = self.getProfileSession()
-        self._frameProfileQueue.push((num, session))
+        # make sure the profile session doesn't get destroyed before we're done with it
+        session.acquire()
+        self._frameProfileQueue.push((num, session, callback))
 
 
     def _doProfiledFrames(self, numFrames):
     def _doProfiledFrames(self, numFrames):
         for i in xrange(numFrames):
         for i in xrange(numFrames):

+ 8 - 3
direct/src/task/TaskOrig.py

@@ -1030,12 +1030,14 @@ class TaskManager:
             name = 'taskMgrFrameProfile'
             name = 'taskMgrFrameProfile'
         return ProfileSession(name)
         return ProfileSession(name)
 
 
-    def profileFrames(self, num=None, session=None):
+    def profileFrames(self, num=None, session=None, callback=None):
         if num is None:
         if num is None:
             num = 1
             num = 1
         if session is None:
         if session is None:
             session = self.getProfileSession()
             session = self.getProfileSession()
-        self._frameProfileQueue.push((num, session))
+        # make sure the profile session doesn't get destroyed before we're done with it
+        session.acquire()
+        self._frameProfileQueue.push((num, session, callback))
     
     
 
 
     # in the event we want to do frame time managment.. this is the function to 
     # in the event we want to do frame time managment.. this is the function to 
@@ -1241,12 +1243,15 @@ class TaskManager:
             while self.running:
             while self.running:
                 try:
                 try:
                     if len(self._frameProfileQueue):
                     if len(self._frameProfileQueue):
-                        numFrames, session = self._frameProfileQueue.pop()
+                        numFrames, session, callback = self._frameProfileQueue.pop()
                         def _profileFunc(numFrames=numFrames):
                         def _profileFunc(numFrames=numFrames):
                             self._doProfiledFrames(numFrames)
                             self._doProfiledFrames(numFrames)
                         session.setFunc(_profileFunc)
                         session.setFunc(_profileFunc)
                         session.run()
                         session.run()
                         _profileFunc = None
                         _profileFunc = None
+                        if callback:
+                            callback()
+                        session.release()
                     else:
                     else:
                         self.step()
                         self.step()
                 except KeyboardInterrupt:
                 except KeyboardInterrupt: