blob: 4e039809e0b69e7de5e021b1a4db80f7eaa15827 [file] [log] [blame]
# Copyright 2015 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Script that shows build timing for a build, and it's stages.
This script shows how long a build took, how long each stage took, and when each
stage started relative to the start of the build.
"""
from __future__ import print_function
import datetime
import sys
from chromite.cbuildbot import constants
from chromite.lib import build_time_stats
from chromite.lib import cidb
from chromite.lib import commandline
from chromite.lib import cros_logging as logging
# MUST be kept in sync with GetParser's build-type option.
BUILD_TYPE_MAP = {
'cq': constants.CQ_MASTER,
'canary': constants.CANARY_MASTER,
'chrome-pfq': constants.PFQ_MASTER,
}
def GetParser():
"""Creates the argparse parser."""
parser = commandline.ArgumentParser(description=__doc__)
parser.add_argument('--cred-dir', action='store', required=True,
metavar='CIDB_CREDENTIALS_DIR',
help='Database credentials directory with certificates '
'and other connection information. Obtain your '
'credentials at go/cros-cidb-admin .')
ex_group = parser.add_mutually_exclusive_group(required=True)
# Ask for pull out a single build id to compare against other values.
ex_group.add_argument('--build-id', action='store', type=int, default=None,
help="Single build with comparison to 'normal'.")
# Look at all builds for a build_config.
ex_group.add_argument('--build-config', action='store', default=None,
help='Build config to gather stats for.')
# Look at all builds for a master/slave group.
ex_group.add_argument('--build-type', default=None,
choices=['cq', 'chrome-pfq', 'canary'],
help='Build master/salves to gather stats for: cq.')
# How many builds are included, for builder/build-types.
start_group = parser.add_mutually_exclusive_group()
start_group.add_argument('--start-date', action='store', type='date',
default=None,
help='Limit scope to a start date in the past.')
start_group.add_argument('--month', action='store_true', default=False,
help='Limit scope to the past 30 days up to now.')
start_group.add_argument('--week', action='store_true', default=False,
help='Limit scope to the past week up to now.')
start_group.add_argument('--day', action='store_true', default=False,
help='Limit scope to the past day up to now.')
start_group.add_argument('--trending', action='store_true', default=False,
help='Show stats for all builds by month.')
parser.add_argument('--end-date', action='store', type='date', default=None,
help='Limit scope to an end date in the past.')
parser.add_argument('--csv', action='store_true', default=False,
help='Output in CSV format.')
parser.add_argument('--stages', action='store_true', default=True,
help='Do not show stats for all stages run.')
parser.add_argument('--nostages', dest='stages', action='store_false',
help='Do not show stats for all stages run.')
return parser
def OptionsToStartEndDates(options):
end_date = options.end_date or datetime.datetime.now().date()
if options.month:
start_date = end_date - datetime.timedelta(days=30)
elif options.day:
start_date = end_date - datetime.timedelta(days=1)
elif options.start_date:
start_date = options.start_date
elif options.trending:
start_date, end_date = None, None
else:
# Default of past_week.
start_date = end_date - datetime.timedelta(days=7)
return start_date, end_date
def main(argv):
parser = GetParser()
options = parser.parse_args(argv)
db = cidb.CIDBConnection(options.cred_dir)
# Timeframe for discovering builds, if options.build_id not used.
start_date, end_date = OptionsToStartEndDates(options)
# Trending is sufficiently different to be handled on it's own.
if not options.trending:
assert not options.csv, '--csv can only be used with --trending.'
# Data about a single build (optional).
focus_build = None
if options.build_id:
logging.info('Gathering data for %s', options.build_id)
focus_status = build_time_stats.BuildIdToBuildStatus(db, options.build_id)
focus_build = build_time_stats.GetBuildTimings(focus_status)
build_config = focus_status['build_config']
builds_statuses = build_time_stats.BuildConfigToStatuses(
db, build_config, start_date, end_date)
description = 'Focus %d - %s' % (options.build_id, build_config)
elif options.build_config:
builds_statuses = build_time_stats.BuildConfigToStatuses(
db, options.build_config, start_date, end_date)
description = 'Config %s' % options.build_config
elif options.build_type:
builds_statuses = build_time_stats.MasterConfigToStatuses(
db, BUILD_TYPE_MAP[options.build_type], start_date, end_date)
description = 'Type %s' % options.build_type
# Compute per-build timing.
builds_timings = [build_time_stats.GetBuildTimings(status)
for status in builds_statuses]
if not builds_timings:
logging.critical('No Builds Found For: %s', description)
return 1
# Report results.
build_time_stats.Report(
sys.stdout,
description,
focus_build,
builds_timings,
options.stages,
options.trending,
options.csv)