Hi, all :-)
We can use the config files (i.e user wide ~/.perfconfig
and system wide $(sysconfdir)/perfconfig)
to configure perf tools. perf-config help user
manage the config files, not manually look into or edit them.
Introduce new infrastructure code for config
management features of perf-config subcommand.
This pathset is for various purposes of configuration management
showing current configs, in the near future,
showing all configs with default value,
getting current configs from the config files
or writing configs that user type on the config files, etc.
IMHO, I want to add new effective funcationalities
for config management of perf-config based on this
infrastructure code.
Thanks,
Taeung
v2:
- remove perf_config_kind (user, system or both config files)
and needless at this time, etc. (Namhyung)
- separate this patch as several patches (Namhyung)
- fix typing errors, etc.
Taeung Song (5):
perf config: Introduce perf_config_set class
perf config: Let show_config() work with perf_config_set
perf config: Prepare all default configs
perf config: Initialize perf_config_set with all default configs
perf config: Add 'list-all' option to show all perf's configs
tools/perf/Documentation/perf-config.txt | 6 +
tools/perf/builtin-config.c | 102 +++++++++++++++--
tools/perf/util/config.c | 186 +++++++++++++++++++++++++++++++
tools/perf/util/config.h | 112 +++++++++++++++++++
4 files changed, 399 insertions(+), 7 deletions(-)
create mode 100644 tools/perf/util/config.h
--
2.5.0
This infrastructure code was designed for
upcoming features of perf-config.
That collect config key-value pairs from user and
system config files (i.e. user wide ~/.perfconfig
and system wide $(sysconfdir)/perfconfig)
to manage perf's configs.
Cc: Namhyung Kim <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
tools/perf/builtin-config.c | 1 +
tools/perf/util/config.c | 123 ++++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/config.h | 21 ++++++++
3 files changed, 145 insertions(+)
create mode 100644 tools/perf/util/config.h
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index c42448e..412c725 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -12,6 +12,7 @@
#include <subcmd/parse-options.h>
#include "util/util.h"
#include "util/debug.h"
+#include "util/config.h"
static bool use_system_config, use_user_config;
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 4e72763..b9660e4 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -13,6 +13,7 @@
#include <subcmd/exec-cmd.h>
#include "util/hist.h" /* perf_hist_config */
#include "util/llvm-utils.h" /* perf_llvm_config */
+#include "config.h"
#define MAXNAME (256)
@@ -506,6 +507,128 @@ out:
return ret;
}
+static struct perf_config_item *find_config(struct list_head *config_list,
+ const char *section,
+ const char *name)
+{
+ struct perf_config_item *config;
+
+ list_for_each_entry(config, config_list, list) {
+ if (!strcmp(config->section, section) &&
+ !strcmp(config->name, name))
+ return config;
+ }
+
+ return NULL;
+}
+
+static struct perf_config_item *add_config(struct list_head *config_list,
+ const char *section,
+ const char *name)
+{
+ struct perf_config_item *config = zalloc(sizeof(*config));
+
+ if (!config)
+ return NULL;
+
+ config->section = strdup(section);
+ if (!section)
+ goto out_err;
+
+ config->name = strdup(name);
+ if (!name) {
+ free((char *)config->section);
+ goto out_err;
+ }
+
+ list_add_tail(&config->list, config_list);
+ return config;
+
+out_err:
+ free(config);
+ pr_err("%s: strdup failed\n", __func__);
+ return NULL;
+}
+
+static int set_value(struct perf_config_item *config, const char *value)
+{
+ char *val = strdup(value);
+
+ if (!val)
+ return -1;
+ config->value = val;
+
+ return 0;
+}
+
+static int collect_config(const char *var, const char *value,
+ void *configs)
+{
+ int ret = 0;
+ char *ptr, *key;
+ char *section, *name;
+ struct perf_config_item *config;
+ struct list_head *config_list = configs;
+
+ key = ptr = strdup(var);
+ if (!key) {
+ pr_err("%s: strdup failed\n", __func__);
+ return -1;
+ }
+
+ section = strsep(&ptr, ".");
+ name = ptr;
+ if (name == NULL || value == NULL) {
+ ret = -1;
+ goto out_free;
+ }
+
+ config = find_config(config_list, section, name);
+ if (!config) {
+ config = add_config(config_list, section, name);
+ if (!config) {
+ free(config->section);
+ free(config->name);
+ ret = -1;
+ goto out_free;
+ }
+ }
+
+ ret = set_value(config, value);
+
+out_free:
+ free(key);
+ return ret;
+}
+
+struct perf_config_set *perf_config_set__new(void)
+{
+ struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));
+
+ if (!perf_configs)
+ return NULL;
+
+ INIT_LIST_HEAD(&perf_configs->config_list);
+ perf_config(collect_config, &perf_configs->config_list);
+
+ return perf_configs;
+}
+
+void perf_config_set__delete(struct perf_config_set *perf_configs)
+{
+ struct perf_config_item *pos, *item;
+
+ list_for_each_entry_safe(pos, item, &perf_configs->config_list, list) {
+ list_del(&pos->list);
+ free(pos->section);
+ free(pos->name);
+ free(pos->value);
+ free(pos);
+ }
+
+ free(perf_configs);
+}
+
/*
* Call this to report error for your variable that should not
* get a boolean value (i.e. "[my] var" means "true").
diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
new file mode 100644
index 0000000..44c226f
--- /dev/null
+++ b/tools/perf/util/config.h
@@ -0,0 +1,21 @@
+#ifndef __PERF_CONFIG_H
+#define __PERF_CONFIG_H
+
+#include <stdbool.h>
+#include <linux/list.h>
+
+struct perf_config_item {
+ char *section;
+ char *name;
+ char *value;
+ struct list_head list;
+};
+
+struct perf_config_set {
+ struct list_head config_list;
+};
+
+struct perf_config_set *perf_config_set__new(void);
+void perf_config_set__delete(struct perf_config_set *perf_configs);
+
+#endif /* __PERF_CONFIG_H */
--
2.5.0
Current show_config() has a problem when user or
system config files have same config variables i.e.
# cat ~/.perfconfig
[top]
children = false
when $(sysconfdir) is /usr/local/etc
# cat /usr/local/etc/perfconfig
[top]
children = true
Before:
# perf config --user --list
top.children=false
# perf config --system --list
top.children=true
# perf config --list
top.children=true
top.children=false
Because perf_config() can call show_config()
each the config file (user and system).
So fix it.
After:
# perf config --user --list
top.children=false
# perf config --system --list
top.children=true
# perf config --list
top.children=false
Cc: Namhyung Kim <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
tools/perf/builtin-config.c | 31 ++++++++++++++++++++++++-------
1 file changed, 24 insertions(+), 7 deletions(-)
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index 412c725..2217772 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -33,13 +33,21 @@ static struct option config_options[] = {
OPT_END()
};
-static int show_config(const char *key, const char *value,
- void *cb __maybe_unused)
+static int show_config(struct perf_config_set *perf_configs)
{
- if (value)
- printf("%s=%s\n", key, value);
- else
- printf("%s\n", key);
+ struct perf_config_item *config;
+ struct list_head *config_list = &perf_configs->config_list;
+
+ if (list_empty(config_list))
+ return -1;
+
+ list_for_each_entry(config, config_list, list) {
+ char *value = config->value;
+
+ if (value)
+ printf("%s.%s=%s\n", config->section,
+ config->name, value);
+ }
return 0;
}
@@ -47,6 +55,7 @@ static int show_config(const char *key, const char *value,
int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
{
int ret = 0;
+ struct perf_config_set *perf_configs;
char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
argc = parse_options(argc, argv, config_options, config_usage,
@@ -64,13 +73,19 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
else if (use_user_config)
config_exclusive_filename = user_config;
+ perf_configs = perf_config_set__new();
+ if (!perf_configs) {
+ ret = -1;
+ goto out_err;
+ }
+
switch (actions) {
case ACTION_LIST:
if (argc) {
pr_err("Error: takes no arguments\n");
parse_options_usage(config_usage, config_options, "l", 1);
} else {
- ret = perf_config(show_config, NULL);
+ ret = show_config(perf_configs);
if (ret < 0) {
const char * config_filename = config_exclusive_filename;
if (!config_exclusive_filename)
@@ -84,5 +99,7 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
usage_with_options(config_usage, config_options);
}
+ perf_config_set__delete(perf_configs);
+out_err:
return ret;
}
--
2.5.0
To precisely manage configs,
prepare all default perf's configs that contain
default section name, variable name, value
and correct type, not string type.
In the near future, this will be used when
checking type of config variable or showing
all configs with default values, etc.
Cc: Namhyung Kim <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
tools/perf/util/config.c | 54 ++++++++++++++++++++++++++---
tools/perf/util/config.h | 89 ++++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 137 insertions(+), 6 deletions(-)
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index b9660e4..0b9ba51 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -29,6 +29,52 @@ static int config_file_eof;
const char *config_exclusive_filename;
+struct perf_config_item default_configs[] = {
+ CONF_STR_VAR(COLORS_TOP, "colors", "top", "red, default"),
+ CONF_STR_VAR(COLORS_MEDIUM, "colors", "medium", "green, default"),
+ CONF_STR_VAR(COLORS_NORMAL, "colors", "normal", "lightgray, default"),
+ CONF_STR_VAR(COLORS_SELECTED, "colors", "selected", "white, lightgray"),
+ CONF_STR_VAR(COLORS_JUMP_ARROWS, "colors", "jump_arrows", "blue, default"),
+ CONF_STR_VAR(COLORS_ADDR, "colors", "addr", "magenta, default"),
+ CONF_STR_VAR(COLORS_ROOT, "colors", "root", "white, blue"),
+ CONF_BOOL_VAR(TUI_REPORT, "tui", "report", true),
+ CONF_BOOL_VAR(TUI_ANNOTATE, "tui", "annotate", true),
+ CONF_BOOL_VAR(TUI_TOP, "tui", "top", true),
+ CONF_STR_VAR(BUILDID_DIR, "buildid", "dir", "~/.debug"),
+ CONF_BOOL_VAR(ANNOTATE_HIDE_SRC_CODE, "annotate", "hide_src_code", false),
+ CONF_BOOL_VAR(ANNOTATE_USE_OFFSET, "annotate", "use_offset", true),
+ CONF_BOOL_VAR(ANNOTATE_JUMP_ARROWS, "annotate", "jump_arrows", true),
+ CONF_BOOL_VAR(ANNOTATE_SHOW_NR_JUMPS, "annotate", "show_nr_jumps", false),
+ CONF_BOOL_VAR(ANNOTATE_SHOW_LINENR, "annotate", "show_linenr", false),
+ CONF_BOOL_VAR(ANNOTATE_SHOW_TOTAL_PERIOD, "annotate", "show_total_period", false),
+ CONF_BOOL_VAR(GTK_ANNOTATE, "gtk", "annotate", false),
+ CONF_BOOL_VAR(GTK_REPORT, "gtk", "report", false),
+ CONF_BOOL_VAR(GTK_TOP, "gtk", "top", false),
+ CONF_BOOL_VAR(PAGER_CMD, "pager", "cmd", true),
+ CONF_BOOL_VAR(PAGER_REPORT, "pager", "report", true),
+ CONF_BOOL_VAR(PAGER_ANNOTATE, "pager", "annotate", true),
+ CONF_BOOL_VAR(PAGER_TOP, "pager", "top", true),
+ CONF_BOOL_VAR(PAGER_DIFF, "pager", "diff", true),
+ CONF_STR_VAR(HELP_FORMAT, "help", "format", "man"),
+ CONF_INT_VAR(HELP_AUTOCORRECT, "help", "autocorrect", 0),
+ CONF_STR_VAR(HIST_PERCENTAGE, "hist", "percentage", "absolute"),
+ CONF_BOOL_VAR(UI_SHOW_HEADERS, "ui", "show-headers", true),
+ CONF_STR_VAR(CALL_GRAPH_RECORD_MODE, "call-graph", "record-mode", "fp"),
+ CONF_LONG_VAR(CALL_GRAPH_DUMP_SIZE, "call-graph", "dump-size", 8192),
+ CONF_STR_VAR(CALL_GRAPH_PRINT_TYPE, "call-graph", "print-type", "graph"),
+ CONF_STR_VAR(CALL_GRAPH_ORDER, "call-graph", "order", "callee"),
+ CONF_STR_VAR(CALL_GRAPH_SORT_KEY, "call-graph", "sort-key", "function"),
+ CONF_DOUBLE_VAR(CALL_GRAPH_THRESHOLD, "call-graph", "threshold", 0.5),
+ CONF_LONG_VAR(CALL_GRAPH_PRINT_LIMIT, "call-graph", "print-limit", 0),
+ CONF_BOOL_VAR(REPORT_GROUP, "report", "group", true),
+ CONF_BOOL_VAR(REPORT_CHILDREN, "report", "children", true),
+ CONF_FLOAT_VAR(REPORT_PERCENT_LIMIT, "report", "percent-limit", 0),
+ CONF_U64_VAR(REPORT_QUEUE_SIZE, "report", "queue-size", 0),
+ CONF_BOOL_VAR(TOP_CHILDREN, "top", "children", true),
+ CONF_STR_VAR(MAN_VIEWER, "man", "viewer", "man"),
+ CONF_STR_VAR(KMEM_DEFAULT, "kmem", "default", "slab"),
+};
+
static int get_next_char(void)
{
int c;
@@ -587,8 +633,8 @@ static int collect_config(const char *var, const char *value,
if (!config) {
config = add_config(config_list, section, name);
if (!config) {
- free(config->section);
- free(config->name);
+ free((char *)config->section);
+ free((char *)config->name);
ret = -1;
goto out_free;
}
@@ -620,8 +666,8 @@ void perf_config_set__delete(struct perf_config_set *perf_configs)
list_for_each_entry_safe(pos, item, &perf_configs->config_list, list) {
list_del(&pos->list);
- free(pos->section);
- free(pos->name);
+ free((char *)pos->section);
+ free((char *)pos->name);
free(pos->value);
free(pos);
}
diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
index 44c226f..3c30576 100644
--- a/tools/perf/util/config.h
+++ b/tools/perf/util/config.h
@@ -4,10 +4,30 @@
#include <stdbool.h>
#include <linux/list.h>
+enum perf_config_type {
+ CONFIG_TYPE_BOOL,
+ CONFIG_TYPE_INT,
+ CONFIG_TYPE_LONG,
+ CONFIG_TYPE_U64,
+ CONFIG_TYPE_FLOAT,
+ CONFIG_TYPE_DOUBLE,
+ CONFIG_TYPE_STRING
+};
+
struct perf_config_item {
- char *section;
- char *name;
+ const char *section;
+ const char *name;
char *value;
+ union {
+ bool b;
+ int i;
+ u32 l;
+ u64 ll;
+ float f;
+ double d;
+ const char *s;
+ } default_value;
+ enum perf_config_type type;
struct list_head list;
};
@@ -15,6 +35,71 @@ struct perf_config_set {
struct list_head config_list;
};
+enum perf_config_idx {
+ CONFIG_COLORS_TOP,
+ CONFIG_COLORS_MEDIUM,
+ CONFIG_COLORS_NORMAL,
+ CONFIG_COLORS_SELECTED,
+ CONFIG_COLORS_JUMP_ARROWS,
+ CONFIG_COLORS_ADDR,
+ CONFIG_COLORS_ROOT,
+ CONFIG_TUI_REPORT,
+ CONFIG_TUI_ANNOTATE,
+ CONFIG_TUI_TOP,
+ CONFIG_BUILDID_DIR,
+ CONFIG_ANNOTATE_HIDE_SRC_CODE,
+ CONFIG_ANNOTATE_USE_OFFSET,
+ CONFIG_ANNOTATE_JUMP_ARROWS,
+ CONFIG_ANNOTATE_SHOW_NR_JUMPS,
+ CONFIG_ANNOTATE_SHOW_LINENR,
+ CONFIG_ANNOTATE_SHOW_TOTAL_PERIOD,
+ CONFIG_GTK_ANNOTATE,
+ CONFIG_GTK_REPORT,
+ CONFIG_GTK_TOP,
+ CONFIG_PAGER_CMD,
+ CONFIG_PAGER_REPORT,
+ CONFIG_PAGER_ANNOTATE,
+ CONFIG_PAGER_TOP,
+ CONFIG_PAGER_DIFF,
+ CONFIG_HELP_FORMAT,
+ CONFIG_HELP_AUTOCORRECT,
+ CONFIG_HIST_PERCENTAGE,
+ CONFIG_UI_SHOW_HEADERS,
+ CONFIG_CALL_GRAPH_RECORD_MODE,
+ CONFIG_CALL_GRAPH_DUMP_SIZE,
+ CONFIG_CALL_GRAPH_PRINT_TYPE,
+ CONFIG_CALL_GRAPH_ORDER,
+ CONFIG_CALL_GRAPH_SORT_KEY,
+ CONFIG_CALL_GRAPH_THRESHOLD,
+ CONFIG_CALL_GRAPH_PRINT_LIMIT,
+ CONFIG_REPORT_GROUP,
+ CONFIG_REPORT_CHILDREN,
+ CONFIG_REPORT_PERCENT_LIMIT,
+ CONFIG_REPORT_QUEUE_SIZE,
+ CONFIG_TOP_CHILDREN,
+ CONFIG_MAN_VIEWER,
+ CONFIG_KMEM_DEFAULT,
+ CONFIG_END
+};
+
+#define CONF_VAR(_sec, _name, _field, _val, _type) \
+ { .section = _sec, .name = _name, .default_value._field = _val, .type = _type }
+
+#define CONF_BOOL_VAR(_idx, _sec, _name, _val) \
+ [CONFIG_##_idx] = CONF_VAR(_sec, _name, b, _val, CONFIG_TYPE_BOOL)
+#define CONF_INT_VAR(_idx, _sec, _name, _val) \
+ [CONFIG_##_idx] = CONF_VAR(_sec, _name, i, _val, CONFIG_TYPE_INT)
+#define CONF_LONG_VAR(_idx, _sec, _name, _val) \
+ [CONFIG_##_idx] = CONF_VAR(_sec, _name, l, _val, CONFIG_TYPE_LONG)
+#define CONF_U64_VAR(_idx, _sec, _name, _val) \
+ [CONFIG_##_idx] = CONF_VAR(_sec, _name, ll, _val, CONFIG_TYPE_U64)
+#define CONF_FLOAT_VAR(_idx, _sec, _name, _val) \
+ [CONFIG_##_idx] = CONF_VAR(_sec, _name, f, _val, CONFIG_TYPE_FLOAT)
+#define CONF_DOUBLE_VAR(_idx, _sec, _name, _val) \
+ [CONFIG_##_idx] = CONF_VAR(_sec, _name, d, _val, CONFIG_TYPE_DOUBLE)
+#define CONF_STR_VAR(_idx, _sec, _name, _val) \
+ [CONFIG_##_idx] = CONF_VAR(_sec, _name, s, _val, CONFIG_TYPE_STRING)
+
struct perf_config_set *perf_config_set__new(void);
void perf_config_set__delete(struct perf_config_set *perf_configs);
--
2.5.0
That show all possible config variables with
default values. The syntax examples are like below.
perf config [<file-option>] [options]
display all perf config with default values.
# perf config -a | --list-all
But configs from user or system
config file have a high priority e.g.
Default of report.children is true
# cat ~/.perfconfig
[report]
children=false
# perf config --list-all
..(omitted)..
call-graph.threshold=0.500000
call-graph.print-limit=0
report.group=true
report.children=false
report.percent-limit=0.000000
report.queue-size=0
..(omitted)..
Cc: Namhyung Kim <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
tools/perf/Documentation/perf-config.txt | 6 +++
tools/perf/builtin-config.c | 69 +++++++++++++++++++++++++++++++-
2 files changed, 74 insertions(+), 1 deletion(-)
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index 15949e2..d9fb8c3 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -9,6 +9,8 @@ SYNOPSIS
--------
[verse]
'perf config' [<file-option>] -l | --list
+or
+'perf config' [<file-option>] -a | --list-all
DESCRIPTION
-----------
@@ -29,6 +31,10 @@ OPTIONS
For writing and reading options: write to system-wide
'$(sysconfdir)/perfconfig' or read it.
+-a::
+--list-all::
+ Show current and all possible config variables with default values.
+
CONFIGURATION FILE
------------------
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index 1bc1121..7ceae55 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -22,17 +22,75 @@ static const char * const config_usage[] = {
};
enum actions {
- ACTION_LIST = 1
+ ACTION_LIST = 1,
+ ACTION_LIST_ALL
} actions;
static struct option config_options[] = {
OPT_SET_UINT('l', "list", &actions,
"show current config variables", ACTION_LIST),
+ OPT_SET_UINT('a', "list-all", &actions,
+ "show current and all possible config"
+ " variables with default values", ACTION_LIST_ALL),
OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
OPT_BOOLEAN(0, "user", &use_user_config, "use user config file"),
OPT_END()
};
+#define DEFAULT_VAL(_field) config->default_value._field
+
+static char *get_default_value(struct perf_config_item *config)
+{
+ int ret = 0;
+ char *value;
+
+ if (config->is_custom)
+ return NULL;
+
+ if (config->type == CONFIG_TYPE_BOOL)
+ ret = asprintf(&value, "%s",
+ DEFAULT_VAL(b) ? "true" : "false");
+ else if (config->type == CONFIG_TYPE_INT)
+ ret = asprintf(&value, "%d", DEFAULT_VAL(i));
+ else if (config->type == CONFIG_TYPE_LONG)
+ ret = asprintf(&value, "%u", DEFAULT_VAL(l));
+ else if (config->type == CONFIG_TYPE_U64)
+ ret = asprintf(&value, "%"PRId64, DEFAULT_VAL(ll));
+ else if (config->type == CONFIG_TYPE_FLOAT)
+ ret = asprintf(&value, "%f", DEFAULT_VAL(f));
+ else if (config->type == CONFIG_TYPE_DOUBLE)
+ ret = asprintf(&value, "%f", DEFAULT_VAL(d));
+ else
+ ret = asprintf(&value, "%s", DEFAULT_VAL(s));
+
+ if (ret < 0)
+ return NULL;
+
+ return value;
+}
+
+static int show_all_config(struct perf_config_set *perf_configs)
+{
+ char *value, *default_value;
+ struct perf_config_item *config;
+ struct list_head *config_list = &perf_configs->config_list;
+
+ list_for_each_entry(config, config_list, list) {
+ value = config->value;
+ if (!value)
+ value = default_value = get_default_value(config);
+
+ if (value)
+ printf("%s.%s=%s\n", config->section,
+ config->name, value);
+
+ free(default_value);
+ default_value = NULL;
+ }
+
+ return 0;
+}
+
static int show_config(struct perf_config_set *perf_configs)
{
bool has_value = false;
@@ -61,6 +119,9 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
struct perf_config_set *perf_configs;
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);
+
argc = parse_options(argc, argv, config_options, config_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
@@ -83,6 +144,12 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
}
switch (actions) {
+ case ACTION_LIST_ALL:
+ if (argc)
+ parse_options_usage(config_usage, config_options, "a", 1);
+ else
+ ret = show_all_config(perf_configs);
+ break;
case ACTION_LIST:
if (argc) {
pr_err("Error: takes no arguments\n");
--
2.5.0
To avoid duplicated config variables and
use perf_config_set classifying between standard
perf config variables and unknown or new config
variables other than them, initialize perf_config_set
with all default configs.
And this will be needed when showing all configs with
default value or checking correct type of a config
variable in the near future.
Cc: Namhyung Kim <[email protected]>
Cc: Jiri Olsa <[email protected]>
Signed-off-by: Taeung Song <[email protected]>
---
tools/perf/builtin-config.c | 11 +++++++----
tools/perf/util/config.c | 27 ++++++++++++++++++++++-----
tools/perf/util/config.h | 6 ++++++
3 files changed, 35 insertions(+), 9 deletions(-)
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index 2217772..1bc1121 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -35,20 +35,23 @@ static struct option config_options[] = {
static int show_config(struct perf_config_set *perf_configs)
{
+ bool has_value = false;
struct perf_config_item *config;
struct list_head *config_list = &perf_configs->config_list;
- if (list_empty(config_list))
- return -1;
-
list_for_each_entry(config, config_list, list) {
char *value = config->value;
- if (value)
+ if (value) {
printf("%s.%s=%s\n", config->section,
config->name, value);
+ has_value = true;
+ }
}
+ if (!has_value)
+ return -1;
+
return 0;
}
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 0b9ba51..5289063 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -647,6 +647,21 @@ out_free:
return ret;
}
+static struct perf_config_set *perf_config_set__init(struct perf_config_set *perf_configs)
+{
+ int i;
+ struct list_head *head = &perf_configs->config_list;
+
+ INIT_LIST_HEAD(&perf_configs->config_list);
+
+ for (i = 0; i != CONFIG_END; i++) {
+ struct perf_config_item *config = &default_configs[i];
+
+ list_add_tail(&config->list, head);
+ }
+ return perf_configs;
+}
+
struct perf_config_set *perf_config_set__new(void)
{
struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));
@@ -654,7 +669,7 @@ struct perf_config_set *perf_config_set__new(void)
if (!perf_configs)
return NULL;
- INIT_LIST_HEAD(&perf_configs->config_list);
+ perf_config_set__init(perf_configs);
perf_config(collect_config, &perf_configs->config_list);
return perf_configs;
@@ -666,10 +681,12 @@ void perf_config_set__delete(struct perf_config_set *perf_configs)
list_for_each_entry_safe(pos, item, &perf_configs->config_list, list) {
list_del(&pos->list);
- free((char *)pos->section);
- free((char *)pos->name);
- free(pos->value);
- free(pos);
+ if (pos->is_custom) {
+ free((char *)pos->section);
+ free((char *)pos->name);
+ free(pos->value);
+ free(pos);
+ }
}
free(perf_configs);
diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
index 3c30576..df47420 100644
--- a/tools/perf/util/config.h
+++ b/tools/perf/util/config.h
@@ -14,6 +14,11 @@ enum perf_config_type {
CONFIG_TYPE_STRING
};
+/**
+ * struct perf_config_item - element of perf's configs
+ *
+ * @is_custom: unknown or new config other than default config
+ */
struct perf_config_item {
const char *section;
const char *name;
@@ -28,6 +33,7 @@ struct perf_config_item {
const char *s;
} default_value;
enum perf_config_type type;
+ bool is_custom;
struct list_head list;
};
--
2.5.0
Hi Taeung,
On Mon, Mar 14, 2016 at 09:16:05PM +0900, Taeung Song wrote:
> This infrastructure code was designed for
> upcoming features of perf-config.
>
> That collect config key-value pairs from user and
> system config files (i.e. user wide ~/.perfconfig
> and system wide $(sysconfdir)/perfconfig)
> to manage perf's configs.
>
> Cc: Namhyung Kim <[email protected]>
> Cc: Jiri Olsa <[email protected]>
> Signed-off-by: Taeung Song <[email protected]>
> ---
> tools/perf/builtin-config.c | 1 +
> tools/perf/util/config.c | 123 ++++++++++++++++++++++++++++++++++++++++++++
> tools/perf/util/config.h | 21 ++++++++
> 3 files changed, 145 insertions(+)
> create mode 100644 tools/perf/util/config.h
>
> diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
> index c42448e..412c725 100644
> --- a/tools/perf/builtin-config.c
> +++ b/tools/perf/builtin-config.c
> @@ -12,6 +12,7 @@
> #include <subcmd/parse-options.h>
> #include "util/util.h"
> #include "util/debug.h"
> +#include "util/config.h"
>
> static bool use_system_config, use_user_config;
>
> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
> index 4e72763..b9660e4 100644
> --- a/tools/perf/util/config.c
> +++ b/tools/perf/util/config.c
> @@ -13,6 +13,7 @@
> #include <subcmd/exec-cmd.h>
> #include "util/hist.h" /* perf_hist_config */
> #include "util/llvm-utils.h" /* perf_llvm_config */
> +#include "config.h"
>
> #define MAXNAME (256)
>
> @@ -506,6 +507,128 @@ out:
> return ret;
> }
>
> +static struct perf_config_item *find_config(struct list_head *config_list,
> + const char *section,
> + const char *name)
> +{
> + struct perf_config_item *config;
> +
> + list_for_each_entry(config, config_list, list) {
> + if (!strcmp(config->section, section) &&
> + !strcmp(config->name, name))
> + return config;
> + }
Hmm.. why do you remove the section list?
> +
> + return NULL;
> +}
> +
> +static struct perf_config_item *add_config(struct list_head *config_list,
> + const char *section,
> + const char *name)
> +{
> + struct perf_config_item *config = zalloc(sizeof(*config));
> +
> + if (!config)
> + return NULL;
> +
> + config->section = strdup(section);
> + if (!section)
> + goto out_err;
> +
> + config->name = strdup(name);
> + if (!name) {
> + free((char *)config->section);
> + goto out_err;
> + }
> +
> + list_add_tail(&config->list, config_list);
> + return config;
> +
> +out_err:
> + free(config);
> + pr_err("%s: strdup failed\n", __func__);
> + return NULL;
> +}
> +
> +static int set_value(struct perf_config_item *config, const char *value)
> +{
> + char *val = strdup(value);
> +
> + if (!val)
> + return -1;
> + config->value = val;
It seems to overwrite old value..
Thanks,
Namhyung
> +
> + return 0;
> +}
> +
> +static int collect_config(const char *var, const char *value,
> + void *configs)
> +{
> + int ret = 0;
> + char *ptr, *key;
> + char *section, *name;
> + struct perf_config_item *config;
> + struct list_head *config_list = configs;
> +
> + key = ptr = strdup(var);
> + if (!key) {
> + pr_err("%s: strdup failed\n", __func__);
> + return -1;
> + }
> +
> + section = strsep(&ptr, ".");
> + name = ptr;
> + if (name == NULL || value == NULL) {
> + ret = -1;
> + goto out_free;
> + }
> +
> + config = find_config(config_list, section, name);
> + if (!config) {
> + config = add_config(config_list, section, name);
> + if (!config) {
> + free(config->section);
> + free(config->name);
> + ret = -1;
> + goto out_free;
> + }
> + }
> +
> + ret = set_value(config, value);
> +
> +out_free:
> + free(key);
> + return ret;
> +}
> +
> +struct perf_config_set *perf_config_set__new(void)
> +{
> + struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));
> +
> + if (!perf_configs)
> + return NULL;
> +
> + INIT_LIST_HEAD(&perf_configs->config_list);
> + perf_config(collect_config, &perf_configs->config_list);
> +
> + return perf_configs;
> +}
> +
> +void perf_config_set__delete(struct perf_config_set *perf_configs)
> +{
> + struct perf_config_item *pos, *item;
> +
> + list_for_each_entry_safe(pos, item, &perf_configs->config_list, list) {
> + list_del(&pos->list);
> + free(pos->section);
> + free(pos->name);
> + free(pos->value);
> + free(pos);
> + }
> +
> + free(perf_configs);
> +}
> +
> /*
> * Call this to report error for your variable that should not
> * get a boolean value (i.e. "[my] var" means "true").
> diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
> new file mode 100644
> index 0000000..44c226f
> --- /dev/null
> +++ b/tools/perf/util/config.h
> @@ -0,0 +1,21 @@
> +#ifndef __PERF_CONFIG_H
> +#define __PERF_CONFIG_H
> +
> +#include <stdbool.h>
> +#include <linux/list.h>
> +
> +struct perf_config_item {
> + char *section;
> + char *name;
> + char *value;
> + struct list_head list;
> +};
> +
> +struct perf_config_set {
> + struct list_head config_list;
> +};
> +
> +struct perf_config_set *perf_config_set__new(void);
> +void perf_config_set__delete(struct perf_config_set *perf_configs);
> +
> +#endif /* __PERF_CONFIG_H */
> --
> 2.5.0
>
Hi, Namhyung
On 03/17/2016 09:31 PM, Namhyung Kim wrote:
> Hi Taeung,
>
> On Mon, Mar 14, 2016 at 09:16:05PM +0900, Taeung Song wrote:
>> This infrastructure code was designed for
>> upcoming features of perf-config.
>>
>> That collect config key-value pairs from user and
>> system config files (i.e. user wide ~/.perfconfig
>> and system wide $(sysconfdir)/perfconfig)
>> to manage perf's configs.
>>
>> Cc: Namhyung Kim <[email protected]>
>> Cc: Jiri Olsa <[email protected]>
>> Signed-off-by: Taeung Song <[email protected]>
>> ---
>> tools/perf/builtin-config.c | 1 +
>> tools/perf/util/config.c | 123 ++++++++++++++++++++++++++++++++++++++++++++
>> tools/perf/util/config.h | 21 ++++++++
>> 3 files changed, 145 insertions(+)
>> create mode 100644 tools/perf/util/config.h
>>
>> diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
>> index c42448e..412c725 100644
>> --- a/tools/perf/builtin-config.c
>> +++ b/tools/perf/builtin-config.c
>> @@ -12,6 +12,7 @@
>> #include <subcmd/parse-options.h>
>> #include "util/util.h"
>> #include "util/debug.h"
>> +#include "util/config.h"
>>
>> static bool use_system_config, use_user_config;
>>
>> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
>> index 4e72763..b9660e4 100644
>> --- a/tools/perf/util/config.c
>> +++ b/tools/perf/util/config.c
>> @@ -13,6 +13,7 @@
>> #include <subcmd/exec-cmd.h>
>> #include "util/hist.h" /* perf_hist_config */
>> #include "util/llvm-utils.h" /* perf_llvm_config */
>> +#include "config.h"
>>
>> #define MAXNAME (256)
>>
>> @@ -506,6 +507,128 @@ out:
>> return ret;
>> }
>>
>> +static struct perf_config_item *find_config(struct list_head *config_list,
>> + const char *section,
>> + const char *name)
>> +{
>> + struct perf_config_item *config;
>> +
>> + list_for_each_entry(config, config_list, list) {
>> + if (!strcmp(config->section, section) &&
>> + !strcmp(config->name, name))
>> + return config;
>> + }
>
> Hmm.. why do you remove the section list?
>
IMHO, there are several reasons
1) To use only one list (default config, custom config(user/system))
1-1) I used two list that were 'list_head sections'
and 'config_item default_configs[]'. So if checking
type of config variable, two for-loop must be needed
for each list. Because two structure was different i.e.
'sections' list mean config_section list
that each section contain config_element list.
(there wasn't telling about correct type of 'value' instead of
string(char *))
struct config_element {
char *name;
char *value;
struct list_head list;
};
struct config_section {
char *name;
struct list_head element_head;
struct list_head list;
};
'struct config_item default_configs[]' mean all default configs.
struct config_item {
const char *section;
const char *name;
union {
bool b;
int i;
u32 l;
u64 ll;
float f;
double d;
const char *s;
} value;
enum config_type type;
const char *desc;
};
IMHO, I think this is a bit complex
and I want to simplify the perf's config list on perf-config.
2) A small number of perf's configs
I think perf's configs aren't too many so I think
two structure for section and element aren't needed.
3) A object for a config variable need to have enough info for itself
This is a bit similar to 1) reason.
If using only 'struct config_item' for the config list,
it can contain section name, name, values(default, user config,
system config, both config), correct type, etc.
If we do, we needn't to find detail for a config variable at other
objects e.g.
When we find correct type of a config variable,
we needn't to do for-loop for default_configs[] in order to know the type.
I think this is better than old two structure.
>> +
>> + return NULL;
>> +}
>> +
>> +static struct perf_config_item *add_config(struct list_head *config_list,
>> + const char *section,
>> + const char *name)
>> +{
>> + struct perf_config_item *config = zalloc(sizeof(*config));
>> +
>> + if (!config)
>> + return NULL;
>> +
>> + config->section = strdup(section);
>> + if (!section)
>> + goto out_err;
>> +
>> + config->name = strdup(name);
>> + if (!name) {
>> + free((char *)config->section);
>> + goto out_err;
>> + }
>> +
>> + list_add_tail(&config->list, config_list);
>> + return config;
>> +
>> +out_err:
>> + free(config);
>> + pr_err("%s: strdup failed\n", __func__);
>> + return NULL;
>> +}
>> +
>> +static int set_value(struct perf_config_item *config, const char *value)
>> +{
>> + char *val = strdup(value);
>> +
>> + if (!val)
>> + return -1;
>> + config->value = val;
>
> It seems to overwrite old value..
>
Yes, I know it.
If don't using '--user' or '--system',
there isn't exclusive config file path
then have to read both config files.
But because user config file has a high order of priority,
if two config file has same variable, old value(for system config)
must be overwrote by new value(for user config).
Thanks,
Taeung
>
>
>> +
>> + return 0;
>> +}
>> +
>> +static int collect_config(const char *var, const char *value,
>> + void *configs)
>> +{
>> + int ret = 0;
>> + char *ptr, *key;
>> + char *section, *name;
>> + struct perf_config_item *config;
>> + struct list_head *config_list = configs;
>> +
>> + key = ptr = strdup(var);
>> + if (!key) {
>> + pr_err("%s: strdup failed\n", __func__);
>> + return -1;
>> + }
>> +
>> + section = strsep(&ptr, ".");
>> + name = ptr;
>> + if (name == NULL || value == NULL) {
>> + ret = -1;
>> + goto out_free;
>> + }
>> +
>> + config = find_config(config_list, section, name);
>> + if (!config) {
>> + config = add_config(config_list, section, name);
>> + if (!config) {
>> + free(config->section);
>> + free(config->name);
>> + ret = -1;
>> + goto out_free;
>> + }
>> + }
>> +
>> + ret = set_value(config, value);
>> +
>> +out_free:
>> + free(key);
>> + return ret;
>> +}
>> +
>> +struct perf_config_set *perf_config_set__new(void)
>> +{
>> + struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));
>> +
>> + if (!perf_configs)
>> + return NULL;
>> +
>> + INIT_LIST_HEAD(&perf_configs->config_list);
>> + perf_config(collect_config, &perf_configs->config_list);
>> +
>> + return perf_configs;
>> +}
>> +
>> +void perf_config_set__delete(struct perf_config_set *perf_configs)
>> +{
>> + struct perf_config_item *pos, *item;
>> +
>> + list_for_each_entry_safe(pos, item, &perf_configs->config_list, list) {
>> + list_del(&pos->list);
>> + free(pos->section);
>> + free(pos->name);
>> + free(pos->value);
>> + free(pos);
>> + }
>> +
>> + free(perf_configs);
>> +}
>> +
>> /*
>> * Call this to report error for your variable that should not
>> * get a boolean value (i.e. "[my] var" means "true").
>> diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
>> new file mode 100644
>> index 0000000..44c226f
>> --- /dev/null
>> +++ b/tools/perf/util/config.h
>> @@ -0,0 +1,21 @@
>> +#ifndef __PERF_CONFIG_H
>> +#define __PERF_CONFIG_H
>> +
>> +#include <stdbool.h>
>> +#include <linux/list.h>
>> +
>> +struct perf_config_item {
>> + char *section;
>> + char *name;
>> + char *value;
>> + struct list_head list;
>> +};
>> +
>> +struct perf_config_set {
>> + struct list_head config_list;
>> +};
>> +
>> +struct perf_config_set *perf_config_set__new(void);
>> +void perf_config_set__delete(struct perf_config_set *perf_configs);
>> +
>> +#endif /* __PERF_CONFIG_H */
>> --
>> 2.5.0
>>
On Thu, Mar 17, 2016 at 11:10:12PM +0900, Taeung Song wrote:
> Hi, Namhyung
>
> On 03/17/2016 09:31 PM, Namhyung Kim wrote:
> >Hi Taeung,
> >
> >On Mon, Mar 14, 2016 at 09:16:05PM +0900, Taeung Song wrote:
> >>This infrastructure code was designed for
> >>upcoming features of perf-config.
> >>
> >>That collect config key-value pairs from user and
> >>system config files (i.e. user wide ~/.perfconfig
> >>and system wide $(sysconfdir)/perfconfig)
> >>to manage perf's configs.
> >>
> >>Cc: Namhyung Kim <[email protected]>
> >>Cc: Jiri Olsa <[email protected]>
> >>Signed-off-by: Taeung Song <[email protected]>
> >>---
> >> tools/perf/builtin-config.c | 1 +
> >> tools/perf/util/config.c | 123 ++++++++++++++++++++++++++++++++++++++++++++
> >> tools/perf/util/config.h | 21 ++++++++
> >> 3 files changed, 145 insertions(+)
> >> create mode 100644 tools/perf/util/config.h
> >>
> >>diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
> >>index c42448e..412c725 100644
> >>--- a/tools/perf/builtin-config.c
> >>+++ b/tools/perf/builtin-config.c
> >>@@ -12,6 +12,7 @@
> >> #include <subcmd/parse-options.h>
> >> #include "util/util.h"
> >> #include "util/debug.h"
> >>+#include "util/config.h"
> >>
> >> static bool use_system_config, use_user_config;
> >>
> >>diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
> >>index 4e72763..b9660e4 100644
> >>--- a/tools/perf/util/config.c
> >>+++ b/tools/perf/util/config.c
> >>@@ -13,6 +13,7 @@
> >> #include <subcmd/exec-cmd.h>
> >> #include "util/hist.h" /* perf_hist_config */
> >> #include "util/llvm-utils.h" /* perf_llvm_config */
> >>+#include "config.h"
> >>
> >> #define MAXNAME (256)
> >>
> >>@@ -506,6 +507,128 @@ out:
> >> return ret;
> >> }
> >>
> >>+static struct perf_config_item *find_config(struct list_head *config_list,
> >>+ const char *section,
> >>+ const char *name)
> >>+{
> >>+ struct perf_config_item *config;
> >>+
> >>+ list_for_each_entry(config, config_list, list) {
> >>+ if (!strcmp(config->section, section) &&
> >>+ !strcmp(config->name, name))
> >>+ return config;
> >>+ }
> >
> >Hmm.. why do you remove the section list?
> >
>
> IMHO, there are several reasons
>
> 1) To use only one list (default config, custom config(user/system))
>
> 1-1) I used two list that were 'list_head sections'
> and 'config_item default_configs[]'. So if checking
> type of config variable, two for-loop must be needed
> for each list. Because two structure was different i.e.
>
> 'sections' list mean config_section list
> that each section contain config_element list.
> (there wasn't telling about correct type of 'value' instead of string(char
> *))
>
> struct config_element {
> char *name;
> char *value;
> struct list_head list;
> };
>
> struct config_section {
> char *name;
> struct list_head element_head;
> struct list_head list;
> };
>
> 'struct config_item default_configs[]' mean all default configs.
>
> struct config_item {
> const char *section;
> const char *name;
> union {
> bool b;
> int i;
> u32 l;
> u64 ll;
> float f;
> double d;
> const char *s;
> } value;
> enum config_type type;
> const char *desc;
> };
>
>
> IMHO, I think this is a bit complex
> and I want to simplify the perf's config list on perf-config.
>
> 2) A small number of perf's configs
>
> I think perf's configs aren't too many so I think
> two structure for section and element aren't needed.
OK.
>
> 3) A object for a config variable need to have enough info for itself
>
> This is a bit similar to 1) reason.
> If using only 'struct config_item' for the config list,
> it can contain section name, name, values(default, user config,
> system config, both config), correct type, etc.
>
> If we do, we needn't to find detail for a config variable at other objects
> e.g.
> When we find correct type of a config variable,
> we needn't to do for-loop for default_configs[] in order to know the
> type.
I'm not sure I understand you correctly, but I think this is not
related to the two-level structure.
>
>
> I think this is better than old two structure.
>
> >>+
> >>+ return NULL;
> >>+}
> >>+
> >>+static struct perf_config_item *add_config(struct list_head *config_list,
> >>+ const char *section,
> >>+ const char *name)
> >>+{
> >>+ struct perf_config_item *config = zalloc(sizeof(*config));
> >>+
> >>+ if (!config)
> >>+ return NULL;
> >>+
> >>+ config->section = strdup(section);
> >>+ if (!section)
> >>+ goto out_err;
> >>+
> >>+ config->name = strdup(name);
> >>+ if (!name) {
> >>+ free((char *)config->section);
> >>+ goto out_err;
> >>+ }
> >>+
> >>+ list_add_tail(&config->list, config_list);
> >>+ return config;
> >>+
> >>+out_err:
> >>+ free(config);
> >>+ pr_err("%s: strdup failed\n", __func__);
> >>+ return NULL;
> >>+}
> >>+
> >>+static int set_value(struct perf_config_item *config, const char *value)
> >>+{
> >>+ char *val = strdup(value);
> >>+
> >>+ if (!val)
> >>+ return -1;
> >>+ config->value = val;
> >
> >It seems to overwrite old value..
> >
>
> Yes, I know it.
> If don't using '--user' or '--system',
> there isn't exclusive config file path
> then have to read both config files.
>
> But because user config file has a high order of priority,
> if two config file has same variable, old value(for system config)
> must be overwrote by new value(for user config).
But shouldn't it free the old value before overwriting?
Thanks,
Namhyung
>
> >
> >
> >>+
> >>+ return 0;
> >>+}
On 03/18/2016 08:27 AM, Namhyung Kim wrote:
> On Thu, Mar 17, 2016 at 11:10:12PM +0900, Taeung Song wrote:
>> Hi, Namhyung
>>
>> On 03/17/2016 09:31 PM, Namhyung Kim wrote:
>>> Hi Taeung,
>>>
>>> On Mon, Mar 14, 2016 at 09:16:05PM +0900, Taeung Song wrote:
>>>> This infrastructure code was designed for
>>>> upcoming features of perf-config.
>>>>
>>>> That collect config key-value pairs from user and
>>>> system config files (i.e. user wide ~/.perfconfig
>>>> and system wide $(sysconfdir)/perfconfig)
>>>> to manage perf's configs.
>>>>
>>>> Cc: Namhyung Kim <[email protected]>
>>>> Cc: Jiri Olsa <[email protected]>
>>>> Signed-off-by: Taeung Song <[email protected]>
>>>> ---
>>>> tools/perf/builtin-config.c | 1 +
>>>> tools/perf/util/config.c | 123 ++++++++++++++++++++++++++++++++++++++++++++
>>>> tools/perf/util/config.h | 21 ++++++++
>>>> 3 files changed, 145 insertions(+)
>>>> create mode 100644 tools/perf/util/config.h
>>>>
>>>> diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
>>>> index c42448e..412c725 100644
>>>> --- a/tools/perf/builtin-config.c
>>>> +++ b/tools/perf/builtin-config.c
>>>> @@ -12,6 +12,7 @@
>>>> #include <subcmd/parse-options.h>
>>>> #include "util/util.h"
>>>> #include "util/debug.h"
>>>> +#include "util/config.h"
>>>>
>>>> static bool use_system_config, use_user_config;
>>>>
>>>> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
>>>> index 4e72763..b9660e4 100644
>>>> --- a/tools/perf/util/config.c
>>>> +++ b/tools/perf/util/config.c
>>>> @@ -13,6 +13,7 @@
>>>> #include <subcmd/exec-cmd.h>
>>>> #include "util/hist.h" /* perf_hist_config */
>>>> #include "util/llvm-utils.h" /* perf_llvm_config */
>>>> +#include "config.h"
>>>>
>>>> #define MAXNAME (256)
>>>>
>>>> @@ -506,6 +507,128 @@ out:
>>>> return ret;
>>>> }
>>>>
>>>> +static struct perf_config_item *find_config(struct list_head *config_list,
>>>> + const char *section,
>>>> + const char *name)
>>>> +{
>>>> + struct perf_config_item *config;
>>>> +
>>>> + list_for_each_entry(config, config_list, list) {
>>>> + if (!strcmp(config->section, section) &&
>>>> + !strcmp(config->name, name))
>>>> + return config;
>>>> + }
>>>
>>> Hmm.. why do you remove the section list?
>>>
>>
>> IMHO, there are several reasons
>>
>> 1) To use only one list (default config, custom config(user/system))
>>
>> 1-1) I used two list that were 'list_head sections'
>> and 'config_item default_configs[]'. So if checking
>> type of config variable, two for-loop must be needed
>> for each list. Because two structure was different i.e.
>>
>> 'sections' list mean config_section list
>> that each section contain config_element list.
>> (there wasn't telling about correct type of 'value' instead of string(char
>> *))
>>
>> struct config_element {
>> char *name;
>> char *value;
>> struct list_head list;
>> };
>>
>> struct config_section {
>> char *name;
>> struct list_head element_head;
>> struct list_head list;
>> };
>>
>> 'struct config_item default_configs[]' mean all default configs.
>>
>> struct config_item {
>> const char *section;
>> const char *name;
>> union {
>> bool b;
>> int i;
>> u32 l;
>> u64 ll;
>> float f;
>> double d;
>> const char *s;
>> } value;
>> enum config_type type;
>> const char *desc;
>> };
>>
>>
>> IMHO, I think this is a bit complex
>> and I want to simplify the perf's config list on perf-config.
>>
>> 2) A small number of perf's configs
>>
>> I think perf's configs aren't too many so I think
>> two structure for section and element aren't needed.
>
> OK.
>
>
>>
>> 3) A object for a config variable need to have enough info for itself
>>
>> This is a bit similar to 1) reason.
>> If using only 'struct config_item' for the config list,
>> it can contain section name, name, values(default, user config,
>> system config, both config), correct type, etc.
>>
>> If we do, we needn't to find detail for a config variable at other objects
>> e.g.
>> When we find correct type of a config variable,
>> we needn't to do for-loop for default_configs[] in order to know the
>> type.
>
> I'm not sure I understand you correctly, but I think this is not
> related to the two-level structure.
What you said is right.
I just thought using two lists (list_head sections, default_configs[])
was complex..
At this patchset, I only focused on simplifying the config list on
perf-config..
As you said, it hasn't problems to use the two-level structure i.e.
struct config_element
struct config_section (that has multiple elements)
So, what about this structures ?
(you may already think about it, but..)
struct config_element {
char *name;
char *value; /*from the two config file (user/system)*/
union {
bool b;
int i;
u32 l;
u64 ll;
float f;
double d;
const char *s;
} default_value; /* perf's default config value */
enum config_type type;
struct list_head list;
};
struct config_section {
char *name;
struct list_head element_head;
struct list_head list;
};
Because I want to use only one list (default_configs + sections)
for more concise code than old code.
>
>>
>>
>> I think this is better than old two structure.
>>
>>>> +
>>>> + return NULL;
>>>> +}
>>>> +
>>>> +static struct perf_config_item *add_config(struct list_head *config_list,
>>>> + const char *section,
>>>> + const char *name)
>>>> +{
>>>> + struct perf_config_item *config = zalloc(sizeof(*config));
>>>> +
>>>> + if (!config)
>>>> + return NULL;
>>>> +
>>>> + config->section = strdup(section);
>>>> + if (!section)
>>>> + goto out_err;
>>>> +
>>>> + config->name = strdup(name);
>>>> + if (!name) {
>>>> + free((char *)config->section);
>>>> + goto out_err;
>>>> + }
>>>> +
>>>> + list_add_tail(&config->list, config_list);
>>>> + return config;
>>>> +
>>>> +out_err:
>>>> + free(config);
>>>> + pr_err("%s: strdup failed\n", __func__);
>>>> + return NULL;
>>>> +}
>>>> +
>>>> +static int set_value(struct perf_config_item *config, const char *value)
>>>> +{
>>>> + char *val = strdup(value);
>>>> +
>>>> + if (!val)
>>>> + return -1;
>>>> + config->value = val;
>>>
>>> It seems to overwrite old value..
>>>
>>
>> Yes, I know it.
>> If don't using '--user' or '--system',
>> there isn't exclusive config file path
>> then have to read both config files.
>>
>> But because user config file has a high order of priority,
>> if two config file has same variable, old value(for system config)
>> must be overwrote by new value(for user config).
>
> But shouldn't it free the old value before overwriting?
>
Sorry, I missed free() out.
I'll fix it.
Thanks,
Taeung
>
>>
>>>
>>>
>>>> +
>>>> + return 0;
>>>> +}