experiment_status.py revision 62422c48de4ab503020b73be0a400873ab96d21d
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 self.log_level = experiment.log_level 20 21 def _GetProgressBar(self, num_complete, num_total): 22 ret = "Done: %s%%" % int(100.0 * num_complete / num_total) 23 bar_length = 50 24 done_char = ">" 25 undone_char = " " 26 num_complete_chars = bar_length * num_complete / num_total 27 num_undone_chars = bar_length - num_complete_chars 28 ret += " [%s%s]" % (num_complete_chars * done_char, num_undone_chars * 29 undone_char) 30 return ret 31 32 def GetProgressString(self): 33 """Get the elapsed_time, ETA.""" 34 current_time = time.time() 35 if self.experiment.start_time: 36 elapsed_time = current_time - self.experiment.start_time 37 else: 38 elapsed_time = 0 39 try: 40 if self.completed != self.experiment.num_complete: 41 self.completed = self.experiment.num_complete 42 self.new_job_start_time = current_time 43 time_completed_jobs = (elapsed_time - 44 (current_time - self.new_job_start_time)) 45 # eta is calculated as: 46 # ETA = (num_jobs_not_yet_started * estimated_time_per_job) 47 # + time_left_for_current_job 48 # 49 # where 50 # num_jobs_not_yet_started = (num_total - num_complete - 1) 51 # 52 # estimated_time_per_job = time_completed_jobs / num_run_complete 53 # 54 # time_left_for_current_job = estimated_time_per_job - 55 # time_spent_so_far_on_current_job 56 # 57 # The biggest problem with this calculation is its assumption that 58 # all jobs have roughly the same running time (blatantly false!). 59 # 60 # ETA can come out negative if the time spent on the current job is 61 # greater than the estimated time per job (e.g. you're running the 62 # first long job, after a series of short jobs). For now, if that 63 # happens, we set the ETA to "Unknown." 64 # 65 eta_seconds = (float(self.num_total - self.experiment.num_complete -1) * 66 time_completed_jobs / self.experiment.num_run_complete 67 + (time_completed_jobs / self.experiment.num_run_complete 68 - (current_time - self.new_job_start_time))) 69 70 eta_seconds = int(eta_seconds) 71 if eta_seconds > 0: 72 eta = datetime.timedelta(seconds=eta_seconds) 73 else: 74 eta = "Unknown" 75 except ZeroDivisionError: 76 eta = "Unknown" 77 strings = [] 78 strings.append("Current time: %s Elapsed: %s ETA: %s" % 79 (datetime.datetime.now(), 80 datetime.timedelta(seconds=int(elapsed_time)), 81 eta)) 82 strings.append(self._GetProgressBar(self.experiment.num_complete, 83 self.num_total)) 84 return "\n".join(strings) 85 86 def GetStatusString(self): 87 """Get the status string of all the benchmark_runs.""" 88 status_bins = {} 89 for benchmark_run in self.experiment.benchmark_runs: 90 if benchmark_run.timeline.GetLastEvent() not in status_bins: 91 status_bins[benchmark_run.timeline.GetLastEvent()] = [] 92 status_bins[benchmark_run.timeline.GetLastEvent()].append(benchmark_run) 93 94 status_strings = [] 95 for key, val in status_bins.items(): 96 if (key == "RUNNING" or self.experiment.log_level == "verbose"): 97 status_strings.append("%s: %s" % 98 (key, self._GetNamesAndIterations(val))) 99 else: 100 status_strings.append("%s: %s" % 101 (key, self._GetCompactNamesAndIterations(val))) 102 103 thread_status = "" 104 thread_status_format = "Thread Status: \n{}\n" 105 if (self.experiment.schedv2() is None and 106 self.experiment.log_level == "verbose"): 107 # Add the machine manager status. 108 thread_status = thread_status_format.format( 109 self.experiment.machine_manager.AsString()) 110 elif self.experiment.schedv2(): 111 # In schedv2 mode, we always print out thread status. 112 thread_status = thread_status_format.format( 113 self.experiment.schedv2().threads_status_as_string()) 114 115 result = "{}{}".format(thread_status, "\n".join(status_strings)) 116 117 return result 118 119 def _GetNamesAndIterations(self, benchmark_runs): 120 strings = [] 121 t = time.time() 122 for benchmark_run in benchmark_runs: 123 t_last = benchmark_run.timeline.GetLastEventTime() 124 elapsed = str(datetime.timedelta(seconds=int(t-t_last))) 125 strings.append("'{0}' {1}".format(benchmark_run.name, elapsed)) 126 return " %s (%s)" % (len(strings), ", ".join(strings)) 127 128 def _GetCompactNamesAndIterations(self, benchmark_runs): 129 output = '' 130 labels = {} 131 for benchmark_run in benchmark_runs: 132 if benchmark_run.label.name not in labels: 133 labels[benchmark_run.label.name] = [] 134 135 for label in labels: 136 strings = [] 137 benchmark_iterations = {} 138 for benchmark_run in benchmark_runs: 139 if benchmark_run.label.name != label: 140 continue 141 benchmark_name = benchmark_run.benchmark.name 142 if benchmark_name not in benchmark_iterations: 143 benchmark_iterations[benchmark_name] = [] 144 benchmark_iterations[benchmark_name].append(benchmark_run.iteration) 145 for key, val in benchmark_iterations.items(): 146 val.sort() 147 iterations = ",".join(map(str,val)) 148 strings.append("{} [{}]".format(key, iterations)) 149 output += " " + label + ": " + ", ".join(strings) + "\n" 150 151 return " %s \n%s" % (len(benchmark_runs), output) 152 153