summaryrefslogtreecommitdiffstats
path: root/scripts/lib/buildstats.py
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/lib/buildstats.py')
-rw-r--r--scripts/lib/buildstats.py38
1 files changed, 30 insertions, 8 deletions
diff --git a/scripts/lib/buildstats.py b/scripts/lib/buildstats.py
index c69b5bf4d7..6db60d5bcf 100644
--- a/scripts/lib/buildstats.py
+++ b/scripts/lib/buildstats.py
@@ -8,7 +8,7 @@ import json
8import logging 8import logging
9import os 9import os
10import re 10import re
11from collections import namedtuple,OrderedDict 11from collections import namedtuple
12from statistics import mean 12from statistics import mean
13 13
14 14
@@ -79,8 +79,8 @@ class BSTask(dict):
79 return self['rusage']['ru_oublock'] 79 return self['rusage']['ru_oublock']
80 80
81 @classmethod 81 @classmethod
82 def from_file(cls, buildstat_file): 82 def from_file(cls, buildstat_file, fallback_end=0):
83 """Read buildstat text file""" 83 """Read buildstat text file. fallback_end is an optional end time for tasks that are not recorded as finishing."""
84 bs_task = cls() 84 bs_task = cls()
85 log.debug("Reading task buildstats from %s", buildstat_file) 85 log.debug("Reading task buildstats from %s", buildstat_file)
86 end_time = None 86 end_time = None
@@ -108,7 +108,10 @@ class BSTask(dict):
108 bs_task[ru_type][ru_key] = val 108 bs_task[ru_type][ru_key] = val
109 elif key == 'Status': 109 elif key == 'Status':
110 bs_task['status'] = val 110 bs_task['status'] = val
111 if end_time is not None and start_time is not None: 111 # If the task didn't finish, fill in the fallback end time if specified
112 if start_time and not end_time and fallback_end:
113 end_time = fallback_end
114 if start_time and end_time:
112 bs_task['elapsed_time'] = end_time - start_time 115 bs_task['elapsed_time'] = end_time - start_time
113 else: 116 else:
114 raise BSError("{} looks like a invalid buildstats file".format(buildstat_file)) 117 raise BSError("{} looks like a invalid buildstats file".format(buildstat_file))
@@ -226,25 +229,44 @@ class BuildStats(dict):
226 epoch = match.group('epoch') 229 epoch = match.group('epoch')
227 return name, epoch, version, revision 230 return name, epoch, version, revision
228 231
232 @staticmethod
233 def parse_top_build_stats(path):
234 """
235 Parse the top-level build_stats file for build-wide start and duration.
236 """
237 start = elapsed = 0
238 with open(path) as fobj:
239 for line in fobj.readlines():
240 key, val = line.split(':', 1)
241 val = val.strip()
242 if key == 'Build Started':
243 start = float(val)
244 elif key == "Elapsed time":
245 elapsed = float(val.split()[0])
246 return start, elapsed
247
229 @classmethod 248 @classmethod
230 def from_dir(cls, path): 249 def from_dir(cls, path):
231 """Load buildstats from a buildstats directory""" 250 """Load buildstats from a buildstats directory"""
232 if not os.path.isfile(os.path.join(path, 'build_stats')): 251 top_stats = os.path.join(path, 'build_stats')
252 if not os.path.isfile(top_stats):
233 raise BSError("{} does not look like a buildstats directory".format(path)) 253 raise BSError("{} does not look like a buildstats directory".format(path))
234 254
235 log.debug("Reading buildstats directory %s", path) 255 log.debug("Reading buildstats directory %s", path)
236
237 buildstats = cls() 256 buildstats = cls()
257 build_started, build_elapsed = buildstats.parse_top_build_stats(top_stats)
258 build_end = build_started + build_elapsed
259
238 subdirs = os.listdir(path) 260 subdirs = os.listdir(path)
239 for dirname in subdirs: 261 for dirname in subdirs:
240 recipe_dir = os.path.join(path, dirname) 262 recipe_dir = os.path.join(path, dirname)
241 if not os.path.isdir(recipe_dir): 263 if dirname == "reduced_proc_pressure" or not os.path.isdir(recipe_dir):
242 continue 264 continue
243 name, epoch, version, revision = cls.split_nevr(dirname) 265 name, epoch, version, revision = cls.split_nevr(dirname)
244 bsrecipe = BSRecipe(name, epoch, version, revision) 266 bsrecipe = BSRecipe(name, epoch, version, revision)
245 for task in os.listdir(recipe_dir): 267 for task in os.listdir(recipe_dir):
246 bsrecipe.tasks[task] = BSTask.from_file( 268 bsrecipe.tasks[task] = BSTask.from_file(
247 os.path.join(recipe_dir, task)) 269 os.path.join(recipe_dir, task), build_end)
248 if name in buildstats: 270 if name in buildstats:
249 raise BSError("Cannot handle multiple versions of the same " 271 raise BSError("Cannot handle multiple versions of the same "
250 "package ({})".format(name)) 272 "package ({})".format(name))