linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 1/4] perf config: Introduce perf_config_set class
@ 2016-03-29  0:43 Taeung Song
  2016-03-29 16:12 ` Arnaldo Carvalho de Melo
  2016-03-31 17:31 ` Arnaldo Carvalho de Melo
  0 siblings, 2 replies; 9+ messages in thread
From: Taeung Song @ 2016-03-29  0:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo, Namhyung Kim
  Cc: linux-kernel, Jiri Olsa, Ingo Molnar, Peter Zijlstra, Taeung Song

This infrastructure code was designed for
upcoming features of perf-config.

That collect config key-value pairs from user and
system config files (i.e. user wide ~/.perfconfig
and system wide $(sysconfdir)/perfconfig)
to manage perf's configs.

Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Jiri Olsa <jolsa@kernel.org>
Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
---
 tools/perf/util/config.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/config.h |  26 +++++++
 2 files changed, 197 insertions(+)
 create mode 100644 tools/perf/util/config.h

diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 4e72763..2dbf47c 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -13,6 +13,7 @@
 #include <subcmd/exec-cmd.h>
 #include "util/hist.h"  /* perf_hist_config */
 #include "util/llvm-utils.h"   /* perf_llvm_config */
+#include "config.h"
 
 #define MAXNAME (256)
 
@@ -506,6 +507,176 @@ out:
 	return ret;
 }
 
+static struct perf_config_section *find_section(struct list_head *sections,
+						const char *section_name)
+{
+	struct perf_config_section *section;
+
+	list_for_each_entry(section, sections, list)
+		if (!strcmp(section->name, section_name))
+			return section;
+
+	return NULL;
+}
+
+static struct perf_config_item *find_config_item(const char *name,
+						 struct perf_config_section *section)
+{
+	struct perf_config_item *config_item;
+
+	list_for_each_entry(config_item, &section->config_items, list)
+		if (!strcmp(config_item->name, name))
+			return config_item;
+
+	return NULL;
+}
+
+static void find_config(struct list_head *sections,
+			struct perf_config_section **section,
+			struct perf_config_item **config_item,
+			const char *section_name, const char *name)
+{
+	*section = find_section(sections, section_name);
+
+	if (*section != NULL)
+		*config_item = find_config_item(name, *section);
+	else
+		*config_item = NULL;
+}
+
+static struct perf_config_section *add_section(struct list_head *sections,
+					       const char *section_name)
+{
+	struct perf_config_section *section = zalloc(sizeof(*section));
+
+	if (!section)
+		return NULL;
+
+	INIT_LIST_HEAD(&section->config_items);
+	section->name = strdup(section_name);
+	if (!section->name) {
+		pr_err("%s: strdup failed\n", __func__);
+		free(section);
+		return NULL;
+	}
+
+	list_add_tail(&section->list, sections);
+	return section;
+}
+
+static struct perf_config_item *add_config_item(struct perf_config_section *section,
+						const char *name)
+{
+	struct perf_config_item *config_item = zalloc(sizeof(*config_item));
+
+	if (!config_item)
+		return NULL;
+
+	config_item->name = strdup(name);
+	if (!name) {
+		pr_err("%s: strdup failed\n", __func__);
+		goto out_err;
+	}
+
+	list_add_tail(&config_item->list, &section->config_items);
+	return config_item;
+
+out_err:
+	free(config_item);
+	return NULL;
+}
+
+static int set_value(struct perf_config_item *config_item, const char *value)
+{
+	char *val = strdup(value);
+
+	if (!val)
+		return -1;
+
+	free(config_item->value);
+	config_item->value = val;
+	return 0;
+}
+
+static int collect_config(const char *var, const char *value,
+			  void *perf_config_set)
+{
+	int ret = -1;
+	char *ptr, *key;
+	char *section_name, *name;
+	struct perf_config_section *section = NULL;
+	struct perf_config_item *config_item = NULL;
+	struct perf_config_set *perf_configs = perf_config_set;
+	struct list_head *sections = &perf_configs->sections;
+
+	key = ptr = strdup(var);
+	if (!key) {
+		pr_err("%s: strdup failed\n", __func__);
+		return -1;
+	}
+
+	section_name = strsep(&ptr, ".");
+	name = ptr;
+	if (name == NULL || value == NULL)
+		goto out_free;
+
+	find_config(sections, &section, &config_item, section_name, name);
+
+	if (!section) {
+		section = add_section(sections, section_name);
+		if (!section)
+			goto out_free;
+	}
+	if (!config_item) {
+		config_item = add_config_item(section, name);
+		if (!config_item)
+			goto out_free;
+	}
+
+	ret = set_value(config_item, value);
+	return ret;
+
+out_free:
+	free(key);
+	perf_config_set__delete(perf_configs);
+	return -1;
+}
+
+struct perf_config_set *perf_config_set__new(void)
+{
+	struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));
+
+	if (!perf_configs)
+		return NULL;
+
+	INIT_LIST_HEAD(&perf_configs->sections);
+	perf_config(collect_config, perf_configs);
+
+	return perf_configs;
+}
+
+void perf_config_set__delete(struct perf_config_set *perf_configs)
+{
+	struct perf_config_section *section, *section_tmp;
+	struct perf_config_item *config_item, *item_tmp;
+
+	list_for_each_entry_safe(section, section_tmp,
+				 &perf_configs->sections, list) {
+		list_for_each_entry_safe(config_item, item_tmp,
+					 &section->config_items, list) {
+			list_del(&config_item->list);
+			free(config_item->name);
+			free(config_item->value);
+			free(config_item);
+		}
+		list_del(&section->list);
+		free(section->name);
+		free(section);
+	}
+
+	free(perf_configs);
+}
+
 /*
  * Call this to report error for your variable that should not
  * get a boolean value (i.e. "[my] var" means "true").
diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
new file mode 100644
index 0000000..e270e51
--- /dev/null
+++ b/tools/perf/util/config.h
@@ -0,0 +1,26 @@
+#ifndef __PERF_CONFIG_H
+#define __PERF_CONFIG_H
+
+#include <stdbool.h>
+#include <linux/list.h>
+
+struct perf_config_item {
+	char *name;
+	char *value;
+	struct list_head list;
+};
+
+struct perf_config_section {
+	char *name;
+	struct list_head config_items;
+	struct list_head list;
+};
+
+struct perf_config_set {
+	struct list_head sections;
+};
+
+struct perf_config_set *perf_config_set__new(void);
+void perf_config_set__delete(struct perf_config_set *perf_configs);
+
+#endif /* __PERF_CONFIG_H */
-- 
2.5.0

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

* Re: [PATCH v4 1/4] perf config: Introduce perf_config_set class
  2016-03-29  0:43 [PATCH v4 1/4] perf config: Introduce perf_config_set class Taeung Song
@ 2016-03-29 16:12 ` Arnaldo Carvalho de Melo
  2016-03-29 23:28   ` Taeung Song
  2016-03-31 17:31 ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 9+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-03-29 16:12 UTC (permalink / raw)
  To: Taeung Song
  Cc: Namhyung Kim, linux-kernel, Jiri Olsa, Ingo Molnar, Peter Zijlstra

Em Tue, Mar 29, 2016 at 09:43:13AM +0900, Taeung Song escreveu:
> This infrastructure code was designed for
> upcoming features of perf-config.
> 
> That collect config key-value pairs from user and
> system config files (i.e. user wide ~/.perfconfig
> and system wide $(sysconfdir)/perfconfig)
> to manage perf's configs.
> 
> Cc: Namhyung Kim <namhyung@kernel.org>
> Cc: Jiri Olsa <jolsa@kernel.org>
> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>

Waiting for ack.
> ---
>  tools/perf/util/config.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/config.h |  26 +++++++
>  2 files changed, 197 insertions(+)
>  create mode 100644 tools/perf/util/config.h
> 
> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
> index 4e72763..2dbf47c 100644
> --- a/tools/perf/util/config.c
> +++ b/tools/perf/util/config.c
> @@ -13,6 +13,7 @@
>  #include <subcmd/exec-cmd.h>
>  #include "util/hist.h"  /* perf_hist_config */
>  #include "util/llvm-utils.h"   /* perf_llvm_config */
> +#include "config.h"
>  
>  #define MAXNAME (256)
>  
> @@ -506,6 +507,176 @@ out:
>  	return ret;
>  }
>  
> +static struct perf_config_section *find_section(struct list_head *sections,
> +						const char *section_name)
> +{
> +	struct perf_config_section *section;
> +
> +	list_for_each_entry(section, sections, list)
> +		if (!strcmp(section->name, section_name))
> +			return section;
> +
> +	return NULL;
> +}
> +
> +static struct perf_config_item *find_config_item(const char *name,
> +						 struct perf_config_section *section)
> +{
> +	struct perf_config_item *config_item;
> +
> +	list_for_each_entry(config_item, &section->config_items, list)
> +		if (!strcmp(config_item->name, name))
> +			return config_item;
> +
> +	return NULL;
> +}
> +
> +static void find_config(struct list_head *sections,
> +			struct perf_config_section **section,
> +			struct perf_config_item **config_item,
> +			const char *section_name, const char *name)
> +{
> +	*section = find_section(sections, section_name);
> +
> +	if (*section != NULL)
> +		*config_item = find_config_item(name, *section);
> +	else
> +		*config_item = NULL;
> +}
> +
> +static struct perf_config_section *add_section(struct list_head *sections,
> +					       const char *section_name)
> +{
> +	struct perf_config_section *section = zalloc(sizeof(*section));
> +
> +	if (!section)
> +		return NULL;
> +
> +	INIT_LIST_HEAD(&section->config_items);
> +	section->name = strdup(section_name);
> +	if (!section->name) {
> +		pr_err("%s: strdup failed\n", __func__);
> +		free(section);
> +		return NULL;
> +	}
> +
> +	list_add_tail(&section->list, sections);
> +	return section;
> +}
> +
> +static struct perf_config_item *add_config_item(struct perf_config_section *section,
> +						const char *name)
> +{
> +	struct perf_config_item *config_item = zalloc(sizeof(*config_item));
> +
> +	if (!config_item)
> +		return NULL;
> +
> +	config_item->name = strdup(name);
> +	if (!name) {
> +		pr_err("%s: strdup failed\n", __func__);
> +		goto out_err;
> +	}
> +
> +	list_add_tail(&config_item->list, &section->config_items);
> +	return config_item;
> +
> +out_err:
> +	free(config_item);
> +	return NULL;
> +}
> +
> +static int set_value(struct perf_config_item *config_item, const char *value)
> +{
> +	char *val = strdup(value);
> +
> +	if (!val)
> +		return -1;
> +
> +	free(config_item->value);
> +	config_item->value = val;
> +	return 0;
> +}
> +
> +static int collect_config(const char *var, const char *value,
> +			  void *perf_config_set)
> +{
> +	int ret = -1;
> +	char *ptr, *key;
> +	char *section_name, *name;
> +	struct perf_config_section *section = NULL;
> +	struct perf_config_item *config_item = NULL;
> +	struct perf_config_set *perf_configs = perf_config_set;
> +	struct list_head *sections = &perf_configs->sections;
> +
> +	key = ptr = strdup(var);
> +	if (!key) {
> +		pr_err("%s: strdup failed\n", __func__);
> +		return -1;
> +	}
> +
> +	section_name = strsep(&ptr, ".");
> +	name = ptr;
> +	if (name == NULL || value == NULL)
> +		goto out_free;
> +
> +	find_config(sections, &section, &config_item, section_name, name);
> +
> +	if (!section) {
> +		section = add_section(sections, section_name);
> +		if (!section)
> +			goto out_free;
> +	}
> +	if (!config_item) {
> +		config_item = add_config_item(section, name);
> +		if (!config_item)
> +			goto out_free;
> +	}
> +
> +	ret = set_value(config_item, value);
> +	return ret;
> +
> +out_free:
> +	free(key);
> +	perf_config_set__delete(perf_configs);
> +	return -1;
> +}
> +
> +struct perf_config_set *perf_config_set__new(void)
> +{
> +	struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));
> +
> +	if (!perf_configs)
> +		return NULL;
> +
> +	INIT_LIST_HEAD(&perf_configs->sections);
> +	perf_config(collect_config, perf_configs);
> +
> +	return perf_configs;
> +}
> +
> +void perf_config_set__delete(struct perf_config_set *perf_configs)
> +{
> +	struct perf_config_section *section, *section_tmp;
> +	struct perf_config_item *config_item, *item_tmp;
> +
> +	list_for_each_entry_safe(section, section_tmp,
> +				 &perf_configs->sections, list) {
> +		list_for_each_entry_safe(config_item, item_tmp,
> +					 &section->config_items, list) {
> +			list_del(&config_item->list);
> +			free(config_item->name);
> +			free(config_item->value);
> +			free(config_item);
> +		}
> +		list_del(&section->list);
> +		free(section->name);
> +		free(section);
> +	}
> +
> +	free(perf_configs);
> +}
> +
>  /*
>   * Call this to report error for your variable that should not
>   * get a boolean value (i.e. "[my] var" means "true").
> diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
> new file mode 100644
> index 0000000..e270e51
> --- /dev/null
> +++ b/tools/perf/util/config.h
> @@ -0,0 +1,26 @@
> +#ifndef __PERF_CONFIG_H
> +#define __PERF_CONFIG_H
> +
> +#include <stdbool.h>
> +#include <linux/list.h>
> +
> +struct perf_config_item {
> +	char *name;
> +	char *value;
> +	struct list_head list;
> +};
> +
> +struct perf_config_section {
> +	char *name;
> +	struct list_head config_items;
> +	struct list_head list;
> +};
> +
> +struct perf_config_set {
> +	struct list_head sections;
> +};
> +
> +struct perf_config_set *perf_config_set__new(void);
> +void perf_config_set__delete(struct perf_config_set *perf_configs);
> +
> +#endif /* __PERF_CONFIG_H */
> -- 
> 2.5.0

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

* Re: [PATCH v4 1/4] perf config: Introduce perf_config_set class
  2016-03-29 16:12 ` Arnaldo Carvalho de Melo
@ 2016-03-29 23:28   ` Taeung Song
  2016-03-30  2:09     ` Namhyung Kim
  0 siblings, 1 reply; 9+ messages in thread
From: Taeung Song @ 2016-03-29 23:28 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, linux-kernel, Jiri Olsa, Ingo Molnar,
	Peter Zijlstra

Hi, Arnaldo and Namhyung

On 03/30/2016 01:12 AM, Arnaldo Carvalho de Melo wrote:
> Em Tue, Mar 29, 2016 at 09:43:13AM +0900, Taeung Song escreveu:
>> This infrastructure code was designed for
>> upcoming features of perf-config.
>>
>> That collect config key-value pairs from user and
>> system config files (i.e. user wide ~/.perfconfig
>> and system wide $(sysconfdir)/perfconfig)
>> to manage perf's configs.
>>
>> Cc: Namhyung Kim <namhyung@kernel.org>
>> Cc: Jiri Olsa <jolsa@kernel.org>
>> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
>
> Waiting for ack.

Namhyung,
The difference between v3 and v4 for this patch as below.
(fill perf_config_set__delete() in collect_config() for state of error)

Can you review this patch, again ?

diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
index 725015f..2cfafff 100644
--- a/tools/perf/util/config.c
+++ b/tools/perf/util/config.c
@@ -705,14 +706,15 @@ static int set_value(struct perf_config_item 
*config_item, const char *value)
  }

  static int collect_config(const char *var, const char *value,
-                          void *section_list)
+                          void *perf_config_set)
  {
          int ret = -1;
          char *ptr, *key;
          char *section_name, *name;
          struct perf_config_section *section = NULL;
          struct perf_config_item *config_item = NULL;
-        struct list_head *sections = section_list;
+        struct perf_config_set *perf_configs = perf_config_set;
+        struct list_head *sections = &perf_configs->sections;

          key = ptr = strdup(var);
          if (!key) {
@@ -743,7 +745,8 @@ static int collect_config(const char *var, const 
char *value,

  out_free:
          free(key);
-        return ret;
+        perf_config_set__delete(perf_configs);
+        return -1;
  }

  static struct perf_config_set *perf_config_set__init(struct 
perf_config_set *perf_configs)
@@ -777,7 +780,7 @@ struct perf_config_set *perf_config_set__new(void)
                  return NULL;

          perf_config_set__init(perf_configs);
-        perf_config(collect_config, &perf_configs->sections);
+        perf_config(collect_config, perf_configs);

          return perf_configs;
  }


Thanks,
Taeung


>> ---
>>   tools/perf/util/config.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++
>>   tools/perf/util/config.h |  26 +++++++
>>   2 files changed, 197 insertions(+)
>>   create mode 100644 tools/perf/util/config.h
>>
>> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
>> index 4e72763..2dbf47c 100644
>> --- a/tools/perf/util/config.c
>> +++ b/tools/perf/util/config.c
>> @@ -13,6 +13,7 @@
>>   #include <subcmd/exec-cmd.h>
>>   #include "util/hist.h"  /* perf_hist_config */
>>   #include "util/llvm-utils.h"   /* perf_llvm_config */
>> +#include "config.h"
>>
>>   #define MAXNAME (256)
>>
>> @@ -506,6 +507,176 @@ out:
>>   	return ret;
>>   }
>>
>> +static struct perf_config_section *find_section(struct list_head *sections,
>> +						const char *section_name)
>> +{
>> +	struct perf_config_section *section;
>> +
>> +	list_for_each_entry(section, sections, list)
>> +		if (!strcmp(section->name, section_name))
>> +			return section;
>> +
>> +	return NULL;
>> +}
>> +
>> +static struct perf_config_item *find_config_item(const char *name,
>> +						 struct perf_config_section *section)
>> +{
>> +	struct perf_config_item *config_item;
>> +
>> +	list_for_each_entry(config_item, &section->config_items, list)
>> +		if (!strcmp(config_item->name, name))
>> +			return config_item;
>> +
>> +	return NULL;
>> +}
>> +
>> +static void find_config(struct list_head *sections,
>> +			struct perf_config_section **section,
>> +			struct perf_config_item **config_item,
>> +			const char *section_name, const char *name)
>> +{
>> +	*section = find_section(sections, section_name);
>> +
>> +	if (*section != NULL)
>> +		*config_item = find_config_item(name, *section);
>> +	else
>> +		*config_item = NULL;
>> +}
>> +
>> +static struct perf_config_section *add_section(struct list_head *sections,
>> +					       const char *section_name)
>> +{
>> +	struct perf_config_section *section = zalloc(sizeof(*section));
>> +
>> +	if (!section)
>> +		return NULL;
>> +
>> +	INIT_LIST_HEAD(&section->config_items);
>> +	section->name = strdup(section_name);
>> +	if (!section->name) {
>> +		pr_err("%s: strdup failed\n", __func__);
>> +		free(section);
>> +		return NULL;
>> +	}
>> +
>> +	list_add_tail(&section->list, sections);
>> +	return section;
>> +}
>> +
>> +static struct perf_config_item *add_config_item(struct perf_config_section *section,
>> +						const char *name)
>> +{
>> +	struct perf_config_item *config_item = zalloc(sizeof(*config_item));
>> +
>> +	if (!config_item)
>> +		return NULL;
>> +
>> +	config_item->name = strdup(name);
>> +	if (!name) {
>> +		pr_err("%s: strdup failed\n", __func__);
>> +		goto out_err;
>> +	}
>> +
>> +	list_add_tail(&config_item->list, &section->config_items);
>> +	return config_item;
>> +
>> +out_err:
>> +	free(config_item);
>> +	return NULL;
>> +}
>> +
>> +static int set_value(struct perf_config_item *config_item, const char *value)
>> +{
>> +	char *val = strdup(value);
>> +
>> +	if (!val)
>> +		return -1;
>> +
>> +	free(config_item->value);
>> +	config_item->value = val;
>> +	return 0;
>> +}
>> +
>> +static int collect_config(const char *var, const char *value,
>> +			  void *perf_config_set)
>> +{
>> +	int ret = -1;
>> +	char *ptr, *key;
>> +	char *section_name, *name;
>> +	struct perf_config_section *section = NULL;
>> +	struct perf_config_item *config_item = NULL;
>> +	struct perf_config_set *perf_configs = perf_config_set;
>> +	struct list_head *sections = &perf_configs->sections;
>> +
>> +	key = ptr = strdup(var);
>> +	if (!key) {
>> +		pr_err("%s: strdup failed\n", __func__);
>> +		return -1;
>> +	}
>> +
>> +	section_name = strsep(&ptr, ".");
>> +	name = ptr;
>> +	if (name == NULL || value == NULL)
>> +		goto out_free;
>> +
>> +	find_config(sections, &section, &config_item, section_name, name);
>> +
>> +	if (!section) {
>> +		section = add_section(sections, section_name);
>> +		if (!section)
>> +			goto out_free;
>> +	}
>> +	if (!config_item) {
>> +		config_item = add_config_item(section, name);
>> +		if (!config_item)
>> +			goto out_free;
>> +	}
>> +
>> +	ret = set_value(config_item, value);
>> +	return ret;
>> +
>> +out_free:
>> +	free(key);
>> +	perf_config_set__delete(perf_configs);
>> +	return -1;
>> +}
>> +
>> +struct perf_config_set *perf_config_set__new(void)
>> +{
>> +	struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));
>> +
>> +	if (!perf_configs)
>> +		return NULL;
>> +
>> +	INIT_LIST_HEAD(&perf_configs->sections);
>> +	perf_config(collect_config, perf_configs);
>> +
>> +	return perf_configs;
>> +}
>> +
>> +void perf_config_set__delete(struct perf_config_set *perf_configs)
>> +{
>> +	struct perf_config_section *section, *section_tmp;
>> +	struct perf_config_item *config_item, *item_tmp;
>> +
>> +	list_for_each_entry_safe(section, section_tmp,
>> +				 &perf_configs->sections, list) {
>> +		list_for_each_entry_safe(config_item, item_tmp,
>> +					 &section->config_items, list) {
>> +			list_del(&config_item->list);
>> +			free(config_item->name);
>> +			free(config_item->value);
>> +			free(config_item);
>> +		}
>> +		list_del(&section->list);
>> +		free(section->name);
>> +		free(section);
>> +	}
>> +
>> +	free(perf_configs);
>> +}
>> +
>>   /*
>>    * Call this to report error for your variable that should not
>>    * get a boolean value (i.e. "[my] var" means "true").
>> diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
>> new file mode 100644
>> index 0000000..e270e51
>> --- /dev/null
>> +++ b/tools/perf/util/config.h
>> @@ -0,0 +1,26 @@
>> +#ifndef __PERF_CONFIG_H
>> +#define __PERF_CONFIG_H
>> +
>> +#include <stdbool.h>
>> +#include <linux/list.h>
>> +
>> +struct perf_config_item {
>> +	char *name;
>> +	char *value;
>> +	struct list_head list;
>> +};
>> +
>> +struct perf_config_section {
>> +	char *name;
>> +	struct list_head config_items;
>> +	struct list_head list;
>> +};
>> +
>> +struct perf_config_set {
>> +	struct list_head sections;
>> +};
>> +
>> +struct perf_config_set *perf_config_set__new(void);
>> +void perf_config_set__delete(struct perf_config_set *perf_configs);
>> +
>> +#endif /* __PERF_CONFIG_H */
>> --
>> 2.5.0

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

* Re: [PATCH v4 1/4] perf config: Introduce perf_config_set class
  2016-03-29 23:28   ` Taeung Song
@ 2016-03-30  2:09     ` Namhyung Kim
  2016-03-30 11:04       ` Taeung Song
  0 siblings, 1 reply; 9+ messages in thread
From: Namhyung Kim @ 2016-03-30  2:09 UTC (permalink / raw)
  To: Taeung Song, Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, linux-kernel, Jiri Olsa, Ingo Molnar,
	Peter Zijlstra

On March 30, 2016 8:28:21 AM GMT+09:00, Taeung Song <treeze.taeung@gmail.com> wrote:
>Hi, Arnaldo and Namhyung
>
>On 03/30/2016 01:12 AM, Arnaldo Carvalho de Melo wrote:
>> Em Tue, Mar 29, 2016 at 09:43:13AM +0900, Taeung Song escreveu:
>>> This infrastructure code was designed for
>>> upcoming features of perf-config.
>>>
>>> That collect config key-value pairs from user and
>>> system config files (i.e. user wide ~/.perfconfig
>>> and system wide $(sysconfdir)/perfconfig)
>>> to manage perf's configs.
>>>
>>> Cc: Namhyung Kim <namhyung@kernel.org>
>>> Cc: Jiri Olsa <jolsa@kernel.org>
>>> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
>>
>> Waiting for ack.
>
>Namhyung,
>The difference between v3 and v4 for this patch as below.
>(fill perf_config_set__delete() in collect_config() for state of error)
>
>Can you review this patch, again ?

Acked-by: Namhyung Kim <namhyung@kernel.org>

Thanks
Namhyung


>diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
>index 725015f..2cfafff 100644
>--- a/tools/perf/util/config.c
>+++ b/tools/perf/util/config.c
>@@ -705,14 +706,15 @@ static int set_value(struct perf_config_item 
>*config_item, const char *value)
>  }
>
>  static int collect_config(const char *var, const char *value,
>-                          void *section_list)
>+                          void *perf_config_set)
>  {
>          int ret = -1;
>          char *ptr, *key;
>          char *section_name, *name;
>          struct perf_config_section *section = NULL;
>          struct perf_config_item *config_item = NULL;
>-        struct list_head *sections = section_list;
>+        struct perf_config_set *perf_configs = perf_config_set;
>+        struct list_head *sections = &perf_configs->sections;
>
>          key = ptr = strdup(var);
>          if (!key) {
>@@ -743,7 +745,8 @@ static int collect_config(const char *var, const 
>char *value,
>
>  out_free:
>          free(key);
>-        return ret;
>+        perf_config_set__delete(perf_configs);
>+        return -1;
>  }
>
>  static struct perf_config_set *perf_config_set__init(struct 
>perf_config_set *perf_configs)
>@@ -777,7 +780,7 @@ struct perf_config_set *perf_config_set__new(void)
>                  return NULL;
>
>          perf_config_set__init(perf_configs);
>-        perf_config(collect_config, &perf_configs->sections);
>+        perf_config(collect_config, perf_configs);
>
>          return perf_configs;
>  }
>
>
>Thanks,
>Taeung
>
>
>>> ---
>>>   tools/perf/util/config.c | 171
>+++++++++++++++++++++++++++++++++++++++++++++++
>>>   tools/perf/util/config.h |  26 +++++++
>>>   2 files changed, 197 insertions(+)
>>>   create mode 100644 tools/perf/util/config.h
>>>
>>> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
>>> index 4e72763..2dbf47c 100644
>>> --- a/tools/perf/util/config.c
>>> +++ b/tools/perf/util/config.c
>>> @@ -13,6 +13,7 @@
>>>   #include <subcmd/exec-cmd.h>
>>>   #include "util/hist.h"  /* perf_hist_config */
>>>   #include "util/llvm-utils.h"   /* perf_llvm_config */
>>> +#include "config.h"
>>>
>>>   #define MAXNAME (256)
>>>
>>> @@ -506,6 +507,176 @@ out:
>>>   	return ret;
>>>   }
>>>
>>> +static struct perf_config_section *find_section(struct list_head
>*sections,
>>> +						const char *section_name)
>>> +{
>>> +	struct perf_config_section *section;
>>> +
>>> +	list_for_each_entry(section, sections, list)
>>> +		if (!strcmp(section->name, section_name))
>>> +			return section;
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +static struct perf_config_item *find_config_item(const char *name,
>>> +						 struct perf_config_section *section)
>>> +{
>>> +	struct perf_config_item *config_item;
>>> +
>>> +	list_for_each_entry(config_item, &section->config_items, list)
>>> +		if (!strcmp(config_item->name, name))
>>> +			return config_item;
>>> +
>>> +	return NULL;
>>> +}
>>> +
>>> +static void find_config(struct list_head *sections,
>>> +			struct perf_config_section **section,
>>> +			struct perf_config_item **config_item,
>>> +			const char *section_name, const char *name)
>>> +{
>>> +	*section = find_section(sections, section_name);
>>> +
>>> +	if (*section != NULL)
>>> +		*config_item = find_config_item(name, *section);
>>> +	else
>>> +		*config_item = NULL;
>>> +}
>>> +
>>> +static struct perf_config_section *add_section(struct list_head
>*sections,
>>> +					       const char *section_name)
>>> +{
>>> +	struct perf_config_section *section = zalloc(sizeof(*section));
>>> +
>>> +	if (!section)
>>> +		return NULL;
>>> +
>>> +	INIT_LIST_HEAD(&section->config_items);
>>> +	section->name = strdup(section_name);
>>> +	if (!section->name) {
>>> +		pr_err("%s: strdup failed\n", __func__);
>>> +		free(section);
>>> +		return NULL;
>>> +	}
>>> +
>>> +	list_add_tail(&section->list, sections);
>>> +	return section;
>>> +}
>>> +
>>> +static struct perf_config_item *add_config_item(struct
>perf_config_section *section,
>>> +						const char *name)
>>> +{
>>> +	struct perf_config_item *config_item =
>zalloc(sizeof(*config_item));
>>> +
>>> +	if (!config_item)
>>> +		return NULL;
>>> +
>>> +	config_item->name = strdup(name);
>>> +	if (!name) {
>>> +		pr_err("%s: strdup failed\n", __func__);
>>> +		goto out_err;
>>> +	}
>>> +
>>> +	list_add_tail(&config_item->list, &section->config_items);
>>> +	return config_item;
>>> +
>>> +out_err:
>>> +	free(config_item);
>>> +	return NULL;
>>> +}
>>> +
>>> +static int set_value(struct perf_config_item *config_item, const
>char *value)
>>> +{
>>> +	char *val = strdup(value);
>>> +
>>> +	if (!val)
>>> +		return -1;
>>> +
>>> +	free(config_item->value);
>>> +	config_item->value = val;
>>> +	return 0;
>>> +}
>>> +
>>> +static int collect_config(const char *var, const char *value,
>>> +			  void *perf_config_set)
>>> +{
>>> +	int ret = -1;
>>> +	char *ptr, *key;
>>> +	char *section_name, *name;
>>> +	struct perf_config_section *section = NULL;
>>> +	struct perf_config_item *config_item = NULL;
>>> +	struct perf_config_set *perf_configs = perf_config_set;
>>> +	struct list_head *sections = &perf_configs->sections;
>>> +
>>> +	key = ptr = strdup(var);
>>> +	if (!key) {
>>> +		pr_err("%s: strdup failed\n", __func__);
>>> +		return -1;
>>> +	}
>>> +
>>> +	section_name = strsep(&ptr, ".");
>>> +	name = ptr;
>>> +	if (name == NULL || value == NULL)
>>> +		goto out_free;
>>> +
>>> +	find_config(sections, &section, &config_item, section_name, name);
>>> +
>>> +	if (!section) {
>>> +		section = add_section(sections, section_name);
>>> +		if (!section)
>>> +			goto out_free;
>>> +	}
>>> +	if (!config_item) {
>>> +		config_item = add_config_item(section, name);
>>> +		if (!config_item)
>>> +			goto out_free;
>>> +	}
>>> +
>>> +	ret = set_value(config_item, value);
>>> +	return ret;
>>> +
>>> +out_free:
>>> +	free(key);
>>> +	perf_config_set__delete(perf_configs);
>>> +	return -1;
>>> +}
>>> +
>>> +struct perf_config_set *perf_config_set__new(void)
>>> +{
>>> +	struct perf_config_set *perf_configs =
>zalloc(sizeof(*perf_configs));
>>> +
>>> +	if (!perf_configs)
>>> +		return NULL;
>>> +
>>> +	INIT_LIST_HEAD(&perf_configs->sections);
>>> +	perf_config(collect_config, perf_configs);
>>> +
>>> +	return perf_configs;
>>> +}
>>> +
>>> +void perf_config_set__delete(struct perf_config_set *perf_configs)
>>> +{
>>> +	struct perf_config_section *section, *section_tmp;
>>> +	struct perf_config_item *config_item, *item_tmp;
>>> +
>>> +	list_for_each_entry_safe(section, section_tmp,
>>> +				 &perf_configs->sections, list) {
>>> +		list_for_each_entry_safe(config_item, item_tmp,
>>> +					 &section->config_items, list) {
>>> +			list_del(&config_item->list);
>>> +			free(config_item->name);
>>> +			free(config_item->value);
>>> +			free(config_item);
>>> +		}
>>> +		list_del(&section->list);
>>> +		free(section->name);
>>> +		free(section);
>>> +	}
>>> +
>>> +	free(perf_configs);
>>> +}
>>> +
>>>   /*
>>>    * Call this to report error for your variable that should not
>>>    * get a boolean value (i.e. "[my] var" means "true").
>>> diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
>>> new file mode 100644
>>> index 0000000..e270e51
>>> --- /dev/null
>>> +++ b/tools/perf/util/config.h
>>> @@ -0,0 +1,26 @@
>>> +#ifndef __PERF_CONFIG_H
>>> +#define __PERF_CONFIG_H
>>> +
>>> +#include <stdbool.h>
>>> +#include <linux/list.h>
>>> +
>>> +struct perf_config_item {
>>> +	char *name;
>>> +	char *value;
>>> +	struct list_head list;
>>> +};
>>> +
>>> +struct perf_config_section {
>>> +	char *name;
>>> +	struct list_head config_items;
>>> +	struct list_head list;
>>> +};
>>> +
>>> +struct perf_config_set {
>>> +	struct list_head sections;
>>> +};
>>> +
>>> +struct perf_config_set *perf_config_set__new(void);
>>> +void perf_config_set__delete(struct perf_config_set *perf_configs);
>>> +
>>> +#endif /* __PERF_CONFIG_H */
>>> --
>>> 2.5.0


-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity.

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

* Re: [PATCH v4 1/4] perf config: Introduce perf_config_set class
  2016-03-30  2:09     ` Namhyung Kim
@ 2016-03-30 11:04       ` Taeung Song
  0 siblings, 0 replies; 9+ messages in thread
From: Taeung Song @ 2016-03-30 11:04 UTC (permalink / raw)
  To: Namhyung Kim
  Cc: Arnaldo Carvalho de Melo, linux-kernel, Jiri Olsa, Ingo Molnar,
	Peter Zijlstra

Hi, Namhyung

On 03/30/2016 11:09 AM, Namhyung Kim wrote:
> On March 30, 2016 8:28:21 AM GMT+09:00, Taeung Song <treeze.taeung@gmail.com> wrote:
>> Hi, Arnaldo and Namhyung
>>
>> On 03/30/2016 01:12 AM, Arnaldo Carvalho de Melo wrote:
>>> Em Tue, Mar 29, 2016 at 09:43:13AM +0900, Taeung Song escreveu:
>>>> This infrastructure code was designed for
>>>> upcoming features of perf-config.
>>>>
>>>> That collect config key-value pairs from user and
>>>> system config files (i.e. user wide ~/.perfconfig
>>>> and system wide $(sysconfdir)/perfconfig)
>>>> to manage perf's configs.
>>>>
>>>> Cc: Namhyung Kim <namhyung@kernel.org>
>>>> Cc: Jiri Olsa <jolsa@kernel.org>
>>>> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
>>>
>>> Waiting for ack.
>>
>> Namhyung,
>> The difference between v3 and v4 for this patch as below.
>> (fill perf_config_set__delete() in collect_config() for state of error)
>>
>> Can you review this patch, again ?
>
> Acked-by: Namhyung Kim <namhyung@kernel.org>
>

Thank you !! :-)

Taeung

>
>
>> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
>> index 725015f..2cfafff 100644
>> --- a/tools/perf/util/config.c
>> +++ b/tools/perf/util/config.c
>> @@ -705,14 +706,15 @@ static int set_value(struct perf_config_item
>> *config_item, const char *value)
>>   }
>>
>>   static int collect_config(const char *var, const char *value,
>> -                          void *section_list)
>> +                          void *perf_config_set)
>>   {
>>           int ret = -1;
>>           char *ptr, *key;
>>           char *section_name, *name;
>>           struct perf_config_section *section = NULL;
>>           struct perf_config_item *config_item = NULL;
>> -        struct list_head *sections = section_list;
>> +        struct perf_config_set *perf_configs = perf_config_set;
>> +        struct list_head *sections = &perf_configs->sections;
>>
>>           key = ptr = strdup(var);
>>           if (!key) {
>> @@ -743,7 +745,8 @@ static int collect_config(const char *var, const
>> char *value,
>>
>>   out_free:
>>           free(key);
>> -        return ret;
>> +        perf_config_set__delete(perf_configs);
>> +        return -1;
>>   }
>>
>>   static struct perf_config_set *perf_config_set__init(struct
>> perf_config_set *perf_configs)
>> @@ -777,7 +780,7 @@ struct perf_config_set *perf_config_set__new(void)
>>                   return NULL;
>>
>>           perf_config_set__init(perf_configs);
>> -        perf_config(collect_config, &perf_configs->sections);
>> +        perf_config(collect_config, perf_configs);
>>
>>           return perf_configs;
>>   }
>>
>>
>> Thanks,
>> Taeung
>>
>>
>>>> ---
>>>>    tools/perf/util/config.c | 171
>> +++++++++++++++++++++++++++++++++++++++++++++++
>>>>    tools/perf/util/config.h |  26 +++++++
>>>>    2 files changed, 197 insertions(+)
>>>>    create mode 100644 tools/perf/util/config.h
>>>>
>>>> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
>>>> index 4e72763..2dbf47c 100644
>>>> --- a/tools/perf/util/config.c
>>>> +++ b/tools/perf/util/config.c
>>>> @@ -13,6 +13,7 @@
>>>>    #include <subcmd/exec-cmd.h>
>>>>    #include "util/hist.h"  /* perf_hist_config */
>>>>    #include "util/llvm-utils.h"   /* perf_llvm_config */
>>>> +#include "config.h"
>>>>
>>>>    #define MAXNAME (256)
>>>>
>>>> @@ -506,6 +507,176 @@ out:
>>>>    	return ret;
>>>>    }
>>>>
>>>> +static struct perf_config_section *find_section(struct list_head
>> *sections,
>>>> +						const char *section_name)
>>>> +{
>>>> +	struct perf_config_section *section;
>>>> +
>>>> +	list_for_each_entry(section, sections, list)
>>>> +		if (!strcmp(section->name, section_name))
>>>> +			return section;
>>>> +
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +static struct perf_config_item *find_config_item(const char *name,
>>>> +						 struct perf_config_section *section)
>>>> +{
>>>> +	struct perf_config_item *config_item;
>>>> +
>>>> +	list_for_each_entry(config_item, &section->config_items, list)
>>>> +		if (!strcmp(config_item->name, name))
>>>> +			return config_item;
>>>> +
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +static void find_config(struct list_head *sections,
>>>> +			struct perf_config_section **section,
>>>> +			struct perf_config_item **config_item,
>>>> +			const char *section_name, const char *name)
>>>> +{
>>>> +	*section = find_section(sections, section_name);
>>>> +
>>>> +	if (*section != NULL)
>>>> +		*config_item = find_config_item(name, *section);
>>>> +	else
>>>> +		*config_item = NULL;
>>>> +}
>>>> +
>>>> +static struct perf_config_section *add_section(struct list_head
>> *sections,
>>>> +					       const char *section_name)
>>>> +{
>>>> +	struct perf_config_section *section = zalloc(sizeof(*section));
>>>> +
>>>> +	if (!section)
>>>> +		return NULL;
>>>> +
>>>> +	INIT_LIST_HEAD(&section->config_items);
>>>> +	section->name = strdup(section_name);
>>>> +	if (!section->name) {
>>>> +		pr_err("%s: strdup failed\n", __func__);
>>>> +		free(section);
>>>> +		return NULL;
>>>> +	}
>>>> +
>>>> +	list_add_tail(&section->list, sections);
>>>> +	return section;
>>>> +}
>>>> +
>>>> +static struct perf_config_item *add_config_item(struct
>> perf_config_section *section,
>>>> +						const char *name)
>>>> +{
>>>> +	struct perf_config_item *config_item =
>> zalloc(sizeof(*config_item));
>>>> +
>>>> +	if (!config_item)
>>>> +		return NULL;
>>>> +
>>>> +	config_item->name = strdup(name);
>>>> +	if (!name) {
>>>> +		pr_err("%s: strdup failed\n", __func__);
>>>> +		goto out_err;
>>>> +	}
>>>> +
>>>> +	list_add_tail(&config_item->list, &section->config_items);
>>>> +	return config_item;
>>>> +
>>>> +out_err:
>>>> +	free(config_item);
>>>> +	return NULL;
>>>> +}
>>>> +
>>>> +static int set_value(struct perf_config_item *config_item, const
>> char *value)
>>>> +{
>>>> +	char *val = strdup(value);
>>>> +
>>>> +	if (!val)
>>>> +		return -1;
>>>> +
>>>> +	free(config_item->value);
>>>> +	config_item->value = val;
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +static int collect_config(const char *var, const char *value,
>>>> +			  void *perf_config_set)
>>>> +{
>>>> +	int ret = -1;
>>>> +	char *ptr, *key;
>>>> +	char *section_name, *name;
>>>> +	struct perf_config_section *section = NULL;
>>>> +	struct perf_config_item *config_item = NULL;
>>>> +	struct perf_config_set *perf_configs = perf_config_set;
>>>> +	struct list_head *sections = &perf_configs->sections;
>>>> +
>>>> +	key = ptr = strdup(var);
>>>> +	if (!key) {
>>>> +		pr_err("%s: strdup failed\n", __func__);
>>>> +		return -1;
>>>> +	}
>>>> +
>>>> +	section_name = strsep(&ptr, ".");
>>>> +	name = ptr;
>>>> +	if (name == NULL || value == NULL)
>>>> +		goto out_free;
>>>> +
>>>> +	find_config(sections, &section, &config_item, section_name, name);
>>>> +
>>>> +	if (!section) {
>>>> +		section = add_section(sections, section_name);
>>>> +		if (!section)
>>>> +			goto out_free;
>>>> +	}
>>>> +	if (!config_item) {
>>>> +		config_item = add_config_item(section, name);
>>>> +		if (!config_item)
>>>> +			goto out_free;
>>>> +	}
>>>> +
>>>> +	ret = set_value(config_item, value);
>>>> +	return ret;
>>>> +
>>>> +out_free:
>>>> +	free(key);
>>>> +	perf_config_set__delete(perf_configs);
>>>> +	return -1;
>>>> +}
>>>> +
>>>> +struct perf_config_set *perf_config_set__new(void)
>>>> +{
>>>> +	struct perf_config_set *perf_configs =
>> zalloc(sizeof(*perf_configs));
>>>> +
>>>> +	if (!perf_configs)
>>>> +		return NULL;
>>>> +
>>>> +	INIT_LIST_HEAD(&perf_configs->sections);
>>>> +	perf_config(collect_config, perf_configs);
>>>> +
>>>> +	return perf_configs;
>>>> +}
>>>> +
>>>> +void perf_config_set__delete(struct perf_config_set *perf_configs)
>>>> +{
>>>> +	struct perf_config_section *section, *section_tmp;
>>>> +	struct perf_config_item *config_item, *item_tmp;
>>>> +
>>>> +	list_for_each_entry_safe(section, section_tmp,
>>>> +				 &perf_configs->sections, list) {
>>>> +		list_for_each_entry_safe(config_item, item_tmp,
>>>> +					 &section->config_items, list) {
>>>> +			list_del(&config_item->list);
>>>> +			free(config_item->name);
>>>> +			free(config_item->value);
>>>> +			free(config_item);
>>>> +		}
>>>> +		list_del(&section->list);
>>>> +		free(section->name);
>>>> +		free(section);
>>>> +	}
>>>> +
>>>> +	free(perf_configs);
>>>> +}
>>>> +
>>>>    /*
>>>>     * Call this to report error for your variable that should not
>>>>     * get a boolean value (i.e. "[my] var" means "true").
>>>> diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
>>>> new file mode 100644
>>>> index 0000000..e270e51
>>>> --- /dev/null
>>>> +++ b/tools/perf/util/config.h
>>>> @@ -0,0 +1,26 @@
>>>> +#ifndef __PERF_CONFIG_H
>>>> +#define __PERF_CONFIG_H
>>>> +
>>>> +#include <stdbool.h>
>>>> +#include <linux/list.h>
>>>> +
>>>> +struct perf_config_item {
>>>> +	char *name;
>>>> +	char *value;
>>>> +	struct list_head list;
>>>> +};
>>>> +
>>>> +struct perf_config_section {
>>>> +	char *name;
>>>> +	struct list_head config_items;
>>>> +	struct list_head list;
>>>> +};
>>>> +
>>>> +struct perf_config_set {
>>>> +	struct list_head sections;
>>>> +};
>>>> +
>>>> +struct perf_config_set *perf_config_set__new(void);
>>>> +void perf_config_set__delete(struct perf_config_set *perf_configs);
>>>> +
>>>> +#endif /* __PERF_CONFIG_H */
>>>> --
>>>> 2.5.0
>
>

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

* Re: [PATCH v4 1/4] perf config: Introduce perf_config_set class
  2016-03-29  0:43 [PATCH v4 1/4] perf config: Introduce perf_config_set class Taeung Song
  2016-03-29 16:12 ` Arnaldo Carvalho de Melo
@ 2016-03-31 17:31 ` Arnaldo Carvalho de Melo
  2016-04-01 10:27   ` Taeung Song
  1 sibling, 1 reply; 9+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-03-31 17:31 UTC (permalink / raw)
  To: Taeung Song
  Cc: Namhyung Kim, linux-kernel, Jiri Olsa, Ingo Molnar, Peter Zijlstra

Em Tue, Mar 29, 2016 at 09:43:13AM +0900, Taeung Song escreveu:
> This infrastructure code was designed for
> upcoming features of perf-config.
> 
> That collect config key-value pairs from user and
> system config files (i.e. user wide ~/.perfconfig
> and system wide $(sysconfdir)/perfconfig)
> to manage perf's configs.
> 
> Cc: Namhyung Kim <namhyung@kernel.org>
> Cc: Jiri Olsa <jolsa@kernel.org>
> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
> ---
>  tools/perf/util/config.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++
>  tools/perf/util/config.h |  26 +++++++
>  2 files changed, 197 insertions(+)
>  create mode 100644 tools/perf/util/config.h
> 
> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
> index 4e72763..2dbf47c 100644
> --- a/tools/perf/util/config.c
> +++ b/tools/perf/util/config.c
> @@ -13,6 +13,7 @@
>  #include <subcmd/exec-cmd.h>
>  #include "util/hist.h"  /* perf_hist_config */
>  #include "util/llvm-utils.h"   /* perf_llvm_config */
> +#include "config.h"
>  
>  #define MAXNAME (256)
>  
> @@ -506,6 +507,176 @@ out:
>  	return ret;
>  }
>  
> +static struct perf_config_section *find_section(struct list_head *sections,
> +						const char *section_name)
> +{
> +	struct perf_config_section *section;
> +
> +	list_for_each_entry(section, sections, list)
> +		if (!strcmp(section->name, section_name))
> +			return section;
> +
> +	return NULL;
> +}
> +
> +static struct perf_config_item *find_config_item(const char *name,
> +						 struct perf_config_section *section)
> +{
> +	struct perf_config_item *config_item;
> +
> +	list_for_each_entry(config_item, &section->config_items, list)
> +		if (!strcmp(config_item->name, name))
> +			return config_item;
> +
> +	return NULL;
> +}
> +
> +static void find_config(struct list_head *sections,
> +			struct perf_config_section **section,
> +			struct perf_config_item **config_item,
> +			const char *section_name, const char *name)
> +{
> +	*section = find_section(sections, section_name);
> +
> +	if (*section != NULL)
> +		*config_item = find_config_item(name, *section);
> +	else
> +		*config_item = NULL;

> +}
> +
> +static struct perf_config_section *add_section(struct list_head *sections,
> +					       const char *section_name)
> +{
> +	struct perf_config_section *section = zalloc(sizeof(*section));
> +
> +	if (!section)
> +		return NULL;
> +
> +	INIT_LIST_HEAD(&section->config_items);
> +	section->name = strdup(section_name);
> +	if (!section->name) {
> +		pr_err("%s: strdup failed\n", __func__);
> +		free(section);
> +		return NULL;
> +	}
> +
> +	list_add_tail(&section->list, sections);
> +	return section;
> +}
> +
> +static struct perf_config_item *add_config_item(struct perf_config_section *section,
> +						const char *name)
> +{
> +	struct perf_config_item *config_item = zalloc(sizeof(*config_item));
> +
> +	if (!config_item)
> +		return NULL;
> +
> +	config_item->name = strdup(name);
> +	if (!name) {

Huh? You're testing the wrong variable.

> +		pr_err("%s: strdup failed\n", __func__);
> +		goto out_err;
> +	}
> +
> +	list_add_tail(&config_item->list, &section->config_items);
> +	return config_item;
> +
> +out_err:
> +	free(config_item);
> +	return NULL;
> +}
> +
> +static int set_value(struct perf_config_item *config_item, const char *value)
> +{
> +	char *val = strdup(value);
> +
> +	if (!val)
> +		return -1;
> +
> +	free(config_item->value);
> +	config_item->value = val;
> +	return 0;
> +}
> +
> +static int collect_config(const char *var, const char *value,
> +			  void *perf_config_set)
> +{
> +	int ret = -1;
> +	char *ptr, *key;
> +	char *section_name, *name;
> +	struct perf_config_section *section = NULL;
> +	struct perf_config_item *config_item = NULL;
> +	struct perf_config_set *perf_configs = perf_config_set;
> +	struct list_head *sections = &perf_configs->sections;
> +
> +	key = ptr = strdup(var);
> +	if (!key) {
> +		pr_err("%s: strdup failed\n", __func__);

pr_debug()

> +		return -1;
> +	}
> +
> +	section_name = strsep(&ptr, ".");
> +	name = ptr;
> +	if (name == NULL || value == NULL)
> +		goto out_free;
> +
> +	find_config(sections, &section, &config_item, section_name, name);

This idiom is confusing, why not ditch this 'find_config()' function and
do the searches here? I.e.:

	section = find_section(sections, section_name);
> +	if (!section) {
> +		section = add_section(sections, section_name);
> +		if (!section)
> +			goto out_free;
> +	}

 	config_item = find_config_item(name, section);
> +	if (!config_item) {
> +		config_item = add_config_item(section, name);
> +		if (!config_item)
> +			goto out_free;
> +	}
> +
> +	ret = set_value(config_item, value);
> +	return ret;
> +
> +out_free:
> +	free(key);
> +	perf_config_set__delete(perf_configs);
> +	return -1;
> +}
> +
> +struct perf_config_set *perf_config_set__new(void)
> +{
> +	struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));
> +
> +	if (!perf_configs)
> +		return NULL;
> +
> +	INIT_LIST_HEAD(&perf_configs->sections);
> +	perf_config(collect_config, perf_configs);
> +
> +	return perf_configs;
> +}

Usually for these short functions we could do it more compactly as:

struct perf_config_set *perf_config_set__new(void)
{
	struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));

	if (perf_configs) {
		INIT_LIST_HEAD(&perf_configs->sections);
		perf_config(collect_config, perf_configs);
	}

	return perf_configs;
}

But I'm not dwelling on this...

> +void perf_config_set__delete(struct perf_config_set *perf_configs)
> +{
> +	struct perf_config_section *section, *section_tmp;
> +	struct perf_config_item *config_item, *item_tmp;
> +
> +	list_for_each_entry_safe(section, section_tmp,
> +				 &perf_configs->sections, list) {
> +		list_for_each_entry_safe(config_item, item_tmp,
> +					 &section->config_items, list) {
> +			list_del(&config_item->list);
> +			free(config_item->name);
> +			free(config_item->value);
> +			free(config_item);
> +		}
> +		list_del(&section->list);
> +		free(section->name);
> +		free(section);
> +	}
> +
> +	free(perf_configs);
> +}

What is the problem with having perf_config_item__delete() and
perf_config_section__delete() and then have it like below, also please
rename those foo->list to foo->node.

void perf_config_item__delete(struct perf_config_item *item)
{
	zfree(&item->name);
	zfree(&item->value);
	free(item);
}

void perf_config_section__purge(struct perf_config_section *section)
{
	struct perf_config_item *item, *tmp;

	list_for_each_entry_safe(item, tmp, &section->items, node) {
		list_del_init(&item->node);
		perf_config_item__delete(item);
	}
}

void perf_config_section__delete(struct perf_config_section *section)
{
	perf_config_section__purge(section);
	zfree(&section->name);
	free(section);
}

void perf_config_set__purge(struct perf_config_set *set)
{
	struct perf_config_section *section, *tmp;

	list_for_each_entry_safe(section, tmp, &set->sections, node) {
		list_del_init(&section->node);
		perf_config_section__delete(section);
	}
}

void perf_config_set__delete(struct perf_config_set *set)
{
	perf_config_set__purge(set);
	free(set);
}

Using zfree() and list_del_init to NULL or poison the freed pointers
helps with debugging, please use them.

> +
>  /*
>   * Call this to report error for your variable that should not
>   * get a boolean value (i.e. "[my] var" means "true").
> diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
> new file mode 100644
> index 0000000..e270e51
> --- /dev/null
> +++ b/tools/perf/util/config.h
> @@ -0,0 +1,26 @@
> +#ifndef __PERF_CONFIG_H
> +#define __PERF_CONFIG_H
> +
> +#include <stdbool.h>
> +#include <linux/list.h>
> +
> +struct perf_config_item {
> +	char *name;
> +	char *value;
> +	struct list_head list;

s/list/node/g

> +};
> +
> +struct perf_config_section {
> +	char *name;
> +	struct list_head config_items;

s/config_items/items/g

> +	struct list_head list;

s/list/node/g
> +};
> +
> +struct perf_config_set {
> +	struct list_head sections;

See? Here you did it right, no point in having it as "config_sections"

> +};
> +
> +struct perf_config_set *perf_config_set__new(void);
> +void perf_config_set__delete(struct perf_config_set *perf_configs);

   void perf_config_set__delete(struct perf_config_set *set);

> +
> +#endif /* __PERF_CONFIG_H */
> -- 
> 2.5.0

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

* Re: [PATCH v4 1/4] perf config: Introduce perf_config_set class
  2016-03-31 17:31 ` Arnaldo Carvalho de Melo
@ 2016-04-01 10:27   ` Taeung Song
  2016-04-01 14:35     ` Arnaldo Carvalho de Melo
  0 siblings, 1 reply; 9+ messages in thread
From: Taeung Song @ 2016-04-01 10:27 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, linux-kernel, Jiri Olsa, Ingo Molnar, Peter Zijlstra

Hi, Arnaldo

Thank you for your review.

On 04/01/2016 02:31 AM, Arnaldo Carvalho de Melo wrote:
> Em Tue, Mar 29, 2016 at 09:43:13AM +0900, Taeung Song escreveu:
>> This infrastructure code was designed for
>> upcoming features of perf-config.
>>
>> That collect config key-value pairs from user and
>> system config files (i.e. user wide ~/.perfconfig
>> and system wide $(sysconfdir)/perfconfig)
>> to manage perf's configs.
>>
>> Cc: Namhyung Kim <namhyung@kernel.org>
>> Cc: Jiri Olsa <jolsa@kernel.org>
>> Signed-off-by: Taeung Song <treeze.taeung@gmail.com>
>> ---
>>   tools/perf/util/config.c | 171 +++++++++++++++++++++++++++++++++++++++++++++++
>>   tools/perf/util/config.h |  26 +++++++
>>   2 files changed, 197 insertions(+)
>>   create mode 100644 tools/perf/util/config.h
>>
>> diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c
>> index 4e72763..2dbf47c 100644
>> --- a/tools/perf/util/config.c
>> +++ b/tools/perf/util/config.c
>> @@ -13,6 +13,7 @@
>>   #include <subcmd/exec-cmd.h>
>>   #include "util/hist.h"  /* perf_hist_config */
>>   #include "util/llvm-utils.h"   /* perf_llvm_config */
>> +#include "config.h"
>>
>>   #define MAXNAME (256)
>>
>> @@ -506,6 +507,176 @@ out:
>>   	return ret;
>>   }
>>
>> +static struct perf_config_section *find_section(struct list_head *sections,
>> +						const char *section_name)
>> +{
>> +	struct perf_config_section *section;
>> +
>> +	list_for_each_entry(section, sections, list)
>> +		if (!strcmp(section->name, section_name))
>> +			return section;
>> +
>> +	return NULL;
>> +}
>> +
>> +static struct perf_config_item *find_config_item(const char *name,
>> +						 struct perf_config_section *section)
>> +{
>> +	struct perf_config_item *config_item;
>> +
>> +	list_for_each_entry(config_item, &section->config_items, list)
>> +		if (!strcmp(config_item->name, name))
>> +			return config_item;
>> +
>> +	return NULL;
>> +}
>> +
>> +static void find_config(struct list_head *sections,
>> +			struct perf_config_section **section,
>> +			struct perf_config_item **config_item,
>> +			const char *section_name, const char *name)
>> +{
>> +	*section = find_section(sections, section_name);
>> +
>> +	if (*section != NULL)
>> +		*config_item = find_config_item(name, *section);
>> +	else
>> +		*config_item = NULL;
>
>> +}
>> +
>> +static struct perf_config_section *add_section(struct list_head *sections,
>> +					       const char *section_name)
>> +{
>> +	struct perf_config_section *section = zalloc(sizeof(*section));
>> +
>> +	if (!section)
>> +		return NULL;
>> +
>> +	INIT_LIST_HEAD(&section->config_items);
>> +	section->name = strdup(section_name);
>> +	if (!section->name) {
>> +		pr_err("%s: strdup failed\n", __func__);
>> +		free(section);
>> +		return NULL;
>> +	}
>> +
>> +	list_add_tail(&section->list, sections);
>> +	return section;
>> +}
>> +
>> +static struct perf_config_item *add_config_item(struct perf_config_section *section,
>> +						const char *name)
>> +{
>> +	struct perf_config_item *config_item = zalloc(sizeof(*config_item));
>> +
>> +	if (!config_item)
>> +		return NULL;
>> +
>> +	config_item->name = strdup(name);
>> +	if (!name) {
>
> Huh? You're testing the wrong variable.
>

Sorry, my stupid mistake..

>> +		pr_err("%s: strdup failed\n", __func__);
>> +		goto out_err;
>> +	}
>> +
>> +	list_add_tail(&config_item->list, &section->config_items);
>> +	return config_item;
>> +
>> +out_err:
>> +	free(config_item);
>> +	return NULL;
>> +}
>> +
>> +static int set_value(struct perf_config_item *config_item, const char *value)
>> +{
>> +	char *val = strdup(value);
>> +
>> +	if (!val)
>> +		return -1;
>> +
>> +	free(config_item->value);
>> +	config_item->value = val;
>> +	return 0;
>> +}
>> +
>> +static int collect_config(const char *var, const char *value,
>> +			  void *perf_config_set)
>> +{
>> +	int ret = -1;
>> +	char *ptr, *key;
>> +	char *section_name, *name;
>> +	struct perf_config_section *section = NULL;
>> +	struct perf_config_item *config_item = NULL;
>> +	struct perf_config_set *perf_configs = perf_config_set;
>> +	struct list_head *sections = &perf_configs->sections;
>> +
>> +	key = ptr = strdup(var);
>> +	if (!key) {
>> +		pr_err("%s: strdup failed\n", __func__);
>
> pr_debug()
>

I'll change pr_err to pr_debug.
But why do use pr_debug at only this part ?

>> +		return -1;
>> +	}
>> +
>> +	section_name = strsep(&ptr, ".");
>> +	name = ptr;
>> +	if (name == NULL || value == NULL)
>> +		goto out_free;
>> +
>> +	find_config(sections, &section, &config_item, section_name, name);
>
> This idiom is confusing, why not ditch this 'find_config()' function and
> do the searches here? I.e.:
>
> 	section = find_section(sections, section_name);

I got it.
I think it is needed to remove needless find_config() function as you said.

>> +	if (!section) {
>> +		section = add_section(sections, section_name);
>> +		if (!section)
>> +			goto out_free;
>> +	}
>
>   	config_item = find_config_item(name, section);

ok.

>> +	if (!config_item) {
>> +		config_item = add_config_item(section, name);
>> +		if (!config_item)
>> +			goto out_free;
>> +	}
>> +
>> +	ret = set_value(config_item, value);
>> +	return ret;
>> +
>> +out_free:
>> +	free(key);
>> +	perf_config_set__delete(perf_configs);
>> +	return -1;
>> +}
>> +
>> +struct perf_config_set *perf_config_set__new(void)
>> +{
>> +	struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));
>> +
>> +	if (!perf_configs)
>> +		return NULL;
>> +
>> +	INIT_LIST_HEAD(&perf_configs->sections);
>> +	perf_config(collect_config, perf_configs);
>> +
>> +	return perf_configs;
>> +}
>
> Usually for these short functions we could do it more compactly as:
>
> struct perf_config_set *perf_config_set__new(void)
> {
> 	struct perf_config_set *perf_configs = zalloc(sizeof(*perf_configs));
>
> 	if (perf_configs) {
> 		INIT_LIST_HEAD(&perf_configs->sections);
> 		perf_config(collect_config, perf_configs);
> 	}
>
> 	return perf_configs;
> }
>
> But I'm not dwelling on this...
>

I got it, too!

>> +void perf_config_set__delete(struct perf_config_set *perf_configs)
>> +{
>> +	struct perf_config_section *section, *section_tmp;
>> +	struct perf_config_item *config_item, *item_tmp;
>> +
>> +	list_for_each_entry_safe(section, section_tmp,
>> +				 &perf_configs->sections, list) {
>> +		list_for_each_entry_safe(config_item, item_tmp,
>> +					 &section->config_items, list) {
>> +			list_del(&config_item->list);
>> +			free(config_item->name);
>> +			free(config_item->value);
>> +			free(config_item);
>> +		}
>> +		list_del(&section->list);
>> +		free(section->name);
>> +		free(section);
>> +	}
>> +
>> +	free(perf_configs);
>> +}
>
> What is the problem with having perf_config_item__delete() and
> perf_config_section__delete() and then have it like below, also please
> rename those foo->list to foo->node.
>

No problem!
OK, I'll rename it.

> void perf_config_item__delete(struct perf_config_item *item)
> {
> 	zfree(&item->name);
> 	zfree(&item->value);
> 	free(item);
> }
>
> void perf_config_section__purge(struct perf_config_section *section)
> {
> 	struct perf_config_item *item, *tmp;
>
> 	list_for_each_entry_safe(item, tmp, &section->items, node) {
> 		list_del_init(&item->node);
> 		perf_config_item__delete(item);
> 	}
> }
>
> void perf_config_section__delete(struct perf_config_section *section)
> {
> 	perf_config_section__purge(section);
> 	zfree(&section->name);
> 	free(section);
> }
>
> void perf_config_set__purge(struct perf_config_set *set)
> {
> 	struct perf_config_section *section, *tmp;
>
> 	list_for_each_entry_safe(section, tmp, &set->sections, node) {
> 		list_del_init(&section->node);
> 		perf_config_section__delete(section);
> 	}
> }
>
> void perf_config_set__delete(struct perf_config_set *set)
> {
> 	perf_config_set__purge(set);
> 	free(set);
> }
>
> Using zfree() and list_del_init to NULL or poison the freed pointers
> helps with debugging, please use them.

ok.

>
>> +
>>   /*
>>    * Call this to report error for your variable that should not
>>    * get a boolean value (i.e. "[my] var" means "true").
>> diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h
>> new file mode 100644
>> index 0000000..e270e51
>> --- /dev/null
>> +++ b/tools/perf/util/config.h
>> @@ -0,0 +1,26 @@
>> +#ifndef __PERF_CONFIG_H
>> +#define __PERF_CONFIG_H
>> +
>> +#include <stdbool.h>
>> +#include <linux/list.h>
>> +
>> +struct perf_config_item {
>> +	char *name;
>> +	char *value;
>> +	struct list_head list;
>
> s/list/node/g
>
>> +};
>> +
>> +struct perf_config_section {
>> +	char *name;
>> +	struct list_head config_items;
>
> s/config_items/items/g
>
>> +	struct list_head list;
>
> s/list/node/g
>> +};
>> +
>> +struct perf_config_set {
>> +	struct list_head sections;
>
> See? Here you did it right, no point in having it as "config_sections"
>

I'll rename it to 'config_sections'.

>> +};
>> +
>> +struct perf_config_set *perf_config_set__new(void);
>> +void perf_config_set__delete(struct perf_config_set *perf_configs);
>
>     void perf_config_set__delete(struct perf_config_set *set);
>

OK, I'll use 'set' variable name instead of perf_configs on this source 
file.

I'll resend this patch after modifying what you said. :-)

Thanks,
Taeung

>> +
>> +#endif /* __PERF_CONFIG_H */
>> --
>> 2.5.0

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

* Re: [PATCH v4 1/4] perf config: Introduce perf_config_set class
  2016-04-01 10:27   ` Taeung Song
@ 2016-04-01 14:35     ` Arnaldo Carvalho de Melo
  2016-04-02 11:58       ` Taeung Song
  0 siblings, 1 reply; 9+ messages in thread
From: Arnaldo Carvalho de Melo @ 2016-04-01 14:35 UTC (permalink / raw)
  To: Taeung Song
  Cc: Arnaldo Carvalho de Melo, Namhyung Kim, linux-kernel, Jiri Olsa,
	Ingo Molnar, Peter Zijlstra

Em Fri, Apr 01, 2016 at 07:27:22PM +0900, Taeung Song escreveu:
> On 04/01/2016 02:31 AM, Arnaldo Carvalho de Melo wrote:
> >Em Tue, Mar 29, 2016 at 09:43:13AM +0900, Taeung Song escreveu:
> >>+static int collect_config(const char *var, const char *value,
> >>+			  void *perf_config_set)
> >>+{
> >>+	int ret = -1;
> >>+	char *ptr, *key;
> >>+	char *section_name, *name;
> >>+	struct perf_config_section *section = NULL;
> >>+	struct perf_config_item *config_item = NULL;
> >>+	struct perf_config_set *perf_configs = perf_config_set;
> >>+	struct list_head *sections = &perf_configs->sections;

> >>+	key = ptr = strdup(var);
> >>+	if (!key) {
> >>+		pr_err("%s: strdup failed\n", __func__);

> >pr_debug()
 
> I'll change pr_err to pr_debug.
> But why do use pr_debug at only this part ?

Well, ideally one would propagate the errors from library level code to
the code in the tool, i.e. closer to builtin-foo.c, where it would
decide how to present it to the user.

For extra messages, that may help a more advanced user or to be sent to
the tool developers, use pr_debug().

<SNIP>
 
> >>+struct perf_config_section {
> >>+	char *name;
> >>+	struct list_head config_items;

> >s/config_items/items/g

> >>+	struct list_head list;

> >s/list/node/g
> >>+};
> >>+
> >>+struct perf_config_set {
> >>+	struct list_head sections;

> >See? Here you did it right, no point in having it as "config_sections"

> I'll rename it to 'config_sections'.

I meant to keep this one like it is, i.e. perf_config_set->sections, and
use the same principle: shorter names, removing useless stuff like
"config_", that in this case can be implied by the name of the class,
and apply it to the perf_config_section case, making it
perf_config_section->items, ok?

- Arnaldo

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

* Re: [PATCH v4 1/4] perf config: Introduce perf_config_set class
  2016-04-01 14:35     ` Arnaldo Carvalho de Melo
@ 2016-04-02 11:58       ` Taeung Song
  0 siblings, 0 replies; 9+ messages in thread
From: Taeung Song @ 2016-04-02 11:58 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Namhyung Kim, linux-kernel, Jiri Olsa, Ingo Molnar, Peter Zijlstra



On 04/01/2016 11:35 PM, Arnaldo Carvalho de Melo wrote:
> Em Fri, Apr 01, 2016 at 07:27:22PM +0900, Taeung Song escreveu:
>> On 04/01/2016 02:31 AM, Arnaldo Carvalho de Melo wrote:
>>> Em Tue, Mar 29, 2016 at 09:43:13AM +0900, Taeung Song escreveu:
>>>> +static int collect_config(const char *var, const char *value,
>>>> +			  void *perf_config_set)
>>>> +{
>>>> +	int ret = -1;
>>>> +	char *ptr, *key;
>>>> +	char *section_name, *name;
>>>> +	struct perf_config_section *section = NULL;
>>>> +	struct perf_config_item *config_item = NULL;
>>>> +	struct perf_config_set *perf_configs = perf_config_set;
>>>> +	struct list_head *sections = &perf_configs->sections;
>
>>>> +	key = ptr = strdup(var);
>>>> +	if (!key) {
>>>> +		pr_err("%s: strdup failed\n", __func__);
>
>>> pr_debug()
>
>> I'll change pr_err to pr_debug.
>> But why do use pr_debug at only this part ?
>
> Well, ideally one would propagate the errors from library level code to
> the code in the tool, i.e. closer to builtin-foo.c, where it would
> decide how to present it to the user.
>
> For extra messages, that may help a more advanced user or to be sent to
> the tool developers, use pr_debug().

I understood it!

>
>>>> +struct perf_config_section {
>>>> +	char *name;
>>>> +	struct list_head config_items;
>
>>> s/config_items/items/g
>
>>>> +	struct list_head list;
>
>>> s/list/node/g
>>>> +};
>>>> +
>>>> +struct perf_config_set {
>>>> +	struct list_head sections;
>
>>> See? Here you did it right, no point in having it as "config_sections"
>
>> I'll rename it to 'config_sections'.
>
> I meant to keep this one like it is, i.e. perf_config_set->sections, and
> use the same principle: shorter names, removing useless stuff like
> "config_", that in this case can be implied by the name of the class,
> and apply it to the perf_config_section case, making it
> perf_config_section->items, ok?

I got it. :-)

I'll resend v5

Thanks,
Taeung

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

end of thread, other threads:[~2016-04-02 11:58 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-29  0:43 [PATCH v4 1/4] perf config: Introduce perf_config_set class Taeung Song
2016-03-29 16:12 ` Arnaldo Carvalho de Melo
2016-03-29 23:28   ` Taeung Song
2016-03-30  2:09     ` Namhyung Kim
2016-03-30 11:04       ` Taeung Song
2016-03-31 17:31 ` Arnaldo Carvalho de Melo
2016-04-01 10:27   ` Taeung Song
2016-04-01 14:35     ` Arnaldo Carvalho de Melo
2016-04-02 11:58       ` Taeung Song

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).