def print_stats(schedule, jobs, actual_sched, boundaries, possible_sizes): cmax = max(s[1] + jobs[s[0]][1] for s in schedule) actual_min_start = min(s[1] for s in actual_sched) actual_cmax = max((s[1] + s[2]) - actual_min_start for s in actual_sched) actual_cmax = int(actual_cmax.total_seconds()) max_job_time = max(j[1] for j in jobs) jobs_work = sum(j[0] * j[1] for j in jobs) # lower bound for Cmax (non-convex) cmax_lb_non_convex = max(max_job_time, jobs_work / reduce(operator.mul, boundaries, 1)) jobs_convex_work = sum(min(possible_sizes[j[0]]) * j[1] for j in jobs) cmax_lb_convex = max(max_job_time, jobs_convex_work / reduce(operator.mul, boundaries, 1)) max_overalloc = max((reduce(operator.mul, s.boundaries, 1) - jobs[i][0]) * 100 / jobs[i][0] for i, t, s in schedule) avg_overalloc = sum((reduce(operator.mul, s.boundaries, 1) - jobs[i][0]) * 100 / jobs[i][0] for i, t, s in schedule) / len(jobs) dimensions = {c: boundaries[i] for i, c in enumerate(char_range('x', len(boundaries)))} avg_metric = sum(metric_ad(s.boundaries, False, dimensions) for i, t, s in schedule) / len(jobs) avg_opt_metric = sum(opt_ad(j[0], False, dimensions) for j in jobs) / len(jobs) print('Cmax lower bound (non-convex): ' + str(cmax_lb_non_convex) + ', Cmax lower bound (convex): ' + str(cmax_lb_convex) + ', Cmax of schedule: ' + str(cmax) + ' (loss of ' + str((cmax - cmax_lb_non_convex) * 100 / cmax_lb_non_convex) + '% compared to non-convex lower bound, ' + str((cmax - cmax_lb_convex) * 100 / cmax_lb_convex) + '% compared to convex lower bound), actual Cmax: ' + str(actual_cmax) + ', max overalloc: ' + str(max_overalloc) + '% / average overalloc: ' + str(avg_overalloc) + ', average metric: ' + str(avg_metric) + ', average optimal metric: ' + str(avg_opt_metric))
def get_stats(dimensions, request_sizes, bins): total = reduce(operator.mul, dimensions.values(), 1) total_request_size = sum(request_sizes.values()) num_requests = len(request_sizes) num_bins = len(bins) num_opt_bins = int(math.ceil(total_request_size/total)) total_used_space = sum(reduce(operator.mul, s.boundaries, 1) for b in bins for s in b.spaces) total_used_exceeding_percentage = (total_used_space - total_request_size) * 100 / total_request_size # unused space excludes the last bin's free space as it might still be filled unused_space = total_used_space - sum(reduce(operator.mul, s.boundaries, 1) for s in bins[-1].spaces) unused_space = (len(bins)-1) * total - unused_space unused_percentage = unused_space * 100 / ((len(bins) - 1) * total) def convex_used_space(b): # return space used by a convex mesh around all assigned spaces in bin b # get max coordinate in each dimension (assumes that spaces are packed from # min to max coordinate which is the case in all strategies) # this is not the tightest convex space in a torus, but an approximation for it return reduce(operator.mul, [max(min(s.coordinates[d] + s.boundaries[d], s.coordBoundaries[d]) for s in b.spaces) for d in range(len(b.boundaries))], 1) total_sub_mesh_space = sum(convex_used_space(b) for b in bins) total_sub_mesh_percentage = (total_sub_mesh_space - total_request_size) * 100 / total_request_size avg_metric = sum(metric_ad(p.boundaries, False, dimensions) for b in bins for p in b.spaces) / len(request_sizes) avg_opt_metric = sum(opt_ad(r, False, dimensions) for r in request_sizes.values()) / len(request_sizes) return [total_request_size, num_requests, num_bins, num_opt_bins, unused_space, unused_percentage, total_used_space, total_used_exceeding_percentage, total_sub_mesh_space, total_sub_mesh_percentage, avg_metric, avg_opt_metric]
def shape_gen(size, last_shape, possible_sizes, shape_candidates): # try any shape, from best metric to worst # choose diameter/AD as metric because bigger shapes should not get precedence # sort by size first to give precedence to smaller shapes if diameter/AD is the same sorted_shapes = sorted((p for n in possible_sizes[size] for p in shape_candidates[n]), key=lambda p: reduce(operator.mul, p, 1)) return (s for s in sorted(sorted_shapes, key=lambda p: metric_ad(p, False, dimensions)))
def shape_gen(size, last_shape, possible_sizes, shape_candidates): # try any shape which is smaller than last, from best metric to worst # choose diameter as metric because bigger shapes should not get precedence # sort by size first to give precedence to smaller shapes if diameter is the same last_size = reduce(operator.mul, (last_shape if last_shape != None else dimensions.values()), 1) considered = filter(lambda s: reduce(operator.mul, s, 1) <= last_size, (p for n in possible_sizes[size] for p in shape_candidates[n])) sorted_shapes = sorted(considered, key=lambda p: reduce(operator.mul, p, 1)) return (s for s in sorted(sorted_shapes, key=lambda p: metric_ad(p, False, dimensions)))
def print_stats(schedule, jobs, actual_sched, boundaries, possible_sizes): cmax = max(s[1] + jobs[s[0]][1] for s in schedule) actual_min_start = min(s[1] for s in actual_sched) actual_cmax = max((s[1] + s[2]) - actual_min_start for s in actual_sched) actual_cmax = int(actual_cmax.total_seconds()) max_job_time = max(j[1] for j in jobs) jobs_work = sum(j[0] * j[1] for j in jobs) # lower bound for Cmax (non-convex) cmax_lb_non_convex = max(max_job_time, jobs_work / reduce(operator.mul, boundaries, 1)) jobs_convex_work = sum(min(possible_sizes[j[0]]) * j[1] for j in jobs) cmax_lb_convex = max( max_job_time, jobs_convex_work / reduce(operator.mul, boundaries, 1)) max_overalloc = max( (reduce(operator.mul, s.boundaries, 1) - jobs[i][0]) * 100 / jobs[i][0] for i, t, s in schedule) avg_overalloc = sum( (reduce(operator.mul, s.boundaries, 1) - jobs[i][0]) * 100 / jobs[i][0] for i, t, s in schedule) / len(jobs) dimensions = { c: boundaries[i] for i, c in enumerate(char_range('x', len(boundaries))) } avg_metric = sum( metric_ad(s.boundaries, False, dimensions) for i, t, s in schedule) / len(jobs) avg_opt_metric = sum(opt_ad(j[0], False, dimensions) for j in jobs) / len(jobs) print('Cmax lower bound (non-convex): ' + str(cmax_lb_non_convex) + ', Cmax lower bound (convex): ' + str(cmax_lb_convex) + ', Cmax of schedule: ' + str(cmax) + ' (loss of ' + str((cmax - cmax_lb_non_convex) * 100 / cmax_lb_non_convex) + '% compared to non-convex lower bound, ' + str((cmax - cmax_lb_convex) * 100 / cmax_lb_convex) + '% compared to convex lower bound), actual Cmax: ' + str(actual_cmax) + ', max overalloc: ' + str(max_overalloc) + '% / average overalloc: ' + str(avg_overalloc) + ', average metric: ' + str(avg_metric) + ', average optimal metric: ' + str(avg_opt_metric))
def shape_gen(size, last_shape, possible_sizes, shape_candidates): # sort by metric (best to worst) and by size for same metric spaces = sorted((p for n in possible_sizes[size] for p in shape_candidates[n]), key=lambda p: reduce(operator.mul, p, 1)) return (s for s in sorted(spaces, key=lambda p: metric_ad(p, False, dimensions)))