#!/usr/bin/env python
# -*- python -*-
# Mark Charney <mark.charney@intel.com>

# Grab the BLOCKCOUNT and MAPPADDR lines from the mix-mt output and
# attach that to a copy of the program. Run mix-mt with the -mapaddr
# pin took knob. And compile your program with -g

import os,sys,re
pcmap={}

class stat_t(object):
    def __init__(self, filename='unknown', line=0, pc=None):
        self.filename=filename
        self.line = int(line)
        self.count = 0
        self.pc = pc
        self.rank = 0

def stat_sorter(a,b):
    if a.count > b.count:
        return -1
    if a.count < b.count:
        return 1
    return 0

def stat_sorter_line(a,b):
    if a.line > b.line:
        return 1
    if a.line < b.line:
        return -1
    return 0

def combine_by_file_and_line(lines):
    """Even though the PC might be different"""
    tmap = {}
    for f in lines:
        key = "%s-%s" % (f.line, f.filename)
        if key not in tmap:
            tmap[key]=f
        else:
            tmap[key].count += f.count
    tmap['0-unknown'].pc = 'various'
    return tmap.values()
        
    
def summarize():
    global pcmap

    #for k,f in pcmap.iteritems():
    #    print "%9s %8s %s:%s" % ( f.count, k, f.filename, f.line)
    lines = pcmap.values()
    # remove the zero entries
    lines = filter(lambda(x): x.count != 0, lines)
    # merge things with the same file and line
    lines = combine_by_file_and_line(lines)
    lines.sort(cmp=stat_sorter)
    for i,f in enumerate(lines):
        f.rank = i
        print "AA%05d: %9s %8s %s:%d" % ( i, f.count, f.pc, f.filename, f.line)
    return lines
        
def store_mapaddr(p):
    global pcmap
    (dummy, pc, line, filename) = p
    #print "setting pc %s to %s : %s" % (pc, filename,line)
    if pc in pcmap:
        pcmap[pc].filename = filename
        pcmap[pc].line = int(line)
        pcmap[pc].pc=pc
    else:
        pcmap[pc]=stat_t(filename,line,pc)
    
def store_blockcount(p):
    global pcmap
    (dummy, pc, count) = p
    if pc in pcmap:
        pcmap[pc].count += int(count)
    else:
        t = stat_t()
        t.pc = pc
        t.count = int(count)
        pcmap[pc]  = t


def make_decorated_file(ifn,flines):
    """Emit a copy of f with the counts specified in the sorted list of stat_t's"""
    fnew = "%s.pcov" % (ifn)
    if os.path.exists(fnew):
        sys.stderr.write("The file %s already exists. Please remove it if you want the new profile\n" % (fnew))
        return
    try:
        f = open(fnew,"w")
    except:
        sys.stderr.write("Could not write %s -- skipping\n" % (fnew))
        return
    sys.stderr.write("Writing [%s]\n" % (fnew))
    nline = 1
    for x in  file(ifn).readlines():
        decorated = False
        while len(flines) > 0 and flines[0].line == nline:
            if decorated:
                f.write("+")
            else:
                f.write("AA%05d " % (flines[0].rank))
            f.write("%9d" % (flines[0].count))
            flines.pop(0)
            decorated = True
        if not decorated:
            f.write("%7s %9s" % ('', '')) # pad the line equivalently
        f.write(" ")
        f.write(x)
        nline += 1
    f.close()

def main(input_fn):
    mapaddr = re.compile("^MAPADDR ")
    blockcount = re.compile("^BLOCKCOUNT ")
    lines = file(input_fn).readlines()
    for line in lines:
        m = mapaddr.match(line)
        if m:
            store_mapaddr(line.strip().split())
        b = blockcount.match(line)
        if b:
            store_blockcount(line.strip().split())
    lines = summarize()
    
    filenames = {}
    for f in lines:
        if f.filename not in filenames and f.filename != 'unknown':
            filenames[f.filename]=1

    for f in filenames.keys():
        flines = filter(lambda(x): x.filename == f, lines)
        flines.sort(cmp=stat_sorter_line)
        make_decorated_file(f,flines)
    
if len(sys.argv) != 2:
    sys.stderr.write("Need an input file\n")
    sys.exit(1)
input_fn = sys.argv[1]
print "Input file %s" % (input_fn)
main(input_fn)
