posts - 225, comments - 62, trackbacks - 0, articles - 0
   :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

Python实现的瓶颈分析计时

Posted on 2021-10-08 10:45 魔のkyo 阅读(128) 评论(0)  编辑 收藏 引用
import time

class PerfCounter():
    def get_time(self):
        return time.perf_counter()


class Node:
    clock = None

    def __init__(self, name, parent):
        # 带父节点的孩子兄弟树结构字段
        self.parent = parent
        self.child = None
        self.sibling = None

        self.name = name
        self.total_calls = 0
        self.recursion_counter = 0
        self.total_ticks = 0

    def __del__(self):
        if self.child:
            del self.child
            self.child = None
        if self.sibling:
            del self.sibling
            self.sibling = None

    def get_child(self, name):
        child = self.child
        while child:
            if child.name == name:
                return child
            child = child.sibling

        # 如果没有找到就新建结点,并插入作为第一个孩子
        node = Node(name=name, parent=self)
        node.sibling = self.child
        self.child = node
        return node

    def reset(self):
        self.total_calls = 0
        self.total_ticks = 0
        if self.child:
            self.child.reset()
        if self.sibling:
            self.sibling.reset()

    def enter(self):
        self.total_calls += 1
        self.recursion_counter += 1
        if self.recursion_counter == 1:
            self.start_tick = self.clock.get_time()

    def exit(self):
        self.recursion_counter -= 1
        if self.recursion_counter == 0 and self.total_calls != 0:
            tick = self.clock.get_time() - self.start_tick;
            self.total_ticks += tick;
        return (self.recursion_counter == 0)


class Profiler:
    def __init__(self, clock=None):
        Node.clock = clock or PerfCounter()
        self.root = Node("", None)
        self.current_node = self.root
        self.root.enter()

    def __del__(self):
        if self.root:
            del self.root

    def set_clock(self, clock):
        Node.clock = clock

    def reset(self):
        self.root.reset()
        self.root.enter()

    def enter(self, name):
        if name != self.current_node.name:
            self.current_node = self.current_node.get_child(name)
        self.current_node.enter()

    def exit(self):
        if self.current_node.exit():
            self.current_node = self.current_node.parent

profiler = Profiler()

def time_me(fn, profiler=profiler):
    def wrapper(*args, **kw):
        profiler.enter(fn.__name__)
        ret = fn(*args, **kw)
        profiler.exit()
        return ret
    return wrapper

def enter_region(name, profiler=profiler):
    profiler.enter(name)

def exit_region(profiler=profiler):
    profiler.exit()

def dfs(node, depth, cb):
    cb(node, depth)
    node = node.child
    while node:
        dfs(node, depth+1, cb)
        node = node.sibling

def travel(cb, profiler=profiler):
    if profiler.root:
        profiler.root.exit()
    dfs(profiler.root, 0, cb)

def view(node, depth):
    print("{space}[{name}] {calls} times {ticks:.3f} seconds {rate:.2f}%".format(
        space=" "*depth, name=node.name, calls=node.total_calls, ticks=node.total_ticks, rate=node.total_ticks*100/(node.parent and node.parent.total_ticks or node.total_ticks) ))


if __name__ == '__main__':
    @time_me
    def func1():
        time.sleep(0.5)
        func3()

    @time_me
    def func2(n):
        if n <= 2:
            func3()
            return 1
        else:
            return func2(n-1) + func2(n-2)

    @time_me
    def func3():
        enter_region("func3 sleep")
        time.sleep(0.1)
        exit_region()

    func1()
    for i in range(1, 5):
        print(func2(i))
    func1()
    travel(view)
只有注册用户登录后才能发表评论。