| #include <stdio.h> |
| #include <stdlib.h> |
| #include <argp.h> |
| |
| #include <parlib/parlib.h> |
| #include <parlib/vcore.h> |
| |
| const char *argp_program_version = "prov v0.1475263"; |
| const char *argp_program_bug_address = "<akaros+subscribe@googlegroups.com>"; |
| |
| static char doc[] = "prov -- control for provisioning resources"; |
| static char args_doc[] = "-p PID\n-c PROGRAM [ARGS]\nPROGRAM [ARGS]\n" |
| "-- PROGRAM [ARGS]\n-s"; |
| |
| static struct argp_option options[] = { |
| {"type", 't', "TYPE",0, "Type of resource to provision"}, |
| {"Possible types:", 0, 0, OPTION_DOC | OPTION_NO_USAGE, "c = cores\n" |
| "m = ram"}, |
| {0, 0, 0, 0, "Call with exactly one of these, or with a program and args:"}, |
| {"pid", 'p', "PID", OPTION_NO_USAGE, "Pid of process to provision " |
| "resources to"}, |
| {0, 0, 0, 0, ""}, |
| {"command", 'c', "PROG",OPTION_NO_USAGE, "Launch a program and " |
| "provision (alternate)"}, |
| {0, 0, 0, 0, ""}, |
| {"show", 's', 0, OPTION_NO_USAGE, "Show current resource " |
| "provisioning"}, |
| {0, 0, 0, OPTION_DOC, "If your command has arguments that conflict with " |
| "prov, then put them after -- to keep prov from " |
| "interpretting them."}, |
| {0, 0, 0, 0, "Call with exactly one of these when changing a provision:"}, |
| {"value", 'v', "VAL", 0, "Type-specific value, passed to the kernel"}, |
| {"max", 'm', 0, 0, "Provision all resources of the given type"}, |
| {0, 0, 0, OPTION_DOC, "Cores are provisioned to processes, so the value is " |
| "a specific pcore id. To undo a core's " |
| "provisioning, pass in pid=0."}, |
| { 0 } |
| }; |
| |
| #define PROV_MODE_PID 1 |
| #define PROV_MODE_CMD 2 |
| #define PROV_MODE_SHOW 3 |
| |
| struct prog_args { |
| char *cmd; |
| char **cmd_args; |
| int mode; /* PROV_MODE_ETC */ |
| pid_t pid; |
| char res_type; /* cores (c), ram (m), etc */ |
| long res_val; /* type-specific value */ |
| int max; |
| int dummy_val_flag; |
| }; |
| |
| static error_t parse_opt (int key, char *arg, struct argp_state *state) |
| { |
| struct prog_args *pargs = state->input; |
| switch (key) { |
| case 't': |
| pargs->res_type = arg[0]; |
| if (arg[1] != '\0') |
| printf("Warning, extra letters detected for -t's argument\n"); |
| break; |
| case 'p': |
| if (pargs->mode) { |
| printf("Too many modes given (-p, -s, COMMAND, etc)\n\n"); |
| argp_usage(state); |
| } |
| pargs->mode = PROV_MODE_PID; |
| pargs->pid = atoi(arg); |
| break; |
| case 's': |
| if (pargs->mode) { |
| printf("Too many modes given (-p, -s, COMMAND, etc)\n\n"); |
| argp_usage(state); |
| } |
| pargs->mode = PROV_MODE_SHOW; |
| break; |
| case 'c': |
| case ARGP_KEY_ARG: |
| if (pargs->mode) { |
| printf("Too many modes given (-p, -s, COMMAND, etc)\n\n"); |
| argp_usage(state); |
| } |
| pargs->mode = PROV_MODE_CMD; |
| pargs->cmd = arg; |
| /* Point to the next arg. We can also check state->arg_num, which |
| * is how many non-arpg arguments there are */ |
| pargs->cmd_args = &state->argv[state->next]; |
| /* Consume all args (it's done when next == argc) */ |
| state->next = state->argc; |
| break; |
| case 'v': |
| /* could also check to make sure we're not -s (and vice versa) */ |
| if (pargs->dummy_val_flag) { |
| printf("Provide only -v or -m, not both\n\n"); |
| argp_usage(state); |
| } |
| pargs->dummy_val_flag = 1; |
| pargs->res_val = atol(arg); |
| break; |
| case 'm': |
| if (pargs->dummy_val_flag) { |
| printf("Provide only -v or -m, not both\n\n"); |
| argp_usage(state); |
| } |
| pargs->dummy_val_flag = 1; |
| pargs->max = 1; |
| break; |
| case ARGP_KEY_END: |
| /* Make sure we selected a mode */ |
| if (!pargs->mode) { |
| printf("No mode selected (-p, -s, etc).\n\n"); |
| argp_usage(state); |
| } |
| break; |
| default: |
| return ARGP_ERR_UNKNOWN; |
| } |
| return 0; |
| } |
| |
| static struct argp argp = {options, parse_opt, args_doc, doc}; |
| |
| /* Used by both -p and -c modes (-c will use it after creating pid) */ |
| static int prov_pid(pid_t pid, struct prog_args *pargs) |
| { |
| unsigned int kernel_res_type; |
| int retval; |
| switch (pargs->res_type) { |
| case ('c'): |
| if (pargs->max) { |
| /* TODO: don't guess the LL/CG layout and num pcores */ |
| #if 1 |
| for (int i = 1; i < max_vcores() + 1; i++) { |
| if ((retval = sys_provision(pid, RES_CORES, i))) { |
| perror("Failed max provisioning"); |
| return retval; |
| } |
| } |
| #else |
| /* To force a vcore shuffle / least optimal ordering, change |
| * the if 1 to 0. Normally, we provision out in a predictable, |
| * VCn->PCn+1 ordering. This splits the odd and even VCs |
| * across sockets on a 32 PC machine (c89). This is only for |
| * perf debugging, when using the lockprov.sh script. */ |
| retval = 0; |
| retval |= sys_provision(pid, RES_CORES, 1); |
| retval |= sys_provision(pid, RES_CORES, 16); |
| retval |= sys_provision(pid, RES_CORES, 2); |
| retval |= sys_provision(pid, RES_CORES, 17); |
| retval |= sys_provision(pid, RES_CORES, 3); |
| retval |= sys_provision(pid, RES_CORES, 18); |
| retval |= sys_provision(pid, RES_CORES, 4); |
| retval |= sys_provision(pid, RES_CORES, 19); |
| retval |= sys_provision(pid, RES_CORES, 5); |
| retval |= sys_provision(pid, RES_CORES, 20); |
| retval |= sys_provision(pid, RES_CORES, 6); |
| retval |= sys_provision(pid, RES_CORES, 21); |
| retval |= sys_provision(pid, RES_CORES, 7); |
| retval |= sys_provision(pid, RES_CORES, 22); |
| retval |= sys_provision(pid, RES_CORES, 8); |
| retval |= sys_provision(pid, RES_CORES, 23); |
| retval |= sys_provision(pid, RES_CORES, 9); |
| retval |= sys_provision(pid, RES_CORES, 24); |
| retval |= sys_provision(pid, RES_CORES, 10); |
| retval |= sys_provision(pid, RES_CORES, 25); |
| retval |= sys_provision(pid, RES_CORES, 11); |
| retval |= sys_provision(pid, RES_CORES, 26); |
| retval |= sys_provision(pid, RES_CORES, 12); |
| retval |= sys_provision(pid, RES_CORES, 27); |
| retval |= sys_provision(pid, RES_CORES, 13); |
| retval |= sys_provision(pid, RES_CORES, 28); |
| retval |= sys_provision(pid, RES_CORES, 14); |
| retval |= sys_provision(pid, RES_CORES, 29); |
| retval |= sys_provision(pid, RES_CORES, 15); |
| retval |= sys_provision(pid, RES_CORES, 31); |
| retval |= sys_provision(pid, RES_CORES, 30); |
| return retval; |
| #endif |
| } else { |
| if ((retval = sys_provision(pid, RES_CORES, pargs->res_val))) { |
| perror("Failed single provision"); |
| return retval; |
| } |
| } |
| kernel_res_type = RES_CORES; |
| break; |
| case ('m'): |
| printf("Provisioning memory is not supported yet\n"); |
| return -1; |
| break; |
| default: |
| if (!pargs->res_type) |
| printf("No resource type selected. Use -t\n"); |
| else |
| printf("Unsupported resource type %c\n", pargs->res_type); |
| return -1; |
| } |
| sys_poke_ksched(pid, kernel_res_type); |
| return 0; |
| } |
| |
| int main(int argc, char **argv) |
| { |
| |
| struct prog_args pargs = {0}; |
| |
| argp_parse(&argp, argc, argv, 0, 0, &pargs); |
| |
| switch (pargs.mode) { |
| case (PROV_MODE_PID): |
| return prov_pid(pargs.pid, &pargs); |
| break; |
| case (PROV_MODE_CMD): |
| printf("Launching programs not supported yet\n"); |
| printf("Would have launched %s with args:", pargs.cmd); |
| if (pargs.cmd_args) |
| for (int i = 0; pargs.cmd_args[i]; i++) |
| printf(" %s", pargs.cmd_args[i]); |
| printf("\n"); |
| return 0; |
| break; |
| case (PROV_MODE_SHOW): |
| printf("Show mode not supported yet, using ghetto interface\n\n"); |
| sys_provision(-1, 0, 0); |
| return 0; |
| break; |
| default: |
| return -1; |
| } |
| } |