from pypy.translator.simplify import get_graph
from pypy.tool.compat import md5

def get_statistics(graph, translator, save_per_graph_details=None, ignore_stack_checks=False):
    seen_graphs = {}
    stack = [graph]
    num_graphs = 0
    num_blocks = 0
    num_ops = 0
    num_mallocs = 0
    per_graph = {}
    while stack:
        graph = stack.pop()
        if graph in seen_graphs:
            continue
        seen_graphs[graph] = True
        num_graphs += 1
        old_num_blocks = num_blocks
        old_num_ops = num_ops
        old_num_mallocs = num_mallocs
        for block in graph.iterblocks():
            num_blocks += 1
            for op in block.operations:
                if op.opname == "direct_call":
                    called_graph = get_graph(op.args[0], translator)
                    if called_graph is not None and ignore_stack_checks:
                        if called_graph.name.startswith('ll_stack_check'):
                            continue
                    if called_graph is not None:
                        stack.append(called_graph)
                elif op.opname == "indirect_call":
                    called_graphs = op.args[-1].value
                    if called_graphs is not None:
                        stack.extend(called_graphs)
                elif op.opname.startswith("malloc"):
                    num_mallocs += 1
                num_ops += 1
        per_graph[graph] = (num_blocks-old_num_blocks, num_ops-old_num_ops, num_mallocs-old_num_mallocs)
    if save_per_graph_details:
        details = []
        for graph, (nblocks, nops, nmallocs) in per_graph.iteritems():
            try:
                code = graph.func.func_code.co_code
            except AttributeError:
                code = "None"
            hash = md5(code).hexdigest()
            details.append((hash, graph.name, nblocks, nops, nmallocs))
        details.sort()
        f = open(save_per_graph_details, "w")
        try:
            for hash, name, nblocks, nops, nmallocs in details:
                print >>f, hash, name, nblocks, nops, nmallocs
        finally:
            f.close()
    return num_graphs, num_blocks, num_ops, num_mallocs

def print_statistics(graph, translator, save_per_graph_details=None, ignore_stack_checks=False):
    num_graphs, num_blocks, num_ops, num_mallocs = get_statistics(
            graph, translator, save_per_graph_details,
            ignore_stack_checks=ignore_stack_checks)
    print ("Statistics:\nnumber of graphs %s\n"
           "number of blocks %s\n"
           "number of operations %s\n"
           "number of mallocs %s\n"
           ) % (num_graphs, num_blocks, num_ops, num_mallocs)
