diff options
Diffstat (limited to 'scripts/lib/buildstats.py')
| -rw-r--r-- | scripts/lib/buildstats.py | 38 |
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 | |||
| 8 | import logging | 8 | import logging |
| 9 | import os | 9 | import os |
| 10 | import re | 10 | import re |
| 11 | from collections import namedtuple,OrderedDict | 11 | from collections import namedtuple |
| 12 | from statistics import mean | 12 | from 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)) |
