OLD | NEW |
1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
2 # Copyright (c) 2013 The Native Client Authors. All rights reserved. | 2 # Copyright (c) 2013 The Native Client Authors. All rights reserved. |
3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
5 | 5 |
6 """Manage partitioning of port builds. | 6 """Manage partitioning of port builds. |
7 | 7 |
8 Download historical data from the naclports builders, and use it to | 8 Download historical data from the naclports builders, and use it to |
9 partition all of the projects onto the builder shards so each shard builds in | 9 partition all of the projects onto the builder shards so each shard builds in |
10 about the same amount of time. | 10 about the same amount of time. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 import urllib2 | 58 import urllib2 |
59 | 59 |
60 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) | 60 SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) |
61 ROOT_DIR = os.path.dirname(SCRIPT_DIR) | 61 ROOT_DIR = os.path.dirname(SCRIPT_DIR) |
62 TOOLCHAINS = ('bionic', 'newlib', 'glibc', 'pnacl') | 62 TOOLCHAINS = ('bionic', 'newlib', 'glibc', 'pnacl') |
63 | 63 |
64 sys.path.append(os.path.join(ROOT_DIR, 'lib')) | 64 sys.path.append(os.path.join(ROOT_DIR, 'lib')) |
65 | 65 |
66 import naclports | 66 import naclports |
67 import naclports.source_package | 67 import naclports.source_package |
68 from naclports import Trace | 68 from naclports.util import LogVerbose |
69 | 69 |
70 | 70 |
71 class Error(naclports.Error): | 71 class Error(naclports.Error): |
72 pass | 72 pass |
73 | 73 |
74 | 74 |
75 def GetBuildOrder(projects): | 75 def GetBuildOrder(projects): |
76 rtn = [] | 76 rtn = [] |
77 packages = [naclports.source_package.CreatePackage(p) for p in projects] | 77 packages = [naclports.source_package.CreatePackage(p) for p in projects] |
78 for package in packages: | 78 for package in packages: |
(...skipping 10 matching lines...) Expand all Loading... |
89 deps = GetBuildOrder(projects) | 89 deps = GetBuildOrder(projects) |
90 return set(deps) - set(projects) | 90 return set(deps) - set(projects) |
91 | 91 |
92 | 92 |
93 def DownloadDataFromBuilder(builder, build): | 93 def DownloadDataFromBuilder(builder, build): |
94 max_tries = 10 | 94 max_tries = 10 |
95 | 95 |
96 for _ in xrange(max_tries): | 96 for _ in xrange(max_tries): |
97 url = 'http://build.chromium.org/p/client.nacl.ports/json' | 97 url = 'http://build.chromium.org/p/client.nacl.ports/json' |
98 url += '/builders/%s/builds/%d' % (builder, build) | 98 url += '/builders/%s/builds/%d' % (builder, build) |
99 Trace('Downloading %s' % url) | 99 LogVerbose('Downloading %s' % url) |
100 f = urllib2.urlopen(url) | 100 f = urllib2.urlopen(url) |
101 try: | 101 try: |
102 data = json.loads(f.read()) | 102 data = json.loads(f.read()) |
103 text = data['text'] | 103 text = data['text'] |
104 if text == ['build', 'successful']: | 104 if text == ['build', 'successful']: |
105 Trace(' Success!') | 105 LogVerbose(' Success!') |
106 return data | 106 return data |
107 Trace(' Not successful, trying previous build.') | 107 LogVerbose(' Not successful, trying previous build.') |
108 finally: | 108 finally: |
109 f.close() | 109 f.close() |
110 build -= 1 | 110 build -= 1 |
111 | 111 |
112 raise Error('Unable to find a successful build:\nBuilder: %s\nRange: [%d, %d]' | 112 raise Error('Unable to find a successful build:\nBuilder: %s\nRange: [%d, %d]' |
113 % (builder, build - max_tries, build)) | 113 % (builder, build - max_tries, build)) |
114 | 114 |
115 | 115 |
116 class Project(object): | 116 class Project(object): |
117 def __init__(self, name): | 117 def __init__(self, name): |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
223 return parts | 223 return parts |
224 | 224 |
225 | 225 |
226 def LoadCanned(parts): | 226 def LoadCanned(parts): |
227 # Return an empty partition for the no-sharding case. | 227 # Return an empty partition for the no-sharding case. |
228 if parts == 1: | 228 if parts == 1: |
229 return [[]] | 229 return [[]] |
230 partitions = [] | 230 partitions = [] |
231 partition = [] | 231 partition = [] |
232 input_file = os.path.join(SCRIPT_DIR, 'partition%d.txt' % parts) | 232 input_file = os.path.join(SCRIPT_DIR, 'partition%d.txt' % parts) |
233 Trace("LoadCanned: %s" % input_file) | 233 LogVerbose("LoadCanned: %s" % input_file) |
234 with open(input_file) as fh: | 234 with open(input_file) as fh: |
235 for line in fh: | 235 for line in fh: |
236 if line.strip()[0] == '#': | 236 if line.strip()[0] == '#': |
237 continue | 237 continue |
238 if line.startswith(' '): | 238 if line.startswith(' '): |
239 partition.append(line[2:].strip()) | 239 partition.append(line[2:].strip()) |
240 else: | 240 else: |
241 if partition: | 241 if partition: |
242 partitions.append(partition) | 242 partitions.append(partition) |
243 partition = [] | 243 partition = [] |
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
295 | 295 |
296 def PrintCanned(index, parts): | 296 def PrintCanned(index, parts): |
297 canned = GetCanned(index, parts) | 297 canned = GetCanned(index, parts) |
298 print(' '.join(canned)) | 298 print(' '.join(canned)) |
299 | 299 |
300 | 300 |
301 def GetCanned(index, parts): | 301 def GetCanned(index, parts): |
302 assert index >= 0 and index < parts, [index, parts] | 302 assert index >= 0 and index < parts, [index, parts] |
303 partitions = LoadCanned(parts) | 303 partitions = LoadCanned(parts) |
304 partitions = FixupCanned(partitions) | 304 partitions = FixupCanned(partitions) |
305 Trace("Found %d packages for shard %d" % (len(partitions[index]), index)) | 305 LogVerbose("Found %d packages for shard %d" % (len(partitions[index]), index)) |
306 return partitions[index] | 306 return partitions[index] |
307 | 307 |
308 | 308 |
309 def main(args): | 309 def main(args): |
310 parser = argparse.ArgumentParser() | 310 parser = argparse.ArgumentParser() |
311 parser.add_argument('--check', action='store_true', | 311 parser.add_argument('--check', action='store_true', |
312 help='check canned partition information is up-to-date.') | 312 help='check canned partition information is up-to-date.') |
313 parser.add_argument('-v', '--verbose', action='store_true', | 313 parser.add_argument('-v', '--verbose', action='store_true', |
314 help='Output extra information.') | 314 help='Output extra information.') |
315 parser.add_argument('-t', '--print-canned', type=int, | 315 parser.add_argument('-t', '--print-canned', type=int, |
(...skipping 22 matching lines...) Expand all Loading... |
338 GetCanned(0, num_bots) | 338 GetCanned(0, num_bots) |
339 return | 339 return |
340 | 340 |
341 if options.print_canned is not None: | 341 if options.print_canned is not None: |
342 PrintCanned(options.print_canned, options.num_bots) | 342 PrintCanned(options.print_canned, options.num_bots) |
343 return | 343 return |
344 | 344 |
345 projects = Projects() | 345 projects = Projects() |
346 for bot in range(options.num_bots): | 346 for bot in range(options.num_bots): |
347 bot_name = '%s%d' % (options.bot_prefix, bot) | 347 bot_name = '%s%d' % (options.bot_prefix, bot) |
348 Trace('Attempting to add data from "%s"' % bot_name) | 348 LogVerbose('Attempting to add data from "%s"' % bot_name) |
349 projects.AddDataFromBuilder(bot_name, options.build_number) | 349 projects.AddDataFromBuilder(bot_name, options.build_number) |
350 projects.PostProcessDeps() | 350 projects.PostProcessDeps() |
351 | 351 |
352 parts = Partition(projects, options.num_parts) | 352 parts = Partition(projects, options.num_parts) |
353 for i, project_times in enumerate(parts): | 353 for i, project_times in enumerate(parts): |
354 print('builder %d (total: %d)' % (i, project_times.total_time)) | 354 print('builder %d (total: %d)' % (i, project_times.total_time)) |
355 project_names = project_times.TopologicallySortedProjectNames(projects) | 355 project_names = project_times.TopologicallySortedProjectNames(projects) |
356 print(' %s' % '\n '.join(project_names)) | 356 print(' %s' % '\n '.join(project_names)) |
357 | 357 |
358 times = list(sorted(part.total_time for part in parts)) | 358 times = list(sorted(part.total_time for part in parts)) |
359 difference = 0 | 359 difference = 0 |
360 for i in range(1, len(times)): | 360 for i in range(1, len(times)): |
361 difference += times[i] - times[i - 1] | 361 difference += times[i] - times[i - 1] |
362 print('Difference between total time of builders: %d' % difference) | 362 print('Difference between total time of builders: %d' % difference) |
363 | 363 |
364 | 364 |
365 if __name__ == '__main__': | 365 if __name__ == '__main__': |
366 try: | 366 try: |
367 sys.exit(main(sys.argv[1:])) | 367 sys.exit(main(sys.argv[1:])) |
368 except Error as e: | 368 except Error as e: |
369 sys.stderr.write("%s\n" % e) | 369 sys.stderr.write("%s\n" % e) |
370 sys.exit(1) | 370 sys.exit(1) |
OLD | NEW |