diff options
author | Markus Lehtonen <markus.lehtonen@linux.intel.com> | 2016-12-28 16:01:21 +0200 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2017-01-23 12:05:22 +0000 |
commit | 0981bcb098bc4e5a63d3184fac3a7ab701866c1a (patch) | |
tree | 657a46607d5b9d6f31670ca4e7d31134f09cf861 | |
parent | 0e2d84728bc625b5055bbc0512ae2cd06cd45dcf (diff) | |
download | poky-0981bcb098bc4e5a63d3184fac3a7ab701866c1a.tar.gz |
oe-build-perf-test: save test metadata in a separate file
The patch introduces a new metadata (.json or .xml) file in the output
directory. All test meta data, e.g. git revision information and tester
host information is now stored there. The JSON report format is slightly
changed as the metadata is not present in results.json anymore.
[YOCTO #10590]
(From OE-Core rev: 2036c646019660e32f1bc277fdec0cdbff0afdd4)
Signed-off-by: Markus Lehtonen <markus.lehtonen@linux.intel.com>
Signed-off-by: Ross Burton <ross.burton@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-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 | ||