diff options
| -rw-r--r-- | meta/lib/oeqa/buildperf/base.py | 129 | ||||
| -rwxr-xr-x | scripts/oe-build-perf-test | 118 |
2 files changed, 114 insertions, 133 deletions
diff --git a/meta/lib/oeqa/buildperf/base.py b/meta/lib/oeqa/buildperf/base.py index 92f3e451a3..4027fdbfd6 100644 --- a/meta/lib/oeqa/buildperf/base.py +++ b/meta/lib/oeqa/buildperf/base.py | |||
| @@ -101,40 +101,10 @@ class BuildPerfTestResult(unittest.TextTestResult): | |||
| 101 | super(BuildPerfTestResult, self).__init__(*args, **kwargs) | 101 | super(BuildPerfTestResult, self).__init__(*args, **kwargs) |
| 102 | 102 | ||
| 103 | self.out_dir = out_dir | 103 | self.out_dir = out_dir |
| 104 | # Get Git parameters | ||
| 105 | try: | ||
| 106 | self.repo = GitRepo('.') | ||
| 107 | except GitError: | ||
| 108 | self.repo = None | ||
| 109 | self.git_commit, self.git_commit_count, self.git_branch = \ | ||
| 110 | self.get_git_revision() | ||
| 111 | self.hostname = socket.gethostname() | 104 | self.hostname = socket.gethostname() |
| 112 | self.product = os.getenv('OE_BUILDPERFTEST_PRODUCT', 'oe-core') | 105 | self.product = os.getenv('OE_BUILDPERFTEST_PRODUCT', 'oe-core') |
| 113 | self.start_time = self.elapsed_time = None | 106 | self.start_time = self.elapsed_time = None |
| 114 | self.successes = [] | 107 | self.successes = [] |
| 115 | log.info("Using Git branch:commit %s:%s (%s)", self.git_branch, | ||
| 116 | self.git_commit, self.git_commit_count) | ||
| 117 | |||
| 118 | def get_git_revision(self): | ||
| 119 | """Get git branch and commit under testing""" | ||
| 120 | commit = os.getenv('OE_BUILDPERFTEST_GIT_COMMIT') | ||
| 121 | commit_cnt = os.getenv('OE_BUILDPERFTEST_GIT_COMMIT_COUNT') | ||
| 122 | branch = os.getenv('OE_BUILDPERFTEST_GIT_BRANCH') | ||
| 123 | if not self.repo and (not commit or not commit_cnt or not branch): | ||
| 124 | log.info("The current working directory doesn't seem to be a Git " | ||
| 125 | "repository clone. You can specify branch and commit " | ||
| 126 | "displayed in test results with OE_BUILDPERFTEST_GIT_BRANCH, " | ||
| 127 | "OE_BUILDPERFTEST_GIT_COMMIT and " | ||
| 128 | "OE_BUILDPERFTEST_GIT_COMMIT_COUNT environment variables") | ||
| 129 | else: | ||
| 130 | if not commit: | ||
| 131 | commit = self.repo.rev_parse('HEAD^0') | ||
| 132 | commit_cnt = self.repo.run_cmd(['rev-list', '--count', 'HEAD^0']) | ||
| 133 | if not branch: | ||
| 134 | branch = self.repo.get_current_branch() | ||
| 135 | if not branch: | ||
| 136 | log.debug('Currently on detached HEAD') | ||
| 137 | return str(commit), str(commit_cnt), str(branch) | ||
| 138 | 108 | ||
| 139 | def addSuccess(self, test): | 109 | def addSuccess(self, test): |
| 140 | """Record results from successful tests""" | 110 | """Record results from successful tests""" |
| @@ -182,48 +152,9 @@ class BuildPerfTestResult(unittest.TextTestResult): | |||
| 182 | return sorted(compound, key=lambda info: info[1].start_time) | 152 | return sorted(compound, key=lambda info: info[1].start_time) |
| 183 | 153 | ||
| 184 | 154 | ||
| 185 | def update_globalres_file(self, filename): | ||
| 186 | """Write results to globalres csv file""" | ||
| 187 | # Map test names to time and size columns in globalres | ||
| 188 | # The tuples represent index and length of times and sizes | ||
| 189 | # respectively | ||
| 190 | gr_map = {'test1': ((0, 1), (8, 1)), | ||
| 191 | 'test12': ((1, 1), (None, None)), | ||
| 192 | 'test13': ((2, 1), (9, 1)), | ||
| 193 | 'test2': ((3, 1), (None, None)), | ||
| 194 | 'test3': ((4, 3), (None, None)), | ||
| 195 | 'test4': ((7, 1), (10, 2))} | ||
| 196 | |||
| 197 | if self.repo: | ||
| 198 | git_tag_rev = self.repo.run_cmd(['describe', self.git_commit]) | ||
| 199 | else: | ||
| 200 | git_tag_rev = self.git_commit | ||
| 201 | |||
| 202 | values = ['0'] * 12 | ||
| 203 | for status, test, _ in self.all_results(): | ||
| 204 | if status in ['ERROR', 'SKIPPED']: | ||
| 205 | continue | ||
| 206 | (t_ind, t_len), (s_ind, s_len) = gr_map[test.name] | ||
| 207 | if t_ind is not None: | ||
| 208 | values[t_ind:t_ind + t_len] = test.times | ||
| 209 | if s_ind is not None: | ||
| 210 | values[s_ind:s_ind + s_len] = test.sizes | ||
| 211 | |||
| 212 | log.debug("Writing globalres log to %s", filename) | ||
| 213 | with open(filename, 'a') as fobj: | ||
| 214 | fobj.write('{},{}:{},{},'.format(self.hostname, | ||
| 215 | self.git_branch, | ||
| 216 | self.git_commit, | ||
| 217 | git_tag_rev)) | ||
| 218 | fobj.write(','.join(values) + '\n') | ||
| 219 | |||
| 220 | def write_results_json(self): | 155 | def write_results_json(self): |
| 221 | """Write test results into a json-formatted file""" | 156 | """Write test results into a json-formatted file""" |
| 222 | results = {'tester_host': self.hostname, | 157 | results = {'tester_host': self.hostname, |
| 223 | 'git_branch': self.git_branch, | ||
| 224 | 'git_commit': self.git_commit, | ||
| 225 | 'git_commit_count': self.git_commit_count, | ||
| 226 | 'product': self.product, | ||
| 227 | 'start_time': self.start_time, | 158 | 'start_time': self.start_time, |
| 228 | 'elapsed_time': self.elapsed_time} | 159 | 'elapsed_time': self.elapsed_time} |
| 229 | 160 | ||
| @@ -313,66 +244,6 @@ class BuildPerfTestResult(unittest.TextTestResult): | |||
| 313 | dom_doc.writexml(fobj, addindent=' ', newl='\n', encoding='utf-8') | 244 | dom_doc.writexml(fobj, addindent=' ', newl='\n', encoding='utf-8') |
| 314 | return | 245 | return |
| 315 | 246 | ||
| 316 | def git_commit_results(self, repo_path, branch=None, tag=None): | ||
| 317 | """Commit results into a Git repository""" | ||
| 318 | repo = GitRepo(repo_path, is_topdir=True) | ||
| 319 | if not branch: | ||
| 320 | branch = self.git_branch | ||
| 321 | else: | ||
| 322 | # Replace keywords | ||
| 323 | branch = branch.format(git_branch=self.git_branch, | ||
| 324 | tester_host=self.hostname) | ||
| 325 | |||
| 326 | log.info("Committing test results into %s %s", repo_path, branch) | ||
| 327 | tmp_index = os.path.join(repo_path, '.git', 'index.oe-build-perf') | ||
| 328 | try: | ||
| 329 | # Create new commit object from the new results | ||
| 330 | env_update = {'GIT_INDEX_FILE': tmp_index, | ||
| 331 | 'GIT_WORK_TREE': self.out_dir} | ||
| 332 | repo.run_cmd('add .', env_update) | ||
| 333 | tree = repo.run_cmd('write-tree', env_update) | ||
| 334 | parent = repo.rev_parse(branch) | ||
| 335 | msg = "Results of {}:{}\n".format(self.git_branch, self.git_commit) | ||
| 336 | git_cmd = ['commit-tree', tree, '-m', msg] | ||
| 337 | if parent: | ||
| 338 | git_cmd += ['-p', parent] | ||
| 339 | commit = repo.run_cmd(git_cmd, env_update) | ||
| 340 | |||
| 341 | # Update branch head | ||
| 342 | git_cmd = ['update-ref', 'refs/heads/' + branch, commit] | ||
| 343 | if parent: | ||
| 344 | git_cmd.append(parent) | ||
| 345 | repo.run_cmd(git_cmd) | ||
| 346 | |||
| 347 | # Update current HEAD, if we're on branch 'branch' | ||
| 348 | if repo.get_current_branch() == branch: | ||
| 349 | log.info("Updating %s HEAD to latest commit", repo_path) | ||
| 350 | repo.run_cmd('reset --hard') | ||
| 351 | |||
| 352 | # Create (annotated) tag | ||
| 353 | if tag: | ||
| 354 | # Find tags matching the pattern | ||
| 355 | tag_keywords = dict(git_branch=self.git_branch, | ||
| 356 | git_commit=self.git_commit, | ||
| 357 | git_commit_count=self.git_commit_count, | ||
| 358 | tester_host=self.hostname, | ||
| 359 | tag_num='[0-9]{1,5}') | ||
| 360 | tag_re = re.compile(tag.format(**tag_keywords) + '$') | ||
| 361 | tag_keywords['tag_num'] = 0 | ||
| 362 | for existing_tag in repo.run_cmd('tag').splitlines(): | ||
| 363 | if tag_re.match(existing_tag): | ||
| 364 | tag_keywords['tag_num'] += 1 | ||
| 365 | |||
| 366 | tag = tag.format(**tag_keywords) | ||
| 367 | msg = "Test run #{} of {}:{}\n".format(tag_keywords['tag_num'], | ||
| 368 | self.git_branch, | ||
| 369 | self.git_commit) | ||
| 370 | repo.run_cmd(['tag', '-a', '-m', msg, tag, commit]) | ||
| 371 | |||
| 372 | finally: | ||
| 373 | if os.path.exists(tmp_index): | ||
| 374 | os.unlink(tmp_index) | ||
| 375 | |||
| 376 | 247 | ||
| 377 | class BuildPerfTestCase(unittest.TestCase): | 248 | class BuildPerfTestCase(unittest.TestCase): |
| 378 | """Base class for build performance tests""" | 249 | """Base class for build performance tests""" |
diff --git a/scripts/oe-build-perf-test b/scripts/oe-build-perf-test index 4ec9f1403e..fc4ab3135d 100755 --- a/scripts/oe-build-perf-test +++ b/scripts/oe-build-perf-test | |||
| @@ -17,8 +17,10 @@ | |||
| 17 | import argparse | 17 | import argparse |
| 18 | import errno | 18 | import errno |
| 19 | import fcntl | 19 | import fcntl |
| 20 | import json | ||
| 20 | import logging | 21 | import logging |
| 21 | import os | 22 | import os |
| 23 | import re | ||
| 22 | import shutil | 24 | import shutil |
| 23 | import sys | 25 | import sys |
| 24 | import unittest | 26 | import unittest |
| @@ -27,11 +29,13 @@ from datetime import datetime | |||
| 27 | sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '/lib') | 29 | sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '/lib') |
| 28 | import scriptpath | 30 | import scriptpath |
| 29 | scriptpath.add_oe_lib_path() | 31 | scriptpath.add_oe_lib_path() |
| 32 | scriptpath.add_bitbake_lib_path() | ||
| 30 | import oeqa.buildperf | 33 | import oeqa.buildperf |
| 31 | from oeqa.buildperf import (BuildPerfTestLoader, BuildPerfTestResult, | 34 | from oeqa.buildperf import (BuildPerfTestLoader, BuildPerfTestResult, |
| 32 | BuildPerfTestRunner, KernelDropCaches) | 35 | BuildPerfTestRunner, KernelDropCaches) |
| 33 | from oeqa.utils.commands import runCmd | 36 | from oeqa.utils.commands import runCmd |
| 34 | from oeqa.utils.git import GitRepo, GitError | 37 | from oeqa.utils.git import GitRepo, GitError |
| 38 | from oeqa.utils.metadata import metadata_from_bb, write_metadata_file | ||
| 35 | 39 | ||
| 36 | 40 | ||
| 37 | # Set-up logging | 41 | # Set-up logging |
| @@ -115,6 +119,100 @@ def archive_build_conf(out_dir): | |||
| 115 | shutil.copytree(src_dir, tgt_dir) | 119 | shutil.copytree(src_dir, tgt_dir) |
| 116 | 120 | ||
| 117 | 121 | ||
| 122 | def git_commit_results(repo_dir, results_dir, branch, tag, metadata): | ||
| 123 | """Commit results into a Git repository""" | ||
| 124 | repo = GitRepo(repo_dir, is_topdir=True) | ||
| 125 | distro_branch = metadata['layers']['meta']['branch'] | ||
| 126 | distro_commit = metadata['layers']['meta']['commit'] | ||
| 127 | distro_commit_count = metadata['layers']['meta']['commit_count'] | ||
| 128 | |||
| 129 | # Replace keywords | ||
| 130 | branch = branch.format(git_branch=distro_branch, | ||
| 131 | tester_host=metadata['hostname']) | ||
| 132 | |||
| 133 | log.info("Committing test results into %s %s", repo_dir, branch) | ||
| 134 | tmp_index = os.path.join(repo_dir, '.git', 'index.oe-build-perf') | ||
| 135 | try: | ||
| 136 | # Create new commit object from the new results | ||
| 137 | env_update = {'GIT_INDEX_FILE': tmp_index, | ||
| 138 | 'GIT_WORK_TREE': results_dir} | ||
| 139 | repo.run_cmd('add .', env_update) | ||
| 140 | tree = repo.run_cmd('write-tree', env_update) | ||
| 141 | parent = repo.rev_parse(branch) | ||
| 142 | msg = "Results of {}:{}\n".format(distro_branch, distro_commit) | ||
| 143 | git_cmd = ['commit-tree', tree, '-m', msg] | ||
| 144 | if parent: | ||
| 145 | git_cmd += ['-p', parent] | ||
| 146 | commit = repo.run_cmd(git_cmd, env_update) | ||
| 147 | |||
| 148 | # Update branch head | ||
| 149 | git_cmd = ['update-ref', 'refs/heads/' + branch, commit] | ||
| 150 | if parent: | ||
| 151 | git_cmd.append(parent) | ||
| 152 | repo.run_cmd(git_cmd) | ||
| 153 | |||
| 154 | # Update current HEAD, if we're on branch 'branch' | ||
| 155 | if repo.get_current_branch() == branch: | ||
| 156 | log.info("Updating %s HEAD to latest commit", repo_dir) | ||
| 157 | repo.run_cmd('reset --hard') | ||
| 158 | |||
| 159 | # Create (annotated) tag | ||
| 160 | if tag: | ||
| 161 | # Find tags matching the pattern | ||
| 162 | tag_keywords = dict(git_branch=distro_branch, | ||
| 163 | git_commit=distro_commit, | ||
| 164 | git_commit_count=distro_commit_count, | ||
| 165 | tester_host=metadata['hostname'], | ||
| 166 | tag_num='[0-9]{1,5}') | ||
| 167 | tag_re = re.compile(tag.format(**tag_keywords) + '$') | ||
| 168 | tag_keywords['tag_num'] = 0 | ||
| 169 | for existing_tag in repo.run_cmd('tag').splitlines(): | ||
| 170 | if tag_re.match(existing_tag): | ||
| 171 | tag_keywords['tag_num'] += 1 | ||
| 172 | |||
| 173 | tag = tag.format(**tag_keywords) | ||
| 174 | msg = "Test run #{} of {}:{}\n".format(tag_keywords['tag_num'], | ||
| 175 | distro_branch, | ||
| 176 | distro_commit) | ||
| 177 | repo.run_cmd(['tag', '-a', '-m', msg, tag, commit]) | ||
| 178 | |||
| 179 | finally: | ||
| 180 | if os.path.exists(tmp_index): | ||
| 181 | os.unlink(tmp_index) | ||
| 182 | |||
| 183 | |||
| 184 | def update_globalres_file(result_obj, filename, metadata): | ||
| 185 | """Write results to globalres csv file""" | ||
| 186 | # Map test names to time and size columns in globalres | ||
| 187 | # The tuples represent index and length of times and sizes | ||
| 188 | # respectively | ||
| 189 | gr_map = {'test1': ((0, 1), (8, 1)), | ||
| 190 | 'test12': ((1, 1), (None, None)), | ||
| 191 | 'test13': ((2, 1), (9, 1)), | ||
| 192 | 'test2': ((3, 1), (None, None)), | ||
| 193 | 'test3': ((4, 3), (None, None)), | ||
| 194 | 'test4': ((7, 1), (10, 2))} | ||
| 195 | |||
| 196 | values = ['0'] * 12 | ||
| 197 | for status, test, _ in result_obj.all_results(): | ||
| 198 | if status in ['ERROR', 'SKIPPED']: | ||
| 199 | continue | ||
| 200 | (t_ind, t_len), (s_ind, s_len) = gr_map[test.name] | ||
| 201 | if t_ind is not None: | ||
| 202 | values[t_ind:t_ind + t_len] = test.times | ||
| 203 | if s_ind is not None: | ||
| 204 | values[s_ind:s_ind + s_len] = test.sizes | ||
| 205 | |||
| 206 | log.debug("Writing globalres log to %s", filename) | ||
| 207 | rev_info = metadata['layers']['meta'] | ||
| 208 | with open(filename, 'a') as fobj: | ||
| 209 | fobj.write('{},{}:{},{},'.format(metadata['hostname'], | ||
| 210 | rev_info['branch'], | ||
| 211 | rev_info['commit'], | ||
| 212 | rev_info['commit'])) | ||
| 213 | fobj.write(','.join(values) + '\n') | ||
| 214 | |||
| 215 | |||
| 118 | def parse_args(argv): | 216 | def parse_args(argv): |
| 119 | """Parse command line arguments""" | 217 | """Parse command line arguments""" |
| 120 | parser = argparse.ArgumentParser( | 218 | parser = argparse.ArgumentParser( |
| @@ -183,7 +281,19 @@ def main(argv=None): | |||
| 183 | else: | 281 | else: |
| 184 | suite = loader.loadTestsFromModule(oeqa.buildperf) | 282 | suite = loader.loadTestsFromModule(oeqa.buildperf) |
| 185 | 283 | ||
| 284 | # Save test metadata | ||
| 285 | metadata = metadata_from_bb() | ||
| 286 | log.info("Testing Git revision branch:commit %s:%s (%s)", | ||
| 287 | metadata['layers']['meta']['branch'], | ||
| 288 | metadata['layers']['meta']['commit'], | ||
| 289 | metadata['layers']['meta']['commit_count']) | ||
| 290 | if args.xml: | ||
| 291 | write_metadata_file(os.path.join(out_dir, 'metadata.xml'), metadata) | ||
| 292 | else: | ||
| 293 | with open(os.path.join(out_dir, 'metadata.json'), 'w') as fobj: | ||
| 294 | json.dump(metadata, fobj, indent=2) | ||
| 186 | archive_build_conf(out_dir) | 295 | archive_build_conf(out_dir) |
| 296 | |||
| 187 | runner = BuildPerfTestRunner(out_dir, verbosity=2) | 297 | runner = BuildPerfTestRunner(out_dir, verbosity=2) |
| 188 | 298 | ||
| 189 | # Suppress logger output to stderr so that the output from unittest | 299 | # Suppress logger output to stderr so that the output from unittest |
| @@ -201,11 +311,11 @@ def main(argv=None): | |||
| 201 | else: | 311 | else: |
| 202 | result.write_results_json() | 312 | result.write_results_json() |
| 203 | if args.globalres_file: | 313 | if args.globalres_file: |
| 204 | result.update_globalres_file(args.globalres_file) | 314 | update_globalres_file(result, args.globalres_file, metadata) |
| 205 | if args.commit_results: | 315 | if args.commit_results: |
| 206 | result.git_commit_results(args.commit_results, | 316 | git_commit_results(args.commit_results, out_dir, |
| 207 | args.commit_results_branch, | 317 | args.commit_results_branch, args.commit_results_tag, |
| 208 | args.commit_results_tag) | 318 | metadata) |
| 209 | if result.wasSuccessful(): | 319 | if result.wasSuccessful(): |
| 210 | return 0 | 320 | return 0 |
| 211 | 321 | ||
