@shellex说: RT : 广告之拉拉情缘,SISLEY为主

用Python可视化Profile

得益与Graphviz以及Python强劲的自省能力——Abettor GG,这就是你当年乐道的‘反射’啦,Shellex搞了一个可以生成Call Graph的东东。

谢谢Python-cn的各位同学给偶这个小菜菜的帮助,顺便过了一遍《源码剖析》的第八章。

class call_tracker:
    def __init__(self, cls, logfile='track.log'):
        self.stack = [('Push', 'start')]
        self.call_map = {} 

        cls = cls if isinstance(cls, list) else [cls]

        calls = reduce(lambda a, b: a.__add__(b), [self.get_calls(c) for c in cls])
        for type, name, call in calls:
            call = self.hook(call)
            setattr(type, name, call)
        self.reg = re.compile('<(.*?) (.*?) (.*?)>')

    def __del__(self):
        pass

    def get_calls(self, cls):
        return filter(lambda (type, name, addr): callable(addr), [(cls, x, getattr(cls, x)) for x in dir(cls)])

    def get_func_name(self, proc):
        return self.reg.search(proc.__str__()).group(3)

    def hook(self, proc):
        def uname(*args):
            proc_name = self.get_func_name(proc)
            #print '[Entry]  %s' % ( proc_name)

            action, parent = self.stack[-1]

            self.stack.append(('Push', proc_name))
            start_t = time.time()
            ret = proc(*args)
            cost_t = (time.time() - start_t) * 1000
            self.stack.pop()

            if action == 'Push':
                if not self.call_map.has_key((parent, proc_name)):
                    cnt = 1
                else:
                    cnt, cost = self.call_map[(parent, proc_name)]
                    cnt += 1
                self.call_map[(parent, proc_name)] = (cnt, cost_t)

            #print '[Leave]  %s' % ( proc_name)
            return ret
        return uname

    def write_png(self, png):
        out = 'digraph %s { \n' % png.replace('.', '_')
        out += 'rankdir=LR;\n'
        for (frm, to), (cnt, cost) in self.call_map.iteritems():
            out += '"%s" -> "%s" [label="%s(%.3fms)"];\n' % (frm, to, cnt, cost)
        out += '}\n'
        dot = open(png+'.gv', 'w+')
        dot.write(out)
        dot.close()
        from os import popen2
        popen2('/usr/bin/dot -Tpng %s -o %s' % (png+'.gv', png))
        #popen2('/usr/bin/eog ./%s' % png)

效果如下:
track2

嗯。下面是偶的一个正则解析器解析(a|b|c)*da的过程,有点大哈。:
track1

  1. On February 28, 2009 at 7:24 am

    写得太pythonic,得研究研究。

    Notify
  2. On February 28, 2009 at 5:24 pm

    @HicroKee,
    嘿嘿,不好意思…人懒了。

    Notify
  3. On March 3, 2009 at 4:53 pm
    凡客 :

    博主您好,申请贵站的友情连接,贵站连接已经做好
    希望能通过!
    我的博客是www.f9011.cn/博客名称是 凡客

    Notify
  4. On March 9, 2009 at 9:59 am

    “Abettor GG,这就是你当年乐道的‘反射’啦。”
    ——汗,被点名了!

    Notify
  5. On March 9, 2009 at 6:38 pm

    @abettor,
    挖哈哈哈哈

    Notify
  6. On July 30, 2009 at 10:22 am
    ahbei :

    博主那个最后的图是用什么工具画的啊?

    Notify
  7. On July 30, 2009 at 4:25 pm

    @ahbei,
    哦,那个工具是Graphviz, 文章开头有提到

    Notify

Leave a Reply