#!/usr/bin/env python

"""parse_results.py: Parse results from PaStiX."""

__author__      = "Xavier Lacoste"

import os
import re
import sys
from optparse import OptionParser

class Parser:
    _regex = {}
    _boolean_regex = {}
    def __init__(self, regex, boolean_regex):
        for key, reg in regex.items():
            self._regex[key] = re.compile(reg)
        for key, reg in boolean_regex.items():
            self._boolean_regex[key] = re.compile(reg)

    def parse(self, f):
        _res = {}
        for key in self._boolean_regex.keys():
            _res[key] = False
        for line in open(f):
            for key, reg in self._regex.items():
                tmp = reg.search(line)
                if (tmp):
                    _res[key] = tmp.group(1)
            for key, reg in self._boolean_regex.items():
                tmp = reg.search(line)
                if (tmp):
                    _res[key] = True
        return _res



if __name__ == "__main__":
    usage=u"""usage:%prog <files>
    parse PaStiX output files
    """

    optParser = OptionParser(usage=usage)
    # Parse the command line
    optParser.add_option("-f", "--flops", dest="flops",
                         help="Display flops",
                         action="store_true", default=False)
    optParser.add_option("-t", "--times", dest="times",
                         help="Display times",
                         action="store_true", default=False)
    optParser.add_option("-b", "--best", dest="best",
                         help="Display best values only",
                         action="store_true", default=False)


    (options, args) = optParser.parse_args()
    if (not options.flops and not options.times):
        options.flops = True

    p = Parser({
        u"MPI"       : u"\s*Number of cluster\s*(\d+)",
        u"THREADS"   : u"\s*Number of thread number per MPI process\s*(\d+)",
        u"SCHEDULER" : u"StarPU : Thread policy : (.*)",
        u"MATRIX"    : u"driver: .* file: .*/([^/^.]*).*\n",
        u"FLOPS"     : u"FLOPS during factorization\s*([-.e+0-9]*) GFLOPS",
        u"TIME"      : u"Time to factorize\s*([-.e+0-9]*) s"
    },{
        u"FANIN"     : u"Outgoing Fanin cblk number"
    })
    all_res = []
    for f in args:
        res = {u"FILE" : f}
        directory=os.path.dirname(f)
        directory_name=os.path.basename(directory)
        directory_name.replace(u"pml_DF", u"pmlDF")
        res[u"DATE"]=os.path.basename(os.path.dirname(directory))
        match=re.search("([^_]*)_([^_]*)_([^_]*)_([^_]*)_([^_]*)_([^_]*)_([^_]*)",
                        re.sub(u"pml_DF", "pmlDF", directory_name))
        res[u"MACHINE"]=match.group(1)
        res[u"CUDA"]=match.group(7)
        try:
            match=re.search(".*NESTED([01]).*", directory_name)
            res[u"NESTED"]="NESTED"+match.group(1)
        except:
            res[u"NESTED"]="NESTED0"
        res.update(p.parse(f))
        #if not u"SCHEDULER" in res.keys():
        #    res[u"SCHEDULER"] = u"pastix"
        #    res[u"FANIN"]     = True
        if u"MATRIX" in res.keys():
            res[u"MATRIX"] = re.sub("matrix_acoustic_pml_DF", "pml_DF", res[u"MATRIX"])
            res[u"MATRIX"] = re.sub("10M_Matrice", "10Millions",        res[u"MATRIX"])
            res[u"MATRIX"] = re.sub("matr5",        "MHD",              res[u"MATRIX"])
            all_res.append(res)
        #else:
        #    print(res)#, file=sys.stderr)

    matrices=[u"afshell10",
              u"FilterV2",
              u"Flan1565",
              u"audi",
              u"MHD",
              u"Geo1438",
              u"pml_DF",
              u"Hook",
              u"Serena",
              u"10Millions",
              u"G3"]

    for res in all_res:
        if u"MATRIX" in res.keys():
            if res[u"MATRIX"] not in matrices:
                matrices.append(res[u"MATRIX"])

    schedulers=[]
    for res in all_res:
        if u"SCHEDULER" in res.keys():
            if [res[u"SCHEDULER"],res["FANIN"],res["NESTED"]] not in schedulers:
                schedulers.append([res[u"SCHEDULER"],res["FANIN"],res["NESTED"]])
    fields = ("X", "Matrix")
    FORMAT = u"%2s %10s"
    procs = []
    for res in all_res:
        if u"MPI" in res.keys():
            if float(res[u"MPI"]) not in procs:
                procs.append(float(res[u"MPI"]))
    procs.sort()
    gpus = []
    for res in all_res:
        if u"CUDA" in res.keys():
            if float(res[u"CUDA"]) not in gpus:
                gpus.append(float(res[u"CUDA"]))
    gpus.sort()

   # procs = [1, 2, 4, 8, 16, 32]
    # gpus = [0, 1, 2]
    for p in procs:
        for g in gpus:
            for a in [u"MIN", u"MAX"]:
                if (options.times):
                    if (not options.best or a == u"MIN"):
                        fields = fields + ("%s_TIME_%d_%d" % (a, p, g),)
                        FORMAT = FORMAT + " %14s"
                if (options.flops):
                    if (not options.best or a == u"MAX"):
                        fields = fields + ("%s_FLOPS_%d_%d" % (a, p, g),)
                        FORMAT = FORMAT + " %14s"
    print matrices
    print procs
    print gpus
    for sched in schedulers:
        i=1
        errors=[]
        print("Scheduler %s Fanin %s %s" %(sched[0], sched[1], sched[2]))
        print(FORMAT % fields)
        for matrix in matrices:
            mat_list = {}
            mat_list[u"X"] = i
            i = i + 1
            mat_list["Matrix"] = matrix
            for nmpi in procs:
                for g in gpus:
                    for a in [u"MIN", u"MAX"]:
                        mat_list[u"%s_TIME_%d_%d"  % (a,nmpi,g)] = 0
                        mat_list[u"%s_FLOPS_%d_%d" % (a,nmpi,g)] = 0
            for res in all_res:
                try:
                    if (res[u"MATRIX"]    == matrix   and
                        res[u"SCHEDULER"] == sched[0] and
                        res[u"FANIN"]     == sched[1] and
                        res[u"NESTED"]    == sched[2]):
                        if ( u"MPI" in res.keys()
                             and u"TIME" in res.keys()
                             and u"FLOPS" in res.keys() ):
                            for a in [u"TIME", u"FLOPS"]:
                                if (float(mat_list[u"MIN_%s_%s_%s"  % (a, res["MPI"], res[u"CUDA"])]) == 0 or
                                    float(mat_list[u"MIN_%s_%s_%s"  % (a, res["MPI"], res[u"CUDA"])]) > float( res[a] ) ):
                                    mat_list[u"MIN_%s_%s_%s"  % (a,res["MPI"], res[u"CUDA"])] = res[a]
                                if (float(mat_list[u"MAX_%s_%s_%s"  % (a,res["MPI"], res[u"CUDA"])]) < float( res[a] ) ):
                                    mat_list[u"MAX_%s_%s_%s" % (a,res[u"MPI"], res[u"CUDA"])] = res[a]
                except:
                    errors.append(res)
                    #print(res)
            values = (mat_list[u"X"], mat_list[u"Matrix"],)
            for p in procs:
                for g in gpus:
                    for a in [u"MIN", u"MAX"]:
                        if (options.times) :
                            if (not options.best or a == u"MIN"):
                                values = values + (mat_list[u"%s_TIME_%d_%d"  % (a,p,g)],)
                        if (options.flops):
                            if (not options.best or a == u"MAX"):
                                values = values + (mat_list[u"%s_FLOPS_%d_%d" % (a,p,g)],)
            print(FORMAT % values)
