experiment_status.py revision 2317decf0e3f62297fc09a712bdf7fa253d560f3
1#!/usr/bin/python 2 3# Copyright 2011 Google Inc. All Rights Reserved. 4 5"""The class to show the banner.""" 6 7import datetime 8import time 9 10 11class ExperimentStatus(object): 12 """The status class.""" 13 14 def __init__(self, experiment): 15 self.experiment = experiment 16 self.num_total = len(self.experiment.benchmark_runs) 17 self.completed = 0 18 self.new_job_start_time = time.time() 19 20 def _GetProgressBar(self, num_complete, num_total): 21 ret = "Done: %s%%" % int(100.0 * num_complete / num_total) 22 bar_length = 50 23 done_char = ">" 24 undone_char = " " 25 num_complete_chars = bar_length * num_complete / num_total 26 num_undone_chars = bar_length - num_complete_chars 27 ret += " [%s%s]" % (num_complete_chars * done_char, num_undone_chars * 28 undone_char) 29 return ret 30 31 def GetProgressString(self): 32 """Get the elapsed_time, ETA.""" 33 current_time = time.time() 34 if self.experiment.start_time: 35 elapsed_time = current_time - self.experiment.start_time 36 else: 37 elapsed_time = 0 38 try: 39 if self.completed != self.experiment.num_complete: 40 self.completed = self.experiment.num_complete 41 self.new_job_start_time = current_time 42 time_completed_jobs = (elapsed_time - 43 (current_time - self.new_job_start_time)) 44 # eta is calculated as: 45 # ETA = (num_jobs_not_yet_started * estimated_time_per_job) 46 # + time_left_for_current_job 47 # 48 # where 49 # num_jobs_not_yet_started = (num_total - num_complete - 1) 50 # 51 # estimated_time_per_job = time_completed_jobs / num_run_complete 52 # 53 # time_left_for_current_job = estimated_time_per_job - 54 # time_spent_so_far_on_current_job 55 # 56 # The biggest problem with this calculation is its assumption that 57 # all jobs have roughly the same running time (blatantly false!). 58 # 59 # ETA can come out negative if the time spent on the current job is 60 # greater than the estimated time per job (e.g. you're running the 61 # first long job, after a series of short jobs). For now, if that 62 # happens, we set the ETA to "Unknown." 63 # 64 eta_seconds = (float(self.num_total - self.experiment.num_complete -1) * 65 time_completed_jobs / self.experiment.num_run_complete 66 + (time_completed_jobs / self.experiment.num_run_complete 67 - (current_time - self.new_job_start_time))) 68 69 eta_seconds = int(eta_seconds) 70 if eta_seconds > 0: 71 eta = datetime.timedelta(seconds=eta_seconds) 72 else: 73 eta = "Unknown" 74 except ZeroDivisionError: 75 eta = "Unknown" 76 strings = [] 77 strings.append("Current time: %s Elapsed: %s ETA: %s" % 78 (datetime.datetime.now(), 79 datetime.timedelta(seconds=int(elapsed_time)), 80 eta)) 81 strings.append(self._GetProgressBar(self.experiment.num_complete, 82 self.num_total)) 83 return "\n".join(strings) 84 85 def GetStatusString(self): 86 """Get the status string of all the benchmark_runs.""" 87 status_bins = {} 88 for benchmark_run in self.experiment.benchmark_runs: 89 if benchmark_run.timeline.GetLastEvent() not in status_bins: 90 status_bins[benchmark_run.timeline.GetLastEvent()] = [] 91 status_bins[benchmark_run.timeline.GetLastEvent()].append(benchmark_run) 92 93 status_strings = [] 94 for key, val in status_bins.items(): 95 status_strings.append("%s: %s" % 96 (key, self._GetNamesAndIterations(val))) 97 result = "Thread Status:\n%s" % "\n".join(status_strings) 98 99 # Add the machine manager status. 100 result += "\n" + self.experiment.machine_manager.AsString() + "\n" 101 102 return result 103 104 def _GetNamesAndIterations(self, benchmark_runs): 105 strings = [] 106 t = time.time() 107 for benchmark_run in benchmark_runs: 108 t_last = benchmark_run.timeline.GetLastEventTime() 109 elapsed = str(datetime.timedelta(seconds=int(t-t_last))) 110 strings.append("'{0}' {1}".format(benchmark_run.name, elapsed)) 111 return " %s (%s)" % (len(strings), ", ".join(strings)) 112