experiment_status.py revision f2a3ef46f75d2196a93d3ed27f4d1fcf22b54fbe
1# Copyright 2011 Google Inc. All Rights Reserved. 2"""The class to show the banner.""" 3 4from __future__ import print_function 5 6import datetime 7import time 8 9 10class ExperimentStatus(object): 11 """The status class.""" 12 13 def __init__(self, experiment): 14 self.experiment = experiment 15 self.num_total = len(self.experiment.benchmark_runs) 16 self.completed = 0 17 self.new_job_start_time = time.time() 18 self.log_level = experiment.log_level 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, 28 num_undone_chars * 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)), eta)) 80 strings.append(self._GetProgressBar(self.experiment.num_complete, 81 self.num_total)) 82 return '\n'.join(strings) 83 84 def GetStatusString(self): 85 """Get the status string of all the benchmark_runs.""" 86 status_bins = {} 87 for benchmark_run in self.experiment.benchmark_runs: 88 if benchmark_run.timeline.GetLastEvent() not in status_bins: 89 status_bins[benchmark_run.timeline.GetLastEvent()] = [] 90 status_bins[benchmark_run.timeline.GetLastEvent()].append(benchmark_run) 91 92 status_strings = [] 93 for key, val in status_bins.items(): 94 if key == 'RUNNING': 95 status_strings.append('%s: %s' % 96 (key, self._GetNamesAndIterations(val))) 97 else: 98 status_strings.append('%s: %s' % 99 (key, self._GetCompactNamesAndIterations(val))) 100 101 thread_status = '' 102 thread_status_format = 'Thread Status: \n{}\n' 103 if (self.experiment.schedv2() is None and 104 self.experiment.log_level == 'verbose'): 105 # Add the machine manager status. 106 thread_status = thread_status_format.format( 107 self.experiment.machine_manager.AsString()) 108 elif self.experiment.schedv2(): 109 # In schedv2 mode, we always print out thread status. 110 thread_status = thread_status_format.format(self.experiment.schedv2( 111 ).threads_status_as_string()) 112 113 result = '{}{}'.format(thread_status, '\n'.join(status_strings)) 114 115 return result 116 117 def _GetNamesAndIterations(self, benchmark_runs): 118 strings = [] 119 t = time.time() 120 for benchmark_run in benchmark_runs: 121 t_last = benchmark_run.timeline.GetLastEventTime() 122 elapsed = str(datetime.timedelta(seconds=int(t - t_last))) 123 strings.append("'{0}' {1}".format(benchmark_run.name, elapsed)) 124 return ' %s (%s)' % (len(strings), ', '.join(strings)) 125 126 def _GetCompactNamesAndIterations(self, benchmark_runs): 127 output = '' 128 labels = {} 129 for benchmark_run in benchmark_runs: 130 if benchmark_run.label.name not in labels: 131 labels[benchmark_run.label.name] = [] 132 133 for label in labels: 134 strings = [] 135 benchmark_iterations = {} 136 for benchmark_run in benchmark_runs: 137 if benchmark_run.label.name != label: 138 continue 139 benchmark_name = benchmark_run.benchmark.name 140 if benchmark_name not in benchmark_iterations: 141 benchmark_iterations[benchmark_name] = [] 142 benchmark_iterations[benchmark_name].append(benchmark_run.iteration) 143 for key, val in benchmark_iterations.items(): 144 val.sort() 145 iterations = ','.join(map(str, val)) 146 strings.append('{} [{}]'.format(key, iterations)) 147 output += ' ' + label + ': ' + ', '.join(strings) + '\n' 148 149 return ' %s \n%s' % (len(benchmark_runs), output) 150