# -*- coding: utf-8 -*- # Copyright 2011 The ChromiumOS Authors # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. """The class to show the banner.""" import collections import datetime import time class ExperimentStatus(object): """The status class.""" def __init__(self, experiment): self.experiment = experiment self.num_total = len(self.experiment.benchmark_runs) self.completed = 0 self.new_job_start_time = time.time() self.log_level = experiment.log_level def _GetProgressBar(self, num_complete, num_total): ret = "Done: %s%%" % int(100.0 * num_complete / num_total) bar_length = 50 done_char = ">" undone_char = " " num_complete_chars = bar_length * num_complete // num_total num_undone_chars = bar_length - num_complete_chars ret += " [%s%s]" % ( num_complete_chars * done_char, num_undone_chars * undone_char, ) return ret def GetProgressString(self): """Get the elapsed_time, ETA.""" current_time = time.time() if self.experiment.start_time: elapsed_time = current_time - self.experiment.start_time else: elapsed_time = 0 try: if self.completed != self.experiment.num_complete: self.completed = self.experiment.num_complete self.new_job_start_time = current_time time_completed_jobs = elapsed_time - ( current_time - self.new_job_start_time ) # eta is calculated as: # ETA = (num_jobs_not_yet_started * estimated_time_per_job) # + time_left_for_current_job # # where # num_jobs_not_yet_started = (num_total - num_complete - 1) # # estimated_time_per_job = time_completed_jobs / num_run_complete # # time_left_for_current_job = estimated_time_per_job - # time_spent_so_far_on_current_job # # The biggest problem with this calculation is its assumption that # all jobs have roughly the same running time (blatantly false!). # # ETA can come out negative if the time spent on the current job is # greater than the estimated time per job (e.g. you're running the # first long job, after a series of short jobs). For now, if that # happens, we set the ETA to "Unknown." # eta_seconds = float( self.num_total - self.experiment.num_complete - 1 ) * time_completed_jobs / self.experiment.num_run_complete + ( time_completed_jobs / self.experiment.num_run_complete - (current_time - self.new_job_start_time) ) eta_seconds = int(eta_seconds) if eta_seconds > 0: eta = datetime.timedelta(seconds=eta_seconds) else: eta = "Unknown" except ZeroDivisionError: eta = "Unknown" strings = [] strings.append( "Current time: %s Elapsed: %s ETA: %s" % ( datetime.datetime.now(), datetime.timedelta(seconds=int(elapsed_time)), eta, ) ) strings.append( self._GetProgressBar(self.experiment.num_complete, self.num_total) ) return "\n".join(strings) def GetStatusString(self): """Get the status string of all the benchmark_runs.""" status_bins = collections.defaultdict(list) for benchmark_run in self.experiment.benchmark_runs: status_bins[benchmark_run.timeline.GetLastEvent()].append( benchmark_run ) status_strings = [] for key, val in status_bins.items(): if key == "RUNNING": get_description = self._GetNamesAndIterations else: get_description = self._GetCompactNamesAndIterations status_strings.append("%s: %s" % (key, get_description(val))) thread_status = "" thread_status_format = "Thread Status: \n{}\n" if ( self.experiment.schedv2() is None and self.experiment.log_level == "verbose" ): # Add the machine manager status. thread_status = thread_status_format.format( self.experiment.machine_manager.AsString() ) elif self.experiment.schedv2(): # In schedv2 mode, we always print out thread status. thread_status = thread_status_format.format( self.experiment.schedv2().threads_status_as_string() ) result = "{}{}".format(thread_status, "\n".join(status_strings)) return result def _GetNamesAndIterations(self, benchmark_runs): strings = [] t = time.time() for benchmark_run in benchmark_runs: t_last = benchmark_run.timeline.GetLastEventTime() elapsed = str(datetime.timedelta(seconds=int(t - t_last))) strings.append("'{0}' {1}".format(benchmark_run.name, elapsed)) return " %s (%s)" % (len(strings), ", ".join(strings)) def _GetCompactNamesAndIterations(self, benchmark_runs): grouped_benchmarks = collections.defaultdict(list) for benchmark_run in benchmark_runs: grouped_benchmarks[benchmark_run.label.name].append(benchmark_run) output_segs = [] for label_name, label_runs in grouped_benchmarks.items(): strings = [] benchmark_iterations = collections.defaultdict(list) for benchmark_run in label_runs: assert benchmark_run.label.name == label_name benchmark_name = benchmark_run.benchmark.name benchmark_iterations[benchmark_name].append( benchmark_run.iteration ) for key, val in benchmark_iterations.items(): val.sort() iterations = ",".join(str(v) for v in val) strings.append("{} [{}]".format(key, iterations)) output_segs.append( " " + label_name + ": " + ", ".join(strings) + "\n" ) return " %s \n%s" % (len(benchmark_runs), "".join(output_segs))