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 12 import argparse 13 from datetime import date 14 from datetime import datetime 15 from datetime import timedelta 16 17 import common 18 from autotest_lib.client.common_lib import time_utils 19 from autotest_lib.client.common_lib.cros.graphite import autotest_stats 20 from autotest_lib.site_utils import gmail_lib 21 from autotest_lib.site_utils import host_history 22 from autotest_lib.site_utils import host_history_utils 23 from autotest_lib.site_utils import host_label_utils 24 25 26 def report_stats(board, pool, start_time, end_time, span): 27 """Report machine stats for given board, pool and time period. 28 29 @param board: Name of board. 30 @param pool: Name of pool. 31 @param start_time: start time to collect stats. 32 @param end_time: end time to collect stats. 33 @param span: Number of hours that the stats should be collected for. 34 @return: Error message collected when calculating the stats. 35 """ 36 print '================ %-12s %-12s ================' % (board, pool) 37 try: 38 history = host_history.get_history_details(start_time=start_time, 39 end_time=end_time, 40 board=board, 41 pool=pool) 42 except host_history_utils.NoHostFoundException as e: 43 print 'No history found. Error:\n%s' % e 44 history = None 45 mur = -1 46 mar = -1 47 mir = -1 48 49 if history: 50 status_intervals = host_history_utils.get_status_intervals(history) 51 stats_all, num_hosts = host_history_utils.aggregate_hosts( 52 status_intervals) 53 total = 0 54 total_time = span*3600*num_hosts 55 for status, interval in stats_all.iteritems(): 56 total += interval 57 if abs(total - total_time) > 10: 58 error = ('Status intervals do not add up. No stats will be ' 59 'collected for board: %s, pool: %s, diff: %s' % 60 (board, pool, total - total_time)) 61 hosts = [] 62 for history_for_host in status_intervals: 63 total = 0 64 for interval in history_for_host.keys(): 65 total += interval[1] - interval[0] 66 if total > span*3600: 67 hosts.append(history_for_host.values()[0]['metadata']['hostname']) 68 error += ' hosts: %s' % ','.join(hosts) 69 print error 70 return error 71 72 mur = host_history_utils.get_machine_utilization_rate(stats_all) 73 mar = host_history_utils.get_machine_availability_rate(stats_all) 74 mir = mar - mur 75 76 for status, interval in stats_all.iteritems(): 77 print '%-18s %-16s %-10.2f%%' % (status, interval, 78 100*interval/total_time) 79 print 'Machine utilization rate = %-4.2f%%' % (100*mur) 80 print 'Machine availability rate = %-4.2f%%' % (100*mar) 81 82 autotest_stats.Gauge('machine_utilization_rate').send('%s_hours.%s.%s' % 83 (span, board, pool), 84 mur) 85 autotest_stats.Gauge('machine_availability_rate').send('%s_hours.%s.%s' % 86 (span, board, pool), 87 mar) 88 autotest_stats.Gauge('machine_idle_rate').send('%s_hours.%s.%s' % 89 (span, board, pool), mir) 90 91 92 def main(): 93 """main script. """ 94 parser = argparse.ArgumentParser() 95 parser.add_argument('--span', type=int, dest='span', default=1, 96 help=('Number of hours that stats should be collected. ' 97 'If it is set to 24, the end time of stats being ' 98 'collected will set to the mid of the night. ' 99 'Default is set to 1 hour.')) 100 parser.add_argument('-e', '--email', dest='email', default=None, 101 help='Email any errors to the given email address.') 102 options = parser.parse_args() 103 104 boards = host_label_utils.get_all_boards() 105 pools = ['bvt', 'suites', 'cq'] 106 107 if options.span == 24: 108 today = datetime.combine(date.today(), datetime.min.time()) 109 end_time = time_utils.to_epoch_time(today) 110 else: 111 now = datetime.now() 112 end_time = datetime(year=now.year, month=now.month, day=now.day, 113 hour=now.hour) 114 end_time = time_utils.to_epoch_time(end_time) 115 116 start_time = end_time - timedelta(hours=options.span).total_seconds() 117 print ('Collecting host stats from %s to %s...' % 118 (time_utils.epoch_time_to_date_string(start_time), 119 time_utils.epoch_time_to_date_string(end_time))) 120 121 errors = [] 122 if not boards: 123 errors.append('Error! No board found in metadb.') 124 for board in boards: 125 for pool in pools: 126 error = report_stats(board, pool, start_time, end_time, 127 options.span) 128 if error: 129 errors.append(error) 130 if options.email and errors: 131 gmail_lib.send_email(options.email, 132 'Error occured when collecting host stats.', 133 '\n'.join(errors)) 134 135 136 if __name__ == '__main__': 137 main() 138