| Index: client/tools/cost.py
|
| diff --git a/client/tools/cost.py b/client/tools/cost.py
|
| index 7052eded692370e8e86c81de0c9b1751db0afad4..34cdfbf0bea5ea06cdecac067b55ebadbf1ada84 100755
|
| --- a/client/tools/cost.py
|
| +++ b/client/tools/cost.py
|
| @@ -23,13 +23,19 @@ CLIENT_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
|
| _EPOCH = datetime.datetime.utcfromtimestamp(0)
|
|
|
| +# Type of bucket to use.
|
| +MAJOR_OS, MAJOR_OS_ASAN, MINOR_OS, MINOR_OS_GPU = range(4)
|
|
|
| -def do_bucket(items, bucket_major_os, bucket_gpu):
|
| +
|
| +def do_bucket(items, bucket_type):
|
| + """Categorizes the tasks based on one of the bucket type defined above."""
|
| out = {}
|
| for task in items:
|
| if 'heartbeat:1' in task['tags']:
|
| # Skip heartbeats.
|
| continue
|
| +
|
| + is_asan = 'asan:1' in task['tags']
|
| os_tag = None
|
| gpu_tag = None
|
| for t in task['tags']:
|
| @@ -39,14 +45,22 @@ def do_bucket(items, bucket_major_os, bucket_gpu):
|
| # GPU tests still specify Linux.
|
| # TODO(maruel): Fix the recipe.
|
| os_tag = 'Ubuntu'
|
| - if bucket_major_os:
|
| - os_tag = os_tag.split('-')[0]
|
| elif t.startswith('gpu:'):
|
| gpu_tag = t[4:]
|
| +
|
| + if bucket_type in (MAJOR_OS, MAJOR_OS_ASAN):
|
| + os_tag = os_tag.split('-')[0]
|
| tag = os_tag
|
| - if bucket_gpu and gpu_tag and gpu_tag != 'none':
|
| + if bucket_type == MINOR_OS_GPU and gpu_tag and gpu_tag != 'none':
|
| tag += ' gpu:' + gpu_tag
|
| + if bucket_type == MAJOR_OS_ASAN and is_asan:
|
| + tag += ' ASan'
|
| out.setdefault(tag, []).append(task)
|
| +
|
| + # Also create global buckets for ASan.
|
| + if bucket_type == MAJOR_OS_ASAN:
|
| + tag = '(any OS) ASan' if is_asan else '(any OS) Not ASan'
|
| + out.setdefault(tag, []).append(task)
|
| return out
|
|
|
|
|
| @@ -280,10 +294,10 @@ def stats(tasks, show_cost):
|
| pending_total, pending_avg, pending_med, pending_p99))
|
|
|
|
|
| -def present_data(items, bucket_major_os, bucket_gpu, show_cost):
|
| +def present_task_types(items, bucket_type, show_cost):
|
| cost = ' Usage Cost $USD' if show_cost else ''
|
| print(' Nb of Tasks Total Duration%s' % cost)
|
| - buckets = do_bucket(items, bucket_major_os, bucket_gpu)
|
| + buckets = do_bucket(items, bucket_type)
|
| for index, (bucket, tasks) in enumerate(sorted(buckets.iteritems())):
|
| if index:
|
| print('')
|
| @@ -295,6 +309,33 @@ def present_data(items, bucket_major_os, bucket_gpu, show_cost):
|
| stats(items, show_cost)
|
|
|
|
|
| +def present_users(items):
|
| + users = {}
|
| + for task in items:
|
| + user = ''
|
| + for tag in task['tags']:
|
| + if tag.startswith('user:'):
|
| + if tag[5:]:
|
| + user = tag[5:]
|
| + break
|
| + if tag == 'purpose:CI':
|
| + user = 'CI'
|
| + break
|
| + if tag == 'heartbeat:1':
|
| + user = 'heartbeat'
|
| + break
|
| + if user:
|
| + users.setdefault(user, 0)
|
| + users[user] += 1
|
| + maxlen = max(len(i) for i in users)
|
| + maxusers = 100
|
| + for index, (name, tasks) in enumerate(
|
| + sorted(users.iteritems(), key=lambda x: -x[1])):
|
| + if index == maxusers:
|
| + break
|
| + print('%3d %-*s: %d' % (index + 1, maxlen, name, tasks))
|
| +
|
| +
|
| def main():
|
| parser = optparse.OptionParser(description=sys.modules['__main__'].__doc__)
|
| parser.add_option(
|
| @@ -306,16 +347,34 @@ def main():
|
| parser.add_option(
|
| '--end', help='End date in UTC; defaults to --start+1 day')
|
| parser.add_option(
|
| - '--broad', action='store_true', help='Strip OS version from buckets')
|
| - parser.add_option(
|
| - '--gpu', action='store_true', help='Buckets per GPU')
|
| - parser.add_option(
|
| '--no-cost', action='store_false', dest='cost', default=True,
|
| help='Strip $ from display')
|
| parser.add_option(
|
| - '--json', default='stats.json',
|
| + '--users', action='store_true', help='Display top users instead')
|
| + parser.add_option(
|
| + '--json', default='tasks.json',
|
| help='File containing raw data; default: %default')
|
| parser.add_option('-v', '--verbose', action='count', default=0)
|
| +
|
| + group = optparse.OptionGroup(parser, 'Grouping')
|
| + group.add_option(
|
| + '--major-os', action='store_const',
|
| + dest='bucket', const=MAJOR_OS, default=MAJOR_OS,
|
| + help='Classify by OS type, independent of OS version (default)')
|
| + group.add_option(
|
| + '--minor-os', action='store_const',
|
| + dest='bucket', const=MINOR_OS,
|
| + help='Classify by minor OS version')
|
| + group.add_option(
|
| + '--gpu', action='store_const',
|
| + dest='bucket', const=MINOR_OS_GPU,
|
| + help='Classify by minor OS version and GPU type when requested')
|
| + group.add_option(
|
| + '--asan', action='store_const',
|
| + dest='bucket', const=MAJOR_OS_ASAN,
|
| + help='Classify by major OS version and ASAN')
|
| + parser.add_option_group(group)
|
| +
|
| options, args = parser.parse_args()
|
|
|
| if args:
|
| @@ -337,7 +396,11 @@ def main():
|
| parse_time(last['created_ts']) - parse_time(first['created_ts'])
|
| ))
|
| print('')
|
| - present_data(items, options.broad, options.gpu, options.cost)
|
| +
|
| + if options.users:
|
| + present_users(items)
|
| + else:
|
| + present_task_types(items, options.bucket, options.cost)
|
| return 0
|
|
|
|
|
|
|