My Project
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros
scheduling_decision.c
Go to the documentation of this file.
1 /*
2 START OF LICENSE STUB
3  DeDOS: Declarative Dispersion-Oriented Software
4  Copyright (C) 2017 University of Pennsylvania, Georgetown University
5 
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 END OF LICENSE STUB
19 */
20 #include "controller_dfg.h"
21 #include "stats.h"
22 #include "controller_stats.h"
23 #include "msu_ids.h"
24 #include "logging.h"
25 #include "haproxy.h"
26 #include "scheduling.h"
27 
28 #include <stdbool.h>
29 
30 #define MAX_CLONE_CONDITIONS 2
31 
32 struct cloning_info {
35  double threshold;
36  int n_samples;
37  double stats[MAX_MSU];
38  int num_msus;
39  struct timespec last;
40 };
41 
47  struct timespec last;
48 };
49 
50 #define CLONING_SAMPLES 10
51 static struct clone_decision CLONING_DECISIONS[] = {
58 };
59 
60 #define UNCLONING_SAMPLES 50
67 };
68 
69 
70 #define CLONING_DECISION_LEN sizeof(CLONING_DECISIONS) / sizeof(*CLONING_DECISIONS)
71 #define UNCLONING_DECISION_LEN sizeof(UNCLONING_DECISIONS) / sizeof(*UNCLONING_DECISIONS)
72 
73 static int gather_cloning_info(struct cloning_info *info) {
74 
75  info->num_msus = 0;
76 
77  struct dfg_msu_type *type = get_dfg_msu_type(info->msu_type_id);
78  if (type == NULL) {
79  return 0;
80  }
81 
82  for (int i=0; i<type->n_instances; i++) {
83  struct dfg_msu *instance = type->instances[i];
84  struct timed_rrdb *stat = get_msu_stat(info->stat_id, instance->id);
85 
86  if (stat == NULL) {
87  continue;
88  }
89 
90  info->stats[info->num_msus] = average_n(stat, info->n_samples);
91  if (info->stats[info->num_msus] < 0) {
92  continue;
93  }
94  info->num_msus++;
95  }
96  return 0;
97 }
98 
99 static int gather_cloning_decision(struct clone_decision *decision) {
100  for (int i=0; i < decision->num_conditions; i++) {
101  gather_cloning_info(&decision->conditions[i]);
102  }
103  return 0;
104 }
105 
106 static bool should_clone(struct clone_decision *decision) {
107  for (int i=0; i<decision->num_conditions; i++) {
108  struct cloning_info *info = &decision->conditions[i];
109  double sum = 0;
110  for (int i=0; i<info->num_msus; i++) {
111  sum += info->stats[i];
112  }
113 
114  double mean = sum / info->num_msus;
115  bool do_clone = mean > info->threshold;
116  if (do_clone) {
117  log(LOG_SCHEDULING_DECISIONS, "Trying to clone type %d due to mean: %.2f",
118  info->msu_type_id, mean);
119  return true;
120  }
121  }
122  return false;
123 }
124 
125 static bool should_unclone(struct clone_decision *decision) {
126  struct dfg_msu_type *clone_type = get_dfg_msu_type(decision->clone_type_id);
127  if (clone_type == NULL) {
128  return false;
129  }
130  if (clone_type->n_instances <= decision->min_instances) {
131  return false;
132  }
133  struct cloning_info *info;
134  double max = 0;
135  for (int i=0; i < decision->num_conditions; i++) {
136  info = &decision->conditions[i];
137  if (info->num_msus == 0) {
138  return false;
139  }
140  max = 0;
141  for (int i=0; i<info->num_msus; i++) {
142  if (info->stats[i] > info->threshold) {
143  return false;
144  }
145  max = max > info->stats[i] ? max : info->stats[i];
146  }
147  }
148  log(LOG_SCHEDULING_DECISIONS, "Trying to unclone type %d due to max : %.2f",
149  decision->clone_type_id, max);
150  return true;
151 }
152 
153 #define MIN_CLONE_DURATION_MS 750
154 #define MIN_UNCLONE_DURATION_MS 750
155 
157  struct timespec cur_time;
158  clock_gettime(CLOCK_MONOTONIC, &cur_time);
159  for (int i=0; i<CLONING_DECISION_LEN; i++) {
160  struct clone_decision *decision = &CLONING_DECISIONS[i];
161  if (((cur_time.tv_sec - decision->last.tv_sec) * 1000 ) + ((cur_time.tv_nsec - decision->last.tv_nsec) * 1e-6) > MIN_CLONE_DURATION_MS) {
162  int rtn = gather_cloning_decision(decision);
163  if (rtn < 0) {
164  log_error("Error getting cloning decision %d", i);
165  continue;
166  }
167 
168  if (should_clone(decision)) {
169  decision->last = cur_time;
170  struct dfg_msu_type *clone_type = get_dfg_msu_type(decision->clone_type_id);
171  struct dfg_msu *cloned_msu = clone_type->instances[0];
172  struct dfg_msu *msu = clone_msu(cloned_msu->id);
173  if (msu == NULL) {
174  log_error("Cloning MSU failed for MSU type %d",
175  decision->clone_type_id);
176  continue;
177  }
178  set_haproxy_weights(0,0);
179  }
180  }
181  }
182  return 0;
183 }
184 
186  struct timespec cur_time;
187  clock_gettime(CLOCK_MONOTONIC, &cur_time);
188  for (int i=0; i<UNCLONING_DECISION_LEN; i++) {
189  struct clone_decision *decision = &UNCLONING_DECISIONS[i];
190  if (((cur_time.tv_sec - decision->last.tv_sec) * 1000 ) + ((cur_time.tv_nsec - decision->last.tv_nsec) * 1e-6) > MIN_UNCLONE_DURATION_MS) {
191  int rtn = gather_cloning_decision(decision);
192  if (rtn < 0) {
193  log_error("Error getting cloning info %d", i);
194  continue;
195  }
196  if (should_unclone(decision)) {
197  decision->last = cur_time;
198  struct dfg_msu_type *clone_type = get_dfg_msu_type(decision->clone_type_id);
199  struct dfg_msu *cloned_msu = clone_type->instances[clone_type->n_instances-1];
200  int rtn = unclone_msu(cloned_msu->id);
201  if (rtn < 0) {
202  log(LOG_SCHEDULING, "Uncloning MSU failed for MSU type %d",
203  decision->clone_type_id);
204  continue;
205  }
206  set_haproxy_weights(0,0);
207  }
208  }
209  }
210  return 0;
211 }
212 
213 static bool min_instances_recorded = false;
214 
216  if (!min_instances_recorded) {
217  for (int i=0; i < UNCLONING_DECISION_LEN; i++) {
218  struct dfg_msu_type *clone_type = get_dfg_msu_type(UNCLONING_DECISIONS[i].clone_type_id);
219  if (clone_type != NULL) {
220  UNCLONING_DECISIONS[i].min_instances = clone_type->n_instances;
221  }
222  }
223  min_instances_recorded = true;
224  }
225  try_to_clone();
226  try_to_unclone();
227  return 0;
228 }
#define MIN_CLONE_DURATION_MS
#define CLONING_DECISION_LEN
double average_n(struct timed_rrdb *timeseries, int n_samples)
timeseries.c
Definition: timeseries.c:31
Round-robin database (circular buffer) for storing timeseries data.
Definition: timeseries.h:36
int try_to_clone()
static struct clone_decision UNCLONING_DECISIONS[]
static bool should_unclone(struct clone_decision *decision)
static struct clone_decision CLONING_DECISIONS[]
double stats[MAX_MSU]
struct dfg_msu * instances[512]
Each instance of this MSU type.
Definition: dfg.h:186
int perform_cloning()
struct dfg_msu * clone_msu(int msu_id)
Clone a msu of given ID.
Definition: scheduling.c:619
#define MAX_CLONE_CONDITIONS
stat_id
The identifiers with which stats can be logged.
Definition: stat_ids.h:32
static struct timespec cur_time
Static structure for holding current time, so it can be returned from next_timeout.
Logging of status messages to the terminal.
struct timed_rrdb * get_msu_stat(enum stat_id id, unsigned int msu_id)
#define UNCLONING_SAMPLES
Functions for the sending and receiving of statistics between ctrl and runtime.
#define MIN_UNCLONE_DURATION_MS
static int gather_cloning_info(struct cloning_info *info)
static bool min_instances_recorded
#define log_error(fmt,...)
Definition: logging.h:101
static bool should_clone(struct clone_decision *decision)
int try_to_unclone()
A type of MSU.
Definition: dfg.h:176
int id
A unique identifier for the MSU.
Definition: dfg.h:217
#define CLONING_SAMPLES
Representation of a single MSU in the dfg.
Definition: dfg.h:216
#define UNCLONING_DECISION_LEN
#define MAX_MSU
The maximum number of MSUs which can be present in the system at a time.
Definition: dfg.h:39
struct timespec last
struct local_msu * instance
Definition: socket_msu.c:36
#define WEBSERVER_READ_MSU_TYPE_ID
Definition: msu_ids.h:25
void set_haproxy_weights(int rt_id, int offset)
Definition: haproxy.c:102
enum stat_id stat_id
struct cloning_info conditions[2]
#define WEBSERVER_HTTP_MSU_TYPE_ID
Definition: msu_ids.h:26
int n_instances
The number of instances of this MSU type.
Definition: dfg.h:187
struct timespec last
#define log(level, fmt,...)
Log at a custom level.
Definition: logging.h:147
struct dfg_msu_type * get_dfg_msu_type(unsigned int id)
Returns the MSU type with the given ID.
Definition: dfg.c:68
static int gather_cloning_decision(struct clone_decision *decision)
int unclone_msu(int msu_id)
Definition: scheduling.c:566
#define WEBSERVER_REGEX_MSU_TYPE_ID
Definition: msu_ids.h:27