Dan Shi | 1ccb652 | 2014-09-19 17:15:30 -0700 | [diff] [blame] | 1 | #!/usr/bin/env python |
| 2 | |
| 3 | # Copyright (c) 2014 The Chromium OS Authors. All rights reserved. |
| 4 | # Use of this source code is governed by a BSD-style license that can be |
| 5 | # found in the LICENSE file. |
| 6 | |
| 7 | # This script is to be run daily to report machine utilization stats across |
| 8 | # each board and pool. |
| 9 | |
| 10 | |
| 11 | import argparse |
| 12 | from datetime import date |
| 13 | from datetime import datetime |
| 14 | from datetime import timedelta |
| 15 | |
| 16 | import common |
| 17 | from autotest_lib.client.common_lib import global_config |
| 18 | from autotest_lib.client.common_lib import time_utils |
| 19 | from autotest_lib.client.common_lib.cros.graphite import stats |
| 20 | from autotest_lib.server.cros.dynamic_suite import frontend_wrappers |
| 21 | from autotest_lib.site_utils import host_history_utils |
| 22 | |
| 23 | |
| 24 | INSTANCE_SERVER = global_config.global_config.get_config_value( |
| 25 | 'SERVER', 'hostname', type=str) |
| 26 | _AFE = frontend_wrappers.RetryingAFE( |
| 27 | server=INSTANCE_SERVER, timeout_min=60, delay_sec=0) |
| 28 | |
| 29 | def report_stats(board, pool, start_time, end_time, span): |
| 30 | """Report machine stats for given board, pool and time period. |
| 31 | |
| 32 | @param board: Name of board. |
| 33 | @param pool: Name of pool. |
| 34 | @param start_time: start time to collect stats. |
| 35 | @param end_time: end time to collect stats. |
| 36 | @param span: Number of hours that the stats should be collected for. |
| 37 | """ |
| 38 | print '================ %-12s %-12s ================' % (board, pool) |
| 39 | history = _AFE.run('get_host_history', board=board, pool=pool, |
| 40 | start_time=start_time, end_time=end_time) |
| 41 | if not history: |
| 42 | print 'No history found.' |
| 43 | return |
| 44 | status_intervals = host_history_utils.get_status_intervals(history) |
| 45 | stats_all, num_hosts = host_history_utils.aggregate_hosts( |
| 46 | status_intervals) |
| 47 | total = 0 |
| 48 | total_time = span*3600*num_hosts |
| 49 | for status, interval in stats_all.iteritems(): |
| 50 | total += interval |
| 51 | if abs(total - total_time) > 10: |
| 52 | print ('Status intervals do not add up. No stats will be collected for ' |
| 53 | 'board: %s, pool: %s, diff: %s' % |
| 54 | (board, pool, total - total_time)) |
| 55 | return |
| 56 | |
| 57 | mur = host_history_utils.get_machine_utilization_rate(stats_all) |
| 58 | mar = host_history_utils.get_machine_availability_rate(stats_all) |
| 59 | |
| 60 | stats.Gauge('machine_utilization_rate').send('%s_hours.%s.%s' % |
| 61 | (span, board, pool), mur) |
| 62 | stats.Gauge('machine_availability_rate').send('%s_hours.%s.%s' % |
| 63 | (span, board, pool), mar) |
| 64 | stats.Gauge('machine_idle_rate').send('%s_hours.%s.%s' % |
| 65 | (span, board, pool), mar-mur) |
| 66 | |
| 67 | for status, interval in stats_all.iteritems(): |
| 68 | print '%-18s %-16s %-10.2f%%' % (status, interval, |
| 69 | 100*interval/total_time) |
| 70 | print 'Machine utilization rate = %-4.2f%%' % (100*mur) |
| 71 | print 'Machine availability rate = %-4.2f%%' % (100*mar) |
| 72 | |
| 73 | |
| 74 | def main(): |
| 75 | """main script. """ |
| 76 | parser = argparse.ArgumentParser() |
| 77 | parser.add_argument('--span', type=int, dest='span', |
| 78 | help=('Number of hours that stats should be collected. ' |
| 79 | 'If it is set to 24, the end time of stats being ' |
| 80 | 'collected will set to the mid of the night. ' |
| 81 | 'Default is set to 1 hour.'), |
| 82 | default=1) |
| 83 | options = parser.parse_args() |
| 84 | |
| 85 | labels = _AFE.get_labels(name__startswith='board:') |
| 86 | boards = [label.name[6:] for label in labels] |
| 87 | |
| 88 | pools = ['bvt', 'suites', 'try-bot', 'cq', 'pfq'] |
| 89 | |
| 90 | if options.span == 24: |
| 91 | today = datetime.combine(date.today(), datetime.min.time()) |
| 92 | end_time = time_utils.to_epoch_time(today) |
| 93 | else: |
| 94 | now = datetime.now() |
| 95 | end_time = datetime(year=now.year, month=now.month, day=now.day, |
| 96 | hour=now.hour) |
| 97 | end_time = time_utils.to_epoch_time(end_time) |
| 98 | |
| 99 | start_time = end_time - timedelta(hours=options.span).total_seconds() |
| 100 | print ('Collecting host stats from %s to %s...' % |
| 101 | (time_utils.epoch_time_to_date_string(start_time), |
| 102 | time_utils.epoch_time_to_date_string(end_time))) |
| 103 | |
| 104 | for board in boards: |
| 105 | for pool in pools: |
| 106 | report_stats(board, pool, start_time, end_time, options.span) |
| 107 | |
| 108 | |
| 109 | if __name__ == '__main__': |
| 110 | main() |