1c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu#!/usr/bin/python 2c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu# 3c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu# Copyright (c) 2014 The Chromium OS Authors. All rights reserved. 4c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu# Use of this source code is governed by a BSD-style license that can be 5c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu# found in the LICENSE file. 6c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 7c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 8c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu"""Script to calculate timing stats for suites. 9c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 10c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuThis script measures nine stats for a suite run. 11c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu1. Net suite runtime. 12c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu2. Suite scheduling overhead. 13c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu3. Average scheduling overhead. 14c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu4. Average Queuing time. 15c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu5. Average Resetting time. 16c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu6. Average provisioning time. 17c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu7. Average Running time. 18c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu8. Average Parsing time. 19c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu9. Average Gathering time. 20c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 21c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuWhen the cron_mode is enabled, this script throws all stats but the first one 22c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu(Net suite runtime) to Graphite because the first one is already 23c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryubeing sent to Graphite by Autotest online. 24c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 25c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuNet suite runtime is end-to-end time for a suite from the beginning 26c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuto the end. 27c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuIt is stored in a field, "duration", of a type, "suite_runtime" in 28c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuelasticsearch (ES). 29c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 30c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuSuite scheduling overhead is defined by the average of DUT overheads. 31c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuSuite is composed of one or more jobs, and those jobs are run on 32c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuone or more DUTs that are available. 33c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuA DUT overhead is defined by: 34c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu DUT_i overhead = sum(net time for job_k - runtime for job_k 35c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu - runtime for special tasks of job_k) 36c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Job_k are the jobs run on DUT_i. 37c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 38c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuNet time for a job is the time from job_queued_time to hqe_finished_time. 39c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryujob_queued_time is stored in the "queued_time" column of "tko_jobs" table. 40c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuhqe_finished_time is stored in the "finished_on" of "afe_host_queue_entries" 41c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryutable. 42c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuWe do not use "job_finished_time" of "tko_jobs" as job_finished_time is 43c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryurecorded before gathering/parsing/archiving. 44c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuWe do not use hqe started time ("started_on" of "afe_host_queue_entries"), 45c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuas it does not account for the lag from a host is assigned to the job till 46c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuthe scheduler sees the assignment. 47c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 48c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuRuntime for job_k is the sum of durations for the records of 49c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu"job_time_breakdown" type in ES that have "Queued" or "Running" status. 50c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuIt is possible that a job has multiple "Queued" records when the job's test 51c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryufailed and tried again. 52c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuWe take into account only the last "Queued" record. 53c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 54c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuRuntime for special tasks of job_k is the sum of durations for the records 55c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuof "job_time_breakdown" type in ES that have "Resetting", "Provisioning", 56c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu"Gathering", or "Parsing" status. 57c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK RyuWe take into account only the records whose timestamp is larger than 58c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuthe timestamp of the last "Queued" record. 59c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu""" 60c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 61c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuimport argparse 62c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryufrom datetime import datetime 63c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryufrom datetime import timedelta 64c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 65c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuimport common 66c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryufrom autotest_lib.client.common_lib import host_queue_entry_states 67c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryufrom autotest_lib.client.common_lib import time_utils 68b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Blackfrom autotest_lib.client.common_lib.cros.graphite import autotest_es 691e1c41b1b4a1b97c0b7086b8430856ed45e064d3Gabe Blackfrom autotest_lib.client.common_lib.cros.graphite import autotest_stats 70c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryufrom autotest_lib.frontend import setup_django_environment 71c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryufrom autotest_lib.frontend.afe import models 72c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryufrom autotest_lib.frontend.tko import models as tko_models 73c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryufrom autotest_lib.server import utils 74c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryufrom autotest_lib.site_utils import job_overhead 75c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 76c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 77c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu_options = None 78c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 79c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu_hqes = host_queue_entry_states.Status 80c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu_states = [ 81c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu _hqes.QUEUED, _hqes.RESETTING, _hqes.PROVISIONING, 82c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu _hqes.RUNNING, _hqes.GATHERING, _hqes.PARSING] 83c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 84c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 85c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef mean(l): 86c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 87c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Calculates an Arithmetic Mean for the numbers in a list. 88c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 89c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param l: A list of numbers. 90c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @return: Arithmetic mean if the list is not empty. 91c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Otherwise, returns zero. 92c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 93c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu return float(sum(l)) / len(l) if l else 0 94c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 95c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 96c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef print_verbose(string, *args): 97c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if _options.verbose: 98c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print(string % args) 99c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 100c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 101c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef get_nontask_runtime(job_id, dut, job_info_dict): 102c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 103c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Get sum of durations for "Queued", "Running", "Parsing", and "Gathering" 104c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu status records. 105c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_info_dict will be modified in this function to store the duration 106c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for each status. 107c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 108c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_id: The job id of interest. 109c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param dut: Hostname of a DUT that the job ran on. 110c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_info_dict: Dictionary that has information for jobs. 111c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @return: Tuple of sum of durations and the timestamp for the last 112c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Queued record. 113c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 114b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black results = autotest_es.query( 115c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu fields_returned=['status', 'duration', 'time_recorded'], 116c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu equality_constraints=[('_type', 'job_time_breakdown'), 117c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu ('job_id', job_id), 118c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu ('hostname', dut)], 119c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu sort_specs=[{'time_recorded': 'desc'}]) 120c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 121c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu sum = 0 122c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu last_queued_timestamp = 0 123c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu # There could be multiple "Queued" records. 124c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu # Get sum of durations for the records after the last "Queued" records 125c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu # (including the last "Queued" record). 126c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu # Exploits the fact that "results" are ordered in the descending order 127c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu # of time_recorded. 128b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black for hit in results.hits: 129c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_info_dict[job_id][hit['status']] = float(hit['duration']) 130c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if hit['status'] == 'Queued': 131c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu # The first Queued record is the last one because of the descending 132c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu # order of "results". 133c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu last_queued_timestamp = float(hit['time_recorded']) 134c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu sum += float(hit['duration']) 135c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu break 136c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu else: 137c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu sum += float(hit['duration']) 138c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu return (sum, last_queued_timestamp) 139c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 140c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 141c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef get_tasks_runtime(task_list, dut, t_start, job_id, job_info_dict): 142c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 143c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Get sum of durations for special tasks. 144c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_info_dict will be modified in this function to store the duration 145c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for each special task. 146c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 147c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param task_list: List of task id. 148c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param dut: Hostname of a DUT that the tasks ran on. 149c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param t_start: Beginning timestamp. 150c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_id: The job id that is related to the tasks. 151c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu This is used only for debugging purpose. 152c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_info_dict: Dictionary that has information for jobs. 153c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @return: Sum of durations of the tasks. 154c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 15555bfe14a6c2cc2710593ecf4d461af64181915c0Gabe Black t_start_epoch = time_utils.to_epoch_time(t_start) 156b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black results = autotest_es.query( 157c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu fields_returned=['status', 'task_id', 'duration'], 158c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu equality_constraints=[('_type', 'job_time_breakdown'), 159c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu ('hostname', dut)], 16055bfe14a6c2cc2710593ecf4d461af64181915c0Gabe Black range_constraints=[('time_recorded', t_start_epoch, None)], 161c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu batch_constraints=[('task_id', task_list)]) 162c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu sum = 0 163b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black for hit in results.hits: 164c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu sum += float(hit['duration']) 165c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_info_dict[job_id][hit['status']] = float(hit['duration']) 166c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print_verbose('Task %s for Job %s took %s', 167c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu hit['task_id'], job_id, hit['duration']) 168c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu return sum 169c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 170c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 171c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef get_job_runtime(job_id, dut, job_info_dict): 172c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 173c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Get sum of durations for the entries that are related to a job. 174c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_info_dict will be modified in this function. 175c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 176c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_id: The job id of interest. 177c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param dut: Hostname of a DUT that the job ran on. 178c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_info_dict: Dictionary that has information for jobs. 179c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @return: Total duration taken by a job. 180c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 181c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu sum, t_last_queued = get_nontask_runtime(job_id, dut, job_info_dict) 182c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print_verbose('Job %s took %f, last Queued: %s', 183c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_id, sum, t_last_queued) 184c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu sum += get_tasks_runtime( 185c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu list(job_info_dict[job_id]['tasks']), dut, t_last_queued, 186c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_id, job_info_dict) 187c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu return sum 188c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 189c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 190c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef get_dut_overhead(dut, jobs, job_info_dict): 191c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 192c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Calculates the scheduling overhead of a DUT. 193c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 194c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu The scheduling overhead of a DUT is defined by the sum of scheduling 195c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu overheads for the jobs that ran on the DUT. 196c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu The scheduling overhead for a job is defined by the difference 197c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu of net job runtime and real job runtime. 198c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_info_dict will be modified in this function. 199c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 200c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param dut: Hostname of a DUT. 201c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param jobs: The list of jobs that ran on the DUT. 202c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_info_dict: Dictionary that has information for jobs. 203c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @return: Scheduling overhead of a DUT in a floating point value. 204c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu The unit is a second. 205c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 206c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu overheads = [] 207c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for job_id in jobs: 208c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu (t_start, t_end) = job_info_dict[job_id]['timestamps'] 209c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu runtime = get_job_runtime(job_id, dut, job_info_dict) 210c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu overheads.append(t_end - t_start - runtime) 211c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print_verbose('Job: %s, Net runtime: %f, Real runtime: %f, ' 212c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 'Overhead: %f', job_id, t_end - t_start, runtime, 213c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu t_end - t_start - runtime) 214c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu return sum(overheads) 215c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 216c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 217c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef get_child_jobs_info(suite_job_id, num_child_jobs, sanity_check): 218c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 219c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Gets information about child jobs of a suite. 220c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 221c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param suite_job_id: Job id of a suite. 222c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param num_child_jobs: Number of child jobs of the suite. 223c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param sanity_check: Do sanity check if True. 224c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @return: A tuple of (dictionary, list). For dictionary, the key is 225c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu a DUT's hostname and the value is a list of jobs that ran on 226c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu the DUT. List is the list of all jobs of the suite. 227c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 228b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black results = autotest_es.query( 229c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu fields_returned=['job_id', 'hostname'], 230c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu equality_constraints=[('_type', 'host_history'), 231c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu ('parent_job_id', suite_job_id), 232c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu ('status', 'Running'),]) 233c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 234c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu dut_jobs_dict = {} 235c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_filter = set() 236b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black for hit in results.hits: 237c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_id = hit['job_id'] 238c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu dut = hit['hostname'] 239c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if job_id in job_filter: 240c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu continue 241c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_list = dut_jobs_dict.setdefault(dut, []) 242c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_list.append(job_id) 243c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_filter.add(job_id) 244c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 245c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if sanity_check and len(job_filter) != num_child_jobs: 246c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print('WARNING: Mismatch number of child jobs of a suite (%d): ' 247c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu '%d != %d' % (suite_job_id, len(job_filter), num_child_jobs)) 248c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu return dut_jobs_dict, list(job_filter) 249c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 250c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 251c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef get_job_timestamps(job_list, job_info_dict): 252c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 253c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Get beginning time and ending time for each job. 254c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 255c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu The beginning time of a job is "queued_time" of "tko_jobs" table. 256c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu The ending time of a job is "finished_on" of "afe_host_queue_entries" table. 257c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_info_dict will be modified in this function to store the timestamps. 258c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 259c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_list: List of job ids 260c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_info_dict: Dictionary that timestamps for each job will be stored 261c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 262c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu tko = tko_models.Job.objects.filter(afe_job_id__in=job_list) 263c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu hqe = models.HostQueueEntry.objects.filter(job_id__in=job_list) 264c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_start = {} 265c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for t in tko: 266c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_start[t.afe_job_id] = time_utils.to_epoch_time(t.queued_time) 267c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_end = {} 268c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for h in hqe: 269c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_end[h.job_id] = time_utils.to_epoch_time(h.finished_on) 270c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 271c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for job_id in job_list: 272c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu info_dict = job_info_dict.setdefault(job_id, {}) 273c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu info_dict.setdefault('timestamps', (job_start[job_id], job_end[job_id])) 274c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 275c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 276c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef get_job_tasks(job_list, job_info_dict): 277c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 278c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Get task ids for each job. 279c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_info_dict will be modified in this function to store the task ids. 280c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 281c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_list: List of job ids 282c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param job_info_dict: Dictionary that task ids for each job will be stored. 283c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 284b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black results = autotest_es.query( 285c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu fields_returned=['job_id', 'task_id'], 286c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu equality_constraints=[('_type', 'host_history')], 287c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu batch_constraints=[('job_id', job_list)]) 288b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black for hit in results.hits: 289c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if 'task_id' in hit: 290c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu info_dict = job_info_dict.setdefault(hit['job_id'], {}) 291c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu task_set = info_dict.setdefault('tasks', set()) 292c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu task_set.add(hit['task_id']) 293c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 294c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 295c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef get_scheduling_overhead(suite_job_id, num_child_jobs, sanity_check=True): 296c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 297c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Calculates a scheduling overhead. 298c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 299c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu A scheduling overhead is defined by the average of DUT overheads 300c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for the DUTs that the child jobs of a suite ran on. 301c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 302c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param suite_job_id: Job id of a suite. 303c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param num_child_jobs: Number of child jobs of the suite. 304c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param sanity_check: Do sanity check if True. 305c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @return: Dictionary storing stats. 306c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 307c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu dut_jobs_dict, job_list = get_child_jobs_info( 308c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu suite_job_id, num_child_jobs, sanity_check) 309c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu job_info_dict = {} 310c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu get_job_timestamps(job_list, job_info_dict) 311c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu get_job_tasks(job_list, job_info_dict) 312c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 313c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu dut_overheads = [] 314c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu avg_overhead = 0 315c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for dut, jobs in dut_jobs_dict.iteritems(): 316c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print_verbose('Dut: %s, Jobs: %s', dut, jobs) 317c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu overhead = get_dut_overhead(dut, jobs, job_info_dict) 318c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu avg_overhead += overhead 319c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print_verbose('Dut overhead: %f', overhead) 320c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu dut_overheads.append(overhead) 321c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 322c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if job_list: 323c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu avg_overhead = avg_overhead / len(job_list) 324c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 325c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu state_samples_dict = {} 326c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for info in job_info_dict.itervalues(): 327c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for state in _states: 328c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if state in info: 329c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu samples = state_samples_dict.setdefault(state, []) 330c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu samples.append(info[state]) 331c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 332c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if state_samples_dict: 333c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu result = {state: mean(state_samples_dict[state]) 334c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if state in state_samples_dict else 0 335c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for state in _states} 336c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu result['suite_overhead'] = mean(dut_overheads) 337c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu result['overhead'] = avg_overhead 338c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu result['num_duts'] = len(dut_jobs_dict) 339c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu return result 340c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 341c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 342c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef print_suite_stats(suite_stats): 343c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """Prints out statistics for a suite to standard output.""" 344c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print('suite_overhead: %(suite_overhead)f, overhead: %(overhead)f,' % 345c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu suite_stats), 346c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for state in _states: 347c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if state in suite_stats: 348c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print('%s: %f,' % (state, suite_stats[state])), 349c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print('num_duts: %(num_duts)d' % suite_stats) 350c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 351c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 352c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef analyze_suites(start_time, end_time): 353c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 354c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu Calculates timing stats (i.e., suite runtime, scheduling overhead) 355c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu for the suites that finished within the timestamps given by parameters. 356c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 357c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param start_time: Beginning timestamp. 358c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu @param end_time: Ending timestamp. 359c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """ 360c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print('Analyzing suites from %s to %s...' % ( 361c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu time_utils.epoch_time_to_date_string(start_time), 362c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu time_utils.epoch_time_to_date_string(end_time))) 363c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 364c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if _options.bvtonly: 365c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu batch_constraints = [ 366c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu ('suite_name', ['bvt-inline', 'bvt-cq', 'bvt-perbuild'])] 367c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu else: 368c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu batch_constraints = [] 369c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 37055bfe14a6c2cc2710593ecf4d461af64181915c0Gabe Black start_time_epoch = time_utils.to_epoch_time(start_time) 37155bfe14a6c2cc2710593ecf4d461af64181915c0Gabe Black end_time_epoch = time_utils.to_epoch_time(end_time) 372b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black results = autotest_es.query( 373c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu fields_returned=['suite_name', 'suite_job_id', 'board', 'build', 374c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 'num_child_jobs', 'duration'], 375c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu equality_constraints=[('_type', job_overhead.SUITE_RUNTIME_KEY),], 37655bfe14a6c2cc2710593ecf4d461af64181915c0Gabe Black range_constraints=[('time_recorded', start_time_epoch, 37755bfe14a6c2cc2710593ecf4d461af64181915c0Gabe Black end_time_epoch)], 378c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu sort_specs=[{'time_recorded': 'asc'}], 379c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu batch_constraints=batch_constraints) 380b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black print('Found %d suites' % (results.total)) 381c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 382b72f4fbcf1583da27f09f4abb9d8162530bf4559Gabe Black for hit in results.hits: 383c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu suite_job_id = hit['suite_job_id'] 384c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 385c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu try: 386c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu suite_name = hit['suite_name'] 387c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu num_child_jobs = int(hit['num_child_jobs']) 388c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu suite_runtime = float(hit['duration']) 389c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 390c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print('Suite: %s (%s), Board: %s, Build: %s, Num child jobs: %d' % ( 391c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu suite_name, suite_job_id, hit['board'], hit['build'], 392c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu num_child_jobs)) 393c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 394c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu suite_stats = get_scheduling_overhead(suite_job_id, num_child_jobs) 395c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print('Suite: %s (%s) runtime: %f,' % ( 396c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu suite_name, suite_job_id, suite_runtime)), 397c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print_suite_stats(suite_stats) 398c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 399c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if _options.cron_mode: 40079bb42c9087b2a220bcba9b48e6dbc3438954613MK Ryu key = utils.get_data_key( 401c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 'suite_time_stats', suite_name, hit['build'], 402c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu hit['board']) 4031e1c41b1b4a1b97c0b7086b8430856ed45e064d3Gabe Black autotest_stats.Timer(key).send('suite_runtime', suite_runtime) 40479bb42c9087b2a220bcba9b48e6dbc3438954613MK Ryu for stat, val in suite_stats.iteritems(): 4051e1c41b1b4a1b97c0b7086b8430856ed45e064d3Gabe Black autotest_stats.Timer(key).send(stat, val) 406c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu except Exception as e: 407c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print('ERROR: Exception is raised while processing suite %s' % ( 408c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu suite_job_id)) 409c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print e 410c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 411c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 412c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef analyze_suite(suite_job_id): 413c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu suite_stats = get_scheduling_overhead(suite_job_id, 0, False) 414c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print('Suite (%s)' % suite_job_id), 415c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu print_suite_stats(suite_stats) 416c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 417c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 418c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryudef main(): 419c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu """main script.""" 420c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu parser = argparse.ArgumentParser( 421c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu formatter_class=argparse.ArgumentDefaultsHelpFormatter) 422c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu parser.add_argument('-c', dest='cron_mode', action='store_true', 423c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu help=('Run in a cron mode. Cron mode ' 424c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 'sends calculated stat data to Graphite.'), 425c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu default=False) 426c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu parser.add_argument('-s', type=int, dest='span', 427c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu help=('Number of hours that stats should be ' 428c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 'collected.'), 429c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu default=1) 430c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu parser.add_argument('--bvtonly', dest='bvtonly', action='store_true', 431c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu help=('Gets bvt suites only (i.e., bvt-inline,' 432c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 'bvt-cq, bvt-perbuild).'), 433c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu default=False) 434c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu parser.add_argument('--suite', type=int, dest='suite_job_id', 435c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu help=('Job id of a suite.')) 436c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu parser.add_argument('--verbose', dest='verbose', action='store_true', 437c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu help=('Prints out more info if True.'), 438c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu default=False) 439c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu global _options 440c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu _options = parser.parse_args() 441c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 442c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu if _options.suite_job_id: 443c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu analyze_suite(_options.suite_job_id) 444c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu else: 445c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu end_time = time_utils.to_epoch_time(datetime.now()) 446c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu start_time = end_time - timedelta(hours=_options.span).total_seconds() 447c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu analyze_suites(start_time, end_time) 448c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 449c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu 450c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryuif __name__ == '__main__': 451c9c0c3ff2e8800bfad3f0c79fe5879be0ec78489MK Ryu main() 452