mirror of
https://git.yoctoproject.org/poky
synced 2026-05-31 00:39:46 +00:00
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>
This commit is contained in:
committed by
Richard Purdie
parent
33a38bc18a
commit
0b332039ea
@@ -15,14 +15,16 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import resource
|
||||||
import shutil
|
import shutil
|
||||||
import socket
|
import socket
|
||||||
import tempfile
|
|
||||||
import time
|
import time
|
||||||
import traceback
|
import traceback
|
||||||
import unittest
|
import unittest
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from multiprocessing import Process
|
||||||
|
from multiprocessing import SimpleQueue
|
||||||
|
|
||||||
import oe.path
|
import oe.path
|
||||||
from oeqa.utils.commands import CommandError, runCmd, get_bb_vars
|
from oeqa.utils.commands import CommandError, runCmd, get_bb_vars
|
||||||
@@ -69,16 +71,9 @@ class KernelDropCaches(object):
|
|||||||
runCmd2(cmd, data=input_data)
|
runCmd2(cmd, data=input_data)
|
||||||
|
|
||||||
|
|
||||||
def time_cmd(cmd, **kwargs):
|
def str_to_fn(string):
|
||||||
"""TIme a command"""
|
"""Convert string to a sanitized filename"""
|
||||||
with tempfile.NamedTemporaryFile(mode='w+') as tmpf:
|
return re.sub(r'(\W+)', '-', string, flags=re.LOCALE)
|
||||||
timecmd = ['/usr/bin/time', '-v', '-o', tmpf.name]
|
|
||||||
if isinstance(cmd, str):
|
|
||||||
timecmd = ' '.join(timecmd) + ' '
|
|
||||||
timecmd += cmd
|
|
||||||
ret = runCmd2(timecmd, **kwargs)
|
|
||||||
timedata = tmpf.file.read()
|
|
||||||
return ret, timedata
|
|
||||||
|
|
||||||
|
|
||||||
class ResultsJsonEncoder(json.JSONEncoder):
|
class ResultsJsonEncoder(json.JSONEncoder):
|
||||||
@@ -338,45 +333,56 @@ class BuildPerfTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
def measure_cmd_resources(self, cmd, name, legend):
|
def measure_cmd_resources(self, cmd, name, legend):
|
||||||
"""Measure system resource usage of a command"""
|
"""Measure system resource usage of a command"""
|
||||||
def str_time_to_timedelta(strtime):
|
def _worker(data_q, cmd, **kwargs):
|
||||||
"""Convert time strig from the time utility to timedelta"""
|
"""Worker process for measuring resources"""
|
||||||
split = strtime.split(':')
|
|
||||||
hours = int(split[0]) if len(split) > 2 else 0
|
|
||||||
mins = int(split[-2])
|
|
||||||
try:
|
try:
|
||||||
secs, frac = split[-1].split('.')
|
start_time = datetime.now()
|
||||||
except:
|
ret = runCmd2(cmd, **kwargs)
|
||||||
secs = split[-1]
|
etime = datetime.now() - start_time
|
||||||
frac = '0'
|
rusage_struct = resource.getrusage(resource.RUSAGE_CHILDREN)
|
||||||
secs = int(secs)
|
rusage = {}
|
||||||
microsecs = int(float('0.' + frac) * pow(10, 6))
|
# Skip unused fields, (i.e. 'ru_ixrss', 'ru_idrss', 'ru_isrss',
|
||||||
return timedelta(0, hours*3600 + mins*60 + secs, microsecs)
|
# 'ru_nswap', 'ru_msgsnd', 'ru_msgrcv' and 'ru_nsignals')
|
||||||
|
for key in ['ru_utime', 'ru_stime', 'ru_maxrss', 'ru_minflt',
|
||||||
|
'ru_majflt', 'ru_inblock', 'ru_oublock',
|
||||||
|
'ru_nvcsw', 'ru_nivcsw']:
|
||||||
|
rusage[key] = getattr(rusage_struct, key)
|
||||||
|
data_q.put({'ret': ret,
|
||||||
|
'start_time': start_time,
|
||||||
|
'elapsed_time': etime,
|
||||||
|
'rusage': rusage})
|
||||||
|
except Exception as err:
|
||||||
|
data_q.put(err)
|
||||||
|
|
||||||
cmd_str = cmd if isinstance(cmd, str) else ' '.join(cmd)
|
cmd_str = cmd if isinstance(cmd, str) else ' '.join(cmd)
|
||||||
log.info("Timing command: %s", cmd_str)
|
log.info("Timing command: %s", cmd_str)
|
||||||
|
data_q = SimpleQueue()
|
||||||
cmd_log = os.path.join(self.out_dir, 'commands.log')
|
cmd_log = os.path.join(self.out_dir, 'commands.log')
|
||||||
try:
|
try:
|
||||||
with open(cmd_log, 'a') as fobj:
|
with open(cmd_log, 'a') as fobj:
|
||||||
ret, timedata = time_cmd(cmd, stdout=fobj)
|
proc = Process(target=_worker, args=(data_q, cmd,),
|
||||||
|
kwargs={'stdout': fobj})
|
||||||
|
proc.start()
|
||||||
|
data = data_q.get()
|
||||||
|
proc.join()
|
||||||
|
if isinstance(data, Exception):
|
||||||
|
raise data
|
||||||
except CommandError:
|
except CommandError:
|
||||||
log.error("Command '%s' failed, see %s for more details", cmd_str,
|
log.error("Command '%s' failed, see %s for more details", cmd_str,
|
||||||
cmd_log)
|
cmd_log)
|
||||||
raise
|
raise
|
||||||
match = re.search(r'.*wall clock.*: (?P<etime>.*)\n', timedata)
|
etime = data['elapsed_time']
|
||||||
etime = str_time_to_timedelta(match.group('etime'))
|
|
||||||
|
|
||||||
measurement = {'type': self.SYSRES,
|
measurement = {'type': self.SYSRES,
|
||||||
'name': name,
|
'name': name,
|
||||||
'legend': legend}
|
'legend': legend}
|
||||||
measurement['values'] = {'elapsed_time': etime}
|
measurement['values'] = {'start_time': data['start_time'],
|
||||||
|
'elapsed_time': etime,
|
||||||
|
'rusage': data['rusage']}
|
||||||
self.measurements.append(measurement)
|
self.measurements.append(measurement)
|
||||||
e_sec = etime.total_seconds()
|
|
||||||
nlogs = len(glob.glob(self.out_dir + '/results.log*'))
|
|
||||||
results_log = os.path.join(self.out_dir,
|
|
||||||
'results.log.{}'.format(nlogs + 1))
|
|
||||||
with open(results_log, 'w') as fobj:
|
|
||||||
fobj.write(timedata)
|
|
||||||
# Append to 'times' array for globalres log
|
# Append to 'times' array for globalres log
|
||||||
|
e_sec = etime.total_seconds()
|
||||||
self.times.append('{:d}:{:02d}:{:.2f}'.format(int(e_sec / 3600),
|
self.times.append('{:d}:{:02d}:{:.2f}'.format(int(e_sec / 3600),
|
||||||
int((e_sec % 3600) / 60),
|
int((e_sec % 3600) / 60),
|
||||||
e_sec % 60))
|
e_sec % 60))
|
||||||
|
|||||||
Reference in New Issue
Block a user