/* * chcpumf - Change CPU Measurement Facility Characteristics * * Copyright IBM Corp. 2020 * * s390-tools is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. */ #include #include #include #include #include #include #include #include #include "lib/util_opt.h" #include "lib/util_prg.h" #include "lib/util_base.h" #include "defines.h" static int verbose; static unsigned long min_sdb, max_sdb; static struct util_opt opt_vec[] = { UTIL_OPT_SECTION("OPTIONS"), { .option = { "min", required_argument, NULL, 'm' }, .argument = "num_sdb", .desc = "Specifies the initial size of the sampling buffer.\n" "A sample-data-block (SDB) consumes about 4 kilobytes.", }, { .option = { "max", required_argument, NULL, 'x' }, .argument = "num_sdb", .desc = "Specifies the maximum size of the sampling buffer.\n" "A sample-data-block (SDB) consumes about 4 kilobytes.", }, { .option = { "verbose", no_argument, NULL, 'V' }, .desc = "Verbose, display new sample-data-block values.", }, UTIL_OPT_HELP, UTIL_OPT_VERSION, UTIL_OPT_END }; static const struct util_prg prg = { .desc = "Change CPU Measurement facility charactertics", .copyright_vec = { { .owner = "IBM Corp.", .pub_first = 2020, .pub_last = 2020, }, UTIL_PRG_COPYRIGHT_END } }; /* Parse tool parameters. Fill in global variables keep_case, buffersize and * command according to parameters. Return VMCP_OK on success, VMCP_OPT * in case of parameter errors. In case of --help or --version, print * respective text to stdout and exit. */ static long parse_buffersize(char *string) { char *suffix; long bytes; bytes = strtol(string, &suffix, 10); if (strlen(suffix) > 1) return -1; switch (*suffix) { case 'k': case 'K': bytes *= 1024; break; case 'm': case 'M': bytes *= 1048576; break; case '\0': break; default: return 0; } return bytes; } static int read_sfb(unsigned long *min, unsigned long *max) { int rc = EXIT_SUCCESS; FILE *fp; fp = fopen(PERF_SFB_SIZE, "r"); if (fp == NULL) { linux_error(PERF_SFB_SIZE); return EXIT_FAILURE; } if (fscanf(fp, "%ld,%ld", min, max) != 2) { fprintf(stderr, "Error: Can not parse file " PERF_SFB_SIZE); rc = EXIT_FAILURE; } fclose(fp); return rc; } static int write_sfb(unsigned long min, unsigned long max) { int rc = EXIT_SUCCESS; char text[64]; size_t len; FILE *fp; fp = fopen(PERF_SFB_SIZE, "w"); if (fp == NULL) { linux_error(PERF_SFB_SIZE); return EXIT_FAILURE; } snprintf(text, sizeof text, "%ld,%ld", min, max); len = strlen(text) + 1; if (fwrite(text, 1, len, fp) != len) { linux_error(PERF_SFB_SIZE); rc = EXIT_FAILURE; } if (fclose(fp)) { linux_error(PERF_SFB_SIZE); rc = EXIT_FAILURE; } if (verbose && rc != EXIT_FAILURE) fprintf(stderr, "Sampling buffer sizes:\n" " Minimum:%7ld sample-data-blocks\n" " Maximum:%7ld sample-data-blocks\n", min, max); return rc; } static int parse_args(int argc, char **argv) { int opt, action = 0; long new; while ((opt = util_opt_getopt_long(argc, argv)) != -1) { switch (opt) { case 'h': util_prg_print_help(); util_opt_print_help(); exit(EXIT_SUCCESS); case 'v': util_prg_print_version(); exit(EXIT_SUCCESS); case 'x': new = parse_buffersize(optarg); if (new < 1) { fprintf(stderr, "The specified number(s)" " are not valid\n"); exit(EXIT_FAILURE); } max_sdb = new; action = 1; break; case 'm': new = parse_buffersize(optarg); if (new < 1) { fprintf(stderr, "The specified number(s)" " are not valid\n"); exit(EXIT_FAILURE); } min_sdb = new; action = 1; break; case 'V': verbose = 1; break; case '?': fprintf(stderr, "One or more options are not valid\n"); fprintf(stderr, "Try 'chcpumf --help' for more" " information\n"); exit(EXIT_FAILURE); } } if (!action) { fprintf(stderr, "You must specify a valid option\n"); exit(EXIT_FAILURE); } return action; } int main(int argc, char **argv) { int ret = EXIT_FAILURE; struct stat sbuf; util_prg_init(&prg); util_opt_init(opt_vec, NULL); if (stat(PERF_PATH PERF_SF, &sbuf) != 0) { fprintf(stderr, "No CPU-measurement sampling facility detected\n"); return ret; } if (read_sfb(&min_sdb, &max_sdb)) return ret; /* Overwrite min_sdb and/or max_sdb */ parse_args(argc, argv); if (min_sdb >= max_sdb) { fprintf(stderr, "The specified maximum must be greater " "than the minimum\n"); return ret; } return write_sfb(min_sdb, max_sdb); }