~loggerhead-team/loggerhead/trunk-rich

« back to all changes in this revision

Viewing changes to loggerhead/middleware/profile.py

  • Committer: Matt Nordhoff
  • Date: 2009-04-07 18:35:19 UTC
  • mto: This revision was merged to the branch mainline in revision 324.
  • Revision ID: mnordhoff@mattnordhoff.com-20090407183519-b074keg32g1ho0ga
Badly-written NEWS entry. :D

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
'''Profiling middleware for paste.'''
 
2
import cgi
 
3
import logging
 
4
import sys
 
5
import threading
 
6
 
 
7
from bzrlib.lsprof import profile
 
8
from guppy import hpy
 
9
 
 
10
class LSProfMiddleware(object):
 
11
    '''Paste middleware for profiling with lsprof.'''
 
12
 
 
13
    def __init__(self, app, global_conf=None):
 
14
        self.app = app
 
15
        self.lock = threading.Lock()
 
16
        self.__count = 0
 
17
 
 
18
    def __run_app(self, environ, start_response):
 
19
        app_iter = self.app(environ, start_response)
 
20
        try:
 
21
            return list(app_iter)
 
22
        finally:
 
23
            if getattr(app_iter, 'close', None):
 
24
                app_iter.close()
 
25
 
 
26
    def __call__(self, environ, start_response):
 
27
        """Run a request."""
 
28
        self.lock.acquire()
 
29
        try:
 
30
            ret, stats = profile(self.__run_app, environ, start_response)
 
31
            self.__count += 1
 
32
            stats.save("%d-stats.callgrind" % self.__count, format="callgrind")
 
33
            return ret
 
34
        finally:
 
35
            self.lock.release()
 
36
 
 
37
 
 
38
class MemoryProfileMiddleware(object):
 
39
    '''Paste middleware for profiling memory with heapy.'''
 
40
 
 
41
    def __init__(self, app, limit=40):
 
42
        self.app = app
 
43
        self.lock = threading.Lock()
 
44
 
 
45
        self.type2count = {}
 
46
        self.type2all = {}
 
47
        self.limit = limit
 
48
 
 
49
    def update(self):
 
50
        try:
 
51
            obs = sys.getobjects(0)
 
52
        except AttributeError:
 
53
            logging.error(
 
54
                'Python does not have debug symbols compiled.  Memory will '
 
55
                'not be profiled.')
 
56
            return
 
57
        type2count = {}
 
58
        type2all = {}
 
59
        for o in obs:
 
60
            all = sys.getrefcount(o)
 
61
 
 
62
            if type(o) is str and o == '<dummy key>':
 
63
                # avoid dictionary madness
 
64
                continue
 
65
            t = type(o)
 
66
            if t in type2count:
 
67
                type2count[t] += 1
 
68
                type2all[t] += all
 
69
            else:
 
70
                type2count[t] = 1
 
71
                type2all[t] = all
 
72
 
 
73
        ct = [(type2count[t] - self.type2count.get(t, 0),
 
74
               type2all[t] - self.type2all.get(t, 0),
 
75
               t)
 
76
              for t in type2count.iterkeys()]
 
77
        ct.sort()
 
78
        ct.reverse()
 
79
        printed = False
 
80
 
 
81
        logger = logging.getLogger('loggerhead-memprofile')
 
82
        logger.debug('*' * 20)
 
83
        logger.debug("Loggerhead Memory Profiling")
 
84
        i = 0
 
85
        for delta1, delta2, t in ct:
 
86
            if delta1 or delta2:
 
87
                if not printed:
 
88
                    logger.debug("%-55s %8s %8s" % ('', 'insts', 'refs'))
 
89
                    printed = True
 
90
 
 
91
                logger.debug("%-55s %8d %8d" % (t, delta1, delta2))
 
92
 
 
93
                i += 1
 
94
                if i >= self.limit:
 
95
                    break
 
96
 
 
97
        self.type2count = type2count
 
98
        self.type2all = type2all
 
99
 
 
100
    def __call__(self, environ, start_response):
 
101
        self.lock.acquire()
 
102
        try:
 
103
            # We don't want to be working with the static images
 
104
            # TODO: There needs to be a better way to do this.
 
105
            self.update()
 
106
            return self.app(environ, start_response)
 
107
        finally:
 
108
            self.lock.release()
 
109