]> rtime.felk.cvut.cz Git - frescor/frsh.git/blob - resources/disk_bfq/mngr/diskbfq_mngr.c
BFQ based disk bandwidth resource.
[frescor/frsh.git] / resources / disk_bfq / mngr / diskbfq_mngr.c
1 /**************************************************************************/
2 /* ---------------------------------------------------------------------- */
3 /* Copyright (C) 2006 - 2008 FRESCOR consortium partners:                 */
4 /*                                                                        */
5 /*   Universidad de Cantabria,              SPAIN                         */
6 /*   University of York,                    UK                            */
7 /*   Scuola Superiore Sant'Anna,            ITALY                         */
8 /*   Kaiserslautern University,             GERMANY                       */
9 /*   Univ. Politécnica  Valencia,           SPAIN                        */
10 /*   Czech Technical University in Prague,  CZECH REPUBLIC                */
11 /*   ENEA                                   SWEDEN                        */
12 /*   Thales Communication S.A.              FRANCE                        */
13 /*   Visual Tools S.A.                      SPAIN                         */
14 /*   Rapita Systems Ltd                     UK                            */
15 /*   Evidence                               ITALY                         */
16 /*                                                                        */
17 /*   See http://www.frescor.org for a link to partners' websites          */
18 /*                                                                        */
19 /*          FRESCOR project (FP6/2005/IST/5-034026) is funded             */
20 /*       in part by the European Union Sixth Framework Programme          */
21 /*       The European Union is not liable of any use that may be          */
22 /*       made of this code.                                               */
23 /*                                                                        */
24 /*                                                                        */
25 /*  This file is part of FRESCOR BFQ disk bandwidth reservation           */
26 /*                                                                        */
27 /* FWP is free software; you can redistribute it and/or modify it         */
28 /* under terms of the GNU General Public License as published by the      */
29 /* Free Software Foundation; either version 2, or (at your option) any    */
30 /* later version.  FWP is distributed in the hope that it will be         */
31 /* useful, but WITHOUT ANY WARRANTY; without even the implied warranty    */
32 /* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU    */
33 /* General Public License for more details. You should have received a    */
34 /* copy of the GNU General Public License along with FWP; see file        */
35 /* COPYING. If not, write to the Free Software Foundation, 675 Mass Ave,  */
36 /* Cambridge, MA 02139, USA.                                              */
37 /*                                                                        */
38 /* As a special exception, including FWP header files in a file,          */
39 /* instantiating FWP generics or templates, or linking other files        */
40 /* with FWP objects to produce an executable application, does not        */
41 /* by itself cause the resulting executable application to be covered     */
42 /* by the GNU General Public License. This exception does not             */
43 /* however invalidate any other reasons why the executable file might be  */
44 /* covered by the GNU Public License.                                     */
45 /**************************************************************************/
46 #include <frm_generic.h>
47 #include <forb.h>
48 #include <error.h>
49 #include <errno.h>
50 #include <fres_sa_scenario.h>
51 #include <stdbool.h>
52 #include <ul_log.h>
53 #include <stdio.h>
54 #include <math.h>
55 #include "res_disk.h"
56
57 UL_LOG_CUST(ulogd_frm_diskbfq);
58 ul_log_domain_t ulogd_fra_fwp = {UL_LOGL_DEB, "frm_diskbfq"};
59
60 struct disk_data {
61         long throughput;
62         int budget;
63 };
64
65 static int bandwidth_to_weight(struct disk_data *data,
66                                unsigned long budget,
67                                unsigned long period)
68 {
69         float th, weight;
70         //unsigned long q_i, p_i;
71         int b, w_i;
72
73         th = data->throughput / 10E9;
74         b = data->budget;
75
76         /* Convert to nanoseconds! */
77         //q_i *= 1000;
78         //p_i *= 1000;
79
80         if (period < b / th)
81                 return -1;
82
83         weight = (DISKBFQ_WEIGHT_MAX * budget) / (period - (b / th));
84         w_i = floor(weight);
85         if (weight != w_i)
86                 w_i++;
87
88         return w_i;
89 }
90
91 static int weight_to_ioprio(int weight)
92 {
93         if (weight >= 100)
94                 return 0;
95         if (weight > 14)
96                 return 1;
97         if (weight == -1)
98                 return -1;
99
100         return 8 - 1 - (weight / 2);
101 }
102
103 static int diskbfq_admtest(struct fres_sa_scenario *scenario,
104                            void *priv, 
105                            bool *schedulable)
106 {
107         struct fres_sa_contract *c;
108         long int period, budget;
109         long int sum_weight = 0;
110         struct disk_data *data = priv;
111
112         fres_sa_scenario_for_each_contract(scenario, c) {
113                 fres_block_basic *basic;
114                 fres_block_resource *resource;
115                 fres_block_disk_sched *disk_sched;
116                 char id[40];
117
118                 fres_contract_id_to_string(id, &c->contract->id, sizeof(id));
119                 basic = fres_contract_get_basic(c->contract);
120                 resource = fres_contract_get_resource(c->contract);
121
122                 period = fosa_rel_time_to_nsec(basic->period);
123                 budget = fosa_rel_time_to_nsec(basic->budget);
124                 printf("processing: id=%s, period=%ld ms, budget=%ld ms\n",
125                        id, period, budget);
126
127                 if (c->contract == c->new) {
128                         int ret;
129
130                         /* Calc weight and IO prio for the new contracts */
131                         disk_sched = malloc(sizeof(*disk_sched));
132                         if (!disk_sched) return -1;
133
134                         disk_sched->weight = bandwidth_to_weight(data,
135                                                                  budget,
136                                                                  period);
137                         disk_sched->ioprio =
138                                 weight_to_ioprio(disk_sched->weight);
139                         ret = fres_contract_add_disk_sched(c->contract,
140                                                            disk_sched);
141                         if (ret) {
142                                 fprintf(stderr,
143                                         "Cannot add disk_sched block\n");
144                                 free(disk_sched);
145                                 return -1;
146                         }
147                 } else {
148                         disk_sched = fres_contract_get_disk_sched(c->contract);
149                         if (!disk_sched) {
150                                 fprintf(stderr,
151                                         "disk_sched is not present\n");
152                                 return -1;
153                         }
154                 }
155                 sum_weight += disk_sched->weight;
156         }
157
158         printf("sum_weight=%ld, max_weight=%d\n",
159                sum_weight,
160                DISKBFQ_WEIGHT_MAX);
161         *schedulable = sum_weight < DISKBFQ_WEIGHT_MAX;
162         printf("=>%s\n", (*schedulable) ? "schedulable" : "not schedulable");
163
164         return 0;
165 }
166
167 struct disk_data disk;
168
169 static struct fres_res_manager frm = {
170         .res_type = FRSH_RT_DISK,
171         .res_id = 0,
172         .admission_test = diskbfq_admtest,
173         .priv = &disk
174 };
175
176 int main(int argc, char *argv[])
177 {
178         forb_orb orb;
179         FILE* fd;
180         char disk_name[40];
181         char path[128], scheduler[128];
182         int opt, ret;
183
184         if (argc < 3) {
185 err_usage:
186                 fprintf(stderr, "Usage:\n %s -i disk_id -d disk_dev_name\n",
187                         argv[0]);
188                 error(1, EINVAL, "frm_diskbfq");
189         }
190
191         while ((opt = getopt(argc, argv, "i:d:")) != -1) {
192                 switch (opt) {
193                         case 'i':
194                                 frm.res_id = atoi(optarg);
195                                 break;
196                         case 'd':
197                                 strncpy(disk_name,
198                                         optarg, sizeof(disk_name));
199                                 break;
200                         default:
201                                 goto err_usage;
202                 }
203         }
204
205         orb = forb_init(&argc, &argv, "frm_diskbfq");
206         if (!orb) error(1, errno, "forb_init");
207
208         /*
209          * Check if BFQ I/O scheduler is available
210          *  in the system.
211          */
212         snprintf(path, 128,
213                  SYSFS_BFQ_SCHED_PATH,
214                  disk_name);
215         if (!(fd = fopen(path, "rw")))
216                 error(1, errno, "frm_generic_run");
217
218         ret = fscanf(fd, "%128[^\n]", scheduler);
219         if (ret == 0 || ret == EOF)
220                 error(1, errno, "frm_generic_run");
221         if (!strstr(scheduler, SYSFS_BFQ_NAME))
222                 error(1, errno, "frm_generic_run");
223
224         /*
225          * Now check if BFQ is the default I/O scheduler
226          *  for the specific disk and set it to so if not.
227          */
228         else if (!strstr(scheduler, "[" SYSFS_BFQ_NAME "]")) {
229                 rewind(fd);
230                 ret = fprintf(fd, SYSFS_BFQ_NAME);
231                 if (ret && ret != EOF)
232                         ret = fflush(fd);
233                 if (ret == 0 || ret == EOF)
234                         error(1, errno, "frm_generic_run");
235         }
236         fclose(fd);
237
238         snprintf(path, sizeof(path),
239                  SYSFS_BFQ_BUDGET_PATH,
240                  disk_name);
241         if (!(fd = fopen(path, "r")))
242                 error(1, errno, "frm_generic_run");
243
244         ret = fscanf(fd, "%d", &disk.budget);
245         if (ret == 0 || ret == EOF)
246                 error(1, errno, "frm_generic_run");
247         fclose(fd);
248
249         /*
250          * TODO:
251          *  run the benchmark to get the throughput.
252          */
253         disk.throughput = 100000;
254
255         fprintf(stdout, "disk name: %s\n"
256                 "scheduler: %s\n"
257                 "disk aggregate throughput: %ld\n"
258                 "scheduling budget: %d\n",
259                 disk_name, SYSFS_BFQ_NAME, disk.throughput, disk.budget);
260
261         /* Register fres_block_disk_sched to contract handling
262          *  functions */
263         fres_block_register_disk_sched();
264
265         ret = frm_register_and_run(orb, &frm);
266         if (ret) error(1, errno, "frm_generic_run");
267         
268         return 0;
269 }
270