From 09183b16861d463df73ce52d5d3706ccf9cd2238 Mon Sep 17 00:00:00 2001 From: Lilia Tang Date: Thu, 1 Feb 2018 22:20:34 -0500 Subject: [PATCH 01/18] update with basic equal cost allocation fairness algo --- src/scheduler/Scheduler.py | 119 ++++++++++++++++++++++- src/scheduler/run_scheduler_simulator.py | 34 +++++-- src/scheduler/scheduler_util.py | 10 +- 3 files changed, 152 insertions(+), 11 deletions(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index 1c79578..b6002f7 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -125,6 +125,34 @@ def set_schedule_values(self, schedule): return average_metric + def set_schedule_values_metric(self, schedule): + # Same as set_schedule_values except returns list of metric values + metrics = [] + target_fps_list = [] + num_frozen_list = [] + for unit in schedule: + target_fps = unit.target_fps + num_frozen = unit.num_frozen + app_id = unit.app_id + app = unit.app + metric = self.get_metric(app, + num_frozen, + target_fps) + + target_fps_list.append(target_fps) + num_frozen_list.append(num_frozen) + metrics.append(metric) + print "------------- Schedule -------------" + for unit in schedule: + print "App:", unit.app_id, "- num_frozen:", unit.num_frozen, ", target_fps:", unit.target_fps + + ## Set parameters of schedule + self.schedule = schedule + self.num_frozen_list = num_frozen_list + self.target_fps_list = target_fps_list + + return metrics + def set_max_parameters(self): # Makes schedule which uses max sharing and max target_fps # Sets self.schedule, self.num_frozen_list, self.target_fps_list @@ -207,14 +235,13 @@ def optimize_parameters(self, cost_threshold): ## Calculate all possible schedules possible_params = [] + target_fps_options = range(1, self.stream_fps + 1) for num_frozen in sorted(self.apps[0]["accuracies"].keys()): - for target_fps in range(1, self.stream_fps + 1): + for target_fps in target_fps_options: possible_params.append((num_frozen, target_fps)) cost_benefits = {} - target_fps_options = range(1, self.stream_fps + 1) - current_schedule = [] for app in self.apps: @@ -305,6 +332,92 @@ def optimize_parameters(self, cost_threshold): return average_metric + def optimize_per_app(self, cost_threshold): + # Optimizes by giving equal cost to each app + possible_params = [] + target_fps_options = range(1, self.stream_fps + 1) + for num_frozen in sorted(self.apps[0]["accuracies"]): + for target_fps in target_fps_options: + possible_params.append((num_frozen, target_fps)) + + schedules = [] + app_ids = [app["app_id"] for app in self.apps] + costs = scheduler_util.get_cost_per_app(self.apps, cost_threshold) + current_schedule = [] + + cost_benefits = {} + + for app_id in app_ids: + cost_benefits[app_id] = {} + num_frozen_options = sorted(app["accuracies"].keys()) + for num_frozen in reversed(num_frozen_options): + if num_frozen not in cost_benefits[app_id].keys(): + cost_benefits[app_id][num_frozen] = {} + for target_fps in target_fps_options: + benefit = self.get_metric(app, + num_frozen, + target_fps) + cost = scheduler_util.get_cost(num_frozen, + target_fps, + self.model.layer_latencies) + cost_benefits[app_id][num_frozen][target_fps] = (cost, benefit) + cheapest_target_fps = min(target_fps_options) + cheapest_num_frozen = max(num_frozen_options) + current_schedule.append(Schedule.ScheduleUnit(app, + cheapest_target_fps, + cheapest_num_frozen)) + + ## In order of app id, chooses the model with minimum metric + ## and fit the budget + for unit in current_schedule: + cur_target_fps = unit.target_fps + cur_num_frozen = unit.num_frozen + app_id = unit.app_id + app = unit.app + cur_metric = self.get_metric(app, + cur_num_frozen, + cur_target_fps) + current_sched_cost = scheduler_util.get_cost_schedule(current_schedule, + self.model.layer_latencies, + self.model.final_layer) + max_benefit = 0 + best_new_unit = -1 + for potential_target_fps in target_fps_options: + for potential_num_frozen in num_frozen_options: + potential_metric = self.get_metric(app, + potential_num_frozen, + potential_target_fps) + cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] + benefit = cost_benefit_tup[0] + if potential_metric < cur_metric and benefit > max_benefit: + potential_unit = Schedule.ScheduleUnit(app, + potential_target_fps, + potential_num_frozen) + potential_schedule = [] + for c_unit in current_schedule: + if c_unit.app_id == potential_unit.app_id: + potential_schedule.append(potential_unit) + else: + copy_unit = Schedule.ScheduleUnit(c_unit.app, + c_unit.target_fps, + c_unit.num_frozen) + potential_schedule.append(copy_unit) + potential_sched_cost = scheduler_util.get_cost_schedule(potential_schedule, + self.model.layer_latencies, + self.model.final_layer) + + if potential_sched_cost - current_sched_cost <= costs[app_id]: + max_benefit = benefit + best_new_unit = potential_unit + best_new_schedule = potential_schedule + + if best_new_unit != -1: + current_schedule = best_new_schedule + + metrics = self.set_schedule_values_metric(current_schedule) + return metrics + + def make_streamer_schedule_no_sharing(self): s = Schedule.StreamerSchedule() diff --git a/src/scheduler/run_scheduler_simulator.py b/src/scheduler/run_scheduler_simulator.py index c80a513..5a24b5c 100644 --- a/src/scheduler/run_scheduler_simulator.py +++ b/src/scheduler/run_scheduler_simulator.py @@ -7,12 +7,23 @@ import numpy as np import time import zmq +import argparse if __name__ == "__main__": - num_apps_range = int(sys.argv[1]) - x_vote = int(sys.argv[2]) - outfile_prefix = sys.argv[3] + parser = argparse.ArgumentParser() + parser.add_argument("num_apps_range", type=int) + parser.add_argument("x_vote", type=int) + parser.add_argument("outfile_prefix", type=str) + + # 0 if no fairness, otherwise uses fairness + parser.add_argument("-f", "--fairness", type=int, default='0') + + args = parser.parse_args() + num_apps_range = args.num_apps_range + x_vote = args.x_vote + outfile_prefix = args.outfile_prefix + fairness = args.fairness if x_vote > 0: outfile = outfile_prefix + "-x" + str(x_vote) + "-mainstream-simulator" @@ -39,9 +50,15 @@ s = Scheduler.Scheduler(min_metric, apps, app_data.video_desc, app_data.model_desc, 0) - metric = s.optimize_parameters(350) - rel_accs = s.get_relative_accuracies() - avg_rel_acc = np.average(rel_accs) + if fairness > 0: + metrics = s.optimize_per_app(350) + rel_accs = s.get_relative_accuracies() + avg_rel_acc = np.average(rel_accs) + + else: + metric = s.optimize_parameters(350) + rel_accs = s.get_relative_accuracies() + avg_rel_acc = np.average(rel_accs) # Get streamer schedule sched = s.make_streamer_schedule() @@ -49,7 +66,10 @@ # Use target_fps_str in simulator to avoid running on the hardware fnr, fpr, cost = s.get_observed_performance(sched, s.target_fps_list) - print "Metric:", metric, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list + if fairness: + print "Metrics:", metrics, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list + else: + print "Metric:", metric, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list print "FNR:", fnr, ", FPR:", fpr num_frozen_str = ",".join([str(x) for x in s.num_frozen_list]) diff --git a/src/scheduler/scheduler_util.py b/src/scheduler/scheduler_util.py index 7dd88c7..d3166a2 100644 --- a/src/scheduler/scheduler_util.py +++ b/src/scheduler/scheduler_util.py @@ -52,10 +52,18 @@ def get_cost_schedule(schedule, layer_latencies, num_layers): return cost +def get_cost_per_app(apps, cost_threshold): + # Gets cost per app with fairness + costs = {} + cost = cost_threshold // len(apps) + for app in apps: + costs[app["app_id"]] = cost + return costs + def get_acc_dist(accuracy, sigma): # Make a distribution of accuracies, centered around accuracy value # Represents different accuracies for difference instances of events. - # E.g. a train classifier has 70% accuracy. But for trains at night, + # E.g. a train classifier has 70% accuracy. But for trains at night, # it's 60% accurate, and in the daytime 80% accurate num_events = 10000 acc_dist = [random.gauss(accuracy, sigma) for i in range(num_events)] From 450af83e4eda63eb8b5a49e75015ef4891ac87d8 Mon Sep 17 00:00:00 2001 From: Lilia Tang Date: Sat, 3 Feb 2018 00:56:12 -0500 Subject: [PATCH 02/18] fixed search space and cost counting bugs, incorporated improved output in simulator --- src/scheduler/Scheduler.py | 140 ++++++++++++----------- src/scheduler/run_scheduler_simulator.py | 2 +- src/scheduler/scheduler_util.py | 31 ++++- 3 files changed, 105 insertions(+), 68 deletions(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index b6002f7..a7cec4c 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -334,20 +334,15 @@ def optimize_parameters(self, cost_threshold): def optimize_per_app(self, cost_threshold): # Optimizes by giving equal cost to each app - possible_params = [] - target_fps_options = range(1, self.stream_fps + 1) - for num_frozen in sorted(self.apps[0]["accuracies"]): - for target_fps in target_fps_options: - possible_params.append((num_frozen, target_fps)) - - schedules = [] - app_ids = [app["app_id"] for app in self.apps] - costs = scheduler_util.get_cost_per_app(self.apps, cost_threshold) + costs = scheduler_util.get_alloc_cost_per_app(self.apps, cost_threshold) + #print "Cost allocated: ", costs current_schedule = [] + target_fps_options = range(1, self.stream_fps + 1) cost_benefits = {} - for app_id in app_ids: + for app in self.apps: + app_id = app["app_id"] cost_benefits[app_id] = {} num_frozen_options = sorted(app["accuracies"].keys()) for num_frozen in reversed(num_frozen_options): @@ -369,64 +364,79 @@ def optimize_per_app(self, cost_threshold): ## In order of app id, chooses the model with minimum metric ## and fit the budget - for unit in current_schedule: - cur_target_fps = unit.target_fps - cur_num_frozen = unit.num_frozen - app_id = unit.app_id - app = unit.app - cur_metric = self.get_metric(app, - cur_num_frozen, - cur_target_fps) - current_sched_cost = scheduler_util.get_cost_schedule(current_schedule, - self.model.layer_latencies, - self.model.final_layer) + + updated = True + while (updated): + updated = False max_benefit = 0 best_new_unit = -1 - for potential_target_fps in target_fps_options: - for potential_num_frozen in num_frozen_options: - potential_metric = self.get_metric(app, - potential_num_frozen, - potential_target_fps) - cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] - benefit = cost_benefit_tup[0] - if potential_metric < cur_metric and benefit > max_benefit: - potential_unit = Schedule.ScheduleUnit(app, - potential_target_fps, - potential_num_frozen) - potential_schedule = [] - for c_unit in current_schedule: - if c_unit.app_id == potential_unit.app_id: - potential_schedule.append(potential_unit) - else: - copy_unit = Schedule.ScheduleUnit(c_unit.app, - c_unit.target_fps, - c_unit.num_frozen) - potential_schedule.append(copy_unit) - potential_sched_cost = scheduler_util.get_cost_schedule(potential_schedule, - self.model.layer_latencies, - self.model.final_layer) - - if potential_sched_cost - current_sched_cost <= costs[app_id]: - max_benefit = benefit - best_new_unit = potential_unit - best_new_schedule = potential_schedule - - if best_new_unit != -1: - current_schedule = best_new_schedule - - metrics = self.set_schedule_values_metric(current_schedule) - return metrics - - - def make_streamer_schedule_no_sharing(self): - - s = Schedule.StreamerSchedule() + for unit in current_schedule: + cur_target_fps = unit.target_fps + cur_num_frozen = unit.num_frozen + app_id = unit.app_id + app = unit.app + cur_metric = self.get_metric(app, + cur_num_frozen, + cur_target_fps) + current_sched_cost = scheduler_util.get_cost_schedule(current_schedule, + self.model.layer_latencies, + self.model.final_layer) - for app in self.apps: - num_frozen = min(app["accuracies"].keys()) - net = Schedule.NeuralNet(s.get_id(), - app["app_id"], - self.model, + for potential_target_fps in target_fps_options: + for potential_num_frozen in num_frozen_options: + potential_metric = self.get_metric(app, + potential_num_frozen, + potential_target_fps) + cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] + benefit = cost_benefit_tup[0] + if potential_metric < cur_metric and benefit > max_benefit: + potential_unit = Schedule.ScheduleUnit(app, + potential_target_fps, + potential_num_frozen) + potential_schedule = [] + for c_unit in current_schedule: + if c_unit.app_id == potential_unit.app_id: + potential_schedule.append(potential_unit) + else: + copy_unit = Schedule.ScheduleUnit(c_unit.app, + c_unit.target_fps, + c_unit.num_frozen) + potential_schedule.append(copy_unit) + potential_sched_cost = scheduler_util.get_cost_schedule(potential_schedule, + self.model.layer_latencies, + self.model.final_layer) + + scheduled_cost_app = scheduler_util.get_cost_per_app(self.apps, + potential_schedule, + self.model.layer_latencies, + self.model.final_layer) + + if potential_sched_cost <= cost_threshold and scheduled_cost_app[app_id] <= costs[app_id]: + max_benefit = benefit + best_new_unit = potential_unit + best_new_schedule = potential_schedule + updated = True + + if updated: + current_schedule = best_new_schedule + + final_cost_app = scheduler_util.get_cost_per_app(self.apps, + current_schedule, + self.model.layer_latencies, + self.model.final_layer) + #print "Final Costs: ", final_cost_app + metrics = self.set_schedule_values_metric(current_schedule) + return metrics + + def make_streamer_schedule_no_sharing(self): + + s = Schedule.StreamerSchedule() + + for app in self.apps: + num_frozen = min(app["accuracies"].keys()) + net = Schedule.NeuralNet(s.get_id(), + app["app_id"], + self.model, -1, 1, self.model.final_layer, diff --git a/src/scheduler/run_scheduler_simulator.py b/src/scheduler/run_scheduler_simulator.py index 5a24b5c..b05e8c1 100644 --- a/src/scheduler/run_scheduler_simulator.py +++ b/src/scheduler/run_scheduler_simulator.py @@ -67,7 +67,7 @@ fnr, fpr, cost = s.get_observed_performance(sched, s.target_fps_list) if fairness: - print "Metrics:", metrics, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list + print "Metrics:", metrics, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list, ", Cost:", cost else: print "Metric:", metric, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list print "FNR:", fnr, ", FPR:", fpr diff --git a/src/scheduler/scheduler_util.py b/src/scheduler/scheduler_util.py index d3166a2..4995276 100644 --- a/src/scheduler/scheduler_util.py +++ b/src/scheduler/scheduler_util.py @@ -52,14 +52,41 @@ def get_cost_schedule(schedule, layer_latencies, num_layers): return cost -def get_cost_per_app(apps, cost_threshold): - # Gets cost per app with fairness +def get_alloc_cost_per_app(apps, cost_threshold): + # Gets cost allocated per app with fairness costs = {} cost = cost_threshold // len(apps) for app in apps: costs[app["app_id"]] = cost return costs +def get_cost_per_app(apps, schedule, layer_latencies, num_layers): + # Gets cost of each app with stems weighted by the number of apps that stem + # from it + branch_points = list(set([unit.num_frozen for unit in schedule])) + branch_points.append(num_layers) + seg_start = 0 + costs = {} + for app in apps: + costs[app["app_id"]] = 0 + for seg_end in branch_points: + seg_latency = sum([layer_latencies[i] for i in range(seg_start, seg_end)]) + + apps_branched, apps_not_branched = get_apps_branched(schedule, seg_end) + seg_fps = 0 + branched_fpses = [unit.target_fps for unit in apps_branched] + not_branched_fpses = [unit.target_fps for unit in apps_not_branched] + for app in apps_branched: + task_fps = sum(branched_fpses) + costs[app.app_id] += task_fps * seg_latency + for app in apps_not_branched: + base_fps = max(not_branched_fpses) + costs[app.app_id] += (base_fps * seg_latency) // (len(apps_not_branched)) + + seg_start = seg_end + + return costs + def get_acc_dist(accuracy, sigma): # Make a distribution of accuracies, centered around accuracy value # Represents different accuracies for difference instances of events. From f1170eee380e8c418611780c90c7ba91a5f529b5 Mon Sep 17 00:00:00 2001 From: Lilia Tang Date: Sat, 3 Feb 2018 12:45:37 -0500 Subject: [PATCH 03/18] fixed cost per app bug and optimizer --- src/scheduler/Scheduler.py | 18 ++++++++++++++---- src/scheduler/run_scheduler_simulator.py | 2 +- src/scheduler/scheduler_util.py | 7 ++++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index a7cec4c..0cb5391 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -6,7 +6,7 @@ import operator import pprint as pp import zmq - +from random import shuffle class Scheduler: ### Object that performs optimization of parameters @@ -335,7 +335,7 @@ def optimize_parameters(self, cost_threshold): def optimize_per_app(self, cost_threshold): # Optimizes by giving equal cost to each app costs = scheduler_util.get_alloc_cost_per_app(self.apps, cost_threshold) - #print "Cost allocated: ", costs + print "Cost allocated: ", costs current_schedule = [] target_fps_options = range(1, self.stream_fps + 1) @@ -371,6 +371,7 @@ def optimize_per_app(self, cost_threshold): max_benefit = 0 best_new_unit = -1 for unit in current_schedule: + #print unit cur_target_fps = unit.target_fps cur_num_frozen = unit.num_frozen app_id = unit.app_id @@ -382,6 +383,10 @@ def optimize_per_app(self, cost_threshold): self.model.layer_latencies, self.model.final_layer) + #print target_fps_options + #shuffle(target_fps_options) + #shuffle(num_frozen_options) + #print target_fps_options for potential_target_fps in target_fps_options: for potential_num_frozen in num_frozen_options: potential_metric = self.get_metric(app, @@ -389,7 +394,9 @@ def optimize_per_app(self, cost_threshold): potential_target_fps) cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] benefit = cost_benefit_tup[0] - if potential_metric < cur_metric and benefit > max_benefit: + #print "num_frozen: ", potential_num_frozen, ", target_fps: ", potential_target_fps, ", benefit: ", benefit,\ + # "metric: ", potential_metric + if potential_metric < cur_metric: potential_unit = Schedule.ScheduleUnit(app, potential_target_fps, potential_num_frozen) @@ -416,6 +423,9 @@ def optimize_per_app(self, cost_threshold): best_new_unit = potential_unit best_new_schedule = potential_schedule updated = True + #cur_metric = self.get_metric(app, + # cur_num_frozen, + # cur_target_fps) if updated: current_schedule = best_new_schedule @@ -424,7 +434,7 @@ def optimize_per_app(self, cost_threshold): current_schedule, self.model.layer_latencies, self.model.final_layer) - #print "Final Costs: ", final_cost_app + print "Final Costs: ", final_cost_app metrics = self.set_schedule_values_metric(current_schedule) return metrics diff --git a/src/scheduler/run_scheduler_simulator.py b/src/scheduler/run_scheduler_simulator.py index b05e8c1..3abc2c8 100644 --- a/src/scheduler/run_scheduler_simulator.py +++ b/src/scheduler/run_scheduler_simulator.py @@ -51,7 +51,7 @@ app_data.model_desc, 0) if fairness > 0: - metrics = s.optimize_per_app(350) + metrics = s.optimize_per_app(200) rel_accs = s.get_relative_accuracies() avg_rel_acc = np.average(rel_accs) diff --git a/src/scheduler/scheduler_util.py b/src/scheduler/scheduler_util.py index 4995276..470d0b4 100644 --- a/src/scheduler/scheduler_util.py +++ b/src/scheduler/scheduler_util.py @@ -74,14 +74,15 @@ def get_cost_per_app(apps, schedule, layer_latencies, num_layers): apps_branched, apps_not_branched = get_apps_branched(schedule, seg_end) seg_fps = 0 - branched_fpses = [unit.target_fps for unit in apps_branched] not_branched_fpses = [unit.target_fps for unit in apps_not_branched] + idx = 0 for app in apps_branched: - task_fps = sum(branched_fpses) + task_fps = apps_branched[idx].target_fps + idx += 1 costs[app.app_id] += task_fps * seg_latency for app in apps_not_branched: base_fps = max(not_branched_fpses) - costs[app.app_id] += (base_fps * seg_latency) // (len(apps_not_branched)) + costs[app.app_id] += ((base_fps * seg_latency / len(apps_not_branched))) seg_start = seg_end From 31cc04134baf2ebeae3087324d8606ba74663aca Mon Sep 17 00:00:00 2001 From: Lilia Tang Date: Sat, 3 Feb 2018 15:08:04 -0500 Subject: [PATCH 04/18] removed comments --- src/scheduler/Scheduler.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index 0cb5391..3cbea1f 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -335,7 +335,7 @@ def optimize_parameters(self, cost_threshold): def optimize_per_app(self, cost_threshold): # Optimizes by giving equal cost to each app costs = scheduler_util.get_alloc_cost_per_app(self.apps, cost_threshold) - print "Cost allocated: ", costs + #print "Cost allocated: ", costs current_schedule = [] target_fps_options = range(1, self.stream_fps + 1) @@ -371,7 +371,6 @@ def optimize_per_app(self, cost_threshold): max_benefit = 0 best_new_unit = -1 for unit in current_schedule: - #print unit cur_target_fps = unit.target_fps cur_num_frozen = unit.num_frozen app_id = unit.app_id @@ -383,10 +382,6 @@ def optimize_per_app(self, cost_threshold): self.model.layer_latencies, self.model.final_layer) - #print target_fps_options - #shuffle(target_fps_options) - #shuffle(num_frozen_options) - #print target_fps_options for potential_target_fps in target_fps_options: for potential_num_frozen in num_frozen_options: potential_metric = self.get_metric(app, @@ -394,8 +389,6 @@ def optimize_per_app(self, cost_threshold): potential_target_fps) cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] benefit = cost_benefit_tup[0] - #print "num_frozen: ", potential_num_frozen, ", target_fps: ", potential_target_fps, ", benefit: ", benefit,\ - # "metric: ", potential_metric if potential_metric < cur_metric: potential_unit = Schedule.ScheduleUnit(app, potential_target_fps, @@ -423,9 +416,6 @@ def optimize_per_app(self, cost_threshold): best_new_unit = potential_unit best_new_schedule = potential_schedule updated = True - #cur_metric = self.get_metric(app, - # cur_num_frozen, - # cur_target_fps) if updated: current_schedule = best_new_schedule @@ -434,7 +424,7 @@ def optimize_per_app(self, cost_threshold): current_schedule, self.model.layer_latencies, self.model.final_layer) - print "Final Costs: ", final_cost_app + #print "Final Costs: ", final_cost_app metrics = self.set_schedule_values_metric(current_schedule) return metrics From 70ffdb37f06b9b01f862888bb4fc61b8a8f6a165 Mon Sep 17 00:00:00 2001 From: Lilia Tang Date: Thu, 1 Feb 2018 22:20:34 -0500 Subject: [PATCH 05/18] update with basic equal cost allocation fairness algo --- src/scheduler/Scheduler.py | 119 ++++++++++++++++++++++- src/scheduler/run_scheduler_simulator.py | 21 +++- src/scheduler/scheduler_util.py | 10 +- src/scheduler/tags | 32 ++++++ 4 files changed, 174 insertions(+), 8 deletions(-) create mode 100644 src/scheduler/tags diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index 5d6cb3f..3877e28 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -123,6 +123,34 @@ def set_schedule_values(self, schedule): return average_metric + def set_schedule_values_metric(self, schedule): + # Same as set_schedule_values except returns list of metric values + metrics = [] + target_fps_list = [] + num_frozen_list = [] + for unit in schedule: + target_fps = unit.target_fps + num_frozen = unit.num_frozen + app_id = unit.app_id + app = unit.app + metric = self.get_metric(app, + num_frozen, + target_fps) + + target_fps_list.append(target_fps) + num_frozen_list.append(num_frozen) + metrics.append(metric) + print "------------- Schedule -------------" + for unit in schedule: + print "App:", unit.app_id, "- num_frozen:", unit.num_frozen, ", target_fps:", unit.target_fps + + ## Set parameters of schedule + self.schedule = schedule + self.num_frozen_list = num_frozen_list + self.target_fps_list = target_fps_list + + return metrics + def set_max_parameters(self): # Makes schedule which uses max sharing and max target_fps # Sets self.schedule, self.num_frozen_list, self.target_fps_list @@ -201,14 +229,13 @@ def optimize_parameters(self, cost_threshold): ## Calculate all possible schedules possible_params = [] + target_fps_options = range(1, self.stream_fps + 1) for num_frozen in sorted(self.apps[0]["accuracies"].keys()): - for target_fps in range(1, self.stream_fps + 1): + for target_fps in target_fps_options: possible_params.append((num_frozen, target_fps)) cost_benefits = {} - target_fps_options = range(1, self.stream_fps + 1) - current_schedule = [] for app in self.apps: @@ -299,6 +326,92 @@ def optimize_parameters(self, cost_threshold): return average_metric + def optimize_per_app(self, cost_threshold): + # Optimizes by giving equal cost to each app + possible_params = [] + target_fps_options = range(1, self.stream_fps + 1) + for num_frozen in sorted(self.apps[0]["accuracies"]): + for target_fps in target_fps_options: + possible_params.append((num_frozen, target_fps)) + + schedules = [] + app_ids = [app["app_id"] for app in self.apps] + costs = scheduler_util.get_cost_per_app(self.apps, cost_threshold) + current_schedule = [] + + cost_benefits = {} + + for app_id in app_ids: + cost_benefits[app_id] = {} + num_frozen_options = sorted(app["accuracies"].keys()) + for num_frozen in reversed(num_frozen_options): + if num_frozen not in cost_benefits[app_id].keys(): + cost_benefits[app_id][num_frozen] = {} + for target_fps in target_fps_options: + benefit = self.get_metric(app, + num_frozen, + target_fps) + cost = scheduler_util.get_cost(num_frozen, + target_fps, + self.model.layer_latencies) + cost_benefits[app_id][num_frozen][target_fps] = (cost, benefit) + cheapest_target_fps = min(target_fps_options) + cheapest_num_frozen = max(num_frozen_options) + current_schedule.append(Schedule.ScheduleUnit(app, + cheapest_target_fps, + cheapest_num_frozen)) + + ## In order of app id, chooses the model with minimum metric + ## and fit the budget + for unit in current_schedule: + cur_target_fps = unit.target_fps + cur_num_frozen = unit.num_frozen + app_id = unit.app_id + app = unit.app + cur_metric = self.get_metric(app, + cur_num_frozen, + cur_target_fps) + current_sched_cost = scheduler_util.get_cost_schedule(current_schedule, + self.model.layer_latencies, + self.model.final_layer) + max_benefit = 0 + best_new_unit = -1 + for potential_target_fps in target_fps_options: + for potential_num_frozen in num_frozen_options: + potential_metric = self.get_metric(app, + potential_num_frozen, + potential_target_fps) + cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] + benefit = cost_benefit_tup[0] + if potential_metric < cur_metric and benefit > max_benefit: + potential_unit = Schedule.ScheduleUnit(app, + potential_target_fps, + potential_num_frozen) + potential_schedule = [] + for c_unit in current_schedule: + if c_unit.app_id == potential_unit.app_id: + potential_schedule.append(potential_unit) + else: + copy_unit = Schedule.ScheduleUnit(c_unit.app, + c_unit.target_fps, + c_unit.num_frozen) + potential_schedule.append(copy_unit) + potential_sched_cost = scheduler_util.get_cost_schedule(potential_schedule, + self.model.layer_latencies, + self.model.final_layer) + + if potential_sched_cost - current_sched_cost <= costs[app_id]: + max_benefit = benefit + best_new_unit = potential_unit + best_new_schedule = potential_schedule + + if best_new_unit != -1: + current_schedule = best_new_schedule + + metrics = self.set_schedule_values_metric(current_schedule) + return metrics + + def make_streamer_schedule_no_sharing(self): s = Schedule.StreamerSchedule() diff --git a/src/scheduler/run_scheduler_simulator.py b/src/scheduler/run_scheduler_simulator.py index f6ef067..b979356 100644 --- a/src/scheduler/run_scheduler_simulator.py +++ b/src/scheduler/run_scheduler_simulator.py @@ -15,11 +15,15 @@ parser.add_argument("x_vote", type=int, default=0) parser.add_argument("outfile_prefix") parser.add_argument("-m", "--metric", default="f1") + # 0 if no fairness, otherwise uses fairness + parser.add_argument("-f", "--fairness", type=int, default='0') + args = parser.parse_args() num_apps_range = args.num_apps_range x_vote = args.x_vote outfile_prefix = args.outfile_prefix min_metric = args.metric + fairness = args.fairness if x_vote > 0: outfile = outfile_prefix + "-x" + str(x_vote) + "-mainstream-simulator" @@ -44,9 +48,15 @@ s = Scheduler.Scheduler(min_metric, apps, app_data.video_desc, app_data.model_desc, 0) - metric = s.optimize_parameters(350) - rel_accs = s.get_relative_accuracies() - avg_rel_acc = np.average(rel_accs) + if fairness > 0: + metrics = s.optimize_per_app(350) + rel_accs = s.get_relative_accuracies() + avg_rel_acc = np.average(rel_accs) + + else: + metric = s.optimize_parameters(350) + rel_accs = s.get_relative_accuracies() + avg_rel_acc = np.average(rel_accs) # Get streamer schedule sched = s.make_streamer_schedule() @@ -54,7 +64,10 @@ # Use target_fps_str in simulator to avoid running on the hardware fnr, fpr, cost = s.get_observed_performance(sched, s.target_fps_list) - print "Metric:", metric, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list + if fairness: + print "Metrics:", metrics, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list + else: + print "Metric:", metric, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list print "FNR:", fnr, ", FPR:", fpr num_frozen_str = ",".join([str(x) for x in s.num_frozen_list]) diff --git a/src/scheduler/scheduler_util.py b/src/scheduler/scheduler_util.py index 131533d..b526a64 100644 --- a/src/scheduler/scheduler_util.py +++ b/src/scheduler/scheduler_util.py @@ -55,10 +55,18 @@ def get_cost_schedule(schedule, layer_latencies, num_layers): return cost +def get_cost_per_app(apps, cost_threshold): + # Gets cost per app with fairness + costs = {} + cost = cost_threshold // len(apps) + for app in apps: + costs[app["app_id"]] = cost + return costs + def get_acc_dist(accuracy, sigma): # Make a distribution of accuracies, centered around accuracy value # Represents different accuracies for difference instances of events. - # E.g. a train classifier has 70% accuracy. But for trains at night, + # E.g. a train classifier has 70% accuracy. But for trains at night, # it's 60% accurate, and in the daytime 80% accurate num_events = 10000 acc_dist = [random.gauss(accuracy, sigma) for i in range(num_events)] diff --git a/src/scheduler/tags b/src/scheduler/tags new file mode 100644 index 0000000..54ad5dc --- /dev/null +++ b/src/scheduler/tags @@ -0,0 +1,32 @@ +!_TAG_FILE_SORTED 2 /0=unsorted, 1=sorted, 2=foldcase/ +app /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ app = dict(app_data.app_options[index])$/;" v language:Python +apps /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ apps = []$/;" v language:Python +app_data /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^import app_data_mobilenets as app_data$/;" i language:Python +argparse /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^import argparse$/;" i language:Python +args /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ args = parser.parse_args()$/;" v language:Python +avg_rel_acc /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ avg_rel_acc = np.average(rel_accs)$/;" v language:Python +avg_rel_acc /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ avg_rel_acc = np.average(rel_accs)$/;" v language:Python +fairness /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ fairness = args.fairness$/;" v language:Python +index /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ index = i % len(app_data.app_options)$/;" v language:Python +line /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ num_frozen_str + "," + target_fps_str + "\\n"$/;" v language:Python +metric /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ metric = s.optimize_parameters(350)$/;" v language:Python +metrics /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ metrics = s.optimize_per_app(350)$/;" v language:Python +min_metric /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ min_metric = args.metric$/;" v language:Python +np /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^import numpy as np$/;" i language:Python +num_apps_range /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ num_apps_range = args.num_apps_range$/;" v language:Python +num_frozen_str /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ num_frozen_str = ",".join([str(x) for x in s.num_frozen_list])$/;" v language:Python +outfile /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ outfile = outfile_prefix + "-mainstream-simulator"$/;" v language:Python +outfile /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ outfile = outfile_prefix + "-x" + str(x_vote) + "-mainstream-simulator"$/;" v language:Python +outfile_prefix /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ outfile_prefix = args.outfile_prefix$/;" v language:Python +parser /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ parser = argparse.ArgumentParser()$/;" v language:Python +pp /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^import pprint as pp$/;" i language:Python +rel_accs /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ rel_accs = s.get_relative_accuracies()$/;" v language:Python +rel_accs /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ rel_accs = s.get_relative_accuracies()$/;" v language:Python +s /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ s = Scheduler.Scheduler(min_metric, apps, app_data.video_desc,$/;" v language:Python +sched /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ sched = s.make_streamer_schedule()$/;" v language:Python +Scheduler /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^import Scheduler$/;" i language:Python +sys /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^import sys$/;" i language:Python +target_fps_str /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ target_fps_str = ",".join([str(x) for x in s.target_fps_list])$/;" v language:Python +time /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^import time$/;" i language:Python +x_vote /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^ x_vote = args.x_vote$/;" v language:Python +zmq /afs/andrew.cmu.edu/usr17/liliat/private/mainstream/src/scheduler/run_scheduler_simulator.py /^import zmq$/;" i language:Python From ebafe9c9541eea9427bafd7361a701d4d4d233d0 Mon Sep 17 00:00:00 2001 From: Lilia Tang Date: Sat, 3 Feb 2018 00:56:12 -0500 Subject: [PATCH 06/18] fixed search space and cost counting bugs, incorporated improved output in simulator --- src/scheduler/Scheduler.py | 140 ++++++++++++----------- src/scheduler/run_scheduler_simulator.py | 2 +- src/scheduler/scheduler_util.py | 31 ++++- 3 files changed, 105 insertions(+), 68 deletions(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index 3877e28..51b2c08 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -328,20 +328,15 @@ def optimize_parameters(self, cost_threshold): def optimize_per_app(self, cost_threshold): # Optimizes by giving equal cost to each app - possible_params = [] - target_fps_options = range(1, self.stream_fps + 1) - for num_frozen in sorted(self.apps[0]["accuracies"]): - for target_fps in target_fps_options: - possible_params.append((num_frozen, target_fps)) - - schedules = [] - app_ids = [app["app_id"] for app in self.apps] - costs = scheduler_util.get_cost_per_app(self.apps, cost_threshold) + costs = scheduler_util.get_alloc_cost_per_app(self.apps, cost_threshold) + #print "Cost allocated: ", costs current_schedule = [] + target_fps_options = range(1, self.stream_fps + 1) cost_benefits = {} - for app_id in app_ids: + for app in self.apps: + app_id = app["app_id"] cost_benefits[app_id] = {} num_frozen_options = sorted(app["accuracies"].keys()) for num_frozen in reversed(num_frozen_options): @@ -363,64 +358,79 @@ def optimize_per_app(self, cost_threshold): ## In order of app id, chooses the model with minimum metric ## and fit the budget - for unit in current_schedule: - cur_target_fps = unit.target_fps - cur_num_frozen = unit.num_frozen - app_id = unit.app_id - app = unit.app - cur_metric = self.get_metric(app, - cur_num_frozen, - cur_target_fps) - current_sched_cost = scheduler_util.get_cost_schedule(current_schedule, - self.model.layer_latencies, - self.model.final_layer) + + updated = True + while (updated): + updated = False max_benefit = 0 best_new_unit = -1 - for potential_target_fps in target_fps_options: - for potential_num_frozen in num_frozen_options: - potential_metric = self.get_metric(app, - potential_num_frozen, - potential_target_fps) - cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] - benefit = cost_benefit_tup[0] - if potential_metric < cur_metric and benefit > max_benefit: - potential_unit = Schedule.ScheduleUnit(app, - potential_target_fps, - potential_num_frozen) - potential_schedule = [] - for c_unit in current_schedule: - if c_unit.app_id == potential_unit.app_id: - potential_schedule.append(potential_unit) - else: - copy_unit = Schedule.ScheduleUnit(c_unit.app, - c_unit.target_fps, - c_unit.num_frozen) - potential_schedule.append(copy_unit) - potential_sched_cost = scheduler_util.get_cost_schedule(potential_schedule, - self.model.layer_latencies, - self.model.final_layer) - - if potential_sched_cost - current_sched_cost <= costs[app_id]: - max_benefit = benefit - best_new_unit = potential_unit - best_new_schedule = potential_schedule - - if best_new_unit != -1: - current_schedule = best_new_schedule - - metrics = self.set_schedule_values_metric(current_schedule) - return metrics - - - def make_streamer_schedule_no_sharing(self): - - s = Schedule.StreamerSchedule() + for unit in current_schedule: + cur_target_fps = unit.target_fps + cur_num_frozen = unit.num_frozen + app_id = unit.app_id + app = unit.app + cur_metric = self.get_metric(app, + cur_num_frozen, + cur_target_fps) + current_sched_cost = scheduler_util.get_cost_schedule(current_schedule, + self.model.layer_latencies, + self.model.final_layer) - for app in self.apps: - num_frozen = min(app["accuracies"].keys()) - net = Schedule.NeuralNet(s.get_id(), - app["app_id"], - self.model, + for potential_target_fps in target_fps_options: + for potential_num_frozen in num_frozen_options: + potential_metric = self.get_metric(app, + potential_num_frozen, + potential_target_fps) + cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] + benefit = cost_benefit_tup[0] + if potential_metric < cur_metric and benefit > max_benefit: + potential_unit = Schedule.ScheduleUnit(app, + potential_target_fps, + potential_num_frozen) + potential_schedule = [] + for c_unit in current_schedule: + if c_unit.app_id == potential_unit.app_id: + potential_schedule.append(potential_unit) + else: + copy_unit = Schedule.ScheduleUnit(c_unit.app, + c_unit.target_fps, + c_unit.num_frozen) + potential_schedule.append(copy_unit) + potential_sched_cost = scheduler_util.get_cost_schedule(potential_schedule, + self.model.layer_latencies, + self.model.final_layer) + + scheduled_cost_app = scheduler_util.get_cost_per_app(self.apps, + potential_schedule, + self.model.layer_latencies, + self.model.final_layer) + + if potential_sched_cost <= cost_threshold and scheduled_cost_app[app_id] <= costs[app_id]: + max_benefit = benefit + best_new_unit = potential_unit + best_new_schedule = potential_schedule + updated = True + + if updated: + current_schedule = best_new_schedule + + final_cost_app = scheduler_util.get_cost_per_app(self.apps, + current_schedule, + self.model.layer_latencies, + self.model.final_layer) + #print "Final Costs: ", final_cost_app + metrics = self.set_schedule_values_metric(current_schedule) + return metrics + + def make_streamer_schedule_no_sharing(self): + + s = Schedule.StreamerSchedule() + + for app in self.apps: + num_frozen = min(app["accuracies"].keys()) + net = Schedule.NeuralNet(s.get_id(), + app["app_id"], + self.model, -1, 1, self.model.final_layer, diff --git a/src/scheduler/run_scheduler_simulator.py b/src/scheduler/run_scheduler_simulator.py index b979356..ca7499d 100644 --- a/src/scheduler/run_scheduler_simulator.py +++ b/src/scheduler/run_scheduler_simulator.py @@ -65,7 +65,7 @@ fnr, fpr, cost = s.get_observed_performance(sched, s.target_fps_list) if fairness: - print "Metrics:", metrics, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list + print "Metrics:", metrics, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list, ", Cost:", cost else: print "Metric:", metric, ", Frozen:", s.num_frozen_list, ", FPS:", s.target_fps_list print "FNR:", fnr, ", FPR:", fpr diff --git a/src/scheduler/scheduler_util.py b/src/scheduler/scheduler_util.py index b526a64..492b849 100644 --- a/src/scheduler/scheduler_util.py +++ b/src/scheduler/scheduler_util.py @@ -55,14 +55,41 @@ def get_cost_schedule(schedule, layer_latencies, num_layers): return cost -def get_cost_per_app(apps, cost_threshold): - # Gets cost per app with fairness +def get_alloc_cost_per_app(apps, cost_threshold): + # Gets cost allocated per app with fairness costs = {} cost = cost_threshold // len(apps) for app in apps: costs[app["app_id"]] = cost return costs +def get_cost_per_app(apps, schedule, layer_latencies, num_layers): + # Gets cost of each app with stems weighted by the number of apps that stem + # from it + branch_points = list(set([unit.num_frozen for unit in schedule])) + branch_points.append(num_layers) + seg_start = 0 + costs = {} + for app in apps: + costs[app["app_id"]] = 0 + for seg_end in branch_points: + seg_latency = sum([layer_latencies[i] for i in range(seg_start, seg_end)]) + + apps_branched, apps_not_branched = get_apps_branched(schedule, seg_end) + seg_fps = 0 + branched_fpses = [unit.target_fps for unit in apps_branched] + not_branched_fpses = [unit.target_fps for unit in apps_not_branched] + for app in apps_branched: + task_fps = sum(branched_fpses) + costs[app.app_id] += task_fps * seg_latency + for app in apps_not_branched: + base_fps = max(not_branched_fpses) + costs[app.app_id] += (base_fps * seg_latency) // (len(apps_not_branched)) + + seg_start = seg_end + + return costs + def get_acc_dist(accuracy, sigma): # Make a distribution of accuracies, centered around accuracy value # Represents different accuracies for difference instances of events. From 80e91527b1bcd632cf73fb3beb8d32f9fdf7c156 Mon Sep 17 00:00:00 2001 From: Lilia Tang Date: Sat, 3 Feb 2018 12:45:37 -0500 Subject: [PATCH 07/18] fixed cost per app bug and optimizer --- src/scheduler/Scheduler.py | 18 ++++++++++++++---- src/scheduler/run_scheduler_simulator.py | 2 +- src/scheduler/scheduler_util.py | 7 ++++--- 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index 51b2c08..ed5639e 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -6,7 +6,7 @@ import operator import pprint as pp import zmq - +from random import shuffle class Scheduler: ### Object that performs optimization of parameters @@ -329,7 +329,7 @@ def optimize_parameters(self, cost_threshold): def optimize_per_app(self, cost_threshold): # Optimizes by giving equal cost to each app costs = scheduler_util.get_alloc_cost_per_app(self.apps, cost_threshold) - #print "Cost allocated: ", costs + print "Cost allocated: ", costs current_schedule = [] target_fps_options = range(1, self.stream_fps + 1) @@ -365,6 +365,7 @@ def optimize_per_app(self, cost_threshold): max_benefit = 0 best_new_unit = -1 for unit in current_schedule: + #print unit cur_target_fps = unit.target_fps cur_num_frozen = unit.num_frozen app_id = unit.app_id @@ -376,6 +377,10 @@ def optimize_per_app(self, cost_threshold): self.model.layer_latencies, self.model.final_layer) + #print target_fps_options + #shuffle(target_fps_options) + #shuffle(num_frozen_options) + #print target_fps_options for potential_target_fps in target_fps_options: for potential_num_frozen in num_frozen_options: potential_metric = self.get_metric(app, @@ -383,7 +388,9 @@ def optimize_per_app(self, cost_threshold): potential_target_fps) cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] benefit = cost_benefit_tup[0] - if potential_metric < cur_metric and benefit > max_benefit: + #print "num_frozen: ", potential_num_frozen, ", target_fps: ", potential_target_fps, ", benefit: ", benefit,\ + # "metric: ", potential_metric + if potential_metric < cur_metric: potential_unit = Schedule.ScheduleUnit(app, potential_target_fps, potential_num_frozen) @@ -410,6 +417,9 @@ def optimize_per_app(self, cost_threshold): best_new_unit = potential_unit best_new_schedule = potential_schedule updated = True + #cur_metric = self.get_metric(app, + # cur_num_frozen, + # cur_target_fps) if updated: current_schedule = best_new_schedule @@ -418,7 +428,7 @@ def optimize_per_app(self, cost_threshold): current_schedule, self.model.layer_latencies, self.model.final_layer) - #print "Final Costs: ", final_cost_app + print "Final Costs: ", final_cost_app metrics = self.set_schedule_values_metric(current_schedule) return metrics diff --git a/src/scheduler/run_scheduler_simulator.py b/src/scheduler/run_scheduler_simulator.py index ca7499d..ab288fd 100644 --- a/src/scheduler/run_scheduler_simulator.py +++ b/src/scheduler/run_scheduler_simulator.py @@ -49,7 +49,7 @@ app_data.model_desc, 0) if fairness > 0: - metrics = s.optimize_per_app(350) + metrics = s.optimize_per_app(200) rel_accs = s.get_relative_accuracies() avg_rel_acc = np.average(rel_accs) diff --git a/src/scheduler/scheduler_util.py b/src/scheduler/scheduler_util.py index 492b849..eca5704 100644 --- a/src/scheduler/scheduler_util.py +++ b/src/scheduler/scheduler_util.py @@ -77,14 +77,15 @@ def get_cost_per_app(apps, schedule, layer_latencies, num_layers): apps_branched, apps_not_branched = get_apps_branched(schedule, seg_end) seg_fps = 0 - branched_fpses = [unit.target_fps for unit in apps_branched] not_branched_fpses = [unit.target_fps for unit in apps_not_branched] + idx = 0 for app in apps_branched: - task_fps = sum(branched_fpses) + task_fps = apps_branched[idx].target_fps + idx += 1 costs[app.app_id] += task_fps * seg_latency for app in apps_not_branched: base_fps = max(not_branched_fpses) - costs[app.app_id] += (base_fps * seg_latency) // (len(apps_not_branched)) + costs[app.app_id] += ((base_fps * seg_latency / len(apps_not_branched))) seg_start = seg_end From 282e2044ec08fdb9073f8fccf70ba345fc8a0f21 Mon Sep 17 00:00:00 2001 From: Lilia Tang Date: Sat, 3 Feb 2018 15:08:04 -0500 Subject: [PATCH 08/18] removed comments --- src/scheduler/Scheduler.py | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index ed5639e..f49e819 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -329,7 +329,7 @@ def optimize_parameters(self, cost_threshold): def optimize_per_app(self, cost_threshold): # Optimizes by giving equal cost to each app costs = scheduler_util.get_alloc_cost_per_app(self.apps, cost_threshold) - print "Cost allocated: ", costs + #print "Cost allocated: ", costs current_schedule = [] target_fps_options = range(1, self.stream_fps + 1) @@ -365,7 +365,6 @@ def optimize_per_app(self, cost_threshold): max_benefit = 0 best_new_unit = -1 for unit in current_schedule: - #print unit cur_target_fps = unit.target_fps cur_num_frozen = unit.num_frozen app_id = unit.app_id @@ -377,10 +376,6 @@ def optimize_per_app(self, cost_threshold): self.model.layer_latencies, self.model.final_layer) - #print target_fps_options - #shuffle(target_fps_options) - #shuffle(num_frozen_options) - #print target_fps_options for potential_target_fps in target_fps_options: for potential_num_frozen in num_frozen_options: potential_metric = self.get_metric(app, @@ -388,8 +383,6 @@ def optimize_per_app(self, cost_threshold): potential_target_fps) cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] benefit = cost_benefit_tup[0] - #print "num_frozen: ", potential_num_frozen, ", target_fps: ", potential_target_fps, ", benefit: ", benefit,\ - # "metric: ", potential_metric if potential_metric < cur_metric: potential_unit = Schedule.ScheduleUnit(app, potential_target_fps, @@ -417,9 +410,6 @@ def optimize_per_app(self, cost_threshold): best_new_unit = potential_unit best_new_schedule = potential_schedule updated = True - #cur_metric = self.get_metric(app, - # cur_num_frozen, - # cur_target_fps) if updated: current_schedule = best_new_schedule @@ -428,7 +418,7 @@ def optimize_per_app(self, cost_threshold): current_schedule, self.model.layer_latencies, self.model.final_layer) - print "Final Costs: ", final_cost_app + #print "Final Costs: ", final_cost_app metrics = self.set_schedule_values_metric(current_schedule) return metrics From 32ad4e76e89709d8bed8a81cf90a3b0f1a0f32a9 Mon Sep 17 00:00:00 2001 From: Lilia Tang Date: Sat, 3 Feb 2018 23:31:42 -0500 Subject: [PATCH 09/18] updated schedule simulator to write csv needed for graphing --- src/scheduler/Scheduler.py | 6 +- src/scheduler/run_scheduler_sim_fair.py | 77 +++++++++++++++++++++++++ 2 files changed, 80 insertions(+), 3 deletions(-) create mode 100644 src/scheduler/run_scheduler_sim_fair.py diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index f49e819..4f9e689 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -16,6 +16,7 @@ def __init__(self, metric, apps, video_desc, model_desc, sigma): self.apps = apps self.video_desc = video_desc self.metric = metric + self.metrics = [] self.model = Schedule.Model(model_desc) self.num_frozen_list = [] self.target_fps_list = [] @@ -323,7 +324,6 @@ def optimize_parameters(self, cost_threshold): current_schedule = best_new_schedule average_metric = self.set_schedule_values(current_schedule) - return average_metric def optimize_per_app(self, cost_threshold): @@ -419,8 +419,8 @@ def optimize_per_app(self, cost_threshold): self.model.layer_latencies, self.model.final_layer) #print "Final Costs: ", final_cost_app - metrics = self.set_schedule_values_metric(current_schedule) - return metrics + self.metrics = self.set_schedule_values_metric(current_schedule) + return self.metrics def make_streamer_schedule_no_sharing(self): diff --git a/src/scheduler/run_scheduler_sim_fair.py b/src/scheduler/run_scheduler_sim_fair.py new file mode 100644 index 0000000..968fe3e --- /dev/null +++ b/src/scheduler/run_scheduler_sim_fair.py @@ -0,0 +1,77 @@ +import sys +sys.path.append('src/scheduler') +import Scheduler +sys.path.append('data') +import app_data_mobilenets as app_data +import pprint as pp +import numpy as np +import time +import zmq +from itertools import combinations, combinations_with_replacement +import click +import os +import csv +import random +import argparse + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument('num_apps_range', type=int) + parser.add_argument('x_vote', type=int, default=0) + parser.add_argument('outfile') + parser.add_argument('--agg', default='mean', help='agg (mean, min)') + parser.add_argument('-m', '--metric', default='f1') + parser.add_argument('-f', '--fairness', type=int, default='0') + + args = parser.parse_args() + num_apps_range = args.num_apps_range + x_vote = args.x_vote + outfile = args.outfile + min_metric = args.metric + fairness = args.fairness + agg = args.agg + + if agg == 'min': + agg_func = np.min + else: + agg_func = np.average + print agg, agg_func + + if os.path.isfile(outfile): + with open(outfile) as f: + reader = csv.reader(row for row in f if not row.startswith('#')) + + with open(outfile, "wb", 0) as f: + for num_apps in range(len(app_data.app_options), \ + num_apps_range+1, \ + len(app_data.app_options)): + # Get Schedule + apps = [] + + for i in range(1, num_apps + 1): + index = i % len(app_data.app_options) + app = dict(app_data.app_options[index]) + app["app_id"] = i + app["x_vote"] = x_vote + apps.append(app) + + s = Scheduler.Scheduler(min_metric, apps, app_data.video_desc, + app_data.model_desc, 0) + + metrics = s.optimize_per_app(350) + avg_metric = sum(metrics) / len(metrics) + rel_accs = s.get_relative_accuracies() + avg_rel_acc = agg_func(rel_accs) + print 'Rel accs: ', rel_accs + print 'FNRs:', s.metrics + print "Agg: {}, Num Apps: {}, FNR: {}, Avg Rel Acc: {}, Frozen: {}, FPS: {}".format(agg, num_apps, avg_metric, avg_rel_acc, s.num_frozen_list, s.target_fps_list) + + row = [ + str(num_apps), + str(round(avg_metric, 4)), + str(round(avg_rel_acc, 4)), + "_".join(map(str, s.metrics)), + "_".join(map(str, rel_accs)), + ] + line = ",".join(row) + "\n" + f.write(line) From 1fa1530e08e24b49f00681a362b3db02ca3ce77d Mon Sep 17 00:00:00 2001 From: Daniel Wong Date: Sun, 4 Feb 2018 03:05:59 -0500 Subject: [PATCH 10/18] Add run_fairness.sh + minor changes --- src/scheduler/run_scheduler_sim_fair.py | 8 ++------ src/scheduler/run_scheduler_simulator.py | 2 +- src/scripts/run_fairness.sh | 9 +++++++++ 3 files changed, 12 insertions(+), 7 deletions(-) create mode 100644 src/scripts/run_fairness.sh diff --git a/src/scheduler/run_scheduler_sim_fair.py b/src/scheduler/run_scheduler_sim_fair.py index 968fe3e..b2fe70d 100644 --- a/src/scheduler/run_scheduler_sim_fair.py +++ b/src/scheduler/run_scheduler_sim_fair.py @@ -21,12 +21,12 @@ parser.add_argument('outfile') parser.add_argument('--agg', default='mean', help='agg (mean, min)') parser.add_argument('-m', '--metric', default='f1') - parser.add_argument('-f', '--fairness', type=int, default='0') + parser.add_argument('-f', '--fairness', action='store_true') args = parser.parse_args() num_apps_range = args.num_apps_range x_vote = args.x_vote - outfile = args.outfile + outfile = args.outfile + '-mainstream-simulator' min_metric = args.metric fairness = args.fairness agg = args.agg @@ -37,10 +37,6 @@ agg_func = np.average print agg, agg_func - if os.path.isfile(outfile): - with open(outfile) as f: - reader = csv.reader(row for row in f if not row.startswith('#')) - with open(outfile, "wb", 0) as f: for num_apps in range(len(app_data.app_options), \ num_apps_range+1, \ diff --git a/src/scheduler/run_scheduler_simulator.py b/src/scheduler/run_scheduler_simulator.py index fe6393c..1d53f42 100644 --- a/src/scheduler/run_scheduler_simulator.py +++ b/src/scheduler/run_scheduler_simulator.py @@ -24,7 +24,7 @@ def get_args(simulator=True): app_names = [app["name"] for app in app_data.app_options] parser.add_argument("-d", "--datasets", nargs='+', choices=app_names, required=True, help='provide one or multiple dataset names') parser.add_argument("-m", "--metric", default="f1") - parser.add_argument("-f", "--fairness", type=int, default='0') + parser.add_argument("-f", "--fairness", action='store_true') parser.add_argument("-x", "--x-vote", type=int, default=0) # For combinations parser.add_argument("-c", "--combs", action='store_true') diff --git a/src/scripts/run_fairness.sh b/src/scripts/run_fairness.sh new file mode 100644 index 0000000..104b5ec --- /dev/null +++ b/src/scripts/run_fairness.sh @@ -0,0 +1,9 @@ +#!/bin/bash +MAX_NUM_APPS=30 +METRIC=f1 +python src/scheduler/run_scheduler_sim_fair.py \ + $MAX_NUM_APPS \ + 0 \ + ../mainstream-analysis/output/streamer/scheduler/atc/$METRIC/$METRIC-fairness \ + --metric $METRIC \ + --fairness From f3e2f91c48086942012c6f3e5ba9af4d455b28ce Mon Sep 17 00:00:00 2001 From: Angela Jiang Date: Sun, 4 Feb 2018 13:30:55 -0500 Subject: [PATCH 11/18] Use regular cost --- src/scheduler/Scheduler.py | 15 ++++++++------- src/scheduler/run_scheduler_simulator.py | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index 5b8b15c..199d489 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -382,7 +382,8 @@ def optimize_per_app(self, cost_threshold): potential_num_frozen, potential_target_fps) cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] - benefit = cost_benefit_tup[0] + #benefit = cost_benefit_tup[0] + benefit = cost_benefit_tup[1] if potential_metric < cur_metric: potential_unit = Schedule.ScheduleUnit(app, potential_target_fps, @@ -397,13 +398,13 @@ def optimize_per_app(self, cost_threshold): c_unit.num_frozen) potential_schedule.append(copy_unit) potential_sched_cost = scheduler_util.get_cost_schedule(potential_schedule, - self.model.layer_latencies, - self.model.final_layer) + self.model.layer_latencies, + self.model.final_layer) scheduled_cost_app = scheduler_util.get_cost_per_app(self.apps, - potential_schedule, - self.model.layer_latencies, - self.model.final_layer) + potential_schedule, + self.model.layer_latencies, + self.model.final_layer) if potential_sched_cost <= cost_threshold and scheduled_cost_app[app_id] <= costs[app_id]: max_benefit = benefit @@ -418,7 +419,7 @@ def optimize_per_app(self, cost_threshold): current_schedule, self.model.layer_latencies, self.model.final_layer) - #print "Final Costs: ", final_cost_app + print "Final Costs: ", final_cost_app self.metrics = self.set_schedule_values_metric(current_schedule) return self.metrics diff --git a/src/scheduler/run_scheduler_simulator.py b/src/scheduler/run_scheduler_simulator.py index fe6393c..8fb20b3 100644 --- a/src/scheduler/run_scheduler_simulator.py +++ b/src/scheduler/run_scheduler_simulator.py @@ -125,7 +125,7 @@ def run_simulator(min_metric, apps, fairness=None): stats = {} if fairness: - stats["metric"] = s.optimize_parameters(200) + stats["metric"] = s.optimize_parameters(350) else: stats["metric"] = s.optimize_parameters(350) stats["rel_accs"] = s.get_relative_accuracies() From 2a36d8302636ff8bec780824a5e9bb1149b9f7f9 Mon Sep 17 00:00:00 2001 From: Daniel Wong Date: Sun, 4 Feb 2018 17:37:30 -0500 Subject: [PATCH 12/18] Bugfix: Reenable fairness in run_scheduler_simulator --- src/scheduler/run_scheduler_simulator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scheduler/run_scheduler_simulator.py b/src/scheduler/run_scheduler_simulator.py index ae9861f..c0fb92d 100644 --- a/src/scheduler/run_scheduler_simulator.py +++ b/src/scheduler/run_scheduler_simulator.py @@ -125,7 +125,7 @@ def run_simulator(min_metric, apps, fairness=None): stats = {} if fairness: - stats["metric"] = s.optimize_parameters(350) + stats["metric"] = s.optimize_per_app(350) else: stats["metric"] = s.optimize_parameters(350) stats["rel_accs"] = s.get_relative_accuracies() From 4b387d8f52b38c8061d3d87dbc9338b4f9e5e48a Mon Sep 17 00:00:00 2001 From: Daniel Wong Date: Sun, 4 Feb 2018 17:40:59 -0500 Subject: [PATCH 13/18] Fix datasets for fairness to 4hybrid --- src/scripts/run_fairness.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/scripts/run_fairness.sh b/src/scripts/run_fairness.sh index 104b5ec..f56e117 100644 --- a/src/scripts/run_fairness.sh +++ b/src/scripts/run_fairness.sh @@ -1,9 +1,13 @@ #!/bin/bash +# Run fairness for F1-score MAX_NUM_APPS=30 METRIC=f1 -python src/scheduler/run_scheduler_sim_fair.py \ +OUTFILE_PREFIX=../mainstream-analysis/output/streamer/scheduler/atc/$METRIC/$METRIC-fairness-4hybrid +# Archive old file +mv $OUTFILE_PREFIX-mainstream-simulator $OUTFILE_PREFIX-mainstream-simulator-`date +%Y%m%d-%H%M` +python src/scheduler/run_scheduler_simulator.py \ $MAX_NUM_APPS \ - 0 \ - ../mainstream-analysis/output/streamer/scheduler/atc/$METRIC/$METRIC-fairness \ + $OUTFILE_PREFIX \ --metric $METRIC \ + --datasets pedestrian cars flowers cats \ --fairness From d043207c798f79ee005f258f79bc5cc33996c544 Mon Sep 17 00:00:00 2001 From: Angela Jiang Date: Sun, 4 Feb 2018 18:01:55 -0500 Subject: [PATCH 14/18] Remove click --- src/scheduler/run_scheduler_sim_fair.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/scheduler/run_scheduler_sim_fair.py b/src/scheduler/run_scheduler_sim_fair.py index b2fe70d..c180fc5 100644 --- a/src/scheduler/run_scheduler_sim_fair.py +++ b/src/scheduler/run_scheduler_sim_fair.py @@ -8,7 +8,6 @@ import time import zmq from itertools import combinations, combinations_with_replacement -import click import os import csv import random From b53f0cd14500dac835b952cc82fe71dedd5d2653 Mon Sep 17 00:00:00 2001 From: Daniel Wong Date: Sun, 4 Feb 2018 18:06:15 -0500 Subject: [PATCH 15/18] Set max apps to 32 for fairness --- src/scripts/run_fairness.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scripts/run_fairness.sh b/src/scripts/run_fairness.sh index f56e117..2395a3d 100644 --- a/src/scripts/run_fairness.sh +++ b/src/scripts/run_fairness.sh @@ -1,6 +1,6 @@ #!/bin/bash # Run fairness for F1-score -MAX_NUM_APPS=30 +MAX_NUM_APPS=32 METRIC=f1 OUTFILE_PREFIX=../mainstream-analysis/output/streamer/scheduler/atc/$METRIC/$METRIC-fairness-4hybrid # Archive old file From 50ea8cf269adea4a68d29d24e274c209f2c95b41 Mon Sep 17 00:00:00 2001 From: Angela Jiang Date: Sun, 4 Feb 2018 18:39:22 -0500 Subject: [PATCH 16/18] Fair scheduler with single metric return val --- src/scheduler/Scheduler.py | 114 +++++++++++++----------- src/scheduler/run_scheduler_sim_fair.py | 2 +- 2 files changed, 64 insertions(+), 52 deletions(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index 199d489..f7adbf7 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -327,19 +327,27 @@ def optimize_parameters(self, cost_threshold): return average_metric def optimize_per_app(self, cost_threshold): - # Optimizes by giving equal cost to each app - costs = scheduler_util.get_alloc_cost_per_app(self.apps, cost_threshold) - #print "Cost allocated: ", costs - current_schedule = [] + # Makes schedule with optimal choices for num_frozen and target_fps + # Sets self.schedule, self.num_frozen_list, self.target_fps_list + + ## Calculate all possible schedules + possible_params = [] target_fps_options = range(1, self.stream_fps + 1) + for num_frozen in sorted(self.apps[0]["accuracies"].keys()): + for target_fps in target_fps_options: + possible_params.append((num_frozen, target_fps)) cost_benefits = {} + current_schedule = [] + + app_budget = cost_threshold / len(self.apps) + for app in self.apps: app_id = app["app_id"] cost_benefits[app_id] = {} - num_frozen_options = sorted(app["accuracies"].keys()) - for num_frozen in reversed(num_frozen_options): + num_frozen_options = app["accuracies"].keys() + for num_frozen in reversed(sorted(num_frozen_options)): if num_frozen not in cost_benefits[app_id].keys(): cost_benefits[app_id][num_frozen] = {} for target_fps in target_fps_options: @@ -349,20 +357,23 @@ def optimize_per_app(self, cost_threshold): cost = scheduler_util.get_cost(num_frozen, target_fps, self.model.layer_latencies) - cost_benefits[app_id][num_frozen][target_fps] = (cost, benefit) + cost_benefits[app_id][num_frozen][target_fps] = (cost, + benefit) cheapest_target_fps = min(target_fps_options) cheapest_num_frozen = max(num_frozen_options) current_schedule.append(Schedule.ScheduleUnit(app, cheapest_target_fps, cheapest_num_frozen)) - ## In order of app id, chooses the model with minimum metric - ## and fit the budget - - updated = True + ## Make moves in order of maximal cost/benefit + ## which decrease the metric and fit the budget + updated = True # Stopping condition while (updated): updated = False - max_benefit = 0 + # Get next best change to schedule + # Upgrade is (target_fps, #frozen) with larger + # cost and largest cost/benefit across all apps + max_cost_benefit = 0 best_new_unit = -1 for unit in current_schedule: cur_target_fps = unit.target_fps @@ -372,56 +383,57 @@ def optimize_per_app(self, cost_threshold): cur_metric = self.get_metric(app, cur_num_frozen, cur_target_fps) - current_sched_cost = scheduler_util.get_cost_schedule(current_schedule, - self.model.layer_latencies, - self.model.final_layer) for potential_target_fps in target_fps_options: - for potential_num_frozen in num_frozen_options: + for potential_num_frozen in sorted(num_frozen_options): + # Skip if it is not a change + u_apps = [u for u in current_schedule if u.app_id == app_id] + if (u_apps[0].num_frozen == potential_num_frozen and + u_apps[0].target_fps == potential_target_fps): + continue + + cost_benefit_tup = \ + cost_benefits[app_id][potential_num_frozen][potential_target_fps] + cost_benefit = cost_benefit_tup[1] / float(cost_benefit_tup[0]) potential_metric = self.get_metric(app, potential_num_frozen, potential_target_fps) - cost_benefit_tup = cost_benefits[app_id][potential_num_frozen][potential_target_fps] - #benefit = cost_benefit_tup[0] - benefit = cost_benefit_tup[1] - if potential_metric < cur_metric: - potential_unit = Schedule.ScheduleUnit(app, - potential_target_fps, - potential_num_frozen) - potential_schedule = [] - for c_unit in current_schedule: - if c_unit.app_id == potential_unit.app_id: - potential_schedule.append(potential_unit) - else: - copy_unit = Schedule.ScheduleUnit(c_unit.app, - c_unit.target_fps, - c_unit.num_frozen) - potential_schedule.append(copy_unit) - potential_sched_cost = scheduler_util.get_cost_schedule(potential_schedule, + if potential_metric < cur_metric and cost_benefit > max_cost_benefit: + + # Check that move its within budget + potential_unit = Schedule.ScheduleUnit(app, + potential_target_fps, + potential_num_frozen) + potential_schedule = [] + for c_unit in current_schedule: + if c_unit.app_id == potential_unit.app_id: + potential_schedule.append(potential_unit) + else: + copy_unit = Schedule.ScheduleUnit(c_unit.app, + c_unit.target_fps, + c_unit.num_frozen) + potential_schedule.append(copy_unit) + potential_sched_cost = scheduler_util.get_cost_schedule(potential_schedule, self.model.layer_latencies, self.model.final_layer) - - scheduled_cost_app = scheduler_util.get_cost_per_app(self.apps, + scheduled_cost_app = scheduler_util.get_cost_per_app(self.apps, potential_schedule, self.model.layer_latencies, self.model.final_layer) - if potential_sched_cost <= cost_threshold and scheduled_cost_app[app_id] <= costs[app_id]: - max_benefit = benefit - best_new_unit = potential_unit - best_new_schedule = potential_schedule - updated = True - - if updated: - current_schedule = best_new_schedule - - final_cost_app = scheduler_util.get_cost_per_app(self.apps, - current_schedule, - self.model.layer_latencies, - self.model.final_layer) - print "Final Costs: ", final_cost_app - self.metrics = self.set_schedule_values_metric(current_schedule) - return self.metrics + if potential_sched_cost <= cost_threshold and scheduled_cost_app[app_id] <= app_budget: + #if potential_sched_cost <= cost_threshold: + cost = potential_sched_cost + max_cost_benefit = cost_benefit + best_new_unit = potential_unit + best_new_schedule = potential_schedule + updated = True + + if updated: + current_schedule = best_new_schedule + + average_metric = self.set_schedule_values(current_schedule) + return average_metric def make_streamer_schedule_no_sharing(self): diff --git a/src/scheduler/run_scheduler_sim_fair.py b/src/scheduler/run_scheduler_sim_fair.py index c180fc5..ca10cba 100644 --- a/src/scheduler/run_scheduler_sim_fair.py +++ b/src/scheduler/run_scheduler_sim_fair.py @@ -53,7 +53,7 @@ s = Scheduler.Scheduler(min_metric, apps, app_data.video_desc, app_data.model_desc, 0) - metrics = s.optimize_per_app(350) + metrics = [s.optimize_per_app(350)] avg_metric = sum(metrics) / len(metrics) rel_accs = s.get_relative_accuracies() avg_rel_acc = agg_func(rel_accs) From 14f3392a291a44a90c15823d5cfc9d3f230ded5f Mon Sep 17 00:00:00 2001 From: Daniel Wong Date: Sun, 4 Feb 2018 20:10:13 -0500 Subject: [PATCH 17/18] Fall back to normal Mainstream after fairness is assured --- src/scheduler/Scheduler.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index f7adbf7..6523553 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -368,6 +368,11 @@ def optimize_per_app(self, cost_threshold): ## Make moves in order of maximal cost/benefit ## which decrease the metric and fit the budget updated = True # Stopping condition + + # After each app has been given its opportunity under equal-budget fairness, + # allow other apps to take advantage of remaining budget + ignore_fairness = False + while (updated): updated = False # Get next best change to schedule @@ -416,22 +421,29 @@ def optimize_per_app(self, cost_threshold): potential_sched_cost = scheduler_util.get_cost_schedule(potential_schedule, self.model.layer_latencies, self.model.final_layer) + ##### Fairness modifications##### scheduled_cost_app = scheduler_util.get_cost_per_app(self.apps, potential_schedule, self.model.layer_latencies, self.model.final_layer) - if potential_sched_cost <= cost_threshold and scheduled_cost_app[app_id] <= app_budget: + # TODO: Refactor away duplicated code. + if potential_sched_cost <= cost_threshold and (scheduled_cost_app[app_id] <= app_budget or ignore_fairness): #if potential_sched_cost <= cost_threshold: cost = potential_sched_cost max_cost_benefit = cost_benefit best_new_unit = potential_unit best_new_schedule = potential_schedule updated = True + ##### End Fairness modifications ##### if updated: current_schedule = best_new_schedule + if not updated and not ignore_fairness: + ignore_fairness = True + updated = True + average_metric = self.set_schedule_values(current_schedule) return average_metric From 0bf4508f2f06f37d877da8b85e8c6721f7dbed3a Mon Sep 17 00:00:00 2001 From: Daniel Wong Date: Sun, 4 Feb 2018 20:17:08 -0500 Subject: [PATCH 18/18] More comments for explanation --- src/scheduler/Scheduler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/scheduler/Scheduler.py b/src/scheduler/Scheduler.py index 6523553..8052066 100644 --- a/src/scheduler/Scheduler.py +++ b/src/scheduler/Scheduler.py @@ -370,7 +370,7 @@ def optimize_per_app(self, cost_threshold): updated = True # Stopping condition # After each app has been given its opportunity under equal-budget fairness, - # allow other apps to take advantage of remaining budget + # allow other apps to take advantage of remaining budget by falling back to normal Mainstream ignore_fairness = False while (updated):