00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <unistd.h>
00004 #include <string.h>
00005 
00006 #include <aquosa/qres_lib.h>
00007 #include <linux/aquosa/qos_debug.h>
00008 #include <aquosa/qsup_lib.h>
00009 
00010 extern char **environ;
00011 
00012 static inline void qos_assert(int cond, const char *msg) {
00013   if (! cond) {
00014     printf("%s\n", msg);
00015     exit(-1);
00016   }
00017 }
00018 
00019 static inline unsigned int str2flags(char str_flags[5]) {
00020   unsigned int flags = 0x0000;
00021   if (index(str_flags, 'd') != NULL)
00022     flags |= QOS_F_DEFAULT;
00023   if (index(str_flags, 's') != NULL)
00024     flags |= QOS_F_SOFT;
00025   if (index(str_flags, 'p') != NULL)
00026     flags |= QOS_F_PERSISTENT;
00027   return flags;
00028 }
00029 
00030 static inline void flags2str(unsigned int flags, char str_flags[5]) {
00031   sprintf(str_flags, "----");
00032   if (flags & QOS_F_DEFAULT)
00033     str_flags[3] = 'd';
00034   if (flags & QOS_F_SOFT)
00035     str_flags[2] = 's';
00036   if (flags & QOS_F_PERSISTENT)
00037     str_flags[1] = 'p';
00038 }
00039 
00041 FILE *fproc = NULL;
00042 char fname[32];
00043 
00045 int proc_begin(pid_t pid) {
00046   sprintf(fname, "ls /proc/%d/task", pid);
00047   fproc = popen(fname, "r");
00048   return (fproc != NULL);
00049 }
00050 
00052 tid_t proc_next(void) {
00053   qos_assert(fproc != NULL, "");
00054   if (feof(fproc)) {
00055     pclose(fproc);
00056     return 0;
00057   }
00058   int tid;
00059   if (fscanf(fproc, "%d", &tid) != 1) {
00060     pclose(fproc);
00061     return 0;
00062   }
00063   return (tid_t) tid;
00064 }
00065 
00066 int main(int argc, char *argv[]) {
00067   int Q_min = -1, Q = -1, P = -1;
00068   unsigned int flags = -1, weight = 0;
00069   char str_flags[5] = "NONE";
00070   qos_bw_t bw_min = -1, bw = -1;
00071   int create = 0;
00072   int destroy = 0;
00073   int attach = 0;
00074   int detach = 0;
00075   int wrap = 0;
00076   int getparams = 0;
00077   int gettime = 0;
00078   int getbudgets = 0;
00079   int setparams = 0;
00080   int setspare = 0;
00081   pid_t pid = -1;
00082   tid_t tid = -1;
00083   qres_sid_t sid = -1;
00084   double spare_bw = -1;
00085   qres_params_t params;
00086   char *argv0 = argv[0];
00087 
00088   argc--;  argv++;
00089   while (argc > 0 && ! wrap) {
00090     if (0) {
00091     } else if (sscanf(*argv, "q-min=%d", &Q_min) == 1 || sscanf(*argv, "q_min=%d", &Q_min) == 1) {
00092     } else if (strcmp(*argv, "-q-min") == 0) {
00093       qos_assert(argc > 1, "Missing option parameter");
00094       argc--;  argv++;
00095       Q_min = atoi(*argv);
00096     } else if (sscanf(*argv, "q=%d", &Q) == 1) {
00097     } else if (strcmp(*argv, "-q") == 0) {
00098       qos_assert(argc > 1, "Missing option parameter");
00099       argc--;  argv++;
00100       Q = atoi(*argv);
00101     } else if (sscanf(*argv, "p=%d", &P) == 1) {
00102     } else if (strcmp(*argv, "-p") == 0) {
00103       qos_assert(argc > 1, "Missing option parameter");
00104       argc--;  argv++;
00105       P = atoi(*argv);
00106     } else if (sscanf(*argv, "w=%d", &weight) == 1) {
00107     } else if (strcmp(*argv, "-w") == 0) {
00108       qos_assert(argc > 1, "Missing option parameter");
00109       argc--;  argv++;
00110       weight = atoi(*argv);
00111     } else if (strcmp(*argv, "-b-min") == 0) {
00112       qos_assert(argc > 1, "Missing option parameter");
00113       argc--;  argv++;
00114       bw_min = d2bw(atof(*argv));
00115     } else if (strcmp(*argv, "-b") == 0) {
00116       qos_assert(argc > 1, "Missing option parameter");
00117       argc--;  argv++;
00118       bw = d2bw(atof(*argv));
00119     } else if (sscanf(*argv, "spare=%lg", &spare_bw) == 1) {
00120       qos_assert(spare_bw >= 0.0 && spare_bw <= 1.0,
00121                  "Spare bandwidth must be in the [0.0 1.0] range\n");
00122     } else if (strcmp(*argv, "-spare") == 0) {
00123       qos_assert(argc > 1, "Missing option parameter");
00124       argc--;  argv++;
00125       spare_bw = atof(*argv);
00126       qos_assert(spare_bw >= 0.0 && spare_bw <= 1.0,
00127                  "Spare bandwidth must be in the [0.0 1.0] range\n");
00128     } else if (sscanf(*argv, "pid=%d", &pid) == 1) {
00129     } else if (strcmp(*argv, "-pid") == 0) {
00130       qos_assert(argc > 1, "Missing option parameter");
00131       argc--;  argv++;
00132       pid = atoi(*argv);
00133     } else if (sscanf(*argv, "tid=%d", &tid) == 1) {
00134     } else if (strcmp(*argv, "-tid") == 0) {
00135       qos_assert(argc > 1, "Missing option parameter");
00136       argc--;  argv++;
00137       tid = atoi(*argv);
00138     } else if (sscanf(*argv, "sid=%d", &sid) == 1) {
00139     } else if (strcmp(*argv, "-sid") == 0) {
00140       qos_assert(argc > 1, "Missing option parameter");
00141       argc--;  argv++;
00142       sid = atoi(*argv);
00143     } else if (sscanf(*argv, "f=%x", &flags) == 1) {
00144     } else if (sscanf(*argv, "f=%4s", str_flags) == 1) {
00145     } else if (strcmp(*argv, "-f") == 0) {
00146       qos_assert(argc > 1, "Missing option parameter");
00147       argc--;  argv++;
00148       qos_assert((sscanf(*argv, "%x", &flags) == 1)
00149                  || (sscanf(*argv, "%4s", str_flags) == 1),
00150                  "Wrong option syntax");
00151     } else if (strcmp(*argv, "-create") == 0 || strcmp(*argv, "create") == 0) {
00152       create = 1;
00153     } else if (strcmp(*argv, "-destroy") == 0 || strcmp(*argv, "destroy") == 0) {
00154       destroy = 1;
00155     } else if (strcmp(*argv, "-attach") == 0 || strcmp(*argv, "attach") == 0) {
00156       attach = 1;
00157     } else if (strcmp(*argv, "-detach") == 0 || strcmp(*argv, "detach") == 0) {
00158       detach = 1;
00159     } else if (strcmp(*argv, "-getparams") == 0 || strcmp(*argv, "getparams") == 0) {
00160       getparams = 1;
00161     } else if (strcmp(*argv, "-gettime") == 0 || strcmp(*argv, "gettime") == 0) {
00162       gettime = 1;
00163     } else if (strcmp(*argv, "-getbudgets") == 0 || strcmp(*argv, "getbudgets") == 0) {
00164       getbudgets = 1;
00165     } else if (strcmp(*argv, "-setparams") == 0 || strcmp(*argv, "setparams") == 0) {
00166       setparams = 1;
00167     } else if (strcmp(*argv, "-setspare") == 0 || strcmp(*argv, "setspare") == 0) {
00168       setspare = 1;
00169     } else if (strcmp(*argv, "-h") == 0 || strcmp(*argv, "--help") == 0 || strcmp(*argv, "help") == 0) {
00170       printf("Usage: %s [ options... ]\n", argv0);
00171       printf("  -q-min Q_min : set minimum guaranteed budget per server period\n");
00172       printf("  -q Q_max     : set required budget per server period\n");
00173       printf("  -p P         : set server period\n");
00174       printf("  -w W         : set server weight\n");
00175       printf("  -f flags     : set flags\n");
00176 
00177 
00178       printf("  -pid pid     : set process id to affect or 0 for self (defaults to first tid)\n");
00179       printf("  -tid tid     : set thread id to affect or 0 for self (if omitted, all process threads are affected)\n");
00180       printf("  -sid sid     : set id of existing server to affect\n");
00181       printf("  -create      : create server (requires q, p, q_min=0)\n");
00182       printf("  -destroy     : destroy server (requires sid)\n");
00183       printf("  -attach      : attach thread to server (requires sid, pid, tid)\n");
00184       printf("  -detach      : detach thread from server (requires sid, pid/tid)\n");
00185       printf("  -setparams   : set server params (requires sid, q, p, q_min=0)\n");
00186       printf("  -getparams   : get server params (requires sid or pid/tid)\n");
00187       printf("  -gettime     : get server time figures (requires sid or pid/tid)\n");
00188       printf("  -getbudgets  : get dynamic budget values (requires sid or pid/tid)\n");
00189       printf("  -setspare    : set spare bandwidth (requires -spare)\n");
00190       printf("  -spare bw    : specify the spare bw to be set (range 0..1)\n");
00191       printf("  -wrap cmd [args]: command to wrap (followed by its args, thus this needs to be last option)\n");
00192       printf("\n");
00193       printf("Sample usage   : qres -create -q 10000 -p 30000 -attach -tid 44021\n");
00194       printf("               : qres create q=10000 p=30000 wrap /usr/bin/yes\n");
00195       printf("               : qres attach sid=2 pid=`pidof qemu-kvm`\n");
00196       printf("Altern. syntax : qres create q=10000 p=30000 attach tid=44021\n");
00197       exit(0);
00198     } else if (strcmp(*argv, "-wrap") == 0 || strcmp(*argv, "wrap") == 0) {
00199       
00200       wrap = 1;
00201     } else {
00202       printf("Unknown option: %s\n", *argv);
00203       exit(-1);
00204     }
00205 
00206     argc--;  argv++;
00207   }
00208 
00209   qos_chk_ok_exit(qres_init());
00210   qos_chk_ok_exit(qsup_init());
00211 
00212   tid_t def_tid = tid;
00213   if (def_tid == -1 && pid != -1)
00214     def_tid = pid;
00215   if (pid == -1 && tid != -1)
00216     pid = tid;
00217 
00218   if (sid == -1 && pid != -1 && def_tid != -1) {
00219     if (qres_get_sid(pid, def_tid, &sid) == QOS_OK) {
00220       printf("sid of attached server: %d\n", sid);
00221     }
00222   }
00223 
00224   if (flags == -1) {
00225     if (strcmp(str_flags, "NONE") != 0)
00226       flags = str2flags(str_flags);
00227     else
00228       flags = 0x0000;
00229   }
00230 
00231   if (create == 1 && Q != -1 && P != -1) {
00232     params.Q = Q;
00233     params.P = P;
00234     params.Q_min = (Q_min != -1) ? Q_min : 0;
00235     params.flags = flags;
00236     qos_chk_ok_exit(qres_create_server(¶ms, &sid));
00237     printf("SID of new server: %d\n", sid);
00238   }
00239 
00240   if (sid != -1 && weight != 0)
00241     qos_chk_ok_exit(qres_set_weight(sid, weight));
00242 
00243   if (attach == 1 && sid != -1 && pid != -1 && tid != -1)
00244     qos_chk_ok_exit(qres_attach_thread(sid, pid, tid));
00245   else if (attach == 1 && sid != -1 && pid != -1) {
00246     qos_assert(proc_begin(pid), "No such pid");
00247     tid_t mytid = proc_next();
00248     while (mytid != 0) {
00249       qos_chk_ok_exit(qres_attach_thread(sid, pid, mytid));
00250       mytid = proc_next();
00251     }
00252   }
00253 
00254   if (detach == 1 && sid != -1 && pid != -1 && tid != -1)
00255     qos_chk_ok_exit(qres_detach_thread(sid, pid, tid));
00256   else if (detach == 1 && sid != -1 && pid != -1) {
00257     qos_assert(proc_begin(pid), "No such pid");
00258     tid_t mytid = proc_next();
00259     while (mytid != 0) {
00260       qos_chk_ok_exit(qres_detach_thread(sid, pid, mytid));
00261       mytid = proc_next();
00262     }
00263   }
00264 
00265   if (setparams == 1 && sid != -1) {
00266     qos_chk_ok_exit(qres_get_params(sid, ¶ms));
00267     if (Q != -1) params.Q = Q;
00268     if (Q_min != -1) params.Q_min = Q_min;
00269     if (P != -1) params.P = P;
00270     qos_chk_ok_exit(qres_set_params(sid, ¶ms));
00271   }
00272 
00273   if (destroy == 1 && sid != -1)
00274     qos_chk_ok_exit(qres_destroy_server(sid));
00275 
00276   if (getparams == 1 && sid != -1) {
00277     qos_chk_ok_exit(qres_get_params(sid, ¶ms));
00278     flags2str(params.flags, str_flags);
00279     printf("sid: %d, Q: " QRES_TIME_FMT
00280              ", Q_min: " QRES_TIME_FMT
00281              ", P: " QRES_TIME_FMT
00282              ", f: %s (%04x)"
00283              "\n", sid, params.Q, params.Q_min, params.P, str_flags, params.flags);
00284   }
00285 
00286   if (getbudgets == 1 && sid != -1) {
00287     qres_time_t curr_budget, next_budget, appr_budget;
00288     qos_chk_ok_exit(qres_get_curr_budget(sid, &curr_budget));
00289     qos_chk_ok_exit(qres_get_next_budget(sid, &next_budget));
00290     qos_chk_ok_exit(qres_get_appr_budget(sid, &appr_budget));
00291     printf("sid: %d, Q_curr: " QRES_TIME_FMT
00292             ", Q_next: " QRES_TIME_FMT
00293             ", Q_appr: " QRES_TIME_FMT
00294             "\n", sid, curr_budget, next_budget, appr_budget);
00295   }
00296 
00297   if (gettime == 1 && sid != -1) {
00298     qres_time_t exec_time;
00299     qres_atime_t abs_time;
00300     qos_chk_ok_exit(qres_get_exec_time(sid, &exec_time, &abs_time));
00301     printf("sid: %d"
00302              ", exec_time: " QRES_TIME_FMT
00303              ", abs_time: " QRES_ATIME_FMT
00304            "\n", sid, exec_time, abs_time);
00305   }
00306 
00307   if (setspare == 1) {
00308     qos_assert(spare_bw != -1, "Need to specify the spare bandwidth to be set (through -spare)");
00309     qos_chk_ok_exit(qsup_reserve_spare(d2bw(spare_bw)));
00310     printf("Set spare bandwidth for QoS manager\n");
00311   }
00312 
00313   if (wrap == 1) {
00314     qos_assert(sid != -1, "Need to specify server either by sid or by creating a new one");
00315     const char *cmd = argv[0];
00316     qos_chk_ok_exit(qres_attach_thread(sid, 0, 0));
00317     qos_chk_ok_exit(qsup_cleanup());
00318     qos_chk_ok_exit(qres_cleanup());
00319     execvp(cmd, argv);
00320   }
00321 
00322   qos_chk_ok_exit(qsup_cleanup());
00323   qos_chk_ok_exit(qres_cleanup());
00324 
00325   return 0;
00326 }