Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932754AbbLBL0Z (ORCPT ); Wed, 2 Dec 2015 06:26:25 -0500 Received: from mail-pa0-f43.google.com ([209.85.220.43]:35572 "EHLO mail-pa0-f43.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932140AbbLBL0V (ORCPT ); Wed, 2 Dec 2015 06:26:21 -0500 From: Taeung Song To: Arnaldo Carvalho de Melo Cc: linux-kernel@vger.kernel.org, Ingo Molnar , Taeung Song , Namhyung Kim , Jiri Olsa Subject: [PATCH v12 20/22] perf config: Add 'set' feature Date: Wed, 2 Dec 2015 19:54:38 +0900 Message-Id: <1449053680-31931-20-git-send-email-treeze.taeung@gmail.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1449053680-31931-1-git-send-email-treeze.taeung@gmail.com> References: <1449053680-31931-1-git-send-email-treeze.taeung@gmail.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 9961 Lines: 311 This patch consists of functions which can set specific config variables. For the syntax examples, perf config [] [options] [section.name[=value] ...] set specific config variables # perf config report.queue-size=100M report.children=true Cc: Namhyung Kim Cc: Jiri Olsa Signed-off-by: Taeung Song --- tools/perf/Documentation/perf-config.txt | 2 +- tools/perf/builtin-config.c | 127 +++++++++++++++++++++++++------ tools/perf/util/cache.h | 5 +- tools/perf/util/config.c | 27 ++++++- 4 files changed, 134 insertions(+), 27 deletions(-) diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt index 59733ec..db50d3d 100644 --- a/tools/perf/Documentation/perf-config.txt +++ b/tools/perf/Documentation/perf-config.txt @@ -8,7 +8,7 @@ perf-config - Get and set variables in a configuration file. SYNOPSIS -------- [verse] -'perf config' [] [section.name ...] +'perf config' [] [section.name[=value] ...] or 'perf config' [] -l | --list or diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index 978eee3..33d5ff4 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c @@ -16,7 +16,7 @@ static bool use_system_config, use_user_config; static const char * const config_usage[] = { - "perf config [] [options] [section.name ...]", + "perf config [] [options] [section.name[=value] ...]", NULL }; @@ -397,7 +397,9 @@ static int show_all_config(struct list_head *sections) } static int show_spec_config(struct list_head *sections, - const char *section_name, const char *name) + const char *config_file_name __maybe_unused, + const char *section_name, const char *name, + char *value) { int i; struct config_section *section = NULL; @@ -416,7 +418,7 @@ static int show_spec_config(struct list_head *sections, if (!strcmp(config->section, section_name) && !strcmp(config->name, name)) { - char *value = get_value(config); + value = get_value(config); if (verbose) printf("# %s\n", config->desc); @@ -430,6 +432,39 @@ static int show_spec_config(struct list_head *sections, return -1; } +static int set_config(struct list_head *sections, const char *config_file_name, + const char *section_name, const char *name, char *value) +{ + struct config_section *section = NULL; + struct config_element *element = NULL; + + find_config(sections, §ion, &element, section_name, name); + if (value != NULL) { + value = strdup(value); + if (!value) { + pr_err("%s: strdup failed\n", __func__); + return -1; + } + + /* if there isn't existent section, add a new section */ + if (!section) { + section = init_section(section_name); + if (!section) + return -1; + list_add_tail(§ion->list, sections); + } + /* if nothing to replace, add a new element which contains key-value pair. */ + if (!element) { + add_element(§ion->element_head, name, value); + } else { + free(element->value); + element->value = value; + } + } + + return perf_configset_write_in_full(sections, config_file_name); +} + static int collect_current_config(const char *var, const char *value, void *spec_sections) { @@ -479,8 +514,10 @@ out_err: return ret; } -static int perf_configset_with_option(configset_fn_t fn, struct list_head *sections, - const char *var) +static int perf_configset_with_option(configset_fn_t fn, + struct list_head *sections, + const char *config_file_name, + const char *var, char *value) { int ret = -1; char *ptr, *key; @@ -507,10 +544,24 @@ static int perf_configset_with_option(configset_fn_t fn, struct list_head *secti } section_name = strsep(&ptr, "."); - name = ptr; - fn(sections, section_name, name); - ret = 0; + name = strsep(&ptr, "="); + if (!value) { + /* do nothing */ + } else if (!strcmp(value, "=")) { + pr_err("The config variable does not contain a value: %s.%s\n", + section_name, name); + goto out_err; + } else { + value++; + name = strsep(&name, "="); + if (name[0] == '\0') { + pr_err("invalid key: %s\n", var); + goto out_err; + } + } + fn(sections, config_file_name, section_name, name, value); + ret = 0; out_err: free(key); return ret; @@ -536,7 +587,10 @@ static int show_config(struct list_head *sections) int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) { int i, ret = 0; - struct list_head sections; + struct list_head *sections; + struct list_head all_sections, user_sections, system_sections; + const char *system_config = perf_etc_perfconfig(); + char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); set_option_flag(config_options, 'l', "list", PARSE_OPT_EXCLUSIVE); set_option_flag(config_options, 'a', "list-all", PARSE_OPT_EXCLUSIVE); @@ -551,14 +605,22 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) return -1; } - INIT_LIST_HEAD(§ions); - - if (use_system_config) - config_exclusive_filename = perf_etc_perfconfig(); - else if (use_user_config) - config_exclusive_filename = mkpath("%s/.perfconfig", getenv("HOME")); - - perf_config(collect_current_config, §ions); + INIT_LIST_HEAD(&user_sections); + INIT_LIST_HEAD(&system_sections); + perf_config_from_file(collect_current_config, user_config, &user_sections); + perf_config_from_file(collect_current_config, system_config, &system_sections); + + if (use_system_config) { + sections = &system_sections; + config_exclusive_filename = system_config; + } else if (use_user_config) { + sections = &user_sections; + config_exclusive_filename = user_config; + } else { + sections = &all_sections; + INIT_LIST_HEAD(&all_sections); + perf_config(collect_current_config, &all_sections); + } switch (actions) { case ACTION_SKEL: @@ -569,7 +631,7 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) break; case ACTION_LIST_ALL: if (argc == 0) { - ret = show_all_config(§ions); + ret = show_all_config(sections); break; } case ACTION_LIST: @@ -580,18 +642,35 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) else parse_options_usage(config_usage, config_options, "l", 1); } else { - ret = show_config(§ions); + ret = show_config(sections); if (ret < 0) pr_err("Nothing configured, " "please check your ~/.perfconfig file\n"); } break; default: - if (argc) - for (i = 0; argv[i]; i++) - ret = perf_configset_with_option(show_spec_config, §ions, - argv[i]); - else + if (argc) { + for (i = 0; argv[i]; i++) { + char *value = strchr(argv[i], '='); + + if (value == NULL) + ret = perf_configset_with_option(show_spec_config, + sections, NULL, + argv[i], value); + else { + if (!use_system_config && !use_user_config) + ret = perf_configset_with_option(set_config, + &user_sections, + user_config, + argv[i], value); + else + ret = perf_configset_with_option(set_config, + sections, + config_exclusive_filename, + argv[i], value); + } + } + } else usage_with_options(config_usage, config_options); } diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 71aefed..2ec958e 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h @@ -35,9 +35,12 @@ struct config_section { extern const char *config_exclusive_filename; typedef int (*config_fn_t)(const char *, const char *, void *); -typedef int (*configset_fn_t)(struct list_head *, const char *, const char *); +typedef int (*configset_fn_t)(struct list_head *, const char *, + const char *, const char *, char *); +extern int perf_configset_write_in_full(struct list_head *sections, const char *file_name); extern int perf_default_config(const char *, const char *, void *); extern int perf_config(config_fn_t fn, void *); +extern int perf_config_from_file(config_fn_t fn, const char *filename, void *data); extern int perf_config_int(const char *, const char *); extern u64 perf_config_u64(const char *, const char *); extern int perf_config_bool(const char *, const char *); diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 55ef373..2111695 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c @@ -416,7 +416,7 @@ int perf_default_config(const char *var, const char *value, return 0; } -static int perf_config_from_file(config_fn_t fn, const char *filename, void *data) +int perf_config_from_file(config_fn_t fn, const char *filename, void *data) { int ret; FILE *f = fopen(filename, "r"); @@ -506,6 +506,31 @@ out: return ret; } +int perf_configset_write_in_full(struct list_head *sections, const char *file_name) +{ + struct config_section *section; + struct config_element *element; + const char *first_line = "# this file is auto-generated."; + FILE *fp = fopen(file_name, "w"); + + if (!fp) + return -1; + + fprintf(fp, "%s\n", first_line); + /* overwrite configvariables */ + list_for_each_entry(section, sections, list) { + fprintf(fp, "[%s]\n", section->name); + list_for_each_entry(element, §ion->element_head, list) { + if (element->value) + fprintf(fp, "\t%s = %s\n", + element->name, element->value); + } + } + fclose(fp); + + return 0; +} + /* * Call this to report error for your variable that should not * get a boolean value (i.e. "[my] var" means "true"). -- 1.9.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/