mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH v3 0/5]
@ 2015-07-12  5:10 Taeung Song
  2015-07-12  5:10 ` [PATCH v3 1/5] perf tools: Add 'perf-config' command Taeung Song
                   ` (3 more replies)
  0 siblings, 4 replies; 18+ messages in thread
From: Taeung Song @ 2015-07-12  5:10 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: linux-kernel, jolsa, namhyung, Ingo Molnar, Taeung Song

Changes in v3:
	- builtin-config.c: Add a config variable ’kmem.default’ with a default value into ‘struct default_configset’
	which has default config variables and values.
	- cmd_config(): Add a option ‘—global’ and ‘—local’ to enable  config file location to  be selected

Changes in v2:
	- Renaming variables a more suitable name
	  1. ’—list-all' instead of '--all'
	  2. ’name' instead of 'subkey'
	  3. 'section, name, value' instead of 'given_section,subkey,value'
	- Documentation/perf-config.txt: Correct small infelicities or typing errors in a perf-config documention.
	- Documentation/perf-config.txt: Remove a part description of report.children because it was duplicated
	in Documentation/callchain-overhead-calculation.txt
	- builtin-config.c: Use a variable ’int actions’ instead of struct params which has ‘bool list_action’,
	‘bool get_action’ and etc. , to simplify a branching statement for perf-config options 
	- builtin-config.c: Declaration a global variable ‘static struct default_configsets’ has config variables
	with default values instead of using a 'util/PERFCONFIG-DEFAULT' file and remove functions merge()
	and perse_key() to get perf config default values.
	- normalize_value(): Add a function to normalize a value and check data type of it.
	- cmd_config(): 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.
	- show_all_config(): Print config variables ‘struct default_configsets’ haven't 
	- cmd_config(): Make a command ’perf config' without a option work as with a option ’—list’ instead of ‘—list-all’.

Taeung Song (5):
  perf tools: Add 'perf-config' command
  perf config: Add functions which can get or set perf config variables.
  perf config: Add a option 'list-all' to perf-config.
  perf config: Add a option 'remove' to perf-config.
  perf config: Add ‘—system’ and ‘—global’ options to be able to select
    which config file to be used.

 tools/perf/Build                            |   1 +
 tools/perf/Documentation/perf-config.txt    | 401 ++++++++++++++++
 tools/perf/Documentation/perfconfig.example |  70 ++-
 tools/perf/builtin-config.c                 | 708 ++++++++++++++++++++++++++++
 tools/perf/builtin.h                        |   1 +
 tools/perf/command-list.txt                 |   1 +
 tools/perf/perf.c                           |   1 +
 tools/perf/util/cache.h                     |  20 +
 tools/perf/util/config.c                    |  84 +++-
 9 files changed, 1251 insertions(+), 36 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] 18+ messages in thread

* [PATCH v3 1/5] perf tools: Add 'perf-config' command
  2015-07-12  5:10 [PATCH v3 0/5] Taeung Song
@ 2015-07-12  5:10 ` Taeung Song
  2015-07-12  5:10 ` [PATCH v3 2/5] perf config: Add functions which can get or set perf config variables Taeung Song
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 18+ messages in thread
From: Taeung Song @ 2015-07-12  5:10 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    | 375 ++++++++++++++++++++++++++++
 tools/perf/Documentation/perfconfig.example |  70 +++++-
 tools/perf/builtin-config.c                 |  75 ++++++
 tools/perf/builtin.h                        |   1 +
 tools/perf/command-list.txt                 |   1 +
 tools/perf/perf.c                           |   1 +
 7 files changed, 512 insertions(+), 12 deletions(-)
 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 b77370e..3c1f437 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..afda861
--- /dev/null
+++ b/tools/perf/Documentation/perf-config.txt
@@ -0,0 +1,375 @@
+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 with key and value into each 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
+can are composed of a key and value.
+
+Syntax
+~~~~~~
+
+The file consists of sections and names. A section begins with
+the name of the section in square brackets and continues until the next
+section begins. Each variable have to belong to some section, which means
+there must be a section header before the first setting of a 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 (doublequote `"` and backslash have to be escaped as `\"` and `\\`,
+respectively).  Section headers can't span multiple
+lines.  Variables may belong directly to a section.
+
+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 for them. If you want to keep as colors
+	of your terminal, you should use ‘default’ for the color value.
+	The color names that can be used are:
+	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 launching TUI browser for each subcommand.
+	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 launching GTK+2 GUI browser for
+	each subcommand.  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'.
+
+buildid.*::
+	buildid.dir::
+		Each executable or shared library built with each program is assigned
+		a unique identification as build-id. The option means a path where
+		build-id information can be saved.
+		The default is $HOME/.debug
+
+annotate.*::
+	There’re options which work with a ’annotate’ sub-command.
+	This options is 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 of itself,
+		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’re 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'.
+
+SEE ALSO
+--------
+linkperf:perf[1], linkperf:perf-report[1]
diff --git a/tools/perf/Documentation/perfconfig.example b/tools/perf/Documentation/perfconfig.example
index 767ea24..be820b7 100644
--- a/tools/perf/Documentation/perfconfig.example
+++ b/tools/perf/Documentation/perfconfig.example
@@ -1,29 +1,75 @@
 [colors]
-
-	# These were the old defaults
-	top = red, lightgray
-	medium = green, lightgray
-	normal = black, lightgray
-	selected = lightgray, magenta
-	code = blue, lightgray
-	addr = magenta, lightgray
+	# There are types of colors which are red,
+	# green, default, black, blue,
+	# white, magenta, lightgray
+	# The default is like below
+	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 = /root/.debug
+	dir = ~/.debug
 
 [annotate]
-
 	# Defaults
 	hide_src_code = false
 	use_offset = true
 	jump_arrows = true
 	show_nr_jumps = false
+
+[gtk]
+	report = off
+	annotate = off
+	#top = off
+
+[pager]
+	# That a 'cmd' is true mean to use "pager or less"
+	cmd = true
+	report = false
+	diff = true
+
+[help]
+	# Format can be man, info, web or html
+	format = man
+	autocorrect = 0
+
+[hist]
+	# a value of 'percentage' can be 'relative' or 'absolute'
+	percentage = absolute
+
+[ui]
+	show-headers= true
+
+[call-graph]
+	# fp (framepointer), dwarf
+	record-mode = fp
+
+	# graph (graph absolute), flat, fractal (graph relative)
+	print-type = fractal
+
+	# caller, callee
+	order = caller
+
+	# function, address
+	sort-key = function
+
+[report]
+	percent-limit = 1
+	children = false
+
+[top]
+	children = true
+
+[man]
+	viewer = man
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
new file mode 100644
index 0000000..e7784ed
--- /dev/null
+++ b/tools/perf/builtin-config.c
@@ -0,0 +1,75 @@
+/*
+ * 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 int actions;
+
+static const char * const config_usage[] = {
+	"perf config [options]",
+	NULL
+};
+
+#define ACTION_LIST (1<<0)
+
+static const struct option config_options[] = {
+	OPT_GROUP("Action"),
+	OPT_BIT('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;
+	int origin_argc = argc - 1;
+	bool has_option;
+
+	argc = parse_options(argc, argv, config_options, config_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	if (origin_argc > argc)
+		has_option = true;
+	else
+		has_option = false;
+
+	switch (actions) {
+	case ACTION_LIST:
+		if (argc == 0)
+			ret = perf_config(show_config, NULL);
+		else
+			goto out_err;
+		goto out;
+	default:
+		if (!has_option && argc == 0) {
+			ret = perf_config(show_config, NULL);
+			goto out;
+		} else
+			goto out_err;
+	}
+
+out_err:
+	pr_warning("Error: Unknown argument.\n");
+	usage_with_options(config_usage, config_options);
+out:
+	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 b857fcb..604fa4a 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -37,6 +37,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] 18+ messages in thread

* [PATCH v3 2/5] perf config: Add functions which can get or set perf config variables.
  2015-07-12  5:10 [PATCH v3 0/5] Taeung Song
  2015-07-12  5:10 ` [PATCH v3 1/5] perf tools: Add 'perf-config' command Taeung Song
@ 2015-07-12  5:10 ` Taeung Song
  2015-07-12 14:33   ` Jiri Olsa
  2015-07-12  5:10 ` [PATCH v3 3/5] perf config: Add a option 'list-all' to perf-config Taeung Song
  2015-07-12  5:10 ` [PATCH v3 4/5] perf config: Add a option 'remove' " Taeung Song
  3 siblings, 1 reply; 18+ messages in thread
From: Taeung Song @ 2015-07-12  5:10 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, set specific config variables.
For the syntax examples,

   perf config [options] [section.name[=value] ...]

   display key-value pairs of specific config variables
   # perf config report.queue-size report.children

   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              | 550 ++++++++++++++++++++++++++++++-
 tools/perf/util/cache.h                  |  17 +
 tools/perf/util/config.c                 |  30 +-
 4 files changed, 594 insertions(+), 5 deletions(-)

diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index afda861..f3dae23 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' [section.name[=value] ...]
+or
 'perf config' -l | --list
 
 DESCRIPTION
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
index e7784ed..2d1278d 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -16,7 +16,7 @@
 static int actions;
 
 static const char * const config_usage[] = {
-	"perf config [options]",
+	"perf config [options] [section.name[=value] ...]",
 	NULL
 };
 
@@ -28,6 +28,353 @@ static const struct option config_options[] = {
 	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"
+#define TYPE_ON_OFF "on_off"
+
+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 = "on",
+		.type = TYPE_ON_OFF,
+	},
+	{
+		.section_name = TUI,
+		.name = "annotate",
+		.value = "on",
+		.type = TYPE_ON_OFF,
+	},
+	{
+		.section_name = TUI,
+		.name = "top",
+		.value = "on",
+		.type = TYPE_ON_OFF,
+	},
+	{
+		.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 = "off",
+		.type = TYPE_ON_OFF,
+	},
+	{
+		.section_name = GTK,
+		.name = "report",
+		.value = "off",
+		.type = TYPE_ON_OFF,
+	},
+	{
+		.section_name = GTK,
+		.name = "top",
+		.value = "off",
+		.type = TYPE_ON_OFF,
+	},
+	{
+		.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 = "false",
+		.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 = "page",
+		.type = NULL,
+	},
+	{
+		.section_name = NULL,
+		.name = NULL,
+		.value = NULL,
+		.type = NULL,
+	},
+};
+
+static struct config_section *find_section(const char *section_name)
+{
+	struct config_section *section_node;
+
+	list_for_each_entry(section_node, &sections, list)
+		if (!strcmp(section_node->name, section_name))
+			return section_node;
+
+	return NULL;
+}
+
+static struct config_element *find_element(const char *name,
+					   struct config_section *section_node)
+{
+	struct config_element *element_node;
+
+	list_for_each_entry(element_node, &section_node->element_head, list)
+		if (!strcmp(element_node->name, name))
+			return element_node;
+
+	return NULL;
+}
+
+static struct config_section *init_section(const char *section_name)
+{
+	struct config_section *section_node;
+
+	section_node = zalloc(sizeof(*section_node));
+	if (!section_node)
+		return NULL;
+
+	INIT_LIST_HEAD(&section_node->element_head);
+	section_node->name = strdup(section_name);
+	if (!section_node->name) {
+		pr_err("%s: strdup failed\n", __func__);
+		free(section_node);
+		return NULL;
+	}
+
+	return section_node;
+}
+
+static int add_element(struct list_head *head,
+			      const char *name, const char *value)
+{
+	struct config_element *element_node;
+
+	element_node = zalloc(sizeof(*element_node));
+	element_node->name = strdup(name);
+	if (!element_node->name) {
+		pr_err("%s: strdup failed\n", __func__);
+		goto out_free;
+	}
+	if (value)
+		element_node->value = (char *)value;
+	else
+		element_node->value = NULL;
+
+	list_add_tail(&element_node->list, head);
+	return 0;
+
+out_free:
+	free(element_node);
+	return -1;
+}
+
 static int show_config(const char *key, const char *value,
 		       void *cb __maybe_unused)
 {
@@ -39,10 +386,193 @@ static int show_config(const char *key, const char *value,
 	return 0;
 }
 
+static void find_config(struct config_section **section_node,
+			struct config_element **element_node,
+			const char *section_name, const char *name)
+{
+	*section_node = find_section(section_name);
+
+	if (*section_node != NULL)
+		*element_node = find_element(name, *section_node);
+	else
+		*element_node = NULL;
+}
+
+static int show_spec_config(const char *section_name, const char *name,
+			    char *value __maybe_unused)
+{
+	int i;
+	struct config_section *section_node = NULL;
+	struct config_element *element_node = NULL;
+	char key[BUFSIZ];
+
+	find_config(&section_node, &element_node, section_name, name);
+
+	if (section_node && element_node) {
+		scnprintf(key, sizeof(key), "%s.%s",
+			  section_node->name, element_node->name);
+		return show_config(key, element_node->value, NULL);
+	}
+
+	for (i = 0; default_configsets[i].section_name != NULL; i++) {
+		if (!strcmp(default_configsets[i].section_name, section_name)
+		    && !strcmp(default_configsets[i].name, name)) {
+			printf("%s.%s=%s\n", default_configsets[i].section_name,
+			       default_configsets[i].name, default_configsets[i].value);
+			return 0;
+		}
+	}
+
+	pr_err("Error: Failed to find the variable.\n");
+
+	return 0;
+}
+
+static char *normalize_value(const char *section_name, const char *name, const char *value)
+{
+	int i;
+	char key[BUFSIZ];
+	char *normalized;
+
+	scnprintf(key, sizeof(key), "%s.%s", section_name, name);
+	for (i = 0; default_configsets[i].section_name != NULL; i++) {
+		if (!strcmp(default_configsets[i].section_name, section_name)
+		    && !strcmp(default_configsets[i].name, name)) {
+			normalized = zalloc(BUFSIZ);
+			if (!default_configsets[i].type)
+				scnprintf(normalized, BUFSIZ, "%s", value);
+			else if (!strcmp(default_configsets[i].type, TYPE_BOOL))
+				scnprintf(normalized, BUFSIZ, "%s",
+					  perf_config_bool(key, value) ? "true" : "false");
+			else if (!strcmp(default_configsets[i].type, TYPE_ON_OFF))
+				scnprintf(normalized, BUFSIZ, "%s",
+					  perf_config_bool(key, value) ? "on" : "off");
+			else if (!strcmp(default_configsets[i].type, TYPE_INT))
+				scnprintf(normalized, BUFSIZ, "%d",
+					  perf_config_int(key, value));
+			else if (!strcmp(default_configsets[i].type, TYPE_LONG))
+				scnprintf(normalized, BUFSIZ, "%"PRId64,
+					  perf_config_u64(key, value));
+			else if (!strcmp(default_configsets[i].type, TYPE_DIRNAME))
+				scnprintf(normalized, BUFSIZ, "%s",
+					  perf_config_dirname(key, value));
+			return normalized;
+		}
+	}
+
+	normalized = strdup(value);
+	if (!normalized) {
+		pr_err("%s: strdup failed\n", __func__);
+		return NULL;
+	}
+
+	return normalized;
+}
+
+static int set_config(const char *section_name, const char *name, char *value)
+{
+	struct config_section *section_node = NULL;
+	struct config_element *element_node = NULL;
+
+	find_config(&section_node, &element_node, section_name, name);
+	if (value != NULL) {
+		value = normalize_value(section_name, name, value);
+
+		/* if there isn't existent section, add a new section */
+		if (!section_node) {
+			section_node = init_section(section_name);
+			if (!section_node)
+				return -1;
+			list_add_tail(&section_node->list, &sections);
+		}
+		/* if nothing to replace, add a new element which contains key-value pair. */
+		if (!element_node) {
+			add_element(&section_node->element_head, name, value);
+		} else {
+			if (!element_node->value)
+				free(element_node->value);
+			element_node->value = value;
+		}
+	}
+	return perf_configset_write_in_full();
+}
+
+static int collect_current_config(const char *var, const char *value,
+			  void *cb __maybe_unused)
+{
+	struct config_section *section_node;
+	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, ".");
+
+	section_node = find_section(section_name);
+	if (!section_node) {
+		section_node = init_section(section_name);
+		if (!section_node)
+			return -1;
+		list_add_tail(&section_node->list, &sections);
+	}
+
+	return add_element(&section_node->element_head, name,
+			   normalize_value(section_name, name, value));
+}
+
+static int perf_configset_with_option(configset_fn_t fn, const char *var, char *value)
+{
+	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, ".");
+
+	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, "=");
+	}
+
+	return fn(section_name, name, value);
+
+	pr_err("invalid key: %s\n", var);
+	return -1;
+}
+
 int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
 {
-	int ret = 0;
+	int i, ret = 0;
 	int origin_argc = argc - 1;
+	char *value;
 	bool has_option;
 
 	argc = parse_options(argc, argv, config_options, config_usage,
@@ -52,6 +582,9 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
 	else
 		has_option = false;
 
+	INIT_LIST_HEAD(&sections);
+	perf_config(collect_current_config, NULL);
+
 	switch (actions) {
 	case ACTION_LIST:
 		if (argc == 0)
@@ -63,6 +596,19 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
 		if (!has_option && argc == 0) {
 			ret = perf_config(show_config, NULL);
 			goto out;
+		} else if (argc > 0) {
+			for (i = 0; argv[i]; i++) {
+				value = strchr(argv[i], '=');
+				if (value == NULL)
+					ret = perf_configset_with_option(show_spec_config,
+									 argv[i], value);
+				else
+					ret = perf_configset_with_option(set_config,
+									 argv[i], value);
+				if (ret < 0)
+					break;
+			}
+			goto out;
 		} else
 			goto out_err;
 	}
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index c861373..36d7839 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,6 +20,22 @@
 #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;
+};
+
+struct list_head sections;
+
+typedef int (*configset_fn_t)(const char *, const char *, char*);
+extern int perf_configset_write_in_full(void);
 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 *);
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index e18f653..b6c0d2c 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -21,7 +21,7 @@
 char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
 
 static FILE *config_file;
-static const char *config_file_name;
+static char *config_file_name;
 static int config_linenr;
 static int config_file_eof;
 
@@ -420,12 +420,11 @@ static int perf_config_from_file(config_fn_t fn, const char *filename, void *dat
 	ret = -1;
 	if (f) {
 		config_file = f;
-		config_file_name = filename;
+		config_file_name = strdup(filename);
 		config_linenr = 1;
 		config_file_eof = 0;
 		ret = perf_parse_file(fn, data);
 		fclose(f);
-		config_file_name = NULL;
 	}
 	return ret;
 }
@@ -502,6 +501,31 @@ out:
 	return ret;
 }
 
+int perf_configset_write_in_full(void)
+{
+	struct config_section *section_node;
+	struct config_element *element_node;
+	const char *first_line = "# this file is auto-generated.";
+	FILE *fp = fopen(config_file_name, "w");
+
+	if (!fp)
+		return -1;
+
+	fprintf(fp, "%s\n", first_line);
+	/* overwrite configvariables */
+	list_for_each_entry(section_node, &sections, list) {
+		fprintf(fp, "[%s]\n", section_node->name);
+		list_for_each_entry(element_node, &section_node->element_head, list) {
+			if (element_node->value)
+				fprintf(fp, "\t%s = %s\n",
+					element_node->name, element_node->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	[flat|nested] 18+ messages in thread

* [PATCH v3 3/5] perf config: Add a option 'list-all' to perf-config.
  2015-07-12  5:10 [PATCH v3 0/5] Taeung Song
  2015-07-12  5:10 ` [PATCH v3 1/5] perf tools: Add 'perf-config' command Taeung Song
  2015-07-12  5:10 ` [PATCH v3 2/5] perf config: Add functions which can get or set perf config variables Taeung Song
@ 2015-07-12  5:10 ` Taeung Song
  2015-07-12  5:10 ` [PATCH v3 4/5] perf config: Add a option 'remove' " Taeung Song
  3 siblings, 0 replies; 18+ messages in thread
From: Taeung Song @ 2015-07-12  5:10 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 [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              | 48 ++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+)

diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index f3dae23..e33e481 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -11,6 +11,8 @@ SYNOPSIS
 'perf config' [section.name[=value] ...]
 or
 'perf config' -l | --list
+or
+'perf config' -a | --list-all
 
 DESCRIPTION
 -----------
@@ -23,6 +25,10 @@ OPTIONS
 --list::
 	Show current config variables with key and value into each sections.
 
+-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 2d1278d..ddbf2dc 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -21,10 +21,13 @@ static const char * const config_usage[] = {
 };
 
 #define ACTION_LIST (1<<0)
+#define ACTION_LIST_ALL (1<<1)
 
 static const struct option config_options[] = {
 	OPT_GROUP("Action"),
 	OPT_BIT('l', "list", &actions, "show current config variables", ACTION_LIST),
+	OPT_BIT('a', "list-all", &actions,
+		"show current and all possible config variables with default values", ACTION_LIST_ALL),
 	OPT_END()
 };
 
@@ -523,6 +526,45 @@ static int collect_current_config(const char *var, const char *value,
 			   normalize_value(section_name, name, value));
 }
 
+static int show_all_config(void)
+{
+	int i;
+	bool has_config;
+	struct config_section *section_node;
+	struct config_element *element_node;
+
+	for (i = 0; default_configsets[i].section_name != NULL; i++) {
+		find_config(&section_node, &element_node,
+			    default_configsets[i].section_name, default_configsets[i].name);
+
+		if (!element_node)
+			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_node->name,
+			       element_node->name, element_node->value);
+	}
+
+	/* Print config variables the default configsets haven't */
+	list_for_each_entry(section_node, &sections, list) {
+		list_for_each_entry(element_node, &section_node->element_head, list) {
+			has_config = false;
+			for (i = 0; default_configsets[i].section_name != NULL; i++) {
+				if (!strcmp(default_configsets[i].section_name, section_node->name)
+				    && !strcmp(default_configsets[i].name, element_node->name)) {
+					has_config = true;
+					break;
+				}
+			}
+			if (!has_config)
+				printf("%s.%s=%s\n", section_node->name,
+				       element_node->name, element_node->value);
+		}
+	}
+
+	return 0;
+}
+
 static int perf_configset_with_option(configset_fn_t fn, const char *var, char *value)
 {
 	char *section_name;
@@ -592,6 +634,12 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
 		else
 			goto out_err;
 		goto out;
+	case ACTION_LIST_ALL:
+		if (argc == 0)
+			ret = show_all_config();
+		else
+			goto out_err;
+		goto out;
 	default:
 		if (!has_option && argc == 0) {
 			ret = perf_config(show_config, NULL);
-- 
1.9.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v3 4/5] perf config: Add a option 'remove' to perf-config.
  2015-07-12  5:10 [PATCH v3 0/5] Taeung Song
                   ` (2 preceding siblings ...)
  2015-07-12  5:10 ` [PATCH v3 3/5] perf config: Add a option 'list-all' to perf-config Taeung Song
@ 2015-07-12  5:10 ` Taeung Song
  3 siblings, 0 replies; 18+ messages in thread
From: Taeung Song @ 2015-07-12  5:10 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 -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              | 25 ++++++++++++++++++++++++-
 2 files changed, 30 insertions(+), 1 deletion(-)

diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
index e33e481..a543e1b 100644
--- a/tools/perf/Documentation/perf-config.txt
+++ b/tools/perf/Documentation/perf-config.txt
@@ -13,6 +13,8 @@ or
 'perf config' -l | --list
 or
 'perf config' -a | --list-all
+or
+'perf config' -r | --remove [section.name ...]
 
 DESCRIPTION
 -----------
@@ -29,6 +31,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 ddbf2dc..857e121 100644
--- a/tools/perf/builtin-config.c
+++ b/tools/perf/builtin-config.c
@@ -22,12 +22,14 @@ static const char * const config_usage[] = {
 
 #define ACTION_LIST (1<<0)
 #define ACTION_LIST_ALL (1<<1)
+#define ACTION_REMOVE (1<<2)
 
 static const struct option config_options[] = {
 	OPT_GROUP("Action"),
 	OPT_BIT('l', "list", &actions, "show current config variables", ACTION_LIST),
 	OPT_BIT('a', "list-all", &actions,
 		"show current and all possible config variables with default values", ACTION_LIST_ALL),
+	OPT_BIT('r', "remove", &actions, "remove specific variables: [section.name ...]", ACTION_REMOVE),
 	OPT_END()
 };
 
@@ -478,7 +480,15 @@ static int set_config(const char *section_name, const char *name, char *value)
 	struct config_element *element_node = NULL;
 
 	find_config(&section_node, &element_node, section_name, name);
-	if (value != NULL) {
+	if (!value) {
+		/* value == NULL means remove the variable */
+		if (section_node && element_node) {
+			if (!element_node->value)
+				free(element_node->value);
+			element_node->value = NULL;
+		} else
+			pr_err("Error: Failed to find the variable.\n");
+	} else {
 		value = normalize_value(section_name, name, value);
 
 		/* if there isn't existent section, add a new section */
@@ -497,6 +507,7 @@ static int set_config(const char *section_name, const char *name, char *value)
 			element_node->value = value;
 		}
 	}
+
 	return perf_configset_write_in_full();
 }
 
@@ -640,6 +651,18 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
 		else
 			goto out_err;
 		goto out;
+	case ACTION_REMOVE:
+		for (i = 0; argv[i]; i++) {
+			if (value == NULL)
+				ret = perf_configset_with_option(set_config, argv[i], NULL);
+			else {
+				pr_err("invalid key: %s\n", argv[i]);
+				return -1;
+			}
+			if (ret < 0)
+				goto out;
+		}
+		goto out;
 	default:
 		if (!has_option && argc == 0) {
 			ret = perf_config(show_config, NULL);
-- 
1.9.1


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/5] perf config: Add functions which can get or set perf config variables.
  2015-07-12  5:10 ` [PATCH v3 2/5] perf config: Add functions which can get or set perf config variables Taeung Song
@ 2015-07-12 14:33   ` Jiri Olsa
  2015-07-19  9:57     ` Taewoong Song
  0 siblings, 1 reply; 18+ messages in thread
From: Jiri Olsa @ 2015-07-12 14:33 UTC (permalink / raw)
  To: Taeung Song; +Cc: Arnaldo Carvalho de Melo, linux-kernel, namhyung, Ingo Molnar

On Sun, Jul 12, 2015 at 02:10:56PM +0900, Taeung Song wrote:
> This patch consists of functions
> which can get, set specific config variables.
> For the syntax examples,
> 
>    perf config [options] [section.name[=value] ...]
> 
>    display key-value pairs of specific config variables
>    # perf config report.queue-size report.children
> 
>    set specific config variables
>    # perf config report.queue-size=100M report.children=true

having just patch 1 and 2 applied:

[jolsa@krava perf]$ ./perf config
[jolsa@krava perf]$ ./perf config report.queue-size report.children
report.queue-size=0
report.children=false
[jolsa@krava perf]$ ./perf config report.queue-size=100M
report.children=true
[jolsa@krava perf]$ ./perf config report.queue-size report.children
report.queue-size=0
report.children=false

[jolsa@krava perf]$ ./perf config colors.normal
colors.normal=lightgray, default
[jolsa@krava perf]$ ./perf config colors.normal=blue
[jolsa@krava perf]$ ./perf config colors.normal
colors.normal=lightgray, default
[jolsa@krava perf]$ ./perf config colors.normal=red
[jolsa@krava perf]$ ./perf config colors.normal
colors.normal=lightgray, default

also notice the 'default' for colors.normal while
it's missing for report.children and report.queue-size
above

jirka


> 
> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
> ---
>  tools/perf/Documentation/perf-config.txt |   2 +
>  tools/perf/builtin-config.c              | 550 ++++++++++++++++++++++++++++++-
>  tools/perf/util/cache.h                  |  17 +
>  tools/perf/util/config.c                 |  30 +-
>  4 files changed, 594 insertions(+), 5 deletions(-)
> 
> diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
> index afda861..f3dae23 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' [section.name[=value] ...]
> +or
>  'perf config' -l | --list
>  
>  DESCRIPTION
> diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
> index e7784ed..2d1278d 100644
> --- a/tools/perf/builtin-config.c
> +++ b/tools/perf/builtin-config.c
> @@ -16,7 +16,7 @@
>  static int actions;
>  
>  static const char * const config_usage[] = {
> -	"perf config [options]",
> +	"perf config [options] [section.name[=value] ...]",
>  	NULL
>  };
>  
> @@ -28,6 +28,353 @@ static const struct option config_options[] = {
>  	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"
> +#define TYPE_ON_OFF "on_off"
> +
> +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 = "on",
> +		.type = TYPE_ON_OFF,
> +	},
> +	{
> +		.section_name = TUI,
> +		.name = "annotate",
> +		.value = "on",
> +		.type = TYPE_ON_OFF,
> +	},
> +	{
> +		.section_name = TUI,
> +		.name = "top",
> +		.value = "on",
> +		.type = TYPE_ON_OFF,
> +	},
> +	{
> +		.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 = "off",
> +		.type = TYPE_ON_OFF,
> +	},
> +	{
> +		.section_name = GTK,
> +		.name = "report",
> +		.value = "off",
> +		.type = TYPE_ON_OFF,
> +	},
> +	{
> +		.section_name = GTK,
> +		.name = "top",
> +		.value = "off",
> +		.type = TYPE_ON_OFF,
> +	},
> +	{
> +		.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 = "false",
> +		.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 = "page",
> +		.type = NULL,
> +	},
> +	{
> +		.section_name = NULL,
> +		.name = NULL,
> +		.value = NULL,
> +		.type = NULL,
> +	},
> +};
> +
> +static struct config_section *find_section(const char *section_name)
> +{
> +	struct config_section *section_node;
> +
> +	list_for_each_entry(section_node, &sections, list)
> +		if (!strcmp(section_node->name, section_name))
> +			return section_node;
> +
> +	return NULL;
> +}
> +
> +static struct config_element *find_element(const char *name,
> +					   struct config_section *section_node)
> +{
> +	struct config_element *element_node;
> +
> +	list_for_each_entry(element_node, &section_node->element_head, list)
> +		if (!strcmp(element_node->name, name))
> +			return element_node;
> +
> +	return NULL;
> +}
> +
> +static struct config_section *init_section(const char *section_name)
> +{
> +	struct config_section *section_node;
> +
> +	section_node = zalloc(sizeof(*section_node));
> +	if (!section_node)
> +		return NULL;
> +
> +	INIT_LIST_HEAD(&section_node->element_head);
> +	section_node->name = strdup(section_name);
> +	if (!section_node->name) {
> +		pr_err("%s: strdup failed\n", __func__);
> +		free(section_node);
> +		return NULL;
> +	}
> +
> +	return section_node;
> +}
> +
> +static int add_element(struct list_head *head,
> +			      const char *name, const char *value)
> +{
> +	struct config_element *element_node;
> +
> +	element_node = zalloc(sizeof(*element_node));
> +	element_node->name = strdup(name);
> +	if (!element_node->name) {
> +		pr_err("%s: strdup failed\n", __func__);
> +		goto out_free;
> +	}
> +	if (value)
> +		element_node->value = (char *)value;
> +	else
> +		element_node->value = NULL;
> +
> +	list_add_tail(&element_node->list, head);
> +	return 0;
> +
> +out_free:
> +	free(element_node);
> +	return -1;
> +}
> +
>  static int show_config(const char *key, const char *value,
>  		       void *cb __maybe_unused)
>  {
> @@ -39,10 +386,193 @@ static int show_config(const char *key, const char *value,
>  	return 0;
>  }
>  
> +static void find_config(struct config_section **section_node,
> +			struct config_element **element_node,
> +			const char *section_name, const char *name)
> +{
> +	*section_node = find_section(section_name);
> +
> +	if (*section_node != NULL)
> +		*element_node = find_element(name, *section_node);
> +	else
> +		*element_node = NULL;
> +}
> +
> +static int show_spec_config(const char *section_name, const char *name,
> +			    char *value __maybe_unused)
> +{
> +	int i;
> +	struct config_section *section_node = NULL;
> +	struct config_element *element_node = NULL;
> +	char key[BUFSIZ];
> +
> +	find_config(&section_node, &element_node, section_name, name);
> +
> +	if (section_node && element_node) {
> +		scnprintf(key, sizeof(key), "%s.%s",
> +			  section_node->name, element_node->name);
> +		return show_config(key, element_node->value, NULL);
> +	}
> +
> +	for (i = 0; default_configsets[i].section_name != NULL; i++) {
> +		if (!strcmp(default_configsets[i].section_name, section_name)
> +		    && !strcmp(default_configsets[i].name, name)) {
> +			printf("%s.%s=%s\n", default_configsets[i].section_name,
> +			       default_configsets[i].name, default_configsets[i].value);
> +			return 0;
> +		}
> +	}
> +
> +	pr_err("Error: Failed to find the variable.\n");
> +
> +	return 0;
> +}
> +
> +static char *normalize_value(const char *section_name, const char *name, const char *value)
> +{
> +	int i;
> +	char key[BUFSIZ];
> +	char *normalized;
> +
> +	scnprintf(key, sizeof(key), "%s.%s", section_name, name);
> +	for (i = 0; default_configsets[i].section_name != NULL; i++) {
> +		if (!strcmp(default_configsets[i].section_name, section_name)
> +		    && !strcmp(default_configsets[i].name, name)) {
> +			normalized = zalloc(BUFSIZ);
> +			if (!default_configsets[i].type)
> +				scnprintf(normalized, BUFSIZ, "%s", value);
> +			else if (!strcmp(default_configsets[i].type, TYPE_BOOL))
> +				scnprintf(normalized, BUFSIZ, "%s",
> +					  perf_config_bool(key, value) ? "true" : "false");
> +			else if (!strcmp(default_configsets[i].type, TYPE_ON_OFF))
> +				scnprintf(normalized, BUFSIZ, "%s",
> +					  perf_config_bool(key, value) ? "on" : "off");
> +			else if (!strcmp(default_configsets[i].type, TYPE_INT))
> +				scnprintf(normalized, BUFSIZ, "%d",
> +					  perf_config_int(key, value));
> +			else if (!strcmp(default_configsets[i].type, TYPE_LONG))
> +				scnprintf(normalized, BUFSIZ, "%"PRId64,
> +					  perf_config_u64(key, value));
> +			else if (!strcmp(default_configsets[i].type, TYPE_DIRNAME))
> +				scnprintf(normalized, BUFSIZ, "%s",
> +					  perf_config_dirname(key, value));
> +			return normalized;
> +		}
> +	}
> +
> +	normalized = strdup(value);
> +	if (!normalized) {
> +		pr_err("%s: strdup failed\n", __func__);
> +		return NULL;
> +	}
> +
> +	return normalized;
> +}
> +
> +static int set_config(const char *section_name, const char *name, char *value)
> +{
> +	struct config_section *section_node = NULL;
> +	struct config_element *element_node = NULL;
> +
> +	find_config(&section_node, &element_node, section_name, name);
> +	if (value != NULL) {
> +		value = normalize_value(section_name, name, value);
> +
> +		/* if there isn't existent section, add a new section */
> +		if (!section_node) {
> +			section_node = init_section(section_name);
> +			if (!section_node)
> +				return -1;
> +			list_add_tail(&section_node->list, &sections);
> +		}
> +		/* if nothing to replace, add a new element which contains key-value pair. */
> +		if (!element_node) {
> +			add_element(&section_node->element_head, name, value);
> +		} else {
> +			if (!element_node->value)
> +				free(element_node->value);
> +			element_node->value = value;
> +		}
> +	}
> +	return perf_configset_write_in_full();
> +}
> +
> +static int collect_current_config(const char *var, const char *value,
> +			  void *cb __maybe_unused)
> +{
> +	struct config_section *section_node;
> +	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, ".");
> +
> +	section_node = find_section(section_name);
> +	if (!section_node) {
> +		section_node = init_section(section_name);
> +		if (!section_node)
> +			return -1;
> +		list_add_tail(&section_node->list, &sections);
> +	}
> +
> +	return add_element(&section_node->element_head, name,
> +			   normalize_value(section_name, name, value));
> +}
> +
> +static int perf_configset_with_option(configset_fn_t fn, const char *var, char *value)
> +{
> +	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, ".");
> +
> +	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, "=");
> +	}
> +
> +	return fn(section_name, name, value);
> +
> +	pr_err("invalid key: %s\n", var);
> +	return -1;
> +}
> +
>  int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
>  {
> -	int ret = 0;
> +	int i, ret = 0;
>  	int origin_argc = argc - 1;
> +	char *value;
>  	bool has_option;
>  
>  	argc = parse_options(argc, argv, config_options, config_usage,
> @@ -52,6 +582,9 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
>  	else
>  		has_option = false;
>  
> +	INIT_LIST_HEAD(&sections);
> +	perf_config(collect_current_config, NULL);
> +
>  	switch (actions) {
>  	case ACTION_LIST:
>  		if (argc == 0)
> @@ -63,6 +596,19 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
>  		if (!has_option && argc == 0) {
>  			ret = perf_config(show_config, NULL);
>  			goto out;
> +		} else if (argc > 0) {
> +			for (i = 0; argv[i]; i++) {
> +				value = strchr(argv[i], '=');
> +				if (value == NULL)
> +					ret = perf_configset_with_option(show_spec_config,
> +									 argv[i], value);
> +				else
> +					ret = perf_configset_with_option(set_config,
> +									 argv[i], value);
> +				if (ret < 0)
> +					break;
> +			}
> +			goto out;
>  		} else
>  			goto out_err;
>  	}
> diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
> index c861373..36d7839 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,6 +20,22 @@
>  #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;
> +};
> +
> +struct list_head sections;
> +
> +typedef int (*configset_fn_t)(const char *, const char *, char*);
> +extern int perf_configset_write_in_full(void);
>  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 *);
> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
> index e18f653..b6c0d2c 100644
> --- a/tools/perf/util/config.c
> +++ b/tools/perf/util/config.c
> @@ -21,7 +21,7 @@
>  char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
>  
>  static FILE *config_file;
> -static const char *config_file_name;
> +static char *config_file_name;
>  static int config_linenr;
>  static int config_file_eof;
>  
> @@ -420,12 +420,11 @@ static int perf_config_from_file(config_fn_t fn, const char *filename, void *dat
>  	ret = -1;
>  	if (f) {
>  		config_file = f;
> -		config_file_name = filename;
> +		config_file_name = strdup(filename);
>  		config_linenr = 1;
>  		config_file_eof = 0;
>  		ret = perf_parse_file(fn, data);
>  		fclose(f);
> -		config_file_name = NULL;
>  	}
>  	return ret;
>  }
> @@ -502,6 +501,31 @@ out:
>  	return ret;
>  }
>  
> +int perf_configset_write_in_full(void)
> +{
> +	struct config_section *section_node;
> +	struct config_element *element_node;
> +	const char *first_line = "# this file is auto-generated.";
> +	FILE *fp = fopen(config_file_name, "w");
> +
> +	if (!fp)
> +		return -1;
> +
> +	fprintf(fp, "%s\n", first_line);
> +	/* overwrite configvariables */
> +	list_for_each_entry(section_node, &sections, list) {
> +		fprintf(fp, "[%s]\n", section_node->name);
> +		list_for_each_entry(element_node, &section_node->element_head, list) {
> +			if (element_node->value)
> +				fprintf(fp, "\t%s = %s\n",
> +					element_node->name, element_node->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	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 2/5] perf config: Add functions which can get or set perf config variables.
  2015-07-12 14:33   ` Jiri Olsa
@ 2015-07-19  9:57     ` Taewoong Song
  0 siblings, 0 replies; 18+ messages in thread
From: Taewoong Song @ 2015-07-19  9:57 UTC (permalink / raw)
  To: Jiri Olsa; +Cc: Arnaldo Carvalho de Melo, linux-kernel, namhyung, Ingo Molnar


> On Jul 12, 2015, at 11:33 PM, Jiri Olsa <jolsa@redhat.com> wrote:
> 
> On Sun, Jul 12, 2015 at 02:10:56PM +0900, Taeung Song wrote:
>> This patch consists of functions
>> which can get, set specific config variables.
>> For the syntax examples,
>> 
>>   perf config [options] [section.name[=value] ...]
>> 
>>   display key-value pairs of specific config variables
>>   # perf config report.queue-size report.children
>> 
>>   set specific config variables
>>   # perf config report.queue-size=100M report.children=true
> 
> having just patch 1 and 2 applied:
> 
> [jolsa@krava perf]$ ./perf config
> [jolsa@krava perf]$ ./perf config report.queue-size report.children
> report.queue-size=0
> report.children=false
> [jolsa@krava perf]$ ./perf config report.queue-size=100M
> report.children=true
> [jolsa@krava perf]$ ./perf config report.queue-size report.children
> report.queue-size=0
> report.children=false
> 
> [jolsa@krava perf]$ ./perf config colors.normal
> colors.normal=lightgray, default
> [jolsa@krava perf]$ ./perf config colors.normal=blue
> [jolsa@krava perf]$ ./perf config colors.normal
> colors.normal=lightgray, default
> [jolsa@krava perf]$ ./perf config colors.normal=red
> [jolsa@krava perf]$ ./perf config colors.normal
> colors.normal=lightgray, default
> 
> also notice the 'default' for colors.normal while
> it's missing for report.children and report.queue-size
> above
> 
> jirka
> 

Thank you for your review.

I modified the patch following what you point out as below.

1. If some config value is default value, notice it is '(default)' as below
 
 :> ./perf config colors.normal
colors.normal=lightgray, default (default)

2. A bug about report.queue-size and report.children was because of config file path.
   If there aren't both global and system config file, can’t write config variables to the files. 
   So, I added new options which are '--global' and '--system' to be enable to select config file path to be used.
    (If there aren’t perfconfig files or can’t write to the file, print error a message.)

I sent PATCH v4 patch files.
If you have spare time, please recheck the patch v4. 


Thanks,
Taeung

> 
>> 
>> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
>> ---
>> tools/perf/Documentation/perf-config.txt |   2 +
>> tools/perf/builtin-config.c              | 550 ++++++++++++++++++++++++++++++-
>> tools/perf/util/cache.h                  |  17 +
>> tools/perf/util/config.c                 |  30 +-
>> 4 files changed, 594 insertions(+), 5 deletions(-)
>> 
>> diff --git a/tools/perf/Documentation/perf-config.txt b/tools/perf/Documentation/perf-config.txt
>> index afda861..f3dae23 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' [section.name[=value] ...]
>> +or
>> 'perf config' -l | --list
>> 
>> DESCRIPTION
>> diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c
>> index e7784ed..2d1278d 100644
>> --- a/tools/perf/builtin-config.c
>> +++ b/tools/perf/builtin-config.c
>> @@ -16,7 +16,7 @@
>> static int actions;
>> 
>> static const char * const config_usage[] = {
>> -	"perf config [options]",
>> +	"perf config [options] [section.name[=value] ...]",
>> 	NULL
>> };
>> 
>> @@ -28,6 +28,353 @@ static const struct option config_options[] = {
>> 	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"
>> +#define TYPE_ON_OFF "on_off"
>> +
>> +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 = "on",
>> +		.type = TYPE_ON_OFF,
>> +	},
>> +	{
>> +		.section_name = TUI,
>> +		.name = "annotate",
>> +		.value = "on",
>> +		.type = TYPE_ON_OFF,
>> +	},
>> +	{
>> +		.section_name = TUI,
>> +		.name = "top",
>> +		.value = "on",
>> +		.type = TYPE_ON_OFF,
>> +	},
>> +	{
>> +		.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 = "off",
>> +		.type = TYPE_ON_OFF,
>> +	},
>> +	{
>> +		.section_name = GTK,
>> +		.name = "report",
>> +		.value = "off",
>> +		.type = TYPE_ON_OFF,
>> +	},
>> +	{
>> +		.section_name = GTK,
>> +		.name = "top",
>> +		.value = "off",
>> +		.type = TYPE_ON_OFF,
>> +	},
>> +	{
>> +		.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 = "false",
>> +		.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 = "page",
>> +		.type = NULL,
>> +	},
>> +	{
>> +		.section_name = NULL,
>> +		.name = NULL,
>> +		.value = NULL,
>> +		.type = NULL,
>> +	},
>> +};
>> +
>> +static struct config_section *find_section(const char *section_name)
>> +{
>> +	struct config_section *section_node;
>> +
>> +	list_for_each_entry(section_node, &sections, list)
>> +		if (!strcmp(section_node->name, section_name))
>> +			return section_node;
>> +
>> +	return NULL;
>> +}
>> +
>> +static struct config_element *find_element(const char *name,
>> +					   struct config_section *section_node)
>> +{
>> +	struct config_element *element_node;
>> +
>> +	list_for_each_entry(element_node, &section_node->element_head, list)
>> +		if (!strcmp(element_node->name, name))
>> +			return element_node;
>> +
>> +	return NULL;
>> +}
>> +
>> +static struct config_section *init_section(const char *section_name)
>> +{
>> +	struct config_section *section_node;
>> +
>> +	section_node = zalloc(sizeof(*section_node));
>> +	if (!section_node)
>> +		return NULL;
>> +
>> +	INIT_LIST_HEAD(&section_node->element_head);
>> +	section_node->name = strdup(section_name);
>> +	if (!section_node->name) {
>> +		pr_err("%s: strdup failed\n", __func__);
>> +		free(section_node);
>> +		return NULL;
>> +	}
>> +
>> +	return section_node;
>> +}
>> +
>> +static int add_element(struct list_head *head,
>> +			      const char *name, const char *value)
>> +{
>> +	struct config_element *element_node;
>> +
>> +	element_node = zalloc(sizeof(*element_node));
>> +	element_node->name = strdup(name);
>> +	if (!element_node->name) {
>> +		pr_err("%s: strdup failed\n", __func__);
>> +		goto out_free;
>> +	}
>> +	if (value)
>> +		element_node->value = (char *)value;
>> +	else
>> +		element_node->value = NULL;
>> +
>> +	list_add_tail(&element_node->list, head);
>> +	return 0;
>> +
>> +out_free:
>> +	free(element_node);
>> +	return -1;
>> +}
>> +
>> static int show_config(const char *key, const char *value,
>> 		       void *cb __maybe_unused)
>> {
>> @@ -39,10 +386,193 @@ static int show_config(const char *key, const char *value,
>> 	return 0;
>> }
>> 
>> +static void find_config(struct config_section **section_node,
>> +			struct config_element **element_node,
>> +			const char *section_name, const char *name)
>> +{
>> +	*section_node = find_section(section_name);
>> +
>> +	if (*section_node != NULL)
>> +		*element_node = find_element(name, *section_node);
>> +	else
>> +		*element_node = NULL;
>> +}
>> +
>> +static int show_spec_config(const char *section_name, const char *name,
>> +			    char *value __maybe_unused)
>> +{
>> +	int i;
>> +	struct config_section *section_node = NULL;
>> +	struct config_element *element_node = NULL;
>> +	char key[BUFSIZ];
>> +
>> +	find_config(&section_node, &element_node, section_name, name);
>> +
>> +	if (section_node && element_node) {
>> +		scnprintf(key, sizeof(key), "%s.%s",
>> +			  section_node->name, element_node->name);
>> +		return show_config(key, element_node->value, NULL);
>> +	}
>> +
>> +	for (i = 0; default_configsets[i].section_name != NULL; i++) {
>> +		if (!strcmp(default_configsets[i].section_name, section_name)
>> +		    && !strcmp(default_configsets[i].name, name)) {
>> +			printf("%s.%s=%s\n", default_configsets[i].section_name,
>> +			       default_configsets[i].name, default_configsets[i].value);
>> +			return 0;
>> +		}
>> +	}
>> +
>> +	pr_err("Error: Failed to find the variable.\n");
>> +
>> +	return 0;
>> +}
>> +
>> +static char *normalize_value(const char *section_name, const char *name, const char *value)
>> +{
>> +	int i;
>> +	char key[BUFSIZ];
>> +	char *normalized;
>> +
>> +	scnprintf(key, sizeof(key), "%s.%s", section_name, name);
>> +	for (i = 0; default_configsets[i].section_name != NULL; i++) {
>> +		if (!strcmp(default_configsets[i].section_name, section_name)
>> +		    && !strcmp(default_configsets[i].name, name)) {
>> +			normalized = zalloc(BUFSIZ);
>> +			if (!default_configsets[i].type)
>> +				scnprintf(normalized, BUFSIZ, "%s", value);
>> +			else if (!strcmp(default_configsets[i].type, TYPE_BOOL))
>> +				scnprintf(normalized, BUFSIZ, "%s",
>> +					  perf_config_bool(key, value) ? "true" : "false");
>> +			else if (!strcmp(default_configsets[i].type, TYPE_ON_OFF))
>> +				scnprintf(normalized, BUFSIZ, "%s",
>> +					  perf_config_bool(key, value) ? "on" : "off");
>> +			else if (!strcmp(default_configsets[i].type, TYPE_INT))
>> +				scnprintf(normalized, BUFSIZ, "%d",
>> +					  perf_config_int(key, value));
>> +			else if (!strcmp(default_configsets[i].type, TYPE_LONG))
>> +				scnprintf(normalized, BUFSIZ, "%"PRId64,
>> +					  perf_config_u64(key, value));
>> +			else if (!strcmp(default_configsets[i].type, TYPE_DIRNAME))
>> +				scnprintf(normalized, BUFSIZ, "%s",
>> +					  perf_config_dirname(key, value));
>> +			return normalized;
>> +		}
>> +	}
>> +
>> +	normalized = strdup(value);
>> +	if (!normalized) {
>> +		pr_err("%s: strdup failed\n", __func__);
>> +		return NULL;
>> +	}
>> +
>> +	return normalized;
>> +}
>> +
>> +static int set_config(const char *section_name, const char *name, char *value)
>> +{
>> +	struct config_section *section_node = NULL;
>> +	struct config_element *element_node = NULL;
>> +
>> +	find_config(&section_node, &element_node, section_name, name);
>> +	if (value != NULL) {
>> +		value = normalize_value(section_name, name, value);
>> +
>> +		/* if there isn't existent section, add a new section */
>> +		if (!section_node) {
>> +			section_node = init_section(section_name);
>> +			if (!section_node)
>> +				return -1;
>> +			list_add_tail(&section_node->list, &sections);
>> +		}
>> +		/* if nothing to replace, add a new element which contains key-value pair. */
>> +		if (!element_node) {
>> +			add_element(&section_node->element_head, name, value);
>> +		} else {
>> +			if (!element_node->value)
>> +				free(element_node->value);
>> +			element_node->value = value;
>> +		}
>> +	}
>> +	return perf_configset_write_in_full();
>> +}
>> +
>> +static int collect_current_config(const char *var, const char *value,
>> +			  void *cb __maybe_unused)
>> +{
>> +	struct config_section *section_node;
>> +	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, ".");
>> +
>> +	section_node = find_section(section_name);
>> +	if (!section_node) {
>> +		section_node = init_section(section_name);
>> +		if (!section_node)
>> +			return -1;
>> +		list_add_tail(&section_node->list, &sections);
>> +	}
>> +
>> +	return add_element(&section_node->element_head, name,
>> +			   normalize_value(section_name, name, value));
>> +}
>> +
>> +static int perf_configset_with_option(configset_fn_t fn, const char *var, char *value)
>> +{
>> +	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, ".");
>> +
>> +	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, "=");
>> +	}
>> +
>> +	return fn(section_name, name, value);
>> +
>> +	pr_err("invalid key: %s\n", var);
>> +	return -1;
>> +}
>> +
>> int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
>> {
>> -	int ret = 0;
>> +	int i, ret = 0;
>> 	int origin_argc = argc - 1;
>> +	char *value;
>> 	bool has_option;
>> 
>> 	argc = parse_options(argc, argv, config_options, config_usage,
>> @@ -52,6 +582,9 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
>> 	else
>> 		has_option = false;
>> 
>> +	INIT_LIST_HEAD(&sections);
>> +	perf_config(collect_current_config, NULL);
>> +
>> 	switch (actions) {
>> 	case ACTION_LIST:
>> 		if (argc == 0)
>> @@ -63,6 +596,19 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused)
>> 		if (!has_option && argc == 0) {
>> 			ret = perf_config(show_config, NULL);
>> 			goto out;
>> +		} else if (argc > 0) {
>> +			for (i = 0; argv[i]; i++) {
>> +				value = strchr(argv[i], '=');
>> +				if (value == NULL)
>> +					ret = perf_configset_with_option(show_spec_config,
>> +									 argv[i], value);
>> +				else
>> +					ret = perf_configset_with_option(set_config,
>> +									 argv[i], value);
>> +				if (ret < 0)
>> +					break;
>> +			}
>> +			goto out;
>> 		} else
>> 			goto out_err;
>> 	}
>> diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
>> index c861373..36d7839 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,6 +20,22 @@
>> #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;
>> +};
>> +
>> +struct list_head sections;
>> +
>> +typedef int (*configset_fn_t)(const char *, const char *, char*);
>> +extern int perf_configset_write_in_full(void);
>> 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 *);
>> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
>> index e18f653..b6c0d2c 100644
>> --- a/tools/perf/util/config.c
>> +++ b/tools/perf/util/config.c
>> @@ -21,7 +21,7 @@
>> char buildid_dir[MAXPATHLEN]; /* root dir for buildid, binary cache */
>> 
>> static FILE *config_file;
>> -static const char *config_file_name;
>> +static char *config_file_name;
>> static int config_linenr;
>> static int config_file_eof;
>> 
>> @@ -420,12 +420,11 @@ static int perf_config_from_file(config_fn_t fn, const char *filename, void *dat
>> 	ret = -1;
>> 	if (f) {
>> 		config_file = f;
>> -		config_file_name = filename;
>> +		config_file_name = strdup(filename);
>> 		config_linenr = 1;
>> 		config_file_eof = 0;
>> 		ret = perf_parse_file(fn, data);
>> 		fclose(f);
>> -		config_file_name = NULL;
>> 	}
>> 	return ret;
>> }
>> @@ -502,6 +501,31 @@ out:
>> 	return ret;
>> }
>> 
>> +int perf_configset_write_in_full(void)
>> +{
>> +	struct config_section *section_node;
>> +	struct config_element *element_node;
>> +	const char *first_line = "# this file is auto-generated.";
>> +	FILE *fp = fopen(config_file_name, "w");
>> +
>> +	if (!fp)
>> +		return -1;
>> +
>> +	fprintf(fp, "%s\n", first_line);
>> +	/* overwrite configvariables */
>> +	list_for_each_entry(section_node, &sections, list) {
>> +		fprintf(fp, "[%s]\n", section_node->name);
>> +		list_for_each_entry(element_node, &section_node->element_head, list) {
>> +			if (element_node->value)
>> +				fprintf(fp, "\t%s = %s\n",
>> +					element_node->name, element_node->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	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 0/5]
  2023-05-29 15:35 [PATCH v3 0/5] Bernhard Rosenkränzer
@ 2023-05-29 16:30 ` Matthias Brugger
  0 siblings, 0 replies; 18+ messages in thread
From: Matthias Brugger @ 2023-05-29 16:30 UTC (permalink / raw)
  To: Bernhard Rosenkränzer, daniel.lezcano,
	angelogioacchino.delregno, rafael, amitk, rui.zhang, robh+dt,
	krzystof.kozlowski+dt, rdunlap, ye.xingchen, p.zabel
  Cc: linux-pm, linux-kernel, linux-arm-kernel, linux-mediatek,
	devicetree, wenst, james.lo, rex-bc.chen, nfraprado, abailon,
	amergnat, khilman

Hi Bernhard,

Please resend with a subject line for the cover letter.

Regards,
Matthias

On 29/05/2023 17:35, Bernhard Rosenkränzer wrote:
> From: Balsam CHIHI <bchihi@baylibre.com>
> 
> Add full LVTS support (MCU thermal domain + AP thermal domain) to MediaTek MT8192 SoC.
> Also, add Suspend and Resume support to LVTS Driver (all SoCs),
> and update the documentation that describes the Calibration Data Offsets.
> 
> Changelog:
>      v3 :
>          - Rebased :
>              base-commit: 6a3d37b4d885129561e1cef361216f00472f7d2e
>          - Fix issues in v2 pointed out by Nícolas F. R. A. Prado <nfraprado@collabora.com>:
>            Use filtered mode to make sure threshold interrupts are triggered,
>            protocol documentation, cosmetics
>          - I (bero@baylibre.com) will be taking care of this patchset
>            from now on, since Balsam has left BayLibre. Thanks for
>            getting it almost ready, Balsam!
> 
>      v2 :
>          - Based on top of thermal/linux-next :
>              base-commit: 7ac82227ee046f8234471de4c12a40b8c2d3ddcc
>          - Squash "add thermal zones and thermal nodes" and
>              "add temperature mitigation threshold" commits together to form
>              "arm64: dts: mediatek: mt8192: Add thermal nodes and thermal zones" commit.
>          - Add Suspend and Resume support to LVTS Driver.
>          - Update Calibration Data documentation.
>          - Fix calibration data offsets for mt8192
>              (Thanks to "Chen-Yu Tsai" and "Nícolas F. R. A. Prado").
>          https://lore.kernel.org/all/20230425133052.199767-1-bchihi@baylibre.com/
>          Tested-by: Chen-Yu Tsai <wenst@chromium.org>
> 
>      v1 :
>          - The initial series "Add LVTS support for mt8192" :
>              "https://lore.kernel.org/all/20230307163413.143334-1-bchihi@baylibre.com/".
> 
> Balsam CHIHI (5):
>    dt-bindings: thermal: mediatek: Add LVTS thermal controller definition
>      for mt8192
>    thermal/drivers/mediatek/lvts_thermal: Add suspend and resume
>    thermal/drivers/mediatek/lvts_thermal: Add mt8192 support
>    arm64: dts: mediatek: mt8192: Add thermal nodes and thermal zones
>    thermal/drivers/mediatek/lvts_thermal: Update calibration data
>      documentation
> 
>   arch/arm64/boot/dts/mediatek/mt8192.dtsi      | 454 ++++++++++++++++++
>   drivers/thermal/mediatek/lvts_thermal.c       | 160 +++++-
>   .../thermal/mediatek,lvts-thermal.h           |  19 +
>   3 files changed, 631 insertions(+), 2 deletions(-)
> 
> base-commit: 6a3d37b4d885129561e1cef361216f00472f7d2e

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v3 0/5]
@ 2023-05-29 15:35 Bernhard Rosenkränzer
  2023-05-29 16:30 ` Matthias Brugger
  0 siblings, 1 reply; 18+ messages in thread
From: Bernhard Rosenkränzer @ 2023-05-29 15:35 UTC (permalink / raw)
  To: daniel.lezcano, angelogioacchino.delregno, rafael, amitk,
	rui.zhang, matthias.bgg, robh+dt, krzystof.kozlowski+dt, rdunlap,
	ye.xingchen, p.zabel
  Cc: linux-pm, linux-kernel, linux-arm-kernel, linux-mediatek,
	devicetree, wenst, james.lo, rex-bc.chen, nfraprado, abailon,
	amergnat, khilman

From: Balsam CHIHI <bchihi@baylibre.com>

Add full LVTS support (MCU thermal domain + AP thermal domain) to MediaTek MT8192 SoC.
Also, add Suspend and Resume support to LVTS Driver (all SoCs),
and update the documentation that describes the Calibration Data Offsets.

Changelog:
    v3 : 
        - Rebased :
            base-commit: 6a3d37b4d885129561e1cef361216f00472f7d2e
        - Fix issues in v2 pointed out by Nícolas F. R. A. Prado <nfraprado@collabora.com>:
          Use filtered mode to make sure threshold interrupts are triggered,
          protocol documentation, cosmetics
        - I (bero@baylibre.com) will be taking care of this patchset
          from now on, since Balsam has left BayLibre. Thanks for
          getting it almost ready, Balsam!

    v2 :
        - Based on top of thermal/linux-next :
            base-commit: 7ac82227ee046f8234471de4c12a40b8c2d3ddcc
        - Squash "add thermal zones and thermal nodes" and
            "add temperature mitigation threshold" commits together to form
            "arm64: dts: mediatek: mt8192: Add thermal nodes and thermal zones" commit.
        - Add Suspend and Resume support to LVTS Driver.
        - Update Calibration Data documentation.
        - Fix calibration data offsets for mt8192
            (Thanks to "Chen-Yu Tsai" and "Nícolas F. R. A. Prado").
        https://lore.kernel.org/all/20230425133052.199767-1-bchihi@baylibre.com/
        Tested-by: Chen-Yu Tsai <wenst@chromium.org>

    v1 :
        - The initial series "Add LVTS support for mt8192" :
            "https://lore.kernel.org/all/20230307163413.143334-1-bchihi@baylibre.com/".

Balsam CHIHI (5):
  dt-bindings: thermal: mediatek: Add LVTS thermal controller definition
    for mt8192
  thermal/drivers/mediatek/lvts_thermal: Add suspend and resume
  thermal/drivers/mediatek/lvts_thermal: Add mt8192 support
  arm64: dts: mediatek: mt8192: Add thermal nodes and thermal zones
  thermal/drivers/mediatek/lvts_thermal: Update calibration data
    documentation

 arch/arm64/boot/dts/mediatek/mt8192.dtsi      | 454 ++++++++++++++++++
 drivers/thermal/mediatek/lvts_thermal.c       | 160 +++++-
 .../thermal/mediatek,lvts-thermal.h           |  19 +
 3 files changed, 631 insertions(+), 2 deletions(-)

base-commit: 6a3d37b4d885129561e1cef361216f00472f7d2e
-- 
2.41.0.rc2


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 0/5]
  2019-02-08 16:11 Federico Vaga
@ 2019-02-09 21:41 ` Andrew Lunn
  0 siblings, 0 replies; 18+ messages in thread
From: Andrew Lunn @ 2019-02-09 21:41 UTC (permalink / raw)
  To: Federico Vaga; +Cc: Peter Korsgaard, linux-i2c, linux-kernel

On Fri, Feb 08, 2019 at 05:11:56PM +0100, Federico Vaga wrote:
> This patch set provides improvements to the i2c-ocore driver.

Hi Federico

Please could you fixup the SPDX patch, add my review/tested by tags,
and i think we are good to go.

Thanks
	Andrew

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v3 0/5]
@ 2019-02-08 16:11 Federico Vaga
  2019-02-09 21:41 ` Andrew Lunn
  0 siblings, 1 reply; 18+ messages in thread
From: Federico Vaga @ 2019-02-08 16:11 UTC (permalink / raw)
  To: Peter Korsgaard, Andrew Lunn; +Cc: linux-i2c, linux-kernel

This patch set provides improvements to the i2c-ocore driver.

[V2 -> V3]
- fix error condition on platform_get_irq(). Copied from
  https://patchwork.ozlabs.org/patch/1038409/

[V1 -> V2]
- replaced usleep_range() with udelay() so that the polling version can be
  used in atomic context.
- added dedicated patch for minor style issues
- fixed delay computation
- use spin_lock_irqsave(), instead of spin_trylock_irqsave(). IACK is always
  necessary and a trylock would generate an extra interrupt for nothing
- make the driver ready for an eventual master_xfer_irqless()


^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 0/5]
  2018-05-18 14:39 Marc Zyngier
  2018-05-18 16:29 ` Vince Weaver
@ 2018-05-21 18:19 ` Will Deacon
  1 sibling, 0 replies; 18+ messages in thread
From: Will Deacon @ 2018-05-21 18:19 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: linux-arm-kernel, linux-kernel, Mark Rutland, Russell King,
	Vladimir Murzin, Vince Weaver, Peter Zijlstra, Stefan Wahren,
	Eric Anholt, Florian Fainelli

Hi Marc,

Thanks for this.

On Fri, May 18, 2018 at 03:39:08PM +0100, Marc Zyngier wrote:
> PMUv3 has been introduced with ARMv8 and, while it has only been used
> on 64bit systems so far, it would definitely be useful for 32bit
> guests running under KVM/arm64, for example.
> 
> There is also the case of people natively running 32bit kernels on
> 64bit HW and trying to upstream unspeakable hacks, hoping that the
> stars will align and that they'll win the lottery (see [1]).
> 
> So let's try again, and make the PMUv3 driver usable for everyone.
> 
> This is done in three steps:
> (1) Move the driver from arch/arm64 to drivers/perf
> (2) Add a handful of system register accessors so that we can reuse
>     the driver on 32bit
> (3) Provide the same accessors on 32bit, enable compilation, and
>     make it the default selection for mach-virt.
> 
> Tested on a Seattle box with 32bit guests.

I think we should go ahead with something like this, but I don't think
we're quite there with these patches. If we're going to move the arch code
out into drivers, let's do that for the perf_event* files under arch/arm/
as well. Then we could have a structure along the lines of:


  drivers/perf/arm_pmu.c			- As it is today
  drivers/perf/arm_cpu/xscale_pmu.c		- Only builds for 32-bit
  drivers/perf/arm_cpu/armv6_pmu.c		- Only builds for 32-bit
  drivers/perf/arm_cpu/arch_pmu.c		- Works for v7/v8 on
                                                  both 32-bit and 64-bit

The latter can then pull in whatever accessors it needs from the arch
code headers.

I know it's more of an invasive change, but this way we always end up
running the same code on the two architectures and it will be much easier
to maintain.

Will

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 0/5]
  2018-05-18 16:41   ` Marc Zyngier
@ 2018-05-18 17:39     ` Stefan Wahren
  0 siblings, 0 replies; 18+ messages in thread
From: Stefan Wahren @ 2018-05-18 17:39 UTC (permalink / raw)
  To: Marc Zyngier, Vince Weaver
  Cc: Peter Zijlstra, Florian Fainelli, Vladimir Murzin, Eric Anholt,
	Mark Rutland, Russell King, Will Deacon, linux-kernel,
	linux-arm-kernel

> Marc Zyngier <marc.zyngier@arm.com> hat am 18. Mai 2018 um 18:41 geschrieben:
> 
> 
> [/me beats himself for not writing a subject line...]
> 
> On 18/05/18 17:29, Vince Weaver wrote:
> > On Fri, 18 May 2018, Marc Zyngier wrote:
> > 
> >> There is also the case of people natively running 32bit kernels on
> >> 64bit HW and trying to upstream unspeakable hacks, hoping that the
> >> stars will align and that they'll win the lottery (see [1]).
> > 
> > I've tested these patches on a Raspberry Pi 3B running a 32-bit upstream 
> > (4.17-rc5-git) kernel and they work.
> > 
> > [    0.472906] hw perfevents: enabled with armv8_cortex_a53 PMU driver, 7 counters available
> > 
> > I only needed to add this to the devicetree
> > 
> > 	arm-pmu {
> > 		compatible = "arm,cortex-a53-pmu";
> > 		interrupt-parent = <&local_intc>;
> > 		interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
> > 	};
> 
> That's definitely the sensible thing to have on such hardware. Why isn't
> it in the upstream DT already, irrespective of the state of the kernel
> support?

I remember that Vince point out the absence. He asked about how to implement it and i wasn't sure about it. At this time we hadn't IRQ polarity support. So we wanted to get this puzzle piece before. In march i put it on my TODO list, but then RPI 3 B+ support had higher prio to get into 4.18.

In general we have the problem that most of the users take the downstream kernel and don't know about the differences. Luckily more distributions switch to the upstream kernel, which increases the feedback.

> 
> > Tested-by: Vince Weaver <vincent.weaver@maine.edu>

Thanks again
Stefan

> 
> Thanks a lot for testing.
> 
> 	M.
> -- 
> Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 0/5]
  2018-05-18 16:29 ` Vince Weaver
@ 2018-05-18 16:41   ` Marc Zyngier
  2018-05-18 17:39     ` Stefan Wahren
  0 siblings, 1 reply; 18+ messages in thread
From: Marc Zyngier @ 2018-05-18 16:41 UTC (permalink / raw)
  To: Vince Weaver
  Cc: linux-arm-kernel, linux-kernel, Will Deacon, Mark Rutland,
	Russell King, Vladimir Murzin, Peter Zijlstra, Stefan Wahren,
	Eric Anholt, Florian Fainelli

[/me beats himself for not writing a subject line...]

On 18/05/18 17:29, Vince Weaver wrote:
> On Fri, 18 May 2018, Marc Zyngier wrote:
> 
>> There is also the case of people natively running 32bit kernels on
>> 64bit HW and trying to upstream unspeakable hacks, hoping that the
>> stars will align and that they'll win the lottery (see [1]).
> 
> I've tested these patches on a Raspberry Pi 3B running a 32-bit upstream 
> (4.17-rc5-git) kernel and they work.
> 
> [    0.472906] hw perfevents: enabled with armv8_cortex_a53 PMU driver, 7 counters available
> 
> I only needed to add this to the devicetree
> 
> 	arm-pmu {
> 		compatible = "arm,cortex-a53-pmu";
> 		interrupt-parent = <&local_intc>;
> 		interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
> 	};

That's definitely the sensible thing to have on such hardware. Why isn't
it in the upstream DT already, irrespective of the state of the kernel
support?

> Tested-by: Vince Weaver <vincent.weaver@maine.edu>

Thanks a lot for testing.

	M.
-- 
Jazz is not dead. It just smells funny...

^ permalink raw reply	[flat|nested] 18+ messages in thread

* Re: [PATCH v3 0/5]
  2018-05-18 14:39 Marc Zyngier
@ 2018-05-18 16:29 ` Vince Weaver
  2018-05-18 16:41   ` Marc Zyngier
  2018-05-21 18:19 ` Will Deacon
  1 sibling, 1 reply; 18+ messages in thread
From: Vince Weaver @ 2018-05-18 16:29 UTC (permalink / raw)
  To: Marc Zyngier
  Cc: linux-arm-kernel, linux-kernel, Will Deacon, Mark Rutland,
	Russell King, Vladimir Murzin, Vince Weaver, Peter Zijlstra,
	Stefan Wahren, Eric Anholt, Florian Fainelli

On Fri, 18 May 2018, Marc Zyngier wrote:

> There is also the case of people natively running 32bit kernels on
> 64bit HW and trying to upstream unspeakable hacks, hoping that the
> stars will align and that they'll win the lottery (see [1]).

I've tested these patches on a Raspberry Pi 3B running a 32-bit upstream 
(4.17-rc5-git) kernel and they work.

[    0.472906] hw perfevents: enabled with armv8_cortex_a53 PMU driver, 7 counters available

I only needed to add this to the devicetree

	arm-pmu {
		compatible = "arm,cortex-a53-pmu";
		interrupt-parent = <&local_intc>;
		interrupts = <9 IRQ_TYPE_LEVEL_HIGH>;
	};


Tested-by: Vince Weaver <vincent.weaver@maine.edu>

Vince

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v3 0/5]
@ 2018-05-18 14:39 Marc Zyngier
  2018-05-18 16:29 ` Vince Weaver
  2018-05-21 18:19 ` Will Deacon
  0 siblings, 2 replies; 18+ messages in thread
From: Marc Zyngier @ 2018-05-18 14:39 UTC (permalink / raw)
  To: linux-arm-kernel, linux-kernel
  Cc: Will Deacon, Mark Rutland, Russell King, Vladimir Murzin,
	Vince Weaver, Peter Zijlstra, Stefan Wahren, Eric Anholt,
	Florian Fainelli

PMUv3 has been introduced with ARMv8 and, while it has only been used
on 64bit systems so far, it would definitely be useful for 32bit
guests running under KVM/arm64, for example.

There is also the case of people natively running 32bit kernels on
64bit HW and trying to upstream unspeakable hacks, hoping that the
stars will align and that they'll win the lottery (see [1]).

So let's try again, and make the PMUv3 driver usable for everyone.

This is done in three steps:
(1) Move the driver from arch/arm64 to drivers/perf
(2) Add a handful of system register accessors so that we can reuse
    the driver on 32bit
(3) Provide the same accessors on 32bit, enable compilation, and
    make it the default selection for mach-virt.

Tested on a Seattle box with 32bit guests.

* From v1:
  - Fixed encodings for some CP15 accessors
  - Added a terse note saying that CPU_V7 also covers ARMv8
  - Rebased on v4.12-rc5

* From v2:
  - SPDX tags on new and moved files. Yeah!
  - Annual rebase on 4.17-rc5

[1] https://patchwork.kernel.org/patch/10406793/

Marc Zyngier (5):
  arm64: perf: Move PMUv3 driver to drivers/perf
  arm64: perf: Abstract system register accesses away
  ARM: Make CONFIG_CPU_V7 valid for 32bit ARMv8 implementations
  ARM: perf: Allow the use of the PMUv3 driver on 32bit ARM
  ARM: mach-virt: Select PMUv3 driver by default

 arch/arm/Kconfig                                   |   1 +
 arch/arm/include/asm/arm_pmuv3.h                   | 125 +++++++++++++++++++++
 arch/arm/mm/Kconfig                                |   2 +-
 arch/arm64/include/asm/arm_pmuv3.h                 | 111 ++++++++++++++++++
 arch/arm64/include/asm/perf_event.h                |  55 ---------
 arch/arm64/kernel/Makefile                         |   1 -
 drivers/perf/Kconfig                               |   8 ++
 drivers/perf/Makefile                              |   1 +
 .../perf_event.c => drivers/perf/arm_pmuv3.c       |  42 ++++---
 include/kvm/arm_pmu.h                              |   2 +-
 include/linux/perf/arm_pmuv3.h                     |  78 +++++++++++++
 11 files changed, 346 insertions(+), 80 deletions(-)
 create mode 100644 arch/arm/include/asm/arm_pmuv3.h
 create mode 100644 arch/arm64/include/asm/arm_pmuv3.h
 rename arch/arm64/kernel/perf_event.c => drivers/perf/arm_pmuv3.c (97%)
 create mode 100644 include/linux/perf/arm_pmuv3.h

-- 
2.14.2

^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v3 0/5]
@ 2014-12-08  9:46 Yunzhi Li
  0 siblings, 0 replies; 18+ messages in thread
From: Yunzhi Li @ 2014-12-08  9:46 UTC (permalink / raw)
  To: heiko, dianders, romain.perier
  Cc: olof, huangtao, zyw, cf, linux-rockchip, Yunzhi Li, devicetree,
	Paul Zimmerman, linux-usb, Kumar Gala, linux-kernel,
	Grant Likely, Ian Campbell, Rob Herring, Pawel Moll,
	Kishon Vijay Abraham I, Mark Rutland, Russell King,
	linux-arm-kernel, Greg Kroah-Hartman

Patches to add support for Rockchip usb phys.Add a new Rockchip
usb phy driver and modify dwc2 controller driver to make dwc2
platform devices support a generic PHY framework driver. This
patch set has been tested on my rk3288-evb and power off the usb
phys would reduce about 60mW power budget in total during sustem
suspend.

Changes in v3:
- Use BIT macro instead of bit shift ops.
- Rename the config entry to PHY_ROCKCHIP_USB.
- Fix coding style: both branches of the if() which only one
  branch of the conditional statement is a single statement should
  have braces.
- No need to test dwc2->phy for NULL before calling generic phy
  APIs.
- Add more context about the changes in the long description.

Yunzhi Li (5):
  phy: add a driver for the Rockchip SoC internal USB2.0 PHY
  Documentation: bindings: add doc for the Rockchip usb PHY
  usb: dwc2: add generic PHY framework support for dwc2 usb    
    controler platform driver.
  ARM: dts: add rk3288 usb PHY
  ARM: dts: Enable usb PHY on rk3288-evb board

 .../devicetree/bindings/phy/rockchip-usb-phy.txt   |  22 +++
 arch/arm/boot/dts/rk3288-evb.dtsi                  |   4 +
 arch/arm/boot/dts/rk3288.dtsi                      |  13 ++
 drivers/phy/Kconfig                                |   7 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-rockchip-usb.c                     | 179 +++++++++++++++++++++
 drivers/usb/dwc2/gadget.c                          |  33 ++--
 drivers/usb/dwc2/platform.c                        |  36 ++++-
 8 files changed, 272 insertions(+), 23 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/phy/rockchip-usb-phy.txt
 create mode 100644 drivers/phy/phy-rockchip-usb.c

-- 
2.0.0



^ permalink raw reply	[flat|nested] 18+ messages in thread

* [PATCH v3 0/5]
@ 2009-11-10 22:36 Alex Chiang
  0 siblings, 0 replies; 18+ messages in thread
From: Alex Chiang @ 2009-11-10 22:36 UTC (permalink / raw)
  To: akpm; +Cc: linux-mm, linux-kernel, rientjes

This is v3 of the series.

I based it off of Linus's latest tree. 

I did not include David Rientjes's "mm: slab allocate memory section nodemask
for large systems" patch in my series, since it's not necessarily related.

Please consider for inclusion for the next merge window (v2.6.33).

Thanks,
/ac

v2 -> v3:
	- rebased to Linus's latest tree (799dd75b)
	- Added David Rientjes's Acked-by: flags
	- dropped S390 cc's, since they are unaffected by this series

v1 -> v2: http://thread.gmane.org/gmane.linux.kernel.mm/40084/
        Address David Rientjes's comments
        - check return value of sysfs_create_link in register_cpu_under_node
        - do /not/ convert [un]register_cpu_under_node to return void, since
          sparse starts whinging if you ignore sysfs_create_link()'s return
          value and working around sparse makes the code ugly
        - adjust documentation

        Added S390 maintainers to cc: for patch [1/5] as per Kame-san's
        suggestion. S390 may map a memory section to more than one node,
        causing this series to break.


---

Alex Chiang (5):
      mm: add numa node symlink for memory section in sysfs
      mm: refactor register_cpu_under_node()
      mm: refactor unregister_cpu_under_node()
      mm: add numa node symlink for cpu devices in sysfs
      Documentation: ABI: /sys/devices/system/cpu/cpu#/node


 Documentation/ABI/testing/sysfs-devices-memory     |   14 ++++-
 Documentation/ABI/testing/sysfs-devices-system-cpu |   14 +++++
 Documentation/memory-hotplug.txt                   |   11 ++--
 drivers/base/node.c                                |   58 ++++++++++++++------
 4 files changed, 76 insertions(+), 21 deletions(-)


^ permalink raw reply	[flat|nested] 18+ messages in thread

end of thread, other threads:[~2023-05-29 16:31 UTC | newest]

Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-12  5:10 [PATCH v3 0/5] Taeung Song
2015-07-12  5:10 ` [PATCH v3 1/5] perf tools: Add 'perf-config' command Taeung Song
2015-07-12  5:10 ` [PATCH v3 2/5] perf config: Add functions which can get or set perf config variables Taeung Song
2015-07-12 14:33   ` Jiri Olsa
2015-07-19  9:57     ` Taewoong Song
2015-07-12  5:10 ` [PATCH v3 3/5] perf config: Add a option 'list-all' to perf-config Taeung Song
2015-07-12  5:10 ` [PATCH v3 4/5] perf config: Add a option 'remove' " Taeung Song
  -- strict thread matches above, loose matches on Subject: below --
2023-05-29 15:35 [PATCH v3 0/5] Bernhard Rosenkränzer
2023-05-29 16:30 ` Matthias Brugger
2019-02-08 16:11 Federico Vaga
2019-02-09 21:41 ` Andrew Lunn
2018-05-18 14:39 Marc Zyngier
2018-05-18 16:29 ` Vince Weaver
2018-05-18 16:41   ` Marc Zyngier
2018-05-18 17:39     ` Stefan Wahren
2018-05-21 18:19 ` Will Deacon
2014-12-08  9:46 Yunzhi Li
2009-11-10 22:36 Alex Chiang

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®