summaryrefslogtreecommitdiffstats
path: root/meta/lib/oeqa/buildperf
diff options
context:
space:
mode:
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>2016-05-11 13:39:22 +0300
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-07-01 16:22:46 +0100
commit6e27b2ae0ebab02efefc39014fd59817f53a5853 (patch)
tree242a9fe37c4741e4dd27d56bae820f5b8a2f4ab1 /meta/lib/oeqa/buildperf
parent1b10ded015d4375602c6be0b98493002b984d0e5 (diff)
downloadpoky-6e27b2ae0ebab02efefc39014fd59817f53a5853.tar.gz
oeqa.buildperf: method for measuring system resource usage
Extend BuildPerfTest class with a new method for measuring the system resource usage of a shell command to BuildPerfTest class. For now, easurement of the elapsed time is done with the Gnu time utility, similarly to the build-perf-test.sh shell script. And, it currently only records the elapsed (wall clock). The measured values (currently, only the elapsed time) is actually a dictionary, making it possible to extend it with additional resource values, e.g. cpu time or i/o usage, in the future. In addition to the actual values of the measurement each record contains a 'name' and 'legend' where name is supposed to function as a common key or id over test runs, making comparison and trending easier, for example. Legend is supposed to be a short human readable description. (From OE-Core rev: ced156bfea4a6649d201f41275641a633f218322) Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com> Signed-off-by: Ross Burton <ross.burton@intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta/lib/oeqa/buildperf')
-rw-r--r--meta/lib/oeqa/buildperf/base.py64
1 files changed, 62 insertions, 2 deletions
diff --git a/meta/lib/oeqa/buildperf/base.py b/meta/lib/oeqa/buildperf/base.py
index 3ef038494f..d608061ec0 100644
--- a/meta/lib/oeqa/buildperf/base.py
+++ b/meta/lib/oeqa/buildperf/base.py
@@ -10,11 +10,14 @@
10# more details. 10# more details.
11# 11#
12"""Build performance test base classes and functionality""" 12"""Build performance test base classes and functionality"""
13import glob
13import logging 14import logging
14import os 15import os
16import re
15import shutil 17import shutil
18import tempfile
16import time 19import time
17from datetime import datetime 20from datetime import datetime, timedelta
18 21
19from oeqa.utils.commands import runCmd, get_bb_vars 22from oeqa.utils.commands import runCmd, get_bb_vars
20 23
@@ -55,8 +58,24 @@ class KernelDropCaches(object):
55 runCmd(cmd, data=input_data) 58 runCmd(cmd, data=input_data)
56 59
57 60
61def time_cmd(cmd, **kwargs):
62 """TIme a command"""
63 with tempfile.NamedTemporaryFile(mode='w+') as tmpf:
64 timecmd = ['/usr/bin/time', '-v', '-o', tmpf.name]
65 if isinstance(cmd, str):
66 timecmd = ' '.join(timecmd) + ' '
67 timecmd += cmd
68 # TODO: 'ignore_status' could/should be removed when globalres.log is
69 # deprecated. The function would just raise an exception, instead
70 ret = runCmd(timecmd, ignore_status=True, **kwargs)
71 timedata = tmpf.file.read()
72 return ret, timedata
73
74
58class BuildPerfTest(object): 75class BuildPerfTest(object):
59 """Base class for build performance tests""" 76 """Base class for build performance tests"""
77 SYSRES = 'sysres'
78
60 name = None 79 name = None
61 description = None 80 description = None
62 81
@@ -73,6 +92,10 @@ class BuildPerfTest(object):
73 if not self.name: 92 if not self.name:
74 self.name = self.__class__.__name__ 93 self.name = self.__class__.__name__
75 self.bb_vars = get_bb_vars() 94 self.bb_vars = get_bb_vars()
95 # TODO: remove the _failed flag when globalres.log is ditched as all
96 # failures should raise an exception
97 self._failed = False
98 self.cmd_log = os.path.join(self.out_dir, 'commands.log')
76 99
77 def run(self): 100 def run(self):
78 """Run test""" 101 """Run test"""
@@ -82,12 +105,49 @@ class BuildPerfTest(object):
82 self.results['elapsed_time'] = (datetime.now() - 105 self.results['elapsed_time'] = (datetime.now() -
83 self.results['start_time']) 106 self.results['start_time'])
84 # Test is regarded as completed if it doesn't raise an exception 107 # Test is regarded as completed if it doesn't raise an exception
85 self.results['status'] = 'COMPLETED' 108 if not self._failed:
109 self.results['status'] = 'COMPLETED'
86 110
87 def _run(self): 111 def _run(self):
88 """Actual test payload""" 112 """Actual test payload"""
89 raise NotImplementedError 113 raise NotImplementedError
90 114
115 def measure_cmd_resources(self, cmd, name, legend):
116 """Measure system resource usage of a command"""
117 def str_time_to_timedelta(strtime):
118 """Convert time strig from the time utility to timedelta"""
119 split = strtime.split(':')
120 hours = int(split[0]) if len(split) > 2 else 0
121 mins = int(split[-2])
122 secs, frac = split[-1].split('.')
123 secs = int(secs)
124 microsecs = int(float('0.' + frac) * pow(10, 6))
125 return timedelta(0, hours*3600 + mins*60 + secs, microsecs)
126
127 cmd_str = cmd if isinstance(cmd, str) else ' '.join(cmd)
128 log.info("Timing command: %s", cmd_str)
129 with open(self.cmd_log, 'a') as fobj:
130 ret, timedata = time_cmd(cmd, stdout=fobj)
131 if ret.status:
132 log.error("Time will be reported as 0. Command failed: %s",
133 ret.status)
134 etime = timedelta(0)
135 self._failed = True
136 else:
137 match = re.search(r'.*wall clock.*: (?P<etime>.*)\n', timedata)
138 etime = str_time_to_timedelta(match.group('etime'))
139
140 measurement = {'type': self.SYSRES,
141 'name': name,
142 'legend': legend}
143 measurement['values'] = {'elapsed_time': etime}
144 self.results['measurements'].append(measurement)
145 nlogs = len(glob.glob(self.out_dir + '/results.log*'))
146 results_log = os.path.join(self.out_dir,
147 'results.log.{}'.format(nlogs + 1))
148 with open(results_log, 'w') as fobj:
149 fobj.write(timedata)
150
91 @staticmethod 151 @staticmethod
92 def force_rm(path): 152 def force_rm(path):
93 """Equivalent of 'rm -rf'""" 153 """Equivalent of 'rm -rf'"""