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 8each board and pool. 9""" 10 11 12import argparse 13from datetime import date 14from datetime import datetime 15from datetime import timedelta 16 17import common 18from autotest_lib.client.common_lib import time_utils 19from autotest_lib.client.common_lib.cros.graphite import autotest_stats 20from autotest_lib.site_utils import gmail_lib 21from autotest_lib.site_utils import host_history 22from autotest_lib.site_utils import host_history_utils 23from autotest_lib.site_utils import host_label_utils 24 25 26def 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 92def 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 136if __name__ == '__main__': 137 main() 138