opencv/modules/ts/misc/testlog_parser.py
Roman Donchenko 2688e22cb5 Made xls-report.py use global properties in XML files.
Now it can determine, without looking at the file name, both the module
name and the configuration name (the latter with a little help from the
configuration file).
2013-06-20 19:57:45 +04:00

213 lines
6.3 KiB
Python
Executable File

#!/usr/bin/env python
import collections
import re
import os.path
import sys
from xml.dom.minidom import parse
class TestInfo(object):
def __init__(self, xmlnode):
self.fixture = xmlnode.getAttribute("classname")
self.name = xmlnode.getAttribute("name")
self.value_param = xmlnode.getAttribute("value_param")
self.type_param = xmlnode.getAttribute("type_param")
if xmlnode.getElementsByTagName("failure"):
self.status = "failed"
else:
self.status = xmlnode.getAttribute("status")
if self.name.startswith("DISABLED_"):
self.status = "disabled"
self.fixture = self.fixture.replace("DISABLED_", "")
self.name = self.name.replace("DISABLED_", "")
self.metrix = {}
self.parseLongMetric(xmlnode, "bytesIn");
self.parseLongMetric(xmlnode, "bytesOut");
self.parseIntMetric(xmlnode, "samples");
self.parseIntMetric(xmlnode, "outliers");
self.parseFloatMetric(xmlnode, "frequency", 1);
self.parseLongMetric(xmlnode, "min");
self.parseLongMetric(xmlnode, "median");
self.parseLongMetric(xmlnode, "gmean");
self.parseLongMetric(xmlnode, "mean");
self.parseLongMetric(xmlnode, "stddev");
self.parseFloatMetric(xmlnode, "gstddev");
self.parseFloatMetric(xmlnode, "time");
def parseLongMetric(self, xmlnode, name, default = 0):
if xmlnode.hasAttribute(name):
tmp = xmlnode.getAttribute(name)
val = long(tmp)
self.metrix[name] = val
else:
self.metrix[name] = default
def parseIntMetric(self, xmlnode, name, default = 0):
if xmlnode.hasAttribute(name):
tmp = xmlnode.getAttribute(name)
val = int(tmp)
self.metrix[name] = val
else:
self.metrix[name] = default
def parseFloatMetric(self, xmlnode, name, default = 0):
if xmlnode.hasAttribute(name):
tmp = xmlnode.getAttribute(name)
val = float(tmp)
self.metrix[name] = val
else:
self.metrix[name] = default
def parseStringMetric(self, xmlnode, name, default = None):
if xmlnode.hasAttribute(name):
tmp = xmlnode.getAttribute(name)
self.metrix[name] = tmp.strip()
else:
self.metrix[name] = default
def get(self, name, units="ms"):
if name == "classname":
return self.fixture
if name == "name":
return self.name
if name == "fullname":
return self.__str__()
if name == "value_param":
return self.value_param
if name == "type_param":
return self.type_param
if name == "status":
return self.status
val = self.metrix.get(name, None)
if not val:
return val
if name == "time":
return self.metrix.get("time")
if name in ["gmean", "min", "mean", "median", "stddev"]:
scale = 1.0
frequency = self.metrix.get("frequency", 1.0) or 1.0
if units == "ms":
scale = 1000.0
if units == "mks":
scale = 1000000.0
if units == "ns":
scale = 1000000000.0
if units == "ticks":
frequency = long(1)
scale = long(1)
return val * scale / frequency
return val
def dump(self, units="ms"):
print "%s ->\t\033[1;31m%s\033[0m = \t%.2f%s" % (str(self), self.status, self.get("gmean", units), units)
def getName(self):
pos = self.name.find("/")
if pos > 0:
return self.name[:pos]
return self.name
def getFixture(self):
if self.fixture.endswith(self.getName()):
fixture = self.fixture[:-len(self.getName())]
else:
fixture = self.fixture
if fixture.endswith("_"):
fixture = fixture[:-1]
return fixture
def param(self):
return '::'.join(filter(None, [self.type_param, self.value_param]))
def shortName(self):
name = self.getName()
fixture = self.getFixture()
return '::'.join(filter(None, [name, fixture]))
def __str__(self):
name = self.getName()
fixture = self.getFixture()
return '::'.join(filter(None, [name, fixture, self.type_param, self.value_param]))
def __cmp__(self, other):
r = cmp(self.fixture, other.fixture);
if r != 0:
return r
if self.type_param:
if other.type_param:
r = cmp(self.type_param, other.type_param);
if r != 0:
return r
else:
return -1
else:
if other.type_param:
return 1
if self.value_param:
if other.value_param:
r = cmp(self.value_param, other.value_param);
if r != 0:
return r
else:
return -1
else:
if other.value_param:
return 1
return 0
# This is a Sequence for compatibility with old scripts,
# which treat parseLogFile's return value as a list.
class TestRunInfo(collections.Sequence):
def __init__(self, properties, tests):
self.properties = properties
self.tests = tests
def __len__(self):
return len(self.tests)
def __getitem__(self, key):
return self.tests[key]
def parseLogFile(filename):
log = parse(filename)
properties = {
attr_name[3:]: attr_value
for (attr_name, attr_value) in log.documentElement.attributes.items()
if attr_name.startswith('cv_')
}
tests = map(TestInfo, log.getElementsByTagName("testcase"))
return TestRunInfo(properties, tests)
if __name__ == "__main__":
if len(sys.argv) < 2:
print "Usage:\n", os.path.basename(sys.argv[0]), "<log_name>.xml"
exit(0)
for arg in sys.argv[1:]:
print "Processing {}...".format(arg)
run = parseLogFile(arg)
print "Properties:"
for (prop_name, prop_value) in run.properties.items():
print "\t{} = {}".format(prop_name, prop_value)
print "Tests:"
for t in sorted(run.tests):
t.dump()
print