chart.py 7.77 KB
Newer Older
1 2
#!/usr/bin/env python

3 4 5 6 7
import testlog_parser, sys, os, xml, re
from table_formatter import *
from optparse import OptionParser

cvsize_re = re.compile("^\d+x\d+$")
8
cvtype_re = re.compile("^(CV_)(8U|8S|16U|16S|32S|32F|64F)(C\d{1,3})?$")
9 10 11 12 13 14

def keyselector(a):
    if cvsize_re.match(a):
        size = [int(d) for d in a.split('x')]
        return size[0] * size[1]
    elif cvtype_re.match(a):
15 16
        if a.startswith("CV_"):
            a = a[3:]
17 18 19 20 21 22 23 24 25 26 27
        depth = 7
        if a[0] == '8':
            depth = (0, 1) [a[1] == 'S']
        elif a[0] == '1':
            depth = (2, 3) [a[2] == 'S']
        elif a[2] == 'S':
            depth = 4
        elif a[0] == '3':
            depth = 5
        elif a[0] == '6':
            depth = 6
28 29 30 31 32
        cidx = a.find('C')
        if cidx < 0:
            channels = 1
        else:
            channels = int(a[a.index('C') + 1:])
33
        #return (depth & 7) + ((channels - 1) << 3)
34
        return ((channels-1) & 511) + (depth << 9)
35 36
    return a

37
convert = lambda text: int(text) if text.isdigit() else text
Andrey Morozov's avatar
Andrey Morozov committed
38
alphanum_keyselector = lambda key: [ convert(c) for c in re.split('([0-9]+)', str(keyselector(key))) ]
39

40 41 42 43 44 45 46 47
def getValueParams(test):
    param = test.get("value_param")
    if not param:
        return []
    if param.startswith("("):
        param = param[1:]
    if param.endswith(")"):
        param = param[:-1]
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
    args = []
    prev_pos = 0
    start = 0
    balance = 0
    while True:
        idx = param.find(",", prev_pos)
        if idx < 0:
            break
        idxlb = param.find("(", prev_pos, idx)
        while idxlb >= 0:
            balance += 1
            idxlb = param.find("(", idxlb+1, idx)
        idxrb = param.find(")", prev_pos, idx)
        while idxrb >= 0:
            balance -= 1
            idxrb = param.find(")", idxrb+1, idx)
        assert(balance >= 0)
        if balance == 0:
            args.append(param[start:idx].strip())
            start = idx + 1
        prev_pos = idx + 1
    args.append(param[start:].strip())
    return args
    #return [p.strip() for p in param.split(",")]
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99

def nextPermutation(indexes, lists, x, y):
    idx = len(indexes)-1
    while idx >= 0:
        while idx == x or idx == y:
            idx -= 1
        if idx < 0:
            return False
        v = indexes[idx] + 1
        if v < len(lists[idx]):
            indexes[idx] = v;
            return True;
        else:
            indexes[idx] = 0;
            idx -= 1
    return False

def getTestWideName(sname, indexes, lists, x, y):
    name = sname + "::("
    for i in range(len(indexes)):
        if i > 0:
            name += ", "
        if i == x:
            name += "X"
        elif i == y:
            name += "Y"
        else:
            name += lists[i][indexes[i]]
100 101
    return str(name + ")")

102 103 104 105
def getTest(stests, x, y, row, col):
    for pair in stests:
        if pair[1][x] == row and pair[1][y] == col:
            return pair[0]
106
    return None
107 108 109 110 111 112 113 114 115 116

if __name__ == "__main__":
    parser = OptionParser()
    parser.add_option("-o", "--output", dest="format", help="output results in text format (can be 'txt', 'html' or 'auto' - default)", metavar="FMT", default="auto")
    parser.add_option("-u", "--units", dest="units", help="units for output values (s, ms (default), mks, ns or ticks)", metavar="UNITS", default="ms")
    parser.add_option("-m", "--metric", dest="metric", help="output metric", metavar="NAME", default="gmean")
    parser.add_option("-x", "", dest="x", help="argument number for rows", metavar="ROW", default=1)
    parser.add_option("-y", "", dest="y", help="argument number for columns", metavar="COL", default=0)
    parser.add_option("-f", "--filter", dest="filter", help="regex to filter tests", metavar="REGEX", default=None)
    (options, args) = parser.parse_args()
117

118 119 120 121 122 123 124 125 126 127
    if len(args) != 1:
        print >> sys.stderr, "Usage:\n", os.path.basename(sys.argv[0]), "<log_name1>.xml"
        exit(1)

    options.generateHtml = detectHtmlOutputType(options.format)
    if options.metric not in metrix_table:
        options.metric = "gmean"
    if options.metric.endswith("%"):
        options.metric = options.metric[:-1]
    getter = metrix_table[options.metric][1]
128

129 130 131 132
    tests = testlog_parser.parseLogFile(args[0])
    if options.filter:
        expr = re.compile(options.filter)
        tests = [(t,getValueParams(t)) for t in tests if expr.search(str(t))]
133 134
    else:
        tests = [(t,getValueParams(t)) for t in tests]
135

136
    args[0] = os.path.basename(args[0])
137

138 139 140
    if not tests:
        print >> sys.stderr, "Error - no tests matched"
        exit(1)
141

142 143
    argsnum = len(tests[0][1])
    sname = tests[0][0].shortName()
144

145 146 147
    arglists = []
    for i in range(argsnum):
        arglists.append({})
148

149
    names = set()
150
    names1 = set()
151
    for pair in tests:
152
        sn = pair[0].shortName()
153 154
        if len(pair[1]) > 1:
            names.add(sn)
155 156
        else:
            names1.add(sn)
157 158 159 160 161 162
        if sn == sname:
            if len(pair[1]) != argsnum:
                print >> sys.stderr, "Error - unable to create chart tables for functions having different argument numbers"
                sys.exit(1)
            for i in range(argsnum):
                arglists[i][pair[1][i]] = 1
163

164
    if names1 or len(names) != 1:
165
        print >> sys.stderr, "Error - unable to create tables for functions from different test suits:"
166 167 168 169
        i = 1
        for name in sorted(names):
            print >> sys.stderr, "%4s:   %s" % (i, name)
            i += 1
170
        if names1:
Ilya Lavrenov's avatar
Ilya Lavrenov committed
171
            print >> sys.stderr, "Other suits in this log (can not be chosen):"
172 173 174
            for name in sorted(names1):
                print >> sys.stderr, "%4s:   %s" % (i, name)
                i += 1
175
        sys.exit(1)
176

177 178 179
    if argsnum < 2:
        print >> sys.stderr, "Error - tests from %s have less than 2 parameters" % sname
        exit(1)
180

181
    for i in range(argsnum):
182
        arglists[i] = sorted([str(key) for key in arglists[i].iterkeys()], key=alphanum_keyselector)
183

184
    if options.generateHtml and options.format != "moinwiki":
185
        htmlPrintHeader(sys.stdout, "Report %s for %s" % (args[0], sname))
186

187 188 189 190 191 192
    indexes = [0] * argsnum
    x = int(options.x)
    y = int(options.y)
    if x == y or x < 0 or y < 0 or x >= argsnum or y >= argsnum:
        x = 1
        y = 0
193

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
    while True:
        stests = []
        for pair in tests:
            t = pair[0]
            v = pair[1]
            for i in range(argsnum):
                if i != x and i != y:
                    if v[i] != arglists[i][indexes[i]]:
                        t = None
                        break
            if t:
                stests.append(pair)

        tbl = table(metrix_table[options.metric][0] + " for\n" + getTestWideName(sname, indexes, arglists, x, y))
        tbl.newColumn("x", "X\Y")
        for col in arglists[y]:
            tbl.newColumn(col, col, align="center")
        for row in arglists[x]:
            tbl.newRow()
            tbl.newCell("x", row)
            for col in arglists[y]:
                case = getTest(stests, x, y, row, col)
                if case:
                    status = case.get("status")
                    if status != "run":
                        tbl.newCell(col, status, color = "red")
                    else:
                        val = getter(case, None, options.units)
                        if isinstance(val, float):
                            tbl.newCell(col, "%.2f %s" % (val, options.units), val)
                        else:
                            tbl.newCell(col, val, val)
                else:
                    tbl.newCell(col, "-")
228

229
        if options.generateHtml:
230
            tbl.htmlPrintTable(sys.stdout, options.format == "moinwiki")
231 232 233 234
        else:
            tbl.consolePrintTable(sys.stdout)
        if not nextPermutation(indexes, arglists, x, y):
            break
235

236
    if options.generateHtml and options.format != "moinwiki":
237
        htmlPrintFooter(sys.stdout)