blob: 460c7dcecd97d831e462c83239e8e5286b420e05 [file] [log] [blame]
Dan Shi1ccb6522014-09-19 17:15:30 -07001#!/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
Dan Shi1c3b0d12014-09-26 17:15:41 -07007"""This script is to be run daily to report machine utilization stats across
8each board and pool.
9"""
Dan Shi1ccb6522014-09-19 17:15:30 -070010
11
12import argparse
13from datetime import date
14from datetime import datetime
15from datetime import timedelta
16
17import common
Dan Shi1ccb6522014-09-19 17:15:30 -070018from autotest_lib.client.common_lib import time_utils
Dan Shi5e2efb72017-02-07 11:40:23 -080019from autotest_lib.client.common_lib import utils
Dan Shi1d59a672015-03-31 14:09:03 -070020from autotest_lib.site_utils import gmail_lib
Dan Shi1c3b0d12014-09-26 17:15:41 -070021from autotest_lib.site_utils import host_history
Dan Shi1ccb6522014-09-19 17:15:30 -070022from autotest_lib.site_utils import host_history_utils
Dan Shi1c3b0d12014-09-26 17:15:41 -070023from autotest_lib.site_utils import host_label_utils
Dan Shi1ccb6522014-09-19 17:15:30 -070024
Dan Shi5e2efb72017-02-07 11:40:23 -080025try:
26 from chromite.lib import metrics
27 from chromite.lib import ts_mon_config
28except ImportError:
29 metrics = utils.metrics_mock
30 ts_mon_config = utils.metrics_mock
31
Dan Shi1ccb6522014-09-19 17:15:30 -070032
Dan Shi4a7c5422016-08-26 11:42:10 -070033_MACHINE_UTILIZATION_RATE_HOURLY = metrics.Float(
34 'chromeos/autotest/host/machine_utilization_rate/hourly')
35_MACHINE_AVAILABILITY_RATE_HOURLY = metrics.Float(
36 'chromeos/autotest/host/machine_availability_rate/hourly')
37_MACHINE_IDLE_RATE_HOURLY = metrics.Float(
38 'chromeos/autotest/host/machine_idle_rate/hourly')
39_MACHINE_UTILIZATION_RATE_DAILY = metrics.Float(
40 'chromeos/autotest/host/machine_utilization_rate/daily')
41_MACHINE_AVAILABILITY_RATE_DAILY = metrics.Float(
42 'chromeos/autotest/host/machine_availability_rate/daily')
43_MACHINE_IDLE_RATE_DAILY = metrics.Float(
44 'chromeos/autotest/host/machine_idle_rate/daily')
45
Dan Shi1ccb6522014-09-19 17:15:30 -070046def report_stats(board, pool, start_time, end_time, span):
47 """Report machine stats for given board, pool and time period.
48
49 @param board: Name of board.
50 @param pool: Name of pool.
51 @param start_time: start time to collect stats.
52 @param end_time: end time to collect stats.
53 @param span: Number of hours that the stats should be collected for.
Dan Shi66ba3c92014-10-28 17:39:30 -070054 @return: Error message collected when calculating the stats.
Dan Shi1ccb6522014-09-19 17:15:30 -070055 """
56 print '================ %-12s %-12s ================' % (board, pool)
Dan Shi1c3b0d12014-09-26 17:15:41 -070057 try:
58 history = host_history.get_history_details(start_time=start_time,
59 end_time=end_time,
60 board=board,
61 pool=pool)
62 except host_history_utils.NoHostFoundException as e:
63 print 'No history found. Error:\n%s' % e
64 history = None
65 mur = -1
66 mar = -1
67 mir = -1
Dan Shi1ccb6522014-09-19 17:15:30 -070068
Dan Shi1c3b0d12014-09-26 17:15:41 -070069 if history:
70 status_intervals = host_history_utils.get_status_intervals(history)
71 stats_all, num_hosts = host_history_utils.aggregate_hosts(
72 status_intervals)
73 total = 0
74 total_time = span*3600*num_hosts
75 for status, interval in stats_all.iteritems():
76 total += interval
77 if abs(total - total_time) > 10:
Dan Shi66ba3c92014-10-28 17:39:30 -070078 error = ('Status intervals do not add up. No stats will be '
79 'collected for board: %s, pool: %s, diff: %s' %
80 (board, pool, total - total_time))
81 hosts = []
82 for history_for_host in status_intervals:
83 total = 0
84 for interval in history_for_host.keys():
85 total += interval[1] - interval[0]
86 if total > span*3600:
87 hosts.append(history_for_host.values()[0]['metadata']['hostname'])
88 error += ' hosts: %s' % ','.join(hosts)
89 print error
90 return error
Dan Shi1c3b0d12014-09-26 17:15:41 -070091
92 mur = host_history_utils.get_machine_utilization_rate(stats_all)
93 mar = host_history_utils.get_machine_availability_rate(stats_all)
94 mir = mar - mur
95
96 for status, interval in stats_all.iteritems():
97 print '%-18s %-16s %-10.2f%%' % (status, interval,
98 100*interval/total_time)
99 print 'Machine utilization rate = %-4.2f%%' % (100*mur)
100 print 'Machine availability rate = %-4.2f%%' % (100*mar)
Dan Shi1ccb6522014-09-19 17:15:30 -0700101
Dan Shi4a7c5422016-08-26 11:42:10 -0700102 fields = {'board': board,
103 'pool': pool}
104 if span == 1:
105 _MACHINE_UTILIZATION_RATE_HOURLY.set(mur, fields=fields)
106 _MACHINE_AVAILABILITY_RATE_HOURLY.set(mar, fields=fields)
107 _MACHINE_IDLE_RATE_HOURLY.set(mir, fields=fields)
108 elif span == 24:
109 _MACHINE_UTILIZATION_RATE_DAILY.set(mur, fields=fields)
110 _MACHINE_AVAILABILITY_RATE_DAILY.set(mar, fields=fields)
111 _MACHINE_IDLE_RATE_DAILY.set(mir, fields=fields)
Dan Shi1ccb6522014-09-19 17:15:30 -0700112
113
114def main():
115 """main script. """
116 parser = argparse.ArgumentParser()
Dan Shi66ba3c92014-10-28 17:39:30 -0700117 parser.add_argument('--span', type=int, dest='span', default=1,
Dan Shi1ccb6522014-09-19 17:15:30 -0700118 help=('Number of hours that stats should be collected. '
119 'If it is set to 24, the end time of stats being '
120 'collected will set to the mid of the night. '
Dan Shi66ba3c92014-10-28 17:39:30 -0700121 'Default is set to 1 hour.'))
122 parser.add_argument('-e', '--email', dest='email', default=None,
123 help='Email any errors to the given email address.')
Dan Shi1ccb6522014-09-19 17:15:30 -0700124 options = parser.parse_args()
125
Dan Shi1c3b0d12014-09-26 17:15:41 -0700126 boards = host_label_utils.get_all_boards()
J. Richard Barnette789f87c2015-03-23 16:25:25 -0700127 pools = ['bvt', 'suites', 'cq']
Dan Shi1ccb6522014-09-19 17:15:30 -0700128
129 if options.span == 24:
130 today = datetime.combine(date.today(), datetime.min.time())
131 end_time = time_utils.to_epoch_time(today)
132 else:
133 now = datetime.now()
134 end_time = datetime(year=now.year, month=now.month, day=now.day,
135 hour=now.hour)
136 end_time = time_utils.to_epoch_time(end_time)
137
138 start_time = end_time - timedelta(hours=options.span).total_seconds()
139 print ('Collecting host stats from %s to %s...' %
140 (time_utils.epoch_time_to_date_string(start_time),
141 time_utils.epoch_time_to_date_string(end_time)))
142
Dan Shi4a7c5422016-08-26 11:42:10 -0700143 ts_mon_config.SetupTsMonGlobalState('collect_host_stats')
144
Dan Shi66ba3c92014-10-28 17:39:30 -0700145 errors = []
Dan Shi99be2172015-04-06 14:35:10 -0700146 if not boards:
147 errors.append('Error! No board found in metadb.')
Dan Shi1ccb6522014-09-19 17:15:30 -0700148 for board in boards:
149 for pool in pools:
Dan Shi66ba3c92014-10-28 17:39:30 -0700150 error = report_stats(board, pool, start_time, end_time,
151 options.span)
152 if error:
153 errors.append(error)
154 if options.email and errors:
Dan Shi1d59a672015-03-31 14:09:03 -0700155 gmail_lib.send_email(options.email,
156 'Error occured when collecting host stats.',
157 '\n'.join(errors))
Dan Shi1ccb6522014-09-19 17:15:30 -0700158
159
160if __name__ == '__main__':
161 main()