summaryrefslogtreecommitdiffstats
path: root/meta/lib/oeqa/buildperf
diff options
context:
space:
mode:
authorMarkus Lehtonen <markus.lehtonen@linux.intel.com>2016-08-29 22:48:26 +0300
committerRichard Purdie <richard.purdie@linuxfoundation.org>2016-09-03 09:58:42 +0100
commit0b332039ea445ff03b172bc19c38457b7535df0e (patch)
tree3f6bda9ac665d760a3628046dc0db0192d7b5760 /meta/lib/oeqa/buildperf
parent33a38bc18a9cd3f04c573dab004965d00a1ed81f (diff)
downloadpoky-0b332039ea445ff03b172bc19c38457b7535df0e.tar.gz
oeqa.buildperf: don't use Gnu time
Use Python standard library functionality instead of the time utility for measuring elapsed (wall clock) time of commands. The time.* log files are also ditched. However, the same detailed resource usage data, previously found in time.* logs is now provided in results.json file. This data is collected through the resource module of Python. (From OE-Core rev: d5ad818dd501b18379aa3540bffa9b920d7c3bab) Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.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.py72
1 files changed, 39 insertions, 33 deletions
diff --git a/meta/lib/oeqa/buildperf/base.py b/meta/lib/oeqa/buildperf/base.py
index de22850d4d..5987bfbe4a 100644
--- a/meta/lib/oeqa/buildperf/base.py
+++ b/meta/lib/oeqa/buildperf/base.py
@@ -15,14 +15,16 @@ import json
15import logging 15import logging
16import os 16import os
17import re 17import re
18import resource
18import shutil 19import shutil
19import socket 20import socket
20import tempfile
21import time 21import time
22import traceback 22import traceback
23import unittest 23import unittest
24from datetime import datetime, timedelta 24from datetime import datetime, timedelta
25from functools import partial 25from functools import partial
26from multiprocessing import Process
27from multiprocessing import SimpleQueue
26 28
27import oe.path 29import oe.path
28from oeqa.utils.commands import CommandError, runCmd, get_bb_vars 30from oeqa.utils.commands import CommandError, runCmd, get_bb_vars
@@ -69,16 +71,9 @@ class KernelDropCaches(object):
69 runCmd2(cmd, data=input_data) 71 runCmd2(cmd, data=input_data)
70 72
71 73
72def time_cmd(cmd, **kwargs): 74def str_to_fn(string):
73 """TIme a command""" 75 """Convert string to a sanitized filename"""
74 with tempfile.NamedTemporaryFile(mode='w+') as tmpf: 76 return re.sub(r'(\W+)', '-', string, flags=re.LOCALE)
75 timecmd = ['/usr/bin/time', '-v', '-o', tmpf.name]
76 if isinstance(cmd, str):
77 timecmd = ' '.join(timecmd) + ' '
78 timecmd += cmd
79 ret = runCmd2(timecmd, **kwargs)
80 timedata = tmpf.file.read()
81 return ret, timedata
82 77
83 78
84class ResultsJsonEncoder(json.JSONEncoder): 79class ResultsJsonEncoder(json.JSONEncoder):
@@ -338,45 +333,56 @@ class BuildPerfTestCase(unittest.TestCase):
338 333
339 def measure_cmd_resources(self, cmd, name, legend): 334 def measure_cmd_resources(self, cmd, name, legend):
340 """Measure system resource usage of a command""" 335 """Measure system resource usage of a command"""
341 def str_time_to_timedelta(strtime): 336 def _worker(data_q, cmd, **kwargs):
342 """Convert time strig from the time utility to timedelta""" 337 """Worker process for measuring resources"""
343 split = strtime.split(':')
344 hours = int(split[0]) if len(split) > 2 else 0
345 mins = int(split[-2])
346 try: 338 try:
347 secs, frac = split[-1].split('.') 339 start_time = datetime.now()
348 except: 340 ret = runCmd2(cmd, **kwargs)
349 secs = split[-1] 341 etime = datetime.now() - start_time
350 frac = '0' 342 rusage_struct = resource.getrusage(resource.RUSAGE_CHILDREN)
351 secs = int(secs) 343 rusage = {}
352 microsecs = int(float('0.' + frac) * pow(10, 6)) 344 # Skip unused fields, (i.e. 'ru_ixrss', 'ru_idrss', 'ru_isrss',
353 return timedelta(0, hours*3600 + mins*60 + secs, microsecs) 345 # 'ru_nswap', 'ru_msgsnd', 'ru_msgrcv' and 'ru_nsignals')
346 for key in ['ru_utime', 'ru_stime', 'ru_maxrss', 'ru_minflt',
347 'ru_majflt', 'ru_inblock', 'ru_oublock',
348 'ru_nvcsw', 'ru_nivcsw']:
349 rusage[key] = getattr(rusage_struct, key)
350 data_q.put({'ret': ret,
351 'start_time': start_time,
352 'elapsed_time': etime,
353 'rusage': rusage})
354 except Exception as err:
355 data_q.put(err)
354 356
355 cmd_str = cmd if isinstance(cmd, str) else ' '.join(cmd) 357 cmd_str = cmd if isinstance(cmd, str) else ' '.join(cmd)
356 log.info("Timing command: %s", cmd_str) 358 log.info("Timing command: %s", cmd_str)
359 data_q = SimpleQueue()
357 cmd_log = os.path.join(self.out_dir, 'commands.log') 360 cmd_log = os.path.join(self.out_dir, 'commands.log')
358 try: 361 try:
359 with open(cmd_log, 'a') as fobj: 362 with open(cmd_log, 'a') as fobj:
360 ret, timedata = time_cmd(cmd, stdout=fobj) 363 proc = Process(target=_worker, args=(data_q, cmd,),
364 kwargs={'stdout': fobj})
365 proc.start()
366 data = data_q.get()
367 proc.join()
368 if isinstance(data, Exception):
369 raise data
361 except CommandError: 370 except CommandError:
362 log.error("Command '%s' failed, see %s for more details", cmd_str, 371 log.error("Command '%s' failed, see %s for more details", cmd_str,
363 cmd_log) 372 cmd_log)
364 raise 373 raise
365 match = re.search(r'.*wall clock.*: (?P<etime>.*)\n', timedata) 374 etime = data['elapsed_time']
366 etime = str_time_to_timedelta(match.group('etime'))
367 375
368 measurement = {'type': self.SYSRES, 376 measurement = {'type': self.SYSRES,
369 'name': name, 377 'name': name,
370 'legend': legend} 378 'legend': legend}
371 measurement['values'] = {'elapsed_time': etime} 379 measurement['values'] = {'start_time': data['start_time'],
380 'elapsed_time': etime,
381 'rusage': data['rusage']}
372 self.measurements.append(measurement) 382 self.measurements.append(measurement)
373 e_sec = etime.total_seconds() 383
374 nlogs = len(glob.glob(self.out_dir + '/results.log*'))
375 results_log = os.path.join(self.out_dir,
376 'results.log.{}'.format(nlogs + 1))
377 with open(results_log, 'w') as fobj:
378 fobj.write(timedata)
379 # Append to 'times' array for globalres log 384 # Append to 'times' array for globalres log
385 e_sec = etime.total_seconds()
380 self.times.append('{:d}:{:02d}:{:.2f}'.format(int(e_sec / 3600), 386 self.times.append('{:d}:{:02d}:{:.2f}'.format(int(e_sec / 3600),
381 int((e_sec % 3600) / 60), 387 int((e_sec % 3600) / 60),
382 e_sec % 60)) 388 e_sec % 60))