* [PATCH v7 0/7] perf tools: Add 'perf-config' command
@ 2015-10-04 7:35 Taeung Song
2015-10-04 7:35 ` [PATCH v7 1/7] " Taeung Song
` (6 more replies)
0 siblings, 7 replies; 12+ messages in thread
From: Taeung Song @ 2015-10-04 7:35 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: linux-kernel, jolsa, namhyung, Ingo Molnar, Taeung Song
So far, it is difficult that the state of perf configs is looked through
and there's no knowing what kind of other variables except variables in perfconfig.example.
Also perf configs can't be changed without manually modifying $HOME/.perfconfig or
$(sysconfdir)/perfconfig file. So I suggest this patchset of the perf-config command
which can list, get, set, remove perf configs or list with default config values as below.
Taeung Song (7):
[PATCH v7 1/7] perf tools: Add 'perf-config' command
[PATCH v7 2/7] perf config: Add '--system' and '--user' options to select which
config file is used
[PATCH v7 3/7] perf config: Add a option 'list-all' to perf-config
[PATCH v7 4/7] perf config: Add 'get' functionality
[PATCH v7 5/7] perf config: Add 'set' feature
[PATCH v7 6/7] perf config: normalize a value depending on default type of it
[PATCH v7 7/7] perf config: Add a option 'remove' to perf-config
Changes in v7:
- Modify explanations of syntax and options(color, gtk, tui, buildid, annotate)
to be better proper descriptions as suggested by Arnaldo (PATCH v7 1/7)
Changes in v6:
- Split a 'set' feature patch into two patch to separate normalize_value() from it.
(PATCH v6 5/7, PATCH v6 6/7)
- Bug fix : 'remove' and 'set' malfunctions when without a specific file-option.
(If file-option isn't used, 'remove' feature had to use both user and system
config file and 'set' feature had to only handle user config file.)
(PATCH v6 5/7, PATCH v6 7/7)
Changes in v5:
- Simplify the switch statement in cmd_config()
- Set a config file path with '--system' or '--user'
instead of '--global' or '--system' as suggested by Namhyung. (PATCH v5 2/6)
- The patch about 'get' and 'set 'split into two patchs
as suggested by Namhyung. (PATCH v5 4/6, PATCH v5 5/6)
Changes in v4:
- If some config value is default value, notice it is '(default)'
as suggested by Jirka. (PATCH v4 3/5)
- If there wasn't any perfconfig file, perf-config malfunctioned like
Jirka pointed out. So add exception routine with '--global' and '--system'
option which can select perf config file path. (PATCH v4 2/5)
Changes in v3:
- Add a config variable 'kmem.default' with a default value as suggested by Namhyung.
(PATCH v3 2/5, PATCH v4 3/5)
Changes in v2:
- Change option name of listing all configs as '--list-all' instead of '--all'
as suggested by Namhyung. (PATCH v2 3/4, PATCH v4 4/5)
- Correct small infelicities or typing errors in a perf-config documention
as suggested by Arnaldo. (PATCH v2 1/4, PATCH v4 1/5)
- Declaration a global variable 'static struct default_configsets' has config variables
with default values instead of using a 'util/PERFCONFIG-DEFAULT' file.
(PATCH v2 3/4, PATCH v4 3/5)
- Add a function to normalize a value and check data type of it.
(PATCH v2 2/4, PATCH v4 3/5)
- Simplify parsing arguments as arguments is just divided by '=' and then
in front of '.' is a section, between '.' and '=' is a name, and behind '=' is a value.
(PATCH v2 2/4, PATCH v4 3/5)
- If run perf-config command without any option, perf-config work as '--list'.
(PATCH v2 1/4, PATCH v4 1/5)
tools/perf/Build | 1 +
tools/perf/Documentation/perf-config.txt | 422 +++++++++++++++++
tools/perf/builtin-config.c | 769 +++++++++++++++++++++++++++++++
tools/perf/builtin.h | 1 +
tools/perf/command-list.txt | 1 +
tools/perf/perf.c | 1 +
tools/perf/util/cache.h | 18 +
tools/perf/util/config.c | 31 +-
8 files changed, 1242 insertions(+), 2 deletions(-)
create mode 100644 tools/perf/Documentation/perf-config.txt
create mode 100644 tools/perf/builtin-config.c
--
1.9.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v7 1/7] perf tools: Add 'perf-config' command
2015-10-04 7:35 [PATCH v7 0/7] perf tools: Add 'perf-config' command Taeung Song
@ 2015-10-04 7:35 ` Taeung Song
2015-10-21 3:10 ` Namhyung Kim
2015-10-04 7:35 ` [PATCH v7 2/7] perf config: Add '--system' and '--user' options to select which config file is used Taeung Song
` (5 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Taeung Song @ 2015-10-04 7:35 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: linux-kernel, jolsa, namhyung, Ingo Molnar, Taeung Song
The perf configuration file contains many variables which can make
the perf command's action more effective.
But looking through state of configuration is difficult and there's no knowing
what kind of other variables except variables in perfconfig.example exist.
So This patch adds 'perf-config' command with '--list' option and a document for it.
perf config [options]
display current perf config variables.
# perf config
or
# perf config -l | --list
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
tools/perf/Build | 1 +
tools/perf/Documentation/perf-config.txt | 396 +++++++++++++++++++++++++++++++
tools/perf/builtin-config.c | 62 +++++
tools/perf/builtin.h | 1 +
tools/perf/command-list.txt | 1 +
tools/perf/perf.c | 1 +
6 files changed, 462 insertions(+)
create mode 100644 tools/perf/Documentation/perf-config.txt
create mode 100644 tools/perf/builtin-config.c
diff --git a/tools/perf/Build b/tools/perf/Build
index 7223745..2c7aaf2 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -1,5 +1,6 @@
perf-y += builtin-bench.o
perf-y += builtin-annotate.o
+perf-y += builtin-config.o
perf-y += builtin-diff.o
perf-y += builtin-evlist.o
perf-y += builtin-help.o
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
new file mode 100644
index 0000000..e8013b3
--- /dev/null
+++ b/tools/perf/Documentation/perf-config.txt
@@ -0,0 +1,396 @@
+perf-config(1)
+==============
+
+NAME
+----
+perf-config - Get and set variables in a configuration file.
+
+SYNOPSIS
+--------
+[verse]
+'perf config' -l | --list
+
+DESCRIPTION
+-----------
+You can manage variables in a configuration file with this command.
+
+OPTIONS
+-------
+
+-l::
+--list::
+ Show current config variables, name and value, for all sections.
+
+CONFIGURATION FILE
+------------------
+
+The Perf configuration file contains many variables which can make
+the perf command's action more effective.
+The '$HOME/.perfconfig' file is used to store a per-user configuration.
+The file '$(sysconfdir)/perfconfig' can be used to
+store a system-wide default configuration.
+
+The variables are divided into sections. In each section, the variables
+that are composed of a name and value.
+
+Syntax
+~~~~~~
+
+The file consist of sections. A section starts with its name
+surrounded by square brackets and continues till the next section
+begins. Each variable belong to a section, which means that
+there must be a section header before the first variable, as below:
+Each variable are in the form 'name = value'.
+
+ [section]
+ name1 = value1
+ name2 = value2
+
+Section names are case sensitive and can contain any characters except
+newline (double quote `"` and backslash have to be escaped as `\"` and `\\`,
+respectively). Section headers can't span multiple lines.
+
+Example
+~~~~~~~
+
+Given a $HOME/.perfconfig like this:
+
+#
+# This is the config file, and
+# a '#' and ';' character indicates a comment
+#
+
+[colors]
+ # Color variables
+ top = red, default
+ medium = green, default
+ normal = lightgray, default
+ selected = white, lightgray
+ code = blue, default
+ addr = magenta, default
+ root = white, blue
+
+[tui]
+ # Defaults if linked with libslang
+ report = on
+ annotate = on
+ top = on
+
+[buildid]
+ # Default, disable using /dev/null
+ dir = ~/.debug
+
+[annotate]
+ # Defaults
+ hide_src_code = false
+ use_offset = true
+ jump_arrows = true
+ show_nr_jumps = false
+
+[help]
+ # Format can be man, info, web or html
+ format = man
+ autocorrect = 0
+
+[ui]
+ show-headers= true
+
+[call-graph]
+ # fp (framepointer), dwarf
+ record-mode = fp
+ print-type = graph
+ order = caller
+ sort-key = function
+
+Variables
+~~~~~~~~~
+
+colors.*::
+ Color variables can customize colors of the output which is printed out
+ from ‘report’, ‘top’, ’annotate’ on tui.
+ Color variables are composed of foreground and background
+ and should have two values, comma separated as below.
+
+ medium = green, lightgray
+
+ If you want to keep the background or the foregroud color set for your
+ terminal, replace the desired value with 'default'. For instance:
+
+ medium = default, default
+
+ Available colors:
+ red, green, default, black, blue, white, magenta, lightgray
+
+ colors.top::
+ ‘top’ means a overhead percentage which is more than 5%.
+ And values of this variable specify colors of percentage.
+ Basic key values are foreground-color ’red’ and
+ background-color ’default’.
+ colors.medium::
+ ‘medium’ means a overhead percentage which has more than 0.5%.
+ Default values are ’green’ and ’default’.
+ colors.normal::
+ ‘normal’ means the rest of overhead percentages
+ except ‘top’, ‘medium’, ‘selected’.
+ Default values are ’lightgray’ and ’default’.
+ colors.selected::
+ This selects the colors for the current entry in a list of entries
+ from sub-commands (top,report,annotate).
+ Default values are ’white’ and ’lightgray’.
+ colors.code::
+ Colors for arrows and lines in jumps on assembly code listings
+ such as ‘jns’,’jmp’,’jane’,etc. Default values are ‘blue’, ‘default’.
+ colors.addr::
+ This selects colors for addresses from ’annotate’.
+ Default values are ‘magenta’, ‘default’.
+ colors.root::
+ Colors for headers in the output of a sub-command ‘top’.
+ Default values are ‘white’, ‘blue’.
+
+tui.*::
+ A boolean value that controls if the TUI browser will be used
+ for subcommands having that UI.
+ By default, TUI is enabled if perf detects the required library during build
+ and this config option can control it. Available subcommands are 'top',
+ 'report' and 'annotate'.
+
+gtk.*::
+ A boolean value that controls if GTK+2 GUI browser for
+ each subcommand. By default, GUI can be enabled if perf detects the
+ required library during build and this config option can control it.
+ Available subcommands are 'top', 'report' and 'annotate'.
+
+buildid.*::
+ buildid.dir::
+ Each executable and shared library in modern distributions comes with a
+ content based identified that, if available, will be inserted in a
+ 'perf.data' file header to, at analysis time find what is needed to do
+ symbol resolution, code anotation, etc.
+
+ The recording tools also stores a hard link or copy in a per-user
+ directory, $HOME/.debug/, of binaries, shared libraries, /proc/kallsyms
+ and /proc/kcore files to be used at analysis time.
+
+ The buildid.dir variable can be used to either change this directory
+ cache location, or to disable it altogether. If you want to disable it,
+ set buildid.dir to /dev/null. The default is $HOME/.debug
+
+annotate.*::
+ There’re options which work with a ’annotate’ sub-command.
+ This options are in control of addresses, jump function, source code
+ in lines of assembly code from a specific program.
+
+ annotate.hide_src_code::
+ If a program which is analyzed has source code,
+ this option let ‘annotate’ print a list of assembly code with the source code.
+ For example, let’s see a part of a program. There’re four lines.
+ If this option is ‘false’, they can be printed
+ without source code from a program as below.
+
+ │ push %rbp
+ │ mov %rsp,%rbp
+ │ sub $0x10,%rsp
+ │ mov (%rdi),%rdx
+
+ But if this option is ‘true’, source code of the part
+ can be also printed as below.
+
+ │ struct rb_node *rb_next(const struct rb_node *node)
+ │ {
+ │ push %rbp
+ │ mov %rsp,%rbp
+ │ sub $0x10,%rsp
+ │ struct rb_node *parent;
+ │
+ │ if (RB_EMPTY_NODE(node))
+ │ mov (%rdi),%rdx
+ │ return n;
+
+ annotate.use_offset::
+ Basing on a first address of a loaded function, offset can be used.
+ Instead of using original addresses of assembly code,
+ addresses subtracted from a base address can be printed.
+ Let’s illustrate a example.
+ If a base address is 0XFFFFFFFF81624d50 as below,
+
+ ffffffff81624d50 <load0>
+
+ a address on assembly code has a specific absolute address as below
+
+ ffffffff816250b8:│ mov 0x8(%r14),%rdi
+
+ but if use_offset is ’true’, a address subtracted from a base address is printed.
+ The default is true.
+
+ 368:│ mov 0x8(%r14),%rdi
+
+ annotate.jump_arrows::
+ There can be jump instruction among assembly code.
+ Depending on a boolean value of jump_arrows,
+ arrows can be printed or not which represent
+ where do the instruction jump into as below.
+
+ │ ┌──jmp 1333
+ │ │ xchg %ax,%ax
+ │1330:│ mov %r15,%r10
+ │1333:└─→cmp %r15,%r14
+
+ If jump_arrow is ‘false’, the arrows isn’t printed as below.
+
+ │ ↓ jmp 1333
+ │ xchg %ax,%ax
+ │1330: mov %r15,%r10
+ │1333: cmp %r15,%r14
+
+ annotate.show_nr_jumps::
+ Let’s see a part of assembly code.
+
+ │1382: movb $0x1,-0x270(%rbp)
+
+ If use this, the number of branches branching to that address can be printed as below.
+
+ │1 1382: movb $0x1,-0x270(%rbp)
+
+help.*::
+ help.format:: = man
+ A format of manual page can be ‘man’, ‘info’, ‘web’ or ‘html’.
+ ’man’ is default.
+ help.autocorrect:: = 0
+ Automatically correct and execute mistyped commands after
+ waiting for the given number of deciseconds (0.1 sec).
+ Let's see a example. If a mistyped sub-command is executed like 'perf mistyped-command'
+ and this option is 0, the output is as below.
+
+ perf: 'mistyped-command' is not a perf-command. See 'perf --help’.
+
+ Or if this option is more than 1, the output can be such as.
+
+ WARNING: You called a perf program named 'mistyped-command', which does not exist.
+ Continuing under the assumption that you meant 'with-kcore'
+ in 0.1 seconds automatically...
+ Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]
+ <perf sub-command> can be record, script, report or inject
+ or: perf-with-kcore fix_buildid_cache_permissions
+
+hist.*::
+ hist.percentage::
+ This option control a way to calcurate overhead of filtered entries -
+ that means the value of this option is effective only if there's a
+ filter (by comm, dso or symbol name). Suppose a following example:
+
+ Overhead Symbols
+ ........ .......
+ 33.33% foo
+ 33.33% bar
+ 33.33% baz
+
+ This is an original overhead and we'll filter out the first 'foo'
+ entry. The value of 'relative' would increase the overhead of 'bar'
+ and 'baz' to 50.00% for each, while 'absolute' would show their
+ current overhead (33.33%).
+
+ui.*::
+ ui.show-headers::
+ There’re columns as header ‘Overhead’, ‘Children’, ‘Shared Object’, ‘Symbol’, ’self’.
+ If this option is false, they are hiden.
+
+call-graph.*::
+ When sub-commands ‘top’ and ‘report’ work with -g/—-children
+ there’re options in control of call-graph.
+
+ call-graph.record-mode::
+ The record-mode can be ‘fp’ (frame pointer) and ‘dwarf’.
+ The value of 'dwarf' is effective only if perf detect needed library
+ (libunwind or a recent version of libdw). Also it doesn't *require*
+ the dump-size option since it can use the default value of 8192 if
+ missing.
+
+ call-graph.dump-size::
+ The size of stack to dump in order to do post-unwinding. Default is 8192 (byte).
+ When using dwarf into record-mode this option should have a value.
+
+ call-graph.print-type::
+ The print-types can be graph (graph absolute), fractal (graph relative), flat.
+ This option controls a way to show overhead for each callchain entry.
+ Suppose a following example.
+
+ Overhead Symbols
+ ........ .......
+ 40.00% foo
+ |
+ --- foo
+ |
+ |--50.00%-- bar
+ | main
+ |
+ --50.00%-- baz
+ main
+
+ This output is a default format which is 'fractal'. The 'foo' came
+ from 'bar' and 'baz' exactly half and half so 'fractal' shows 50.00%
+ for each (meaning that it assumes 100% total overhead of 'foo').
+
+ The 'graph' uses absolute overhead value of 'foo' as total so each of
+ 'bar' and 'baz' callchain will have 20.00% of overhead.
+
+ call-graph.order::
+ This option controls print order of callchains. The default is
+ 'callee' which means callee is printed at top and then followed by its
+ caller and so on. The 'caller' prints it in reverse order.
+
+ call-graph.sort-key::
+ The callchains are merged if they contain same information.
+ The sort-key option determines a way to compare the callchains.
+ A value of 'sort-key' can be 'function' or 'address’.
+ The default is ‘function’.
+
+ call-graph.threshold::
+ When there're many callchains it'd print tons of lines. So perf omits
+ small callchains under a certain overhead (threshold) and this option
+ control the threashold. Default is 0.5 (%).
+
+ call-graph.print-limit::
+ This is another way to control the number of callchains printed for a
+ single entry. Default is 0 which means no limitation.
+
+report.*::
+ report.percent-limit::
+ This one is mostly same as call-graph.threshold but works for
+ histogram entries. Entries have overhead lower than this percentage
+ will not be printed. Default is 0.
+ If percent-limit is 70, the output which has percentages of
+ each overhead above 70% can be printed.
+
+ report.queue-size::
+ option to setup the maximum allocation size for session's
+ ordered events queue, if not set there's no default limit.
+
+ report.children::
+ The children means that functions called from another function.
+ If the option is true, accumulate callchain of children and show total overhead.
+ Please refer to the perf-report manual.
+
+top.*::
+ top.children::
+ This option means same as report.children.
+ So it is true, the output of ‘top’ is rearranged by each overhead into children group.
+
+man.*::
+ man.viewer::
+ This option can assign a manual tool with which a subcommand 'help' work.
+ it can used as 'man', 'woman', 'konqueror'. Default value is 'man'.
+
+pager.*::
+ pager.<subcommand>::
+ When a subcommand work as stdio instead of TUI, use pager with it.
+ Default value is 'true'.
+
+kmem.*::
+ kmem.default::
+ This option can decide which allocator is analyzed between 'slab' and 'page'
+ without using options '--slab' and '--page'.
+ Default value is 'slab'.
+
+SEE ALSO
+--------
+linkperf:perf[1], linkperf:perf-report[1]
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
new file mode 100644
index 0000000..30b1500
--- /dev/null
+++ b/tools/perf/builtin-config.c
@@ -0,0 +1,62 @@
+/*
+ * builtin-config.c
+ *
+ * Copyright (C) 2015, Taeung Song <treeze.taeung@gmail.com>
+ *
+ */
+#include "builtin.h"
+
+#include "perf.h"
+
+#include "util/cache.h"
+#include "util/parse-options.h"
+#include "util/util.h"
+#include "util/debug.h"
+
+static const char * const config_usage[] = {
+ "perf config [options]",
+ NULL
+};
+
+enum actions {
+ ACTION_LIST = 1
+} actions;
+
+static struct option config_options[] = {
+ OPT_GROUP("Action"),
+ OPT_SET_UINT('l', "list", &actions,
+ "show current config variables", ACTION_LIST),
+ OPT_END()
+};
+
+static int show_config(const char *key, const char *value,
+ void *cb __maybe_unused)
+{
+ if (value)
+ printf("%s=%s\n", key, value);
+ else
+ printf("%s\n", key);
+
+ return 0;
+}
+
+int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
+{
+ int ret = 0;
+
+ argc = parse_options(argc, argv, config_options, config_usage,
+ PARSE_OPT_STOP_AT_NON_OPTION);
+
+ switch (actions) {
+ case ACTION_LIST:
+ default:
+ if (argc) {
+ pr_err("Error: takes no arguments\n");
+ parse_options_usage(config_usage, config_options, "l", 1);
+ return -1;
+ } else
+ ret = perf_config(show_config, NULL);
+ }
+
+ return ret;
+}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 3688ad2..3f871b5 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -17,6 +17,7 @@ extern int cmd_annotate(int argc, const char **argv, const char *prefix);
extern int cmd_bench(int argc, const char **argv, const char *prefix);
extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
+extern int cmd_config(int argc, const char **argv, const char *prefix);
extern int cmd_diff(int argc, const char **argv, const char *prefix);
extern int cmd_evlist(int argc, const char **argv, const char *prefix);
extern int cmd_help(int argc, const char **argv, const char *prefix);
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 00fcaf8..acc3ea7 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -9,6 +9,7 @@ perf-buildid-cache mainporcelain common
perf-buildid-list mainporcelain common
perf-data mainporcelain common
perf-diff mainporcelain common
+perf-config mainporcelain common
perf-evlist mainporcelain common
perf-inject mainporcelain common
perf-kmem mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 1fded92..6acbfd5 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -38,6 +38,7 @@ struct cmd_struct {
static struct cmd_struct commands[] = {
{ "buildid-cache", cmd_buildid_cache, 0 },
{ "buildid-list", cmd_buildid_list, 0 },
+ { "config", cmd_config, 0 },
{ "diff", cmd_diff, 0 },
{ "evlist", cmd_evlist, 0 },
{ "help", cmd_help, 0 },
--
1.9.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v7 2/7] perf config: Add '--system' and '--user' options to select which config file is used
2015-10-04 7:35 [PATCH v7 0/7] perf tools: Add 'perf-config' command Taeung Song
2015-10-04 7:35 ` [PATCH v7 1/7] " Taeung Song
@ 2015-10-04 7:35 ` Taeung Song
2015-10-21 4:20 ` Namhyung Kim
2015-10-04 7:35 ` [PATCH v7 3/7] perf config: Add a option 'list-all' to perf-config Taeung Song
` (4 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Taeung Song @ 2015-10-04 7:35 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: linux-kernel, jolsa, namhyung, Ingo Molnar, Taeung Song
Which config file is used is decided in only perf_config().
And a perf-config command depend on perf_config() to list
config variables with values. So add '--system' and '--user'
options to select which config file to be used without perf_config().
The file-options '--system' means $(sysconfdir)/perfconfig and
'--user' means $HOME/.perfconfig. If file-option isn't used,
both system and user config file is read
but user config have priority. The syntax examples are like below
perf config [<file-option>] [options]
a specific config file.
# perf config --user | --system
or
both user and system config file.
# perf config
In addition, use List data structure which has config info.
Because perf_config() isn't used any more and directly collect
config info by perf_config_from_file() with a specific config
file path. Whichever config file or both are used, list is required
to keep and handle config variables and values.
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
tools/perf/Documentation/perf-config.txt | 14 ++-
tools/perf/builtin-config.c | 163 +++++++++++++++++++++++++++++--
tools/perf/util/cache.h | 15 +++
tools/perf/util/config.c | 4 +-
4 files changed, 187 insertions(+), 9 deletions(-)
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index e8013b3..a42d409 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' -l | --list
+'perf config' [<file-option>] -l | --list
DESCRIPTION
-----------
@@ -21,6 +21,14 @@ OPTIONS
--list::
Show current config variables, name and value, for all sections.
+--user::
+ For writing and reading options: write to user
+ '$HOME/.perfconfig' file or read it.
+
+--system::
+ For writing and reading options: write to system-wide
+ '$(sysconfdir)/perfconfig' or read it.
+
CONFIGURATION FILE
------------------
@@ -33,6 +41,10 @@ store a system-wide default configuration.
The variables are divided into sections. In each section, the variables
that are composed of a name and value.
+When reading or writing, the values are read from the system and user
+configuration files by default, and options '--system' and '--user'
+can be used to tell the command to read from or write to only that location.
+
Syntax
~~~~~~
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index 30b1500..92be3eb 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -13,8 +13,10 @@
#include "util/util.h"
#include "util/debug.h"
+static bool use_system_config, use_user_config;
+
static const char * const config_usage[] = {
- "perf config [options]",
+ "perf config [<file-option>] [options]",
NULL
};
@@ -23,19 +25,150 @@ enum actions {
} actions;
static struct option config_options[] = {
+ OPT_GROUP("Config file location"),
+ OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
+ OPT_BOOLEAN(0, "user", &use_user_config, "use user config file"),
OPT_GROUP("Action"),
OPT_SET_UINT('l', "list", &actions,
"show current config variables", ACTION_LIST),
OPT_END()
};
+static int show_config(struct list_head *sections)
+{
+ struct config_section *section;
+ struct config_element *element;
+
+ list_for_each_entry(section, sections, list) {
+ list_for_each_entry(element, §ion->element_head, list) {
+ printf("%s.%s=%s\n", section->name,
+ element->name, element->value);
+ }
+ }
+
+ return 0;
+}
-static int show_config(const char *key, const char *value,
- void *cb __maybe_unused)
+static struct config_section *find_section(struct list_head *sections,
+ const char *section_name)
{
+ struct config_section *section;
+
+ list_for_each_entry(section, sections, list)
+ if (!strcmp(section->name, section_name))
+ return section;
+
+ return NULL;
+}
+
+static struct config_element *find_element(const char *name,
+ struct config_section *section)
+{
+ struct config_element *element;
+
+ list_for_each_entry(element, §ion->element_head, list)
+ if (!strcmp(element->name, name))
+ return element;
+
+ return NULL;
+}
+
+static void find_config(struct list_head *sections,
+ struct config_section **section,
+ struct config_element **element,
+ const char *section_name, const char *name)
+{
+ *section = find_section(sections, section_name);
+
+ if (*section != NULL)
+ *element = find_element(name, *section);
+ else
+ *element = NULL;
+}
+
+static struct config_section *init_section(const char *section_name)
+{
+ struct config_section *section;
+
+ section = zalloc(sizeof(*section));
+ if (!section)
+ return NULL;
+
+ INIT_LIST_HEAD(§ion->element_head);
+ section->name = strdup(section_name);
+ if (!section->name) {
+ pr_err("%s: strdup failed\n", __func__);
+ free(section);
+ return NULL;
+ }
+
+ return section;
+}
+
+static int add_element(struct list_head *head,
+ const char *name, const char *value)
+{
+ struct config_element *element;
+
+ element = zalloc(sizeof(*element));
+ if (!element)
+ return -1;
+
+ element->name = strdup(name);
+ if (!element->name) {
+ pr_err("%s: strdup failed\n", __func__);
+ free(element);
+ return -1;
+ }
if (value)
- printf("%s=%s\n", key, value);
+ element->value = (char *)value;
else
- printf("%s\n", key);
+ element->value = NULL;
+
+ list_add_tail(&element->list, head);
+ return 0;
+}
+
+static int collect_current_config(const char *var, const char *value,
+ void *spec_sections __maybe_unused)
+{
+ struct config_section *section = NULL;
+ struct config_element *element = NULL;
+ struct list_head *sections = (struct list_head *)spec_sections;
+ char *key = strdup(var);
+ char *section_name, *name;
+
+ if (!key) {
+ pr_err("%s: strdup failed\n", __func__);
+ return -1;
+ }
+
+ section_name = strsep(&key, ".");
+ name = strsep(&key, ".");
+ free(key);
+ if (name == NULL)
+ return -1;
+
+ find_config(sections, §ion, &element, section_name, name);
+
+ if (!section) {
+ section = init_section(section_name);
+ if (!section)
+ return -1;
+ list_add_tail(§ion->list, sections);
+ }
+
+ value = strdup(value);
+ if (!value) {
+ pr_err("%s: strdup failed\n", __func__);
+ return -1;
+ }
+
+ if (!element)
+ return add_element(§ion->element_head, name, value);
+ else {
+ free(element->value);
+ element->value = (char *)value;
+ }
return 0;
}
@@ -43,10 +176,28 @@ 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 list_head sections;
+ const char *system_config = perf_etc_perfconfig();
+ char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
argc = parse_options(argc, argv, config_options, config_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
+ if (use_system_config && use_user_config) {
+ pr_err("Error: only one config file at a time\n");
+ parse_options_usage(config_usage, config_options, "user", 0);
+ parse_options_usage(NULL, config_options, "system", 0);
+ return -1;
+ }
+
+ INIT_LIST_HEAD(§ions);
+
+ if (use_system_config || (!use_system_config && !use_user_config))
+ perf_config_from_file(collect_current_config, system_config, §ions);
+
+ if (use_user_config || (!use_system_config && !use_user_config))
+ perf_config_from_file(collect_current_config, user_config, §ions);
+
switch (actions) {
case ACTION_LIST:
default:
@@ -55,7 +206,7 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
parse_options_usage(config_usage, config_options, "l", 1);
return -1;
} else
- ret = perf_config(show_config, NULL);
+ ret = show_config(§ions);
}
return ret;
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index c861373..712e82b 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -1,6 +1,7 @@
#ifndef __PERF_CACHE_H
#define __PERF_CACHE_H
+#include <linux/list.h>
#include <stdbool.h>
#include "util.h"
#include "strbuf.h"
@@ -19,14 +20,28 @@
#define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
#define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
+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;
+};
+
typedef int (*config_fn_t)(const char *, const char *, void *);
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 *);
extern int config_error_nonbool(const char *);
extern const char *perf_config_dirname(const char *, const char *);
+extern const char *perf_etc_perfconfig(void);
/* pager.c */
extern void setup_pager(void);
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 2e452ac..23fa8c5 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");
@@ -434,7 +434,7 @@ static int perf_config_from_file(config_fn_t fn, const char *filename, void *dat
return ret;
}
-static const char *perf_etc_perfconfig(void)
+const char *perf_etc_perfconfig(void)
{
static const char *system_wide;
if (!system_wide)
--
1.9.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v7 3/7] perf config: Add a option 'list-all' to perf-config
2015-10-04 7:35 [PATCH v7 0/7] perf tools: Add 'perf-config' command Taeung Song
2015-10-04 7:35 ` [PATCH v7 1/7] " Taeung Song
2015-10-04 7:35 ` [PATCH v7 2/7] perf config: Add '--system' and '--user' options to select which config file is used Taeung Song
@ 2015-10-04 7:35 ` Taeung Song
2015-10-21 5:11 ` Namhyung Kim
2015-10-04 7:35 ` [PATCH v7 4/7] perf config: Add 'get' functionality Taeung Song
` (3 subsequent siblings)
6 siblings, 1 reply; 12+ messages in thread
From: Taeung Song @ 2015-10-04 7:35 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: linux-kernel, jolsa, namhyung, Ingo Molnar, Taeung Song
A option 'list-all' is to display both current config variables and
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
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
tools/perf/Documentation/perf-config.txt | 6 +
tools/perf/builtin-config.c | 339 ++++++++++++++++++++++++++++++-
2 files changed, 343 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index a42d409..15fbbd9 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 92be3eb..8e16e18 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -21,7 +21,8 @@ static const char * const config_usage[] = {
};
enum actions {
- ACTION_LIST = 1
+ ACTION_LIST = 1,
+ ACTION_LIST_ALL
} actions;
static struct option config_options[] = {
@@ -31,8 +32,292 @@ static struct option config_options[] = {
OPT_GROUP("Action"),
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_END()
};
+
+/* section names */
+#define COLORS "colors"
+#define TUI "tui"
+#define BUILDID "buildid"
+#define ANNOTATE "annotate"
+#define GTK "gtk"
+#define PAGER "pager"
+#define HELP "help"
+#define HIST "hist"
+#define UI "ui"
+#define CALL_GRAPH "call-graph"
+#define REPORT "report"
+#define TOP "top"
+#define MAN "man"
+#define KMEM "kmem"
+
+/* config variable types */
+#define TYPE_INT "int"
+#define TYPE_LONG "long"
+#define TYPE_DIRNAME "dirname"
+#define TYPE_BOOL "bool"
+
+static struct default_configset {
+ const char *section_name;
+ const char *name, *value, *type;
+
+} default_configsets[] = {
+ {
+ .section_name = COLORS,
+ .name = "top",
+ .value = "red, default",
+ .type = NULL,
+ },
+ {
+ .section_name = COLORS,
+ .name = "medium",
+ .value = "green, default",
+ .type = NULL,
+ },
+ {
+ .section_name = COLORS,
+ .name = "normal",
+ .value = "lightgray, default",
+ .type = NULL,
+ },
+ {
+ .section_name = COLORS,
+ .name = "selected",
+ .value = "white, lightgray",
+ .type = NULL,
+ },
+ {
+ .section_name = COLORS,
+ .name = "code",
+ .value = "blue, default",
+ .type = NULL,
+ },
+ {
+ .section_name = COLORS,
+ .name = "addr",
+ .value = "magenta, default",
+ .type = NULL,
+ },
+ {
+ .section_name = COLORS,
+ .name = "root",
+ .value = "white, blue",
+ .type = NULL,
+ },
+ {
+ .section_name = TUI,
+ .name = "report",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = TUI,
+ .name = "annotate",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = TUI,
+ .name = "top",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = BUILDID,
+ .name = "dir",
+ .value = "~/.debug",
+ .type = TYPE_DIRNAME,
+ },
+ {
+ .section_name = ANNOTATE,
+ .name = "hide_src_code",
+ .value = "false",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = ANNOTATE,
+ .name = "use_offset",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = ANNOTATE,
+ .name = "jump_arrows",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = ANNOTATE,
+ .name = "show_nr_jumps",
+ .value = "false",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = GTK,
+ .name = "annotate",
+ .value = "false",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = GTK,
+ .name = "report",
+ .value = "false",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = GTK,
+ .name = "top",
+ .value = "false",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = PAGER,
+ .name = "cmd",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = PAGER,
+ .name = "report",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = PAGER,
+ .name = "annotate",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = PAGER,
+ .name = "record",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = PAGER,
+ .name = "top",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = PAGER,
+ .name = "diff",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = HELP,
+ .name = "format",
+ .value = "man",
+ .type = NULL,
+ },
+ {
+ .section_name = HELP,
+ .name = "autocorrect",
+ .value = "0",
+ .type = NULL,
+ },
+ {
+ .section_name = HIST,
+ .name = "percentage",
+ .value = "absolute",
+ .type = NULL,
+ },
+ {
+ .section_name = UI,
+ .name = "show-headers",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = CALL_GRAPH,
+ .name = "record-mode",
+ .value = "fp",
+ },
+ {
+ .section_name = CALL_GRAPH,
+ .name = "dump-size",
+ .value = "8192",
+ .type = TYPE_INT,
+ },
+ {
+ .section_name = CALL_GRAPH,
+ .name = "print-type",
+ .value = "fractal",
+ .type = NULL,
+ },
+ {
+ .section_name = CALL_GRAPH,
+ .name = "order",
+ .value = "caller",
+ .type = NULL,
+ },
+ {
+ .section_name = CALL_GRAPH,
+ .name = "sort-key",
+ .value = "function",
+ .type = NULL,
+ },
+ {
+ .section_name = CALL_GRAPH,
+ .name = "threshold",
+ .value = "0.5",
+ .type = TYPE_LONG,
+ },
+ {
+ .section_name = CALL_GRAPH,
+ .name = "print-limit",
+ .value = "0",
+ .type = TYPE_INT,
+ },
+ {
+ .section_name = REPORT,
+ .name = "children",
+ .value = "true",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = REPORT,
+ .name = "percent-limit",
+ .value = "0",
+ .type = TYPE_INT,
+ },
+ {
+ .section_name = REPORT,
+ .name = "queue-size",
+ .value = "0",
+ .type = TYPE_INT,
+ },
+ {
+ .section_name = TOP,
+ .name = "children",
+ .value = "false",
+ .type = TYPE_BOOL,
+ },
+ {
+ .section_name = MAN,
+ .name = "viewer",
+ .value = "man",
+ .type = NULL,
+ },
+ {
+ .section_name = KMEM,
+ .name = "default",
+ .value = "slab",
+ .type = NULL,
+ },
+ {
+ .section_name = NULL,
+ .name = NULL,
+ .value = NULL,
+ .type = NULL,
+ },
+};
+
static int show_config(struct list_head *sections)
{
struct config_section *section;
@@ -128,6 +413,45 @@ static int add_element(struct list_head *head,
return 0;
}
+static int show_all_config(struct list_head *sections)
+{
+ int i;
+ bool has_config;
+ struct config_section *section;
+ struct config_element *element;
+
+ for (i = 0; default_configsets[i].section_name != NULL; i++) {
+ find_config(sections, §ion, &element,
+ default_configsets[i].section_name, default_configsets[i].name);
+
+ if (!element)
+ printf("%s.%s=%s\n", default_configsets[i].section_name,
+ default_configsets[i].name, default_configsets[i].value);
+ else
+ printf("%s.%s=%s\n", section->name,
+ element->name, element->value);
+ }
+
+ /* Print config variables the default configsets haven't */
+ list_for_each_entry(section, sections, list) {
+ list_for_each_entry(element, §ion->element_head, list) {
+ has_config = false;
+ for (i = 0; default_configsets[i].section_name != NULL; i++) {
+ if (!strcmp(default_configsets[i].section_name, section->name)
+ && !strcmp(default_configsets[i].name, element->name)) {
+ has_config = true;
+ break;
+ }
+ }
+ if (!has_config)
+ printf("%s.%s=%s\n", section->name,
+ element->name, element->value);
+ }
+ }
+
+ return 0;
+}
+
static int collect_current_config(const char *var, const char *value,
void *spec_sections __maybe_unused)
{
@@ -180,6 +504,9 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
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);
+
argc = parse_options(argc, argv, config_options, config_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
@@ -199,11 +526,19 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
perf_config_from_file(collect_current_config, user_config, §ions);
switch (actions) {
+ case ACTION_LIST_ALL:
+ if (argc == 0) {
+ ret = show_all_config(§ions);
+ break;
+ }
case ACTION_LIST:
default:
if (argc) {
pr_err("Error: takes no arguments\n");
- parse_options_usage(config_usage, config_options, "l", 1);
+ if (actions == ACTION_LIST_ALL)
+ parse_options_usage(config_usage, config_options, "a", 1);
+ else
+ parse_options_usage(config_usage, config_options, "l", 1);
return -1;
} else
ret = show_config(§ions);
--
1.9.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v7 4/7] perf config: Add 'get' functionality
2015-10-04 7:35 [PATCH v7 0/7] perf tools: Add 'perf-config' command Taeung Song
` (2 preceding siblings ...)
2015-10-04 7:35 ` [PATCH v7 3/7] perf config: Add a option 'list-all' to perf-config Taeung Song
@ 2015-10-04 7:35 ` Taeung Song
2015-10-04 7:35 ` [PATCH v7 5/7] perf config: Add 'set' feature Taeung Song
` (2 subsequent siblings)
6 siblings, 0 replies; 12+ messages in thread
From: Taeung Song @ 2015-10-04 7:35 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: linux-kernel, jolsa, namhyung, Ingo Molnar, Taeung Song
This patch consists of functions
which can get specific config variables.
For the syntax examples,
perf config [<file-option>] [section.name ...]
display key-value pairs of specific config variables
# perf config report.queue-size report.children
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
tools/perf/Documentation/perf-config.txt | 2 +
tools/perf/builtin-config.c | 75 ++++++++++++++++++++++++++++++--
tools/perf/util/cache.h | 1 +
3 files changed, 74 insertions(+), 4 deletions(-)
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index 15fbbd9..7b83406 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -8,6 +8,8 @@ perf-config - Get and set variables in a configuration file.
SYNOPSIS
--------
[verse]
+'perf config' [<file-option>] [section.name ...]
+or
'perf config' [<file-option>] -l | --list
or
'perf config' [<file-option>] -a | --list-all
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index 8e16e18..731056c 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 [<file-option>] [options]",
+ "perf config [<file-option>] [options] [section.name ...]",
NULL
};
@@ -452,6 +452,35 @@ static int show_all_config(struct list_head *sections)
return 0;
}
+static int show_spec_config(struct list_head *sections,
+ const char *section_name, const char *name)
+{
+ int i;
+ struct config_section *section = NULL;
+ struct config_element *element = NULL;
+
+ find_config(sections, §ion, &element, section_name, name);
+
+ if (section && element) {
+ printf("%s.%s=%s\n", section->name,
+ element->name, element->value);
+ return 0;
+ }
+
+ for (i = 0; default_configsets[i].section_name != NULL; i++) {
+ struct default_configset *config = &default_configsets[i];
+
+ if (!strcmp(config->section_name, section_name) &&
+ !strcmp(config->name, name)) {
+ printf("%s.%s=%s (default)\n", config->section_name,
+ config->name, config->value);
+ return 0;
+ }
+ }
+
+ return -1;
+}
+
static int collect_current_config(const char *var, const char *value,
void *spec_sections __maybe_unused)
{
@@ -497,9 +526,42 @@ static int collect_current_config(const char *var, const char *value,
return 0;
}
+static int perf_configset_with_option(configset_fn_t fn, struct list_head *sections,
+ const char *var)
+{
+ char *section_name;
+ char *name;
+ const char *last_dot;
+ char *key = strdup(var);
+
+ if (!key) {
+ pr_err("%s: strdup failed\n", __func__);
+ return -1;
+ }
+ last_dot = strchr(key, '.');
+ /*
+ * Since "key" actually contains the section name and the real
+ * key name separated by a dot, we have to know where the dot is.
+ */
+ if (last_dot == NULL || last_dot == key) {
+ pr_err("The config variable does not contain a section: %s\n", key);
+ return -1;
+ }
+ if (!last_dot[1]) {
+ pr_err("The config varible does not contain variable name: %s\n", key);
+ return -1;
+ }
+
+ section_name = strsep(&key, ".");
+ name = strsep(&key, ".");
+ free(key);
+
+ return fn(sections, section_name, name);
+}
+
int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
{
- int ret = 0;
+ int i, ret = 0;
struct list_head sections;
const char *system_config = perf_etc_perfconfig();
char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
@@ -532,7 +594,6 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
break;
}
case ACTION_LIST:
- default:
if (argc) {
pr_err("Error: takes no arguments\n");
if (actions == ACTION_LIST_ALL)
@@ -540,7 +601,13 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
else
parse_options_usage(config_usage, config_options, "l", 1);
return -1;
- } else
+ }
+ default:
+ if (argc)
+ for (i = 0; argv[i]; i++)
+ ret = perf_configset_with_option(show_spec_config, §ions,
+ argv[i]);
+ else
ret = show_config(§ions);
}
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 712e82b..e9bb75e 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -33,6 +33,7 @@ struct config_section {
};
typedef int (*config_fn_t)(const char *, const char *, void *);
+typedef int (*configset_fn_t)(struct list_head *, const char *, const char *);
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);
--
1.9.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v7 5/7] perf config: Add 'set' feature
2015-10-04 7:35 [PATCH v7 0/7] perf tools: Add 'perf-config' command Taeung Song
` (3 preceding siblings ...)
2015-10-04 7:35 ` [PATCH v7 4/7] perf config: Add 'get' functionality Taeung Song
@ 2015-10-04 7:35 ` Taeung Song
2015-10-04 7:35 ` [PATCH v7 6/7] perf config: normalize a value depending on default type of it Taeung Song
2015-10-04 7:35 ` [PATCH v7 7/7] perf config: Add a option 'remove' to perf-config Taeung Song
6 siblings, 0 replies; 12+ messages in thread
From: Taeung Song @ 2015-10-04 7:35 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: linux-kernel, jolsa, namhyung, Ingo Molnar, Taeung Song
This patch consists of functions
which can set specific config variables.
For the syntax examples,
perf config [<file-option>] [options] [section.name[=value] ...]
set specific config variables
# perf config report.queue-size=100M report.children=true
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
tools/perf/Documentation/perf-config.txt | 2 +-
tools/perf/builtin-config.c | 122 ++++++++++++++++++++++++++-----
tools/perf/util/cache.h | 4 +-
tools/perf/util/config.c | 27 +++++++
4 files changed, 133 insertions(+), 22 deletions(-)
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index 7b83406..f24926e 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' [<file-option>] [section.name ...]
+'perf config' [<file-option>] [section.name[=value] ...]
or
'perf config' [<file-option>] -l | --list
or
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index 731056c..f034c19 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 [<file-option>] [options] [section.name ...]",
+ "perf config [<file-option>] [options] [section.name[=value] ...]",
NULL
};
@@ -453,7 +453,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 __maybe_unused)
{
int i;
struct config_section *section = NULL;
@@ -481,6 +483,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 __maybe_unused)
{
@@ -526,8 +561,10 @@ static int collect_current_config(const char *var, const char *value,
return 0;
}
-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)
{
char *section_name;
char *name;
@@ -554,15 +591,31 @@ static int perf_configset_with_option(configset_fn_t fn, struct list_head *secti
section_name = strsep(&key, ".");
name = strsep(&key, ".");
+ if (!value) {
+ /* do nothing */
+ } else if (!strcmp(value, "=")) {
+ pr_err("The config variable does not contain a value: %s.%s\n",
+ section_name, name);
+ return -1;
+ } else {
+ value++;
+ name = strsep(&name, "=");
+ if (name[0] == '\0') {
+ pr_err("invalid key: %s\n", var);
+ return -1;
+ }
+ }
free(key);
- return fn(sections, section_name, name);
+ return fn(sections, config_file_name, section_name, name, value);
}
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 *config_file_name;
const char *system_config = perf_etc_perfconfig();
char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
@@ -579,18 +632,29 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
return -1;
}
- INIT_LIST_HEAD(§ions);
-
- if (use_system_config || (!use_system_config && !use_user_config))
- perf_config_from_file(collect_current_config, system_config, §ions);
-
- if (use_user_config || (!use_system_config && !use_user_config))
- perf_config_from_file(collect_current_config, user_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_file_name = system_config;
+ } else if (use_user_config) {
+ sections = &user_sections;
+ config_file_name = user_config;
+ } else {
+ INIT_LIST_HEAD(&all_sections);
+ sections = &all_sections;
+ config_file_name = user_config;
+ perf_config_from_file(collect_current_config, system_config, &all_sections);
+ perf_config_from_file(collect_current_config, user_config, &all_sections);
+ }
switch (actions) {
case ACTION_LIST_ALL:
if (argc == 0) {
- ret = show_all_config(§ions);
+ ret = show_all_config(sections);
break;
}
case ACTION_LIST:
@@ -603,12 +667,30 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
return -1;
}
default:
- if (argc)
- for (i = 0; argv[i]; i++)
- ret = perf_configset_with_option(show_spec_config, §ions,
- argv[i]);
- else
- ret = show_config(§ions);
+
+ 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_file_name,
+ argv[i], value);
+ }
+ }
+ } else
+ ret = show_config(sections);
}
return ret;
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index e9bb75e..0723cdf 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -33,7 +33,9 @@ struct config_section {
};
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);
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 23fa8c5..ad539d9 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -506,6 +506,33 @@ 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) {
+ pr_err("Error: %s: Can't open this file\n", file_name);
+ 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
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v7 6/7] perf config: normalize a value depending on default type of it
2015-10-04 7:35 [PATCH v7 0/7] perf tools: Add 'perf-config' command Taeung Song
` (4 preceding siblings ...)
2015-10-04 7:35 ` [PATCH v7 5/7] perf config: Add 'set' feature Taeung Song
@ 2015-10-04 7:35 ` Taeung Song
2015-10-04 7:35 ` [PATCH v7 7/7] perf config: Add a option 'remove' to perf-config Taeung Song
6 siblings, 0 replies; 12+ messages in thread
From: Taeung Song @ 2015-10-04 7:35 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: linux-kernel, jolsa, namhyung, Ingo Molnar, Taeung Song
Whether or not user mis-type wrong data type to set config,
normalize the value. If a config user enter isn't contained
in default configs, just pass as it is.
For the examples,
# perf config report.queue-size=1M
# perf config report.queue-size
report.queue-size=1048576
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
tools/perf/builtin-config.c | 48 ++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 43 insertions(+), 5 deletions(-)
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index f034c19..680a655 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -483,6 +483,48 @@ static int show_spec_config(struct list_head *sections,
return -1;
}
+static char *normalize_value(const char *section_name, const char *name, const char *value)
+{
+ int i, ret = 0;
+ char key[BUFSIZ];
+ char *normalized;
+
+ scnprintf(key, sizeof(key), "%s.%s", section_name, name);
+ for (i = 0; default_configsets[i].section_name != NULL; i++) {
+ struct default_configset *config = &default_configsets[i];
+
+ if (!strcmp(config->section_name, section_name)
+ && !strcmp(config->name, name)) {
+ if (!config->type)
+ ret = asprintf(&normalized, "%s", value);
+ else if (!strcmp(config->type, TYPE_BOOL))
+ ret = asprintf(&normalized, "%s",
+ perf_config_bool(key, value) ? "true" : "false");
+ else if (!strcmp(config->type, TYPE_INT))
+ ret = asprintf(&normalized, "%d",
+ perf_config_int(key, value));
+ else if (!strcmp(config->type, TYPE_LONG))
+ ret = asprintf(&normalized, "%"PRId64,
+ perf_config_u64(key, value));
+ else if (!strcmp(config->type, TYPE_DIRNAME))
+ ret = asprintf(&normalized, "%s",
+ perf_config_dirname(key, value));
+ if (ret < 0)
+ return NULL;
+
+ return normalized;
+ }
+ }
+
+ normalized = strdup(value);
+ if (!normalized) {
+ pr_err("%s: strdup failed\n", __func__);
+ return NULL;
+ }
+
+ return normalized;
+}
+
static int set_config(struct list_head *sections, const char *config_file_name,
const char *section_name, const char *name, char *value)
{
@@ -491,11 +533,7 @@ static int set_config(struct list_head *sections, const char *config_file_name,
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;
- }
+ value = normalize_value(section_name, name, value);
/* if there isn't existent section, add a new section */
if (!section) {
--
1.9.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v7 7/7] perf config: Add a option 'remove' to perf-config
2015-10-04 7:35 [PATCH v7 0/7] perf tools: Add 'perf-config' command Taeung Song
` (5 preceding siblings ...)
2015-10-04 7:35 ` [PATCH v7 6/7] perf config: normalize a value depending on default type of it Taeung Song
@ 2015-10-04 7:35 ` Taeung Song
6 siblings, 0 replies; 12+ messages in thread
From: Taeung Song @ 2015-10-04 7:35 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo
Cc: linux-kernel, jolsa, namhyung, Ingo Molnar, Taeung Song
A option 'remove' is to remove specific config variables.
For the syntax examples,
# perf config [<file-option>] -r | --remove [section.name ...]
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
tools/perf/Documentation/perf-config.txt | 6 +++++
tools/perf/builtin-config.c | 38 ++++++++++++++++++++++++++++++--
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index f24926e..281e759 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -13,6 +13,8 @@ or
'perf config' [<file-option>] -l | --list
or
'perf config' [<file-option>] -a | --list-all
+or
+'perf config' [<file-option>] -r | --remove [section.name ...]
DESCRIPTION
-----------
@@ -37,6 +39,10 @@ OPTIONS
--list-all::
Show current and all possible config variables with default values.
+-r::
+--remove::
+ Remove specific config variables.
+
CONFIGURATION FILE
------------------
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index 680a655..9253eae 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -22,7 +22,8 @@ static const char * const config_usage[] = {
enum actions {
ACTION_LIST = 1,
- ACTION_LIST_ALL
+ ACTION_LIST_ALL,
+ ACTION_REMOVE
} actions;
static struct option config_options[] = {
@@ -35,6 +36,8 @@ static struct option config_options[] = {
OPT_SET_UINT('a', "list-all", &actions,
"show current and all possible config variables with default values",
ACTION_LIST_ALL),
+ OPT_SET_UINT('r', "remove", &actions,
+ "remove specific variables: [section.name ...]", ACTION_REMOVE),
OPT_END()
};
@@ -532,7 +535,14 @@ static int set_config(struct list_head *sections, const char *config_file_name,
struct config_element *element = NULL;
find_config(sections, §ion, &element, section_name, name);
- if (value != NULL) {
+ if (!value) {
+ /* value == NULL means remove the variable */
+ if (section && element) {
+ if (!element->value)
+ free(element->value);
+ element->value = NULL;
+ }
+ } else {
value = normalize_value(section_name, name, value);
/* if there isn't existent section, add a new section */
@@ -659,6 +669,7 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
set_option_flag(config_options, 'l', "list", PARSE_OPT_EXCLUSIVE);
set_option_flag(config_options, 'a', "list-all", PARSE_OPT_EXCLUSIVE);
+ set_option_flag(config_options, 'r', "remove", PARSE_OPT_EXCLUSIVE);
argc = parse_options(argc, argv, config_options, config_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
@@ -690,6 +701,29 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
}
switch (actions) {
+ case ACTION_REMOVE:
+ if (argc) {
+ for (i = 0; argv[i]; i++) {
+ if (!use_system_config && !use_user_config) {
+ ret = perf_configset_with_option(set_config,
+ &system_sections,
+ system_config,
+ argv[i], NULL);
+ ret = perf_configset_with_option(set_config,
+ &user_sections,
+ user_config,
+ argv[i], NULL);
+ } else
+ ret = perf_configset_with_option(set_config, sections,
+ config_file_name,
+ argv[i], NULL);
+ }
+ } else {
+ pr_err("Error: Missing arguments\n");
+ parse_options_usage(config_usage, config_options, "r", 1);
+ return -1;
+ }
+ break;
case ACTION_LIST_ALL:
if (argc == 0) {
ret = show_all_config(sections);
--
1.9.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v7 1/7] perf tools: Add 'perf-config' command
2015-10-04 7:35 ` [PATCH v7 1/7] " Taeung Song
@ 2015-10-21 3:10 ` Namhyung Kim
0 siblings, 0 replies; 12+ messages in thread
From: Namhyung Kim @ 2015-10-21 3:10 UTC (permalink / raw)
To: Taeung Song; +Cc: Arnaldo Carvalho de Melo, linux-kernel, jolsa, Ingo Molnar
Hi Taeung,
sorry for late!
On Sun, Oct 04, 2015 at 04:35:04PM +0900, Taeung Song wrote:
> The perf configuration file contains many variables which can make
> the perf command's action more effective.
> But looking through state of configuration is difficult and there's no knowing
> what kind of other variables except variables in perfconfig.example exist.
> So This patch adds 'perf-config' command with '--list' option and a document for it.
>
> perf config [options]
>
> display current perf config variables.
> # perf config
> or
> # perf config -l | --list
>
> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
Some nitpicks below, other than that
Acked-by: Namhyung Kim <namhyung@kernel.org>
Thanks,
Namhyung
> ---
> tools/perf/Build | 1 +
> tools/perf/Documentation/perf-config.txt | 396 +++++++++++++++++++++++++++++++
> tools/perf/builtin-config.c | 62 +++++
> tools/perf/builtin.h | 1 +
> tools/perf/command-list.txt | 1 +
> tools/perf/perf.c | 1 +
> 6 files changed, 462 insertions(+)
> create mode 100644 tools/perf/Documentation/perf-config.txt
> create mode 100644 tools/perf/builtin-config.c
>
> diff --git a/tools/perf/Build b/tools/perf/Build
> index 7223745..2c7aaf2 100644
> --- a/tools/perf/Build
> +++ b/tools/perf/Build
> @@ -1,5 +1,6 @@
> perf-y += builtin-bench.o
> perf-y += builtin-annotate.o
> +perf-y += builtin-config.o
> perf-y += builtin-diff.o
> perf-y += builtin-evlist.o
> perf-y += builtin-help.o
> diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
> new file mode 100644
> index 0000000..e8013b3
> --- /dev/null
> +++ b/tools/perf/Documentation/perf-config.txt
> @@ -0,0 +1,396 @@
> +perf-config(1)
> +==============
> +
> +NAME
> +----
> +perf-config - Get and set variables in a configuration file.
> +
> +SYNOPSIS
> +--------
> +[verse]
> +'perf config' -l | --list
> +
> +DESCRIPTION
> +-----------
> +You can manage variables in a configuration file with this command.
> +
> +OPTIONS
> +-------
> +
> +-l::
> +--list::
> + Show current config variables, name and value, for all sections.
> +
> +CONFIGURATION FILE
> +------------------
> +
> +The Perf configuration file contains many variables which can make
> +the perf command's action more effective.
> +The '$HOME/.perfconfig' file is used to store a per-user configuration.
> +The file '$(sysconfdir)/perfconfig' can be used to
> +store a system-wide default configuration.
> +
> +The variables are divided into sections. In each section, the variables
> +that are composed of a name and value.
> +
> +Syntax
> +~~~~~~
> +
> +The file consist of sections. A section starts with its name
> +surrounded by square brackets and continues till the next section
> +begins. Each variable belong to a section, which means that
> +there must be a section header before the first variable, as below:
> +Each variable are in the form 'name = value'.
> +
> + [section]
> + name1 = value1
> + name2 = value2
> +
> +Section names are case sensitive and can contain any characters except
> +newline (double quote `"` and backslash have to be escaped as `\"` and `\\`,
> +respectively). Section headers can't span multiple lines.
> +
> +Example
> +~~~~~~~
> +
> +Given a $HOME/.perfconfig like this:
> +
> +#
> +# This is the config file, and
> +# a '#' and ';' character indicates a comment
> +#
> +
> +[colors]
> + # Color variables
> + top = red, default
> + medium = green, default
> + normal = lightgray, default
> + selected = white, lightgray
> + code = blue, default
> + addr = magenta, default
> + root = white, blue
> +
> +[tui]
> + # Defaults if linked with libslang
> + report = on
> + annotate = on
> + top = on
> +
> +[buildid]
> + # Default, disable using /dev/null
> + dir = ~/.debug
> +
> +[annotate]
> + # Defaults
> + hide_src_code = false
> + use_offset = true
> + jump_arrows = true
> + show_nr_jumps = false
> +
> +[help]
> + # Format can be man, info, web or html
> + format = man
> + autocorrect = 0
> +
> +[ui]
> + show-headers= true
> +
> +[call-graph]
> + # fp (framepointer), dwarf
> + record-mode = fp
> + print-type = graph
> + order = caller
> + sort-key = function
> +
> +Variables
> +~~~~~~~~~
> +
> +colors.*::
> + Color variables can customize colors of the output which is printed out
> + from ‘report’, ‘top’, ’annotate’ on tui.
> + Color variables are composed of foreground and background
> + and should have two values, comma separated as below.
> +
> + medium = green, lightgray
> +
> + If you want to keep the background or the foregroud color set for your
> + terminal, replace the desired value with 'default'. For instance:
> +
> + medium = default, default
> +
> + Available colors:
> + red, green, default, black, blue, white, magenta, lightgray
> +
> + colors.top::
> + ‘top’ means a overhead percentage which is more than 5%.
> + And values of this variable specify colors of percentage.
> + Basic key values are foreground-color ’red’ and
> + background-color ’default’.
> + colors.medium::
> + ‘medium’ means a overhead percentage which has more than 0.5%.
> + Default values are ’green’ and ’default’.
> + colors.normal::
> + ‘normal’ means the rest of overhead percentages
> + except ‘top’, ‘medium’, ‘selected’.
> + Default values are ’lightgray’ and ’default’.
> + colors.selected::
> + This selects the colors for the current entry in a list of entries
> + from sub-commands (top,report,annotate).
> + Default values are ’white’ and ’lightgray’.
> + colors.code::
> + Colors for arrows and lines in jumps on assembly code listings
> + such as ‘jns’,’jmp’,’jane’,etc. Default values are ‘blue’, ‘default’.
> + colors.addr::
> + This selects colors for addresses from ’annotate’.
> + Default values are ‘magenta’, ‘default’.
> + colors.root::
> + Colors for headers in the output of a sub-command ‘top’.
> + Default values are ‘white’, ‘blue’.
> +
> +tui.*::
> + A boolean value that controls if the TUI browser will be used
> + for subcommands having that UI.
> + By default, TUI is enabled if perf detects the required library during build
> + and this config option can control it. Available subcommands are 'top',
> + 'report' and 'annotate'.
> +
> +gtk.*::
> + A boolean value that controls if GTK+2 GUI browser for
> + each subcommand. By default, GUI can be enabled if perf detects the
> + required library during build and this config option can control it.
> + Available subcommands are 'top', 'report' and 'annotate'.
> +
> +buildid.*::
> + buildid.dir::
> + Each executable and shared library in modern distributions comes with a
> + content based identified that, if available, will be inserted in a
> + 'perf.data' file header to, at analysis time find what is needed to do
> + symbol resolution, code anotation, etc.
> +
> + The recording tools also stores a hard link or copy in a per-user
> + directory, $HOME/.debug/, of binaries, shared libraries, /proc/kallsyms
> + and /proc/kcore files to be used at analysis time.
> +
> + The buildid.dir variable can be used to either change this directory
> + cache location, or to disable it altogether. If you want to disable it,
> + set buildid.dir to /dev/null. The default is $HOME/.debug
> +
> +annotate.*::
> + There’re options which work with a ’annotate’ sub-command.
> + This options are in control of addresses, jump function, source code
> + in lines of assembly code from a specific program.
> +
> + annotate.hide_src_code::
> + If a program which is analyzed has source code,
> + this option let ‘annotate’ print a list of assembly code with the source code.
> + For example, let’s see a part of a program. There’re four lines.
> + If this option is ‘false’, they can be printed
> + without source code from a program as below.
> +
> + │ push %rbp
> + │ mov %rsp,%rbp
> + │ sub $0x10,%rsp
> + │ mov (%rdi),%rdx
??? I think this is when the option is 'true' that means *hide* the
source code.
> +
> + But if this option is ‘true’, source code of the part
> + can be also printed as below.
> +
> + │ struct rb_node *rb_next(const struct rb_node *node)
> + │ {
> + │ push %rbp
> + │ mov %rsp,%rbp
> + │ sub $0x10,%rsp
> + │ struct rb_node *parent;
> + │
> + │ if (RB_EMPTY_NODE(node))
> + │ mov (%rdi),%rdx
> + │ return n;
And this is the 'false' case - show me the source.
> +
> + annotate.use_offset::
> + Basing on a first address of a loaded function, offset can be used.
> + Instead of using original addresses of assembly code,
> + addresses subtracted from a base address can be printed.
> + Let’s illustrate a example.
> + If a base address is 0XFFFFFFFF81624d50 as below,
> +
> + ffffffff81624d50 <load0>
> +
> + a address on assembly code has a specific absolute address as below
> +
> + ffffffff816250b8:│ mov 0x8(%r14),%rdi
> +
> + but if use_offset is ’true’, a address subtracted from a base address is printed.
> + The default is true.
> +
> + 368:│ mov 0x8(%r14),%rdi
There was a bug in handling this option and I've sent a fix.
Anyway, it seems that these annotate options are only applied to TUI.
> +
> + annotate.jump_arrows::
> + There can be jump instruction among assembly code.
> + Depending on a boolean value of jump_arrows,
> + arrows can be printed or not which represent
> + where do the instruction jump into as below.
> +
> + │ ┌──jmp 1333
> + │ │ xchg %ax,%ax
> + │1330:│ mov %r15,%r10
> + │1333:└─→cmp %r15,%r14
> +
> + If jump_arrow is ‘false’, the arrows isn’t printed as below.
> +
> + │ ↓ jmp 1333
> + │ xchg %ax,%ax
> + │1330: mov %r15,%r10
> + │1333: cmp %r15,%r14
> +
> + annotate.show_nr_jumps::
> + Let’s see a part of assembly code.
> +
> + │1382: movb $0x1,-0x270(%rbp)
> +
> + If use this, the number of branches branching to that address can be printed as below.
> +
> + │1 1382: movb $0x1,-0x270(%rbp)
> +
> +help.*::
> + help.format:: = man
> + A format of manual page can be ‘man’, ‘info’, ‘web’ or ‘html’.
> + ’man’ is default.
> + help.autocorrect:: = 0
> + Automatically correct and execute mistyped commands after
> + waiting for the given number of deciseconds (0.1 sec).
> + Let's see a example. If a mistyped sub-command is executed like 'perf mistyped-command'
> + and this option is 0, the output is as below.
> +
> + perf: 'mistyped-command' is not a perf-command. See 'perf --help’.
> +
> + Or if this option is more than 1, the output can be such as.
> +
> + WARNING: You called a perf program named 'mistyped-command', which does not exist.
> + Continuing under the assumption that you meant 'with-kcore'
> + in 0.1 seconds automatically...
> + Usage: perf-with-kcore <perf sub-command> <perf.data directory> [<sub-command options> [ -- <workload>]]
> + <perf sub-command> can be record, script, report or inject
> + or: perf-with-kcore fix_buildid_cache_permissions
> +
> +hist.*::
> + hist.percentage::
> + This option control a way to calcurate overhead of filtered entries -
> + that means the value of this option is effective only if there's a
> + filter (by comm, dso or symbol name). Suppose a following example:
> +
> + Overhead Symbols
> + ........ .......
> + 33.33% foo
> + 33.33% bar
> + 33.33% baz
> +
> + This is an original overhead and we'll filter out the first 'foo'
> + entry. The value of 'relative' would increase the overhead of 'bar'
> + and 'baz' to 50.00% for each, while 'absolute' would show their
> + current overhead (33.33%).
> +
> +ui.*::
> + ui.show-headers::
> + There’re columns as header ‘Overhead’, ‘Children’, ‘Shared Object’, ‘Symbol’, ’self’.
> + If this option is false, they are hiden.
It seems not to be applied for --stdio.
> +
> +call-graph.*::
> + When sub-commands ‘top’ and ‘report’ work with -g/—-children
> + there’re options in control of call-graph.
> +
> + call-graph.record-mode::
> + The record-mode can be ‘fp’ (frame pointer) and ‘dwarf’.
> + The value of 'dwarf' is effective only if perf detect needed library
> + (libunwind or a recent version of libdw). Also it doesn't *require*
> + the dump-size option since it can use the default value of 8192 if
> + missing.
> +
> + call-graph.dump-size::
> + The size of stack to dump in order to do post-unwinding. Default is 8192 (byte).
> + When using dwarf into record-mode this option should have a value.
> +
> + call-graph.print-type::
> + The print-types can be graph (graph absolute), fractal (graph relative), flat.
> + This option controls a way to show overhead for each callchain entry.
> + Suppose a following example.
> +
> + Overhead Symbols
> + ........ .......
> + 40.00% foo
> + |
> + --- foo
> + |
> + |--50.00%-- bar
> + | main
> + |
> + --50.00%-- baz
> + main
> +
> + This output is a default format which is 'fractal'. The 'foo' came
> + from 'bar' and 'baz' exactly half and half so 'fractal' shows 50.00%
> + for each (meaning that it assumes 100% total overhead of 'foo').
> +
> + The 'graph' uses absolute overhead value of 'foo' as total so each of
> + 'bar' and 'baz' callchain will have 20.00% of overhead.
> +
> + call-graph.order::
> + This option controls print order of callchains. The default is
> + 'callee' which means callee is printed at top and then followed by its
> + caller and so on. The 'caller' prints it in reverse order.
> +
> + call-graph.sort-key::
> + The callchains are merged if they contain same information.
> + The sort-key option determines a way to compare the callchains.
> + A value of 'sort-key' can be 'function' or 'address’.
> + The default is ‘function’.
> +
> + call-graph.threshold::
> + When there're many callchains it'd print tons of lines. So perf omits
> + small callchains under a certain overhead (threshold) and this option
> + control the threashold. Default is 0.5 (%).
> +
> + call-graph.print-limit::
> + This is another way to control the number of callchains printed for a
> + single entry. Default is 0 which means no limitation.
> +
> +report.*::
> + report.percent-limit::
> + This one is mostly same as call-graph.threshold but works for
> + histogram entries. Entries have overhead lower than this percentage
> + will not be printed. Default is 0.
> + If percent-limit is 70, the output which has percentages of
> + each overhead above 70% can be printed.
> +
> + report.queue-size::
> + option to setup the maximum allocation size for session's
> + ordered events queue, if not set there's no default limit.
> +
> + report.children::
> + The children means that functions called from another function.
> + If the option is true, accumulate callchain of children and show total overhead.
> + Please refer to the perf-report manual.
> +
> +top.*::
> + top.children::
> + This option means same as report.children.
> + So it is true, the output of ‘top’ is rearranged by each overhead into children group.
> +
> +man.*::
> + man.viewer::
> + This option can assign a manual tool with which a subcommand 'help' work.
> + it can used as 'man', 'woman', 'konqueror'. Default value is 'man'.
> +
> +pager.*::
> + pager.<subcommand>::
> + When a subcommand work as stdio instead of TUI, use pager with it.
> + Default value is 'true'.
> +
> +kmem.*::
> + kmem.default::
> + This option can decide which allocator is analyzed between 'slab' and 'page'
> + without using options '--slab' and '--page'.
> + Default value is 'slab'.
> +
> +SEE ALSO
> +--------
> +linkperf:perf[1], linkperf:perf-report[1]
> diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
> new file mode 100644
> index 0000000..30b1500
> --- /dev/null
> +++ b/tools/perf/builtin-config.c
> @@ -0,0 +1,62 @@
> +/*
> + * builtin-config.c
> + *
> + * Copyright (C) 2015, Taeung Song <treeze.taeung@gmail.com>
> + *
> + */
> +#include "builtin.h"
> +
> +#include "perf.h"
> +
> +#include "util/cache.h"
> +#include "util/parse-options.h"
> +#include "util/util.h"
> +#include "util/debug.h"
> +
> +static const char * const config_usage[] = {
> + "perf config [options]",
> + NULL
> +};
> +
> +enum actions {
> + ACTION_LIST = 1
> +} actions;
> +
> +static struct option config_options[] = {
> + OPT_GROUP("Action"),
> + OPT_SET_UINT('l', "list", &actions,
> + "show current config variables", ACTION_LIST),
> + OPT_END()
> +};
> +
> +static int show_config(const char *key, const char *value,
> + void *cb __maybe_unused)
> +{
> + if (value)
> + printf("%s=%s\n", key, value);
> + else
> + printf("%s\n", key);
> +
> + return 0;
> +}
> +
> +int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
> +{
> + int ret = 0;
> +
> + argc = parse_options(argc, argv, config_options, config_usage,
> + PARSE_OPT_STOP_AT_NON_OPTION);
> +
> + switch (actions) {
> + case ACTION_LIST:
> + default:
> + if (argc) {
> + pr_err("Error: takes no arguments\n");
> + parse_options_usage(config_usage, config_options, "l", 1);
> + return -1;
> + } else
> + ret = perf_config(show_config, NULL);
> + }
> +
> + return ret;
> +}
> diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
> index 3688ad2..3f871b5 100644
> --- a/tools/perf/builtin.h
> +++ b/tools/perf/builtin.h
> @@ -17,6 +17,7 @@ extern int cmd_annotate(int argc, const char **argv, const char *prefix);
> extern int cmd_bench(int argc, const char **argv, const char *prefix);
> extern int cmd_buildid_cache(int argc, const char **argv, const char *prefix);
> extern int cmd_buildid_list(int argc, const char **argv, const char *prefix);
> +extern int cmd_config(int argc, const char **argv, const char *prefix);
> extern int cmd_diff(int argc, const char **argv, const char *prefix);
> extern int cmd_evlist(int argc, const char **argv, const char *prefix);
> extern int cmd_help(int argc, const char **argv, const char *prefix);
> diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
> index 00fcaf8..acc3ea7 100644
> --- a/tools/perf/command-list.txt
> +++ b/tools/perf/command-list.txt
> @@ -9,6 +9,7 @@ perf-buildid-cache mainporcelain common
> perf-buildid-list mainporcelain common
> perf-data mainporcelain common
> perf-diff mainporcelain common
> +perf-config mainporcelain common
> perf-evlist mainporcelain common
> perf-inject mainporcelain common
> perf-kmem mainporcelain common
> diff --git a/tools/perf/perf.c b/tools/perf/perf.c
> index 1fded92..6acbfd5 100644
> --- a/tools/perf/perf.c
> +++ b/tools/perf/perf.c
> @@ -38,6 +38,7 @@ struct cmd_struct {
> static struct cmd_struct commands[] = {
> { "buildid-cache", cmd_buildid_cache, 0 },
> { "buildid-list", cmd_buildid_list, 0 },
> + { "config", cmd_config, 0 },
> { "diff", cmd_diff, 0 },
> { "evlist", cmd_evlist, 0 },
> { "help", cmd_help, 0 },
> --
> 1.9.1
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v7 2/7] perf config: Add '--system' and '--user' options to select which config file is used
2015-10-04 7:35 ` [PATCH v7 2/7] perf config: Add '--system' and '--user' options to select which config file is used Taeung Song
@ 2015-10-21 4:20 ` Namhyung Kim
2015-10-21 10:32 ` TaeWoong Song
0 siblings, 1 reply; 12+ messages in thread
From: Namhyung Kim @ 2015-10-21 4:20 UTC (permalink / raw)
To: Taeung Song; +Cc: Arnaldo Carvalho de Melo, linux-kernel, jolsa, Ingo Molnar
On Sun, Oct 04, 2015 at 04:35:05PM +0900, Taeung Song wrote:
> Which config file is used is decided in only perf_config().
> And a perf-config command depend on perf_config() to list
> config variables with values. So add '--system' and '--user'
> options to select which config file to be used without perf_config().
>
> The file-options '--system' means $(sysconfdir)/perfconfig and
> '--user' means $HOME/.perfconfig. If file-option isn't used,
> both system and user config file is read
> but user config have priority. The syntax examples are like below
>
> perf config [<file-option>] [options]
>
> a specific config file.
> # perf config --user | --system
> or
> both user and system config file.
> # perf config
>
> In addition, use List data structure which has config info.
> Because perf_config() isn't used any more and directly collect
> config info by perf_config_from_file() with a specific config
> file path. Whichever config file or both are used, list is required
> to keep and handle config variables and values.
>
> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
> ---
Hmm.. Isn't it just a matter of setting of config_exclusive_filename
variable? And then we can still use perf_config() no?
I think it'd be better to split the collecting configs part into a
separate patch.
Thanks,
Namhyung
> tools/perf/Documentation/perf-config.txt | 14 ++-
> tools/perf/builtin-config.c | 163 +++++++++++++++++++++++++++++--
> tools/perf/util/cache.h | 15 +++
> tools/perf/util/config.c | 4 +-
> 4 files changed, 187 insertions(+), 9 deletions(-)
>
> diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
> index e8013b3..a42d409 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' -l | --list
> +'perf config' [<file-option>] -l | --list
>
> DESCRIPTION
> -----------
> @@ -21,6 +21,14 @@ OPTIONS
> --list::
> Show current config variables, name and value, for all sections.
>
> +--user::
> + For writing and reading options: write to user
> + '$HOME/.perfconfig' file or read it.
> +
> +--system::
> + For writing and reading options: write to system-wide
> + '$(sysconfdir)/perfconfig' or read it.
> +
> CONFIGURATION FILE
> ------------------
>
> @@ -33,6 +41,10 @@ store a system-wide default configuration.
> The variables are divided into sections. In each section, the variables
> that are composed of a name and value.
>
> +When reading or writing, the values are read from the system and user
> +configuration files by default, and options '--system' and '--user'
> +can be used to tell the command to read from or write to only that location.
> +
> Syntax
> ~~~~~~
>
> diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
> index 30b1500..92be3eb 100644
> --- a/tools/perf/builtin-config.c
> +++ b/tools/perf/builtin-config.c
> @@ -13,8 +13,10 @@
> #include "util/util.h"
> #include "util/debug.h"
>
> +static bool use_system_config, use_user_config;
> +
> static const char * const config_usage[] = {
> - "perf config [options]",
> + "perf config [<file-option>] [options]",
> NULL
> };
>
> @@ -23,19 +25,150 @@ enum actions {
> } actions;
>
> static struct option config_options[] = {
> + OPT_GROUP("Config file location"),
> + OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
> + OPT_BOOLEAN(0, "user", &use_user_config, "use user config file"),
> OPT_GROUP("Action"),
> OPT_SET_UINT('l', "list", &actions,
> "show current config variables", ACTION_LIST),
> OPT_END()
> };
> +static int show_config(struct list_head *sections)
> +{
> + struct config_section *section;
> + struct config_element *element;
> +
> + list_for_each_entry(section, sections, list) {
> + list_for_each_entry(element, §ion->element_head, list) {
> + printf("%s.%s=%s\n", section->name,
> + element->name, element->value);
> + }
> + }
> +
> + return 0;
> +}
>
> -static int show_config(const char *key, const char *value,
> - void *cb __maybe_unused)
> +static struct config_section *find_section(struct list_head *sections,
> + const char *section_name)
> {
> + struct config_section *section;
> +
> + list_for_each_entry(section, sections, list)
> + if (!strcmp(section->name, section_name))
> + return section;
> +
> + return NULL;
> +}
> +
> +static struct config_element *find_element(const char *name,
> + struct config_section *section)
> +{
> + struct config_element *element;
> +
> + list_for_each_entry(element, §ion->element_head, list)
> + if (!strcmp(element->name, name))
> + return element;
> +
> + return NULL;
> +}
> +
> +static void find_config(struct list_head *sections,
> + struct config_section **section,
> + struct config_element **element,
> + const char *section_name, const char *name)
> +{
> + *section = find_section(sections, section_name);
> +
> + if (*section != NULL)
> + *element = find_element(name, *section);
> + else
> + *element = NULL;
> +}
> +
> +static struct config_section *init_section(const char *section_name)
> +{
> + struct config_section *section;
> +
> + section = zalloc(sizeof(*section));
> + if (!section)
> + return NULL;
> +
> + INIT_LIST_HEAD(§ion->element_head);
> + section->name = strdup(section_name);
> + if (!section->name) {
> + pr_err("%s: strdup failed\n", __func__);
> + free(section);
> + return NULL;
> + }
> +
> + return section;
> +}
> +
> +static int add_element(struct list_head *head,
> + const char *name, const char *value)
> +{
> + struct config_element *element;
> +
> + element = zalloc(sizeof(*element));
> + if (!element)
> + return -1;
> +
> + element->name = strdup(name);
> + if (!element->name) {
> + pr_err("%s: strdup failed\n", __func__);
> + free(element);
> + return -1;
> + }
> if (value)
> - printf("%s=%s\n", key, value);
> + element->value = (char *)value;
> else
> - printf("%s\n", key);
> + element->value = NULL;
> +
> + list_add_tail(&element->list, head);
> + return 0;
> +}
> +
> +static int collect_current_config(const char *var, const char *value,
> + void *spec_sections __maybe_unused)
> +{
> + struct config_section *section = NULL;
> + struct config_element *element = NULL;
> + struct list_head *sections = (struct list_head *)spec_sections;
> + char *key = strdup(var);
> + char *section_name, *name;
> +
> + if (!key) {
> + pr_err("%s: strdup failed\n", __func__);
> + return -1;
> + }
> +
> + section_name = strsep(&key, ".");
> + name = strsep(&key, ".");
> + free(key);
> + if (name == NULL)
> + return -1;
> +
> + find_config(sections, §ion, &element, section_name, name);
> +
> + if (!section) {
> + section = init_section(section_name);
> + if (!section)
> + return -1;
> + list_add_tail(§ion->list, sections);
> + }
> +
> + value = strdup(value);
> + if (!value) {
> + pr_err("%s: strdup failed\n", __func__);
> + return -1;
> + }
> +
> + if (!element)
> + return add_element(§ion->element_head, name, value);
> + else {
> + free(element->value);
> + element->value = (char *)value;
> + }
>
> return 0;
> }
> @@ -43,10 +176,28 @@ 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 list_head sections;
> + const char *system_config = perf_etc_perfconfig();
> + char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
>
> argc = parse_options(argc, argv, config_options, config_usage,
> PARSE_OPT_STOP_AT_NON_OPTION);
>
> + if (use_system_config && use_user_config) {
> + pr_err("Error: only one config file at a time\n");
> + parse_options_usage(config_usage, config_options, "user", 0);
> + parse_options_usage(NULL, config_options, "system", 0);
> + return -1;
> + }
> +
> + INIT_LIST_HEAD(§ions);
> +
> + if (use_system_config || (!use_system_config && !use_user_config))
> + perf_config_from_file(collect_current_config, system_config, §ions);
> +
> + if (use_user_config || (!use_system_config && !use_user_config))
> + perf_config_from_file(collect_current_config, user_config, §ions);
> +
> switch (actions) {
> case ACTION_LIST:
> default:
> @@ -55,7 +206,7 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
> parse_options_usage(config_usage, config_options, "l", 1);
> return -1;
> } else
> - ret = perf_config(show_config, NULL);
> + ret = show_config(§ions);
> }
>
> return ret;
> diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
> index c861373..712e82b 100644
> --- a/tools/perf/util/cache.h
> +++ b/tools/perf/util/cache.h
> @@ -1,6 +1,7 @@
> #ifndef __PERF_CACHE_H
> #define __PERF_CACHE_H
>
> +#include <linux/list.h>
> #include <stdbool.h>
> #include "util.h"
> #include "strbuf.h"
> @@ -19,14 +20,28 @@
> #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
> #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
>
> +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;
> +};
> +
> typedef int (*config_fn_t)(const char *, const char *, void *);
> 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 *);
> extern int config_error_nonbool(const char *);
> extern const char *perf_config_dirname(const char *, const char *);
> +extern const char *perf_etc_perfconfig(void);
>
> /* pager.c */
> extern void setup_pager(void);
> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
> index 2e452ac..23fa8c5 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");
> @@ -434,7 +434,7 @@ static int perf_config_from_file(config_fn_t fn, const char *filename, void *dat
> return ret;
> }
>
> -static const char *perf_etc_perfconfig(void)
> +const char *perf_etc_perfconfig(void)
> {
> static const char *system_wide;
> if (!system_wide)
> --
> 1.9.1
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v7 3/7] perf config: Add a option 'list-all' to perf-config
2015-10-04 7:35 ` [PATCH v7 3/7] perf config: Add a option 'list-all' to perf-config Taeung Song
@ 2015-10-21 5:11 ` Namhyung Kim
0 siblings, 0 replies; 12+ messages in thread
From: Namhyung Kim @ 2015-10-21 5:11 UTC (permalink / raw)
To: Taeung Song; +Cc: Arnaldo Carvalho de Melo, linux-kernel, jolsa, Ingo Molnar
On Sun, Oct 04, 2015 at 04:35:06PM +0900, Taeung Song wrote:
> A option 'list-all' is to display both current config variables and
> 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
>
> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
> ---
> tools/perf/Documentation/perf-config.txt | 6 +
> tools/perf/builtin-config.c | 339 ++++++++++++++++++++++++++++++-
> 2 files changed, 343 insertions(+), 2 deletions(-)
>
> diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
> index a42d409..15fbbd9 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 92be3eb..8e16e18 100644
> --- a/tools/perf/builtin-config.c
> +++ b/tools/perf/builtin-config.c
> @@ -21,7 +21,8 @@ static const char * const config_usage[] = {
> };
>
> enum actions {
> - ACTION_LIST = 1
> + ACTION_LIST = 1,
> + ACTION_LIST_ALL
> } actions;
>
> static struct option config_options[] = {
> @@ -31,8 +32,292 @@ static struct option config_options[] = {
> OPT_GROUP("Action"),
> 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_END()
> };
> +
> +/* section names */
> +#define COLORS "colors"
> +#define TUI "tui"
> +#define BUILDID "buildid"
> +#define ANNOTATE "annotate"
> +#define GTK "gtk"
> +#define PAGER "pager"
> +#define HELP "help"
> +#define HIST "hist"
> +#define UI "ui"
> +#define CALL_GRAPH "call-graph"
> +#define REPORT "report"
> +#define TOP "top"
> +#define MAN "man"
> +#define KMEM "kmem"
> +
> +/* config variable types */
> +#define TYPE_INT "int"
> +#define TYPE_LONG "long"
> +#define TYPE_DIRNAME "dirname"
> +#define TYPE_BOOL "bool"
> +
> +static struct default_configset {
> + const char *section_name;
> + const char *name, *value, *type;
> +
> +} default_configsets[] = {
I think it should in sync with the actual value. So how about
changing the code to use this table instead of hard-coded value?
Maybe something like this? (untested!!)
enum config_idx {
CONFIG_COLORS_TOP,
CONFIG_COLORS_MEDIUM,
CONFIG_COLORS_NORMAL,
...
CONFIG_ITEM_MAX,
};
enum config_type {
CONFIG_TYPE_BOOL,
CONFIG_TYPE_INT,
CONFIG_TYPE_STRING,
...
};
struct config_item {
const char *section;
const char *name;
union {
bool b;
int i;
char *s;
...
} value;
enum config_type type;
}
#define CONF_VAR(_sec, _name, _field, _val, _type) \
{ .section = _sec, .name = name, .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_STR_VAR(_idx, _sec, _name, _val) \
[CONFIG_##_idx] = CONF_VAR(_sec, _name, s, _val, CONFIG_TYPE_STRING)
struct config_item default_configs[] = {
CONF_STR_VAR(COLORS_TOP, "colors", "top", "red, default"),
CONF_STR_VAR(COLORS_TOP, "colors", "medium", "green, default"),
...
CONF_BOOL_VAR(UI_SHOW_HEADERS, "ui", "show-headers", true),
...
};
And then we can use it, for example, like below..
util/symbol.c:
struct symbol_conf symbol_conf = {
...
.show_hist_headers = default_configs[CONFIG_UI_SHOW_HEADERS].value.b,
...
};
or
#define CONFIG_DEFAULT_BOOL(_sec, _name) \
default_configs[CONFIG_##_sec##_##_name].value.b
...
struct symbol_conf symbol_conf = {
...
.show_hist_headers = CONFIG_DEFAULT_BOOL(UI, SHOW_HEADERS),
...
};
Thanks,
Namhyung
> + {
> + .section_name = COLORS,
> + .name = "top",
> + .value = "red, default",
> + .type = NULL,
> + },
> + {
> + .section_name = COLORS,
> + .name = "medium",
> + .value = "green, default",
> + .type = NULL,
> + },
> + {
> + .section_name = COLORS,
> + .name = "normal",
> + .value = "lightgray, default",
> + .type = NULL,
> + },
> + {
> + .section_name = COLORS,
> + .name = "selected",
> + .value = "white, lightgray",
> + .type = NULL,
> + },
> + {
> + .section_name = COLORS,
> + .name = "code",
> + .value = "blue, default",
> + .type = NULL,
> + },
> + {
> + .section_name = COLORS,
> + .name = "addr",
> + .value = "magenta, default",
> + .type = NULL,
> + },
> + {
> + .section_name = COLORS,
> + .name = "root",
> + .value = "white, blue",
> + .type = NULL,
> + },
> + {
> + .section_name = TUI,
> + .name = "report",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = TUI,
> + .name = "annotate",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = TUI,
> + .name = "top",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = BUILDID,
> + .name = "dir",
> + .value = "~/.debug",
> + .type = TYPE_DIRNAME,
> + },
> + {
> + .section_name = ANNOTATE,
> + .name = "hide_src_code",
> + .value = "false",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = ANNOTATE,
> + .name = "use_offset",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = ANNOTATE,
> + .name = "jump_arrows",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = ANNOTATE,
> + .name = "show_nr_jumps",
> + .value = "false",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = GTK,
> + .name = "annotate",
> + .value = "false",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = GTK,
> + .name = "report",
> + .value = "false",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = GTK,
> + .name = "top",
> + .value = "false",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = PAGER,
> + .name = "cmd",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = PAGER,
> + .name = "report",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = PAGER,
> + .name = "annotate",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = PAGER,
> + .name = "record",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = PAGER,
> + .name = "top",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = PAGER,
> + .name = "diff",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = HELP,
> + .name = "format",
> + .value = "man",
> + .type = NULL,
> + },
> + {
> + .section_name = HELP,
> + .name = "autocorrect",
> + .value = "0",
> + .type = NULL,
> + },
> + {
> + .section_name = HIST,
> + .name = "percentage",
> + .value = "absolute",
> + .type = NULL,
> + },
> + {
> + .section_name = UI,
> + .name = "show-headers",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = CALL_GRAPH,
> + .name = "record-mode",
> + .value = "fp",
> + },
> + {
> + .section_name = CALL_GRAPH,
> + .name = "dump-size",
> + .value = "8192",
> + .type = TYPE_INT,
> + },
> + {
> + .section_name = CALL_GRAPH,
> + .name = "print-type",
> + .value = "fractal",
> + .type = NULL,
> + },
> + {
> + .section_name = CALL_GRAPH,
> + .name = "order",
> + .value = "caller",
> + .type = NULL,
> + },
> + {
> + .section_name = CALL_GRAPH,
> + .name = "sort-key",
> + .value = "function",
> + .type = NULL,
> + },
> + {
> + .section_name = CALL_GRAPH,
> + .name = "threshold",
> + .value = "0.5",
> + .type = TYPE_LONG,
> + },
> + {
> + .section_name = CALL_GRAPH,
> + .name = "print-limit",
> + .value = "0",
> + .type = TYPE_INT,
> + },
> + {
> + .section_name = REPORT,
> + .name = "children",
> + .value = "true",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = REPORT,
> + .name = "percent-limit",
> + .value = "0",
> + .type = TYPE_INT,
> + },
> + {
> + .section_name = REPORT,
> + .name = "queue-size",
> + .value = "0",
> + .type = TYPE_INT,
> + },
> + {
> + .section_name = TOP,
> + .name = "children",
> + .value = "false",
> + .type = TYPE_BOOL,
> + },
> + {
> + .section_name = MAN,
> + .name = "viewer",
> + .value = "man",
> + .type = NULL,
> + },
> + {
> + .section_name = KMEM,
> + .name = "default",
> + .value = "slab",
> + .type = NULL,
> + },
> + {
> + .section_name = NULL,
> + .name = NULL,
> + .value = NULL,
> + .type = NULL,
> + },
> +};
> +
> static int show_config(struct list_head *sections)
> {
> struct config_section *section;
> @@ -128,6 +413,45 @@ static int add_element(struct list_head *head,
> return 0;
> }
>
> +static int show_all_config(struct list_head *sections)
> +{
> + int i;
> + bool has_config;
> + struct config_section *section;
> + struct config_element *element;
> +
> + for (i = 0; default_configsets[i].section_name != NULL; i++) {
> + find_config(sections, §ion, &element,
> + default_configsets[i].section_name, default_configsets[i].name);
> +
> + if (!element)
> + printf("%s.%s=%s\n", default_configsets[i].section_name,
> + default_configsets[i].name, default_configsets[i].value);
> + else
> + printf("%s.%s=%s\n", section->name,
> + element->name, element->value);
> + }
> +
> + /* Print config variables the default configsets haven't */
> + list_for_each_entry(section, sections, list) {
> + list_for_each_entry(element, §ion->element_head, list) {
> + has_config = false;
> + for (i = 0; default_configsets[i].section_name != NULL; i++) {
> + if (!strcmp(default_configsets[i].section_name, section->name)
> + && !strcmp(default_configsets[i].name, element->name)) {
> + has_config = true;
> + break;
> + }
> + }
> + if (!has_config)
> + printf("%s.%s=%s\n", section->name,
> + element->name, element->value);
> + }
> + }
> +
> + return 0;
> +}
> +
> static int collect_current_config(const char *var, const char *value,
> void *spec_sections __maybe_unused)
> {
> @@ -180,6 +504,9 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
> 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);
> +
> argc = parse_options(argc, argv, config_options, config_usage,
> PARSE_OPT_STOP_AT_NON_OPTION);
>
> @@ -199,11 +526,19 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
> perf_config_from_file(collect_current_config, user_config, §ions);
>
> switch (actions) {
> + case ACTION_LIST_ALL:
> + if (argc == 0) {
> + ret = show_all_config(§ions);
> + break;
> + }
> case ACTION_LIST:
> default:
> if (argc) {
> pr_err("Error: takes no arguments\n");
> - parse_options_usage(config_usage, config_options, "l", 1);
> + if (actions == ACTION_LIST_ALL)
> + parse_options_usage(config_usage, config_options, "a", 1);
> + else
> + parse_options_usage(config_usage, config_options, "l", 1);
> return -1;
> } else
> ret = show_config(§ions);
> --
> 1.9.1
>
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v7 2/7] perf config: Add '--system' and '--user' options to select which config file is used
2015-10-21 4:20 ` Namhyung Kim
@ 2015-10-21 10:32 ` TaeWoong Song
0 siblings, 0 replies; 12+ messages in thread
From: TaeWoong Song @ 2015-10-21 10:32 UTC (permalink / raw)
To: Namhyung Kim
Cc: Arnaldo Carvalho de Melo, linux-kernel@vger.kernel.org, jolsa,
Ingo Molnar
Hi, Namhyung
Thanks for your review.
> On Oct 21, 2015, at 1:20 PM, Namhyung Kim <namhyung@kernel.org> wrote:
>
> On Sun, Oct 04, 2015 at 04:35:05PM +0900, Taeung Song wrote:
>> Which config file is used is decided in only perf_config().
>> And a perf-config command depend on perf_config() to list
>> config variables with values. So add '--system' and '--user'
>> options to select which config file to be used without perf_config().
>>
>> The file-options '--system' means $(sysconfdir)/perfconfig and
>> '--user' means $HOME/.perfconfig. If file-option isn't used,
>> both system and user config file is read
>> but user config have priority. The syntax examples are like below
>>
>> perf config [<file-option>] [options]
>>
>> a specific config file.
>> # perf config --user | --system
>> or
>> both user and system config file.
>> # perf config
>>
>> In addition, use List data structure which has config info.
>> Because perf_config() isn't used any more and directly collect
>> config info by perf_config_from_file() with a specific config
>> file path. Whichever config file or both are used, list is required
>> to keep and handle config variables and values.
>>
>> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
>> ---
>
> Hmm.. Isn't it just a matter of setting of config_exclusive_filename
> variable? And then we can still use perf_config() no?
>
Yes, you are right.
I thought in a box.
If using config_exclusive_filename variable, source code will be simplified.
> I think it'd be better to split the collecting configs part into a
> separate patch.
The collecting config info is needed since a ‘list-all’ option.
So I’ll add it after the patch for specific config path (system or user)
But a patch collecting config info is useless in itself.
Starting a patch ‘list-all’, it has meaning.
Thanks,
Taeung
>
> Thanks,
> Namhyung
>
>
>> tools/perf/Documentation/perf-config.txt | 14 ++-
>> tools/perf/builtin-config.c | 163 +++++++++++++++++++++++++++++--
>> tools/perf/util/cache.h | 15 +++
>> tools/perf/util/config.c | 4 +-
>> 4 files changed, 187 insertions(+), 9 deletions(-)
>>
>> diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
>> index e8013b3..a42d409 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' -l | --list
>> +'perf config' [<file-option>] -l | --list
>>
>> DESCRIPTION
>> -----------
>> @@ -21,6 +21,14 @@ OPTIONS
>> --list::
>> Show current config variables, name and value, for all sections.
>>
>> +--user::
>> + For writing and reading options: write to user
>> + '$HOME/.perfconfig' file or read it.
>> +
>> +--system::
>> + For writing and reading options: write to system-wide
>> + '$(sysconfdir)/perfconfig' or read it.
>> +
>> CONFIGURATION FILE
>> ------------------
>>
>> @@ -33,6 +41,10 @@ store a system-wide default configuration.
>> The variables are divided into sections. In each section, the variables
>> that are composed of a name and value.
>>
>> +When reading or writing, the values are read from the system and user
>> +configuration files by default, and options '--system' and '--user'
>> +can be used to tell the command to read from or write to only that location.
>> +
>> Syntax
>> ~~~~~~
>>
>> diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
>> index 30b1500..92be3eb 100644
>> --- a/tools/perf/builtin-config.c
>> +++ b/tools/perf/builtin-config.c
>> @@ -13,8 +13,10 @@
>> #include "util/util.h"
>> #include "util/debug.h"
>>
>> +static bool use_system_config, use_user_config;
>> +
>> static const char * const config_usage[] = {
>> - "perf config [options]",
>> + "perf config [<file-option>] [options]",
>> NULL
>> };
>>
>> @@ -23,19 +25,150 @@ enum actions {
>> } actions;
>>
>> static struct option config_options[] = {
>> + OPT_GROUP("Config file location"),
>> + OPT_BOOLEAN(0, "system", &use_system_config, "use system config file"),
>> + OPT_BOOLEAN(0, "user", &use_user_config, "use user config file"),
>> OPT_GROUP("Action"),
>> OPT_SET_UINT('l', "list", &actions,
>> "show current config variables", ACTION_LIST),
>> OPT_END()
>> };
>> +static int show_config(struct list_head *sections)
>> +{
>> + struct config_section *section;
>> + struct config_element *element;
>> +
>> + list_for_each_entry(section, sections, list) {
>> + list_for_each_entry(element, §ion->element_head, list) {
>> + printf("%s.%s=%s\n", section->name,
>> + element->name, element->value);
>> + }
>> + }
>> +
>> + return 0;
>> +}
>>
>> -static int show_config(const char *key, const char *value,
>> - void *cb __maybe_unused)
>> +static struct config_section *find_section(struct list_head *sections,
>> + const char *section_name)
>> {
>> + struct config_section *section;
>> +
>> + list_for_each_entry(section, sections, list)
>> + if (!strcmp(section->name, section_name))
>> + return section;
>> +
>> + return NULL;
>> +}
>> +
>> +static struct config_element *find_element(const char *name,
>> + struct config_section *section)
>> +{
>> + struct config_element *element;
>> +
>> + list_for_each_entry(element, §ion->element_head, list)
>> + if (!strcmp(element->name, name))
>> + return element;
>> +
>> + return NULL;
>> +}
>> +
>> +static void find_config(struct list_head *sections,
>> + struct config_section **section,
>> + struct config_element **element,
>> + const char *section_name, const char *name)
>> +{
>> + *section = find_section(sections, section_name);
>> +
>> + if (*section != NULL)
>> + *element = find_element(name, *section);
>> + else
>> + *element = NULL;
>> +}
>> +
>> +static struct config_section *init_section(const char *section_name)
>> +{
>> + struct config_section *section;
>> +
>> + section = zalloc(sizeof(*section));
>> + if (!section)
>> + return NULL;
>> +
>> + INIT_LIST_HEAD(§ion->element_head);
>> + section->name = strdup(section_name);
>> + if (!section->name) {
>> + pr_err("%s: strdup failed\n", __func__);
>> + free(section);
>> + return NULL;
>> + }
>> +
>> + return section;
>> +}
>> +
>> +static int add_element(struct list_head *head,
>> + const char *name, const char *value)
>> +{
>> + struct config_element *element;
>> +
>> + element = zalloc(sizeof(*element));
>> + if (!element)
>> + return -1;
>> +
>> + element->name = strdup(name);
>> + if (!element->name) {
>> + pr_err("%s: strdup failed\n", __func__);
>> + free(element);
>> + return -1;
>> + }
>> if (value)
>> - printf("%s=%s\n", key, value);
>> + element->value = (char *)value;
>> else
>> - printf("%s\n", key);
>> + element->value = NULL;
>> +
>> + list_add_tail(&element->list, head);
>> + return 0;
>> +}
>> +
>> +static int collect_current_config(const char *var, const char *value,
>> + void *spec_sections __maybe_unused)
>> +{
>> + struct config_section *section = NULL;
>> + struct config_element *element = NULL;
>> + struct list_head *sections = (struct list_head *)spec_sections;
>> + char *key = strdup(var);
>> + char *section_name, *name;
>> +
>> + if (!key) {
>> + pr_err("%s: strdup failed\n", __func__);
>> + return -1;
>> + }
>> +
>> + section_name = strsep(&key, ".");
>> + name = strsep(&key, ".");
>> + free(key);
>> + if (name == NULL)
>> + return -1;
>> +
>> + find_config(sections, §ion, &element, section_name, name);
>> +
>> + if (!section) {
>> + section = init_section(section_name);
>> + if (!section)
>> + return -1;
>> + list_add_tail(§ion->list, sections);
>> + }
>> +
>> + value = strdup(value);
>> + if (!value) {
>> + pr_err("%s: strdup failed\n", __func__);
>> + return -1;
>> + }
>> +
>> + if (!element)
>> + return add_element(§ion->element_head, name, value);
>> + else {
>> + free(element->value);
>> + element->value = (char *)value;
>> + }
>>
>> return 0;
>> }
>> @@ -43,10 +176,28 @@ 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 list_head sections;
>> + const char *system_config = perf_etc_perfconfig();
>> + char *user_config = mkpath("%s/.perfconfig", getenv("HOME"));
>>
>> argc = parse_options(argc, argv, config_options, config_usage,
>> PARSE_OPT_STOP_AT_NON_OPTION);
>>
>> + if (use_system_config && use_user_config) {
>> + pr_err("Error: only one config file at a time\n");
>> + parse_options_usage(config_usage, config_options, "user", 0);
>> + parse_options_usage(NULL, config_options, "system", 0);
>> + return -1;
>> + }
>> +
>> + INIT_LIST_HEAD(§ions);
>> +
>> + if (use_system_config || (!use_system_config && !use_user_config))
>> + perf_config_from_file(collect_current_config, system_config, §ions);
>> +
>> + if (use_user_config || (!use_system_config && !use_user_config))
>> + perf_config_from_file(collect_current_config, user_config, §ions);
>> +
>> switch (actions) {
>> case ACTION_LIST:
>> default:
>> @@ -55,7 +206,7 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
>> parse_options_usage(config_usage, config_options, "l", 1);
>> return -1;
>> } else
>> - ret = perf_config(show_config, NULL);
>> + ret = show_config(§ions);
>> }
>>
>> return ret;
>> diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
>> index c861373..712e82b 100644
>> --- a/tools/perf/util/cache.h
>> +++ b/tools/perf/util/cache.h
>> @@ -1,6 +1,7 @@
>> #ifndef __PERF_CACHE_H
>> #define __PERF_CACHE_H
>>
>> +#include <linux/list.h>
>> #include <stdbool.h>
>> #include "util.h"
>> #include "strbuf.h"
>> @@ -19,14 +20,28 @@
>> #define PERF_DEBUGFS_ENVIRONMENT "PERF_DEBUGFS_DIR"
>> #define PERF_TRACEFS_ENVIRONMENT "PERF_TRACEFS_DIR"
>>
>> +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;
>> +};
>> +
>> typedef int (*config_fn_t)(const char *, const char *, void *);
>> 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 *);
>> extern int config_error_nonbool(const char *);
>> extern const char *perf_config_dirname(const char *, const char *);
>> +extern const char *perf_etc_perfconfig(void);
>>
>> /* pager.c */
>> extern void setup_pager(void);
>> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
>> index 2e452ac..23fa8c5 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");
>> @@ -434,7 +434,7 @@ static int perf_config_from_file(config_fn_t fn, const char *filename, void *dat
>> return ret;
>> }
>>
>> -static const char *perf_etc_perfconfig(void)
>> +const char *perf_etc_perfconfig(void)
>> {
>> static const char *system_wide;
>> if (!system_wide)
>> --
>> 1.9.1
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2015-10-21 10:32 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-04 7:35 [PATCH v7 0/7] perf tools: Add 'perf-config' command Taeung Song
2015-10-04 7:35 ` [PATCH v7 1/7] " Taeung Song
2015-10-21 3:10 ` Namhyung Kim
2015-10-04 7:35 ` [PATCH v7 2/7] perf config: Add '--system' and '--user' options to select which config file is used Taeung Song
2015-10-21 4:20 ` Namhyung Kim
2015-10-21 10:32 ` TaeWoong Song
2015-10-04 7:35 ` [PATCH v7 3/7] perf config: Add a option 'list-all' to perf-config Taeung Song
2015-10-21 5:11 ` Namhyung Kim
2015-10-04 7:35 ` [PATCH v7 4/7] perf config: Add 'get' functionality Taeung Song
2015-10-04 7:35 ` [PATCH v7 5/7] perf config: Add 'set' feature Taeung Song
2015-10-04 7:35 ` [PATCH v7 6/7] perf config: normalize a value depending on default type of it Taeung Song
2015-10-04 7:35 ` [PATCH v7 7/7] perf config: Add a option 'remove' to perf-config Taeung Song
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).