linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jiri Olsa <jolsa@redhat.com>
To: "Yan, Zheng" <zheng.z.yan@intel.com>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>,
	mingo@elte.hu, andi@firstfloor.org, eranian@google.com,
	ming.m.lin@intel.com, linux-kernel@vger.kernel.org
Subject: Re: [PATCH 9/9] perf tool: Add pmu event alias support
Date: Thu, 10 May 2012 11:52:48 +0200	[thread overview]
Message-ID: <20120510095248.GA3427@m.brq.redhat.com> (raw)
In-Reply-To: <4FA78904.8010306@intel.com>

On Mon, May 07, 2012 at 04:34:12PM +0800, Yan, Zheng wrote:
> On 05/04/2012 04:05 AM, Jiri Olsa wrote:
> > On Thu, May 03, 2012 at 01:24:21PM +0200, Peter Zijlstra wrote:
> >> On Thu, 2012-05-03 at 12:56 +0200, Jiri Olsa wrote:
> >>> - in sysfs you would have directory with aliases (now called 'events')

SNIP

> 
> How is the patch below, it implements option 2.
hi,
sorry for late reply and long email ;) comments below

jirka

> 
> Thanks
> ---
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index c587ae8..4ed4278 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -656,22 +656,33 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
>  	struct perf_event_attr attr;
>  	struct perf_pmu *pmu;
>  
> +	/* called by parse_event_config? */
> +	if (!idx) {
> +		list_splice_init(head_config, list);
> +		return 0;
> +	}

ok, so this is because we want to use current event parser to parse the alias terms

options we have globaly ;) AFAICS:

1) the one you have
   - in case the idx pointer is NULL, we use the event list to store
     terms
   - I guess it works ;) but seems to me like we might have troubles
     in future to expand this code further..

   if we want to have it this way, we better use some new parse events
   function argument to define the function of the parser:
       - return events
       - return terms

2) I'm currently looking on having multiple starting points in the
   grammar. It seems that in some cases this is working option:

   http://www.gnu.org/software/bison/manual/html_node/Multiple-start_002dsymbols.html

   I'll update you later with this one ;)


3) having separate parser for terms parsing, which would be called
   from pmu initialization and during event parsing
   - this seems clean and doable but it smells with -ETOOMANYPARSERS ;)

4) having the alias definitions defined within the tree structure
   I described earlier:
        events/
                CAS_COUNT_RD/
                        # files:
                        config  - value 1
                        config1 - value 2
                        mask    - value ...

      - initialy I thought the current sysfs alias format would clash
        with sysfs rules.. but after talking to Peter ;) I think it's ok,
        because it's still <one file - one value>
      - but using this, we would not need special parser

- ad 4) seems now like avoiding the problem
- ad 1) hackish
- ad 3) seems most clean and extentable in future
- ad 4) need to explore

I think we should ask sysfs folks to confirm the sysfs layout.. :)

> +
>  	pmu = perf_pmu__find(name);
>  	if (!pmu)
>  		return -EINVAL;
>  
>  	memset(&attr, 0, sizeof(attr));
>  
> -	/*
> -	 * Configure hardcoded terms first, no need to check
> -	 * return value when called with fail == 0 ;)
> -	 */
> -	config_attr(&attr, head_config, 0);
> +	while (1) {
> +		/*
> +		 * Configure hardcoded terms first, no need to check
> +		 * return value when called with fail == 0 ;)
> +		 */
> +		config_attr(&attr, head_config, 0);
>  
> -	if (perf_pmu__config(pmu, &attr, head_config))
> -		return -EINVAL;
> +		if (!perf_pmu__config(pmu, &attr, head_config))
> +			return add_event(list, idx, &attr, (char *) "pmu");
>  
> -	return add_event(list, idx, &attr, (char *) "pmu");
> +		head_config = perf_pmu__alias(pmu, head_config);
> +		if (!head_config)
> +			break;
> +	}
> +	return -EINVAL;
The perf_pmu__alias checks first term in the list for the alias, but what
if the alias is second term? I think we could be more general like:


parse_events_add_pmu {
	...

	config_attr(&attr, head_config, 0);

	config_alias(pmu, head_config);

	if (perf_pmu__config(pmu, &attr, head_config))
		return -EINVAL;

	return 0;
}

config_alias(pmu, head) {
	for each term in head {
		if (is term alias in pmu) {
			replace the alias term with its term definition (multiple terms probably)
		}
	}
}

so we just replace the alias term with it's definition terms
and call perf_pmu__config with final terms

this way:
- we could add more terms on command line in addition to the alias
- alias does not need to be the first term specified on command line


>  }
>  
>  void parse_events_update_lists(struct list_head *list_event,
> @@ -771,6 +782,26 @@ static int __parse_events(const char *str, int *idx, struct list_head *list)
>  	return ret;
>  }
>  
> +/*
> + * parse event config string, return a list of event terms.
> + */
> +int parse_event_config(struct list_head *terms, const char *str)
> +{
> +	char *buf;
> +	int ret;
> +
> +	buf = malloc(strlen(str) + 6);
> +	if (!buf)
> +		return -ENOMEM;
> +
> +	/* It is no matter which pmu is used here */
> +	sprintf(buf, "cpu/%s/", str);
> +	ret = __parse_events(buf, NULL, terms);
> +
> +	free(buf);
> +	return ret;
> +}
> +
>  int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
>  {
>  	LIST_HEAD(list);
> diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
> index e1ffeb7..5b5d698 100644
> --- a/tools/perf/util/parse-events.h
> +++ b/tools/perf/util/parse-events.h
> @@ -30,6 +30,7 @@ extern int parse_events_option(const struct option *opt, const char *str,
>  extern int parse_events(struct perf_evlist *evlist, const char *str,
>  			int unset);
>  extern int parse_filter(const struct option *opt, const char *str, int unset);
> +extern int parse_event_config(struct list_head *terms, const char *str);
>  
>  #define EVENTS_HELP_MAX (128*1024)
>  
> diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
> index 52082a7..8a26f3d 100644
> --- a/tools/perf/util/parse-events.y
> +++ b/tools/perf/util/parse-events.y
> @@ -197,7 +197,7 @@ PE_NAME
>  {
>  	struct parse_events__term *term;
>  
> -	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_NUM,
> +	ABORT_ON(parse_events__new_term(&term, PARSE_EVENTS__TERM_TYPE_STR,
>  		 $1, NULL, 1));
>  	$$ = term;
>  }
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index cb08a11..7a85779 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -80,6 +80,95 @@ static int pmu_format(char *name, struct list_head *format)
>  	return 0;
>  }
>  
> +static int perf_pmu__new_alias(struct list_head *list, char *name, FILE *file)
> +{
> +	struct perf_pmu__alias *alias;
> +	char buf[256];
> +	int ret;
> +
> +	ret = fread(buf, 1, sizeof(buf), file);
> +	if (ret == 0)
> +		return -EINVAL;
> +	buf[ret] = 0;
> +
> +	alias = malloc(sizeof(*alias));
> +	if (!alias)
> +		return -ENOMEM;
> +
> +	INIT_LIST_HEAD(&alias->terms);
> +	ret = parse_event_config(&alias->terms, buf);
> +	if (ret) {
> +		free(alias);
> +		return ret;
> +	}
> +
> +	alias->name = strdup(name);
> +	list_add_tail(&alias->list, list);
> +	return 0;
> +}
> +
> +/*
> + * Process all the sysfs attributes located under the directory
> + * specified in 'dir' parameter.
> + */
> +static int pmu_aliases_parse(char *dir, struct list_head *head)
> +{
> +	struct dirent *evt_ent;
> +	DIR *event_dir;
> +	int ret = 0;
> +
> +	event_dir = opendir(dir);
> +	if (!event_dir)
> +		return -EINVAL;
> +
> +	while (!ret && (evt_ent = readdir(event_dir))) {
> +		char path[PATH_MAX];
> +		char *name = evt_ent->d_name;
> +		FILE *file;
> +
> +		if (!strcmp(name, ".") || !strcmp(name, ".."))
> +			continue;
> +
> +		snprintf(path, PATH_MAX, "%s/%s", dir, name);
> +
> +		ret = -EINVAL;
> +		file = fopen(path, "r");
> +		if (!file)
> +			break;
> +		ret = perf_pmu__new_alias(head, name, file);
> +		fclose(file);
> +	}
> +
> +	closedir(event_dir);
> +	return ret;
> +}
> +
> +/*
> + * Reading the pmu event aliases definition, which should be located at:
> + * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
> + */
> +static int pmu_aliases(char *name, struct list_head *head)
> +{
> +	struct stat st;
> +	char path[PATH_MAX];
> +	const char *sysfs;
> +
> +	sysfs = sysfs_find_mountpoint();
> +	if (!sysfs)
> +		return -1;
> +
> +	snprintf(path, PATH_MAX,
> +		 "%s/bus/event_source/devices/%s/events", sysfs, name);
> +
> +	if (stat(path, &st) < 0)
> +		return -1;
> +
> +	if (pmu_aliases_parse(path, head))
> +		return -1;
> +
> +	return 0;
> +}
> +
>  /*
>   * Reading/parsing the default pmu type value, which should be
>   * located at:
> @@ -118,6 +207,7 @@ static struct perf_pmu *pmu_lookup(char *name)
>  {
>  	struct perf_pmu *pmu;
>  	LIST_HEAD(format);
> +	LIST_HEAD(aliases);
>  	__u32 type;
>  
>  	/*
> @@ -135,8 +225,12 @@ static struct perf_pmu *pmu_lookup(char *name)
>  	if (!pmu)
>  		return NULL;
>  
> +	pmu_aliases(name, &aliases);
> +
>  	INIT_LIST_HEAD(&pmu->format);
> +	INIT_LIST_HEAD(&pmu->aliases);
>  	list_splice(&format, &pmu->format);
> +	list_splice(&aliases, &pmu->aliases);
>  	pmu->name = strdup(name);
>  	pmu->type = type;
>  	return pmu;
> @@ -262,6 +356,35 @@ static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
>  	return 0;
>  }
>  
> +static struct perf_pmu__alias *pmu_find_alias(struct list_head *events,
> +					      char *name)
> +{
> +	struct perf_pmu__alias *alias;
> +
> +	list_for_each_entry(alias, events, list) {
> +		if (!strcmp(alias->name, name))
> +			return alias;
> +	}
> +	return NULL;
> +}
> +
> +struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
> +				  struct list_head *head_terms)
> +{
> +	struct parse_events__term *term;
> +	struct perf_pmu__alias *alias;
> +
> +	if (!list_is_singular(head_terms))
> +		return NULL;
> +
> +	term = list_entry(head_terms->next, struct parse_events__term, list);
> +	if (term->type != PARSE_EVENTS__TERM_TYPE_STR || term->val.str)
> +		return NULL;
> +
> +	alias = pmu_find_alias(&pmu->aliases, term->config);
> +	return &alias->terms;
> +}
> +
>  /*
>   * Configures event's 'attr' parameter based on the:
>   * 1) users input - specified in terms parameter
> diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> index 68c0db9..8fad317 100644
> --- a/tools/perf/util/pmu.h
> +++ b/tools/perf/util/pmu.h
> @@ -19,17 +19,25 @@ struct perf_pmu__format {
>  	struct list_head list;
>  };
>  
> +struct perf_pmu__alias {
> +	char *name;
> +	struct list_head terms;
> +	struct list_head list;
> +};
> +
>  struct perf_pmu {
>  	char *name;
>  	__u32 type;
>  	struct list_head format;
> +	struct list_head aliases;
>  	struct list_head list;
>  };
>  
>  struct perf_pmu *perf_pmu__find(char *name);
>  int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
>  		     struct list_head *head_terms);
> -
> +struct list_head *perf_pmu__alias(struct perf_pmu *pmu,
> +				struct list_head *head_terms);
>  int perf_pmu_wrap(void);
>  void perf_pmu_error(struct list_head *list, char *name, char const *msg);
>  
> 
> 
> 
> 
> 
> 

  reply	other threads:[~2012-05-10  9:53 UTC|newest]

Thread overview: 38+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-05-02  2:07 [PATCH V3 0/9] perf: Intel uncore pmu counting support Yan, Zheng
2012-05-02  2:07 ` [PATCH 1/9] perf: Export perf_assign_events Yan, Zheng
2012-05-02  2:07 ` [PATCH 2/9] perf: Allow pmu to choose cpu on which to install event Yan, Zheng
2012-05-09  6:38   ` Anshuman Khandual
2012-05-10  1:09     ` Yan, Zheng
2012-05-10  3:41       ` Anshuman Khandual
2012-05-10 10:56         ` Peter Zijlstra
2012-05-02  2:07 ` [PATCH 3/9] perf: Introduce perf_pmu_migrate_context Yan, Zheng
2012-05-02  2:07 ` [PATCH 4/9] perf: Generic intel uncore support Yan, Zheng
2012-05-03 17:12   ` Peter Zijlstra
2012-05-04  7:33     ` Yan, Zheng
2012-05-04 17:57       ` Peter Zijlstra
2012-05-10  7:34     ` Yan, Zheng
2012-05-10 10:05       ` Peter Zijlstra
2012-05-11  1:54         ` Yan, Zheng
2012-05-03 21:49   ` Peter Zijlstra
2012-05-11  6:31   ` Anshuman Khandual
2012-05-11  6:41     ` Yan, Zheng
2012-05-02  2:07 ` [PATCH 5/9] perf: Add Nehalem and Sandy Bridge " Yan, Zheng
2012-05-03 21:04   ` Peter Zijlstra
2012-05-04  5:47     ` Yan, Zheng
2012-05-03 21:04   ` Peter Zijlstra
2012-05-02  2:07 ` [PATCH 6/9] perf: Generic pci uncore device support Yan, Zheng
2012-05-03 21:37   ` Peter Zijlstra
2012-05-03 21:39   ` Peter Zijlstra
2012-05-03 21:46   ` Peter Zijlstra
2012-05-04  6:07     ` Yan, Zheng
2012-05-02  2:07 ` [PATCH 7/9] perf: Add Sandy Bridge-EP uncore support Yan, Zheng
2012-05-03 21:12   ` Peter Zijlstra
2012-05-02  2:07 ` [PATCH 8/9] perf tool: Make the event parser reentrantable Yan, Zheng
2012-05-02  2:07 ` [PATCH 9/9] perf tool: Add pmu event alias support Yan, Zheng
2012-05-03 10:56   ` Jiri Olsa
2012-05-03 11:24     ` Peter Zijlstra
2012-05-03 20:05       ` Jiri Olsa
2012-05-04 12:32         ` Yan, Zheng
2012-05-07  8:34         ` Yan, Zheng
2012-05-10  9:52           ` Jiri Olsa [this message]
2012-05-07 17:14         ` Peter Zijlstra

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20120510095248.GA3427@m.brq.redhat.com \
    --to=jolsa@redhat.com \
    --cc=a.p.zijlstra@chello.nl \
    --cc=andi@firstfloor.org \
    --cc=eranian@google.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=ming.m.lin@intel.com \
    --cc=mingo@elte.hu \
    --cc=zheng.z.yan@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).