From: Jiri Olsa <jolsa@redhat.com>
To: "Yan, Zheng" <zheng.z.yan@intel.com>
Cc: a.p.zijlstra@chello.nl, mingo@elte.hu, andi@firstfloor.org,
eranian@google.com, linux-kernel@vger.kernel.org,
ming.m.lin@intel.com
Subject: Re: [PATCH 4/6] perf tool: Parse general events from sysfs
Date: Tue, 24 Apr 2012 11:04:27 +0200 [thread overview]
Message-ID: <20120424090427.GA2125@m.brq.redhat.com> (raw)
In-Reply-To: <1333244495-1020-5-git-send-email-zheng.z.yan@intel.com>
On Sun, Apr 01, 2012 at 09:41:33AM +0800, Yan, Zheng wrote:
> From: "Yan, Zheng" <zheng.z.yan@intel.com>
>
> PMU can export general events to sysfs, for example:
>
> /sys/bus/event_source/devices/uncore_nhm/events
hi,
so the point is to have an alias support for pmu event definition.
Seems like good idea to improve usability/readability, I have some
general comments though..
- you suggest to have sysfs files having contents like:
event=0x2c,umask=0xf
when we were adding the formats stuff into sysfs, we had to cut off
the sysfs file contents to bare minimum to obey the sysfs rule:
single file = single value
so you might have some troubles pushing that through.. not sure ;)
- I haven't read the whole patchset, but seems like the "events"
directory is now specific to a 'Intel uncore pmu'. If thats the
case I think there should be generic way for each pmu to define
this stuff.
- as for the tools/pmu.c change I'd like to see more consistent
way of parsing this, than via 'newcfg' variable.. but none
is comming to me so far ;) I'll think about that..
wbr,
jirka
> └── CLOCKTICKS
>
> Then we can specify the event as "<pmu>/<event>/", for example:
>
> perf stat -a -C 0 -e "uncore_nhm/CLOCKTICKS/" sleep 1
>
> Signed-off-by: Zheng Yan <zheng.z.yan@intel.com>
> ---
> tools/perf/util/parse-events.c | 24 ++++++--
> tools/perf/util/parse-events.h | 6 +-
> tools/perf/util/parse-events.y | 6 +-
> tools/perf/util/pmu.c | 140 +++++++++++++++++++++++++++++++++++++++-
> tools/perf/util/pmu.h | 11 +++-
> 5 files changed, 172 insertions(+), 15 deletions(-)
>
> diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
> index 5b3a0ef..fdac544 100644
> --- a/tools/perf/util/parse-events.c
> +++ b/tools/perf/util/parse-events.c
> @@ -24,7 +24,7 @@ struct event_symbol {
> };
>
> int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
> - int *idx);
> + int *idx, char **newcfg);
>
> #define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
> #define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
> @@ -648,8 +648,8 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
> (char *) __event_name(type, config));
> }
>
> -int parse_events_add_pmu(struct list_head *list, int *idx,
> - char *name, struct list_head *head_config)
> +int parse_events_add_pmu(struct list_head *list, char **newcfg,
> + int *idx, char *name, struct list_head *head_config)
> {
> struct perf_event_attr attr;
> struct perf_pmu *pmu;
> @@ -666,9 +666,12 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
> */
> config_attr(&attr, head_config, 0);
>
> - if (perf_pmu__config(pmu, &attr, head_config))
> + if (perf_pmu__config(pmu, head_config, &attr, newcfg))
> return -EINVAL;
>
> + if (newcfg && *newcfg)
> + return 0;
> +
> return add_event(list, idx, &attr, (char *) "pmu");
> }
>
> @@ -753,14 +756,25 @@ int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
> LIST_HEAD(list_tmp);
> YY_BUFFER_STATE buffer;
> int ret, idx = evlist->nr_entries;
> + char *newcfg = NULL;
>
> buffer = parse_events__scan_string(str);
>
> - ret = parse_events_parse(&list, &list_tmp, &idx);
> + ret = parse_events_parse(&list, &list_tmp, &idx, &newcfg);
>
> parse_events__flush_buffer(buffer);
> parse_events__delete_buffer(buffer);
>
> + if (!ret && newcfg) {
> + buffer = parse_events__scan_string(newcfg);
> +
> + ret = parse_events_parse(&list, &list_tmp, &idx, NULL);
> +
> + parse_events__flush_buffer(buffer);
> + parse_events__delete_buffer(buffer);
> + free(newcfg);
> + }
> +
> if (!ret) {
> int entries = idx - evlist->nr_entries;
> perf_evlist__splice_list_tail(evlist, &list, entries);
> diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
> index ca069f8..24924fd 100644
> --- a/tools/perf/util/parse-events.h
> +++ b/tools/perf/util/parse-events.h
> @@ -74,13 +74,13 @@ int parse_events_add_cache(struct list_head *list, int *idx,
> char *type, char *op_result1, char *op_result2);
> int parse_events_add_breakpoint(struct list_head *list, int *idx,
> void *ptr, char *type);
> -int parse_events_add_pmu(struct list_head *list, int *idx,
> - char *pmu , struct list_head *head_config);
> +int parse_events_add_pmu(struct list_head *list, char **newcfg,
> + int *idx, char *pmu , struct list_head *head_config);
> void parse_events_update_lists(struct list_head *list_event,
> struct list_head *list_all);
> void parse_events_error(struct list_head *list_all,
> struct list_head *list_event,
> - int *idx, char const *msg);
> + int *idx, char **newcfg, char const *msg);
>
> void print_events(const char *event_glob);
> void print_events_type(u8 type);
> diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
> index d9637da..5f569f2 100644
> --- a/tools/perf/util/parse-events.y
> +++ b/tools/perf/util/parse-events.y
> @@ -3,6 +3,7 @@
> %parse-param {struct list_head *list_all}
> %parse-param {struct list_head *list_event}
> %parse-param {int *idx}
> +%parse-param {char **newcfg}
>
> %{
>
> @@ -82,7 +83,7 @@ event_def: event_pmu |
> event_pmu:
> PE_NAME '/' event_config '/'
> {
> - ABORT_ON(parse_events_add_pmu(list_event, idx, $1, $3));
> + ABORT_ON(parse_events_add_pmu(list_event, newcfg, idx, $1, $3));
> parse_events__free_terms($3);
> }
>
> @@ -194,7 +195,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;
> }
> @@ -224,6 +225,7 @@ sep_slash_dc: '/' | ':' |
> void parse_events_error(struct list_head *list_all __used,
> struct list_head *list_event __used,
> int *idx __used,
> + char **newcfg __used,
> char const *msg __used)
> {
> }
> diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
> index cb08a11..71244b6 100644
> --- a/tools/perf/util/pmu.c
> +++ b/tools/perf/util/pmu.c
> @@ -80,6 +80,89 @@ static int pmu_format(char *name, struct list_head *format)
> return 0;
> }
>
> +static int perf_pmu__new_event(struct list_head *list, char *name, FILE *file)
> +{
> + struct perf_pmu__event *event;
> + char buf[256];
> + int ret;
> +
> + ret = fread(buf, 1, sizeof(buf), file);
> + if (ret == 0)
> + return -EINVAL;
> +
> + event = zalloc(sizeof(*event));
> + if (!event)
> + return -ENOMEM;
> +
> + event->name = strdup(name);
> + event->config = strndup(buf, ret);
> +
> + list_add_tail(&event->list, list);
> + return 0;
> +}
> +
> +/*
> + * Process all the sysfs attributes located under the directory
> + * specified in 'dir' parameter.
> + */
> +static int pmu_events_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_event(head, name, file);
> + fclose(file);
> + }
> +
> + closedir(event_dir);
> + return ret;
> +}
> +
> +/*
> + * Reading the pmu event definition, which should be located at:
> + * /sys/bus/event_source/devices/<dev>/events as sysfs group attributes.
> + */
> +static int pmu_events(char *name, struct list_head *events)
> +{
> + 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_events_parse(path, events))
> + return -1;
> +
> + return 0;
> +}
> +
> /*
> * Reading/parsing the default pmu type value, which should be
> * located at:
> @@ -118,6 +201,7 @@ static struct perf_pmu *pmu_lookup(char *name)
> {
> struct perf_pmu *pmu;
> LIST_HEAD(format);
> + LIST_HEAD(events);
> __u32 type;
>
> /*
> @@ -135,8 +219,12 @@ static struct perf_pmu *pmu_lookup(char *name)
> if (!pmu)
> return NULL;
>
> + pmu_events(name, &events);
> +
> INIT_LIST_HEAD(&pmu->format);
> + INIT_LIST_HEAD(&pmu->events);
> list_splice(&format, &pmu->format);
> + list_splice(&events, &pmu->events);
> pmu->name = strdup(name);
> pmu->type = type;
> return pmu;
> @@ -262,16 +350,62 @@ static int pmu_config(struct list_head *formats, struct perf_event_attr *attr,
> return 0;
> }
>
> +
> +static struct perf_pmu__event*
> +pmu_find_event(struct list_head *events, char *name)
> +{
> + struct perf_pmu__event *event;
> +
> + list_for_each_entry(event, events, list)
> + if (!strcmp(event->name, name))
> + return event;
> +
> + return NULL;
> +}
> +
> +static int pmu_event(struct perf_pmu *pmu, struct list_head *head_terms,
> + char **newcfg)
> +{
> + struct parse_events__term *term;
> + struct perf_pmu__event *event;
> + char *buf;
> +
> + if (!list_is_singular(head_terms))
> + return -EINVAL;
> +
> + term = list_entry(head_terms->next, struct parse_events__term, list);
> +
> + if (term->type != PARSE_EVENTS__TERM_TYPE_STR || term->val.str)
> + return -EINVAL;
> +
> + event = pmu_find_event(&pmu->events, term->config);
> + if (!event)
> + return -EINVAL;
> +
> + buf = malloc(strlen(pmu->name) + strlen(event->config) + 3);
> + if (!buf)
> + return -ENOMEM;
> +
> + sprintf(buf, "%s/%s/", pmu->name, event->config);
> + *newcfg = buf;
> +
> + return 0;
> +}
> +
> /*
> * Configures event's 'attr' parameter based on the:
> * 1) users input - specified in terms parameter
> * 2) pmu format definitions - specified by pmu parameter
> */
> -int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
> - struct list_head *head_terms)
> +int perf_pmu__config(struct perf_pmu *pmu, struct list_head *head_terms,
> + struct perf_event_attr *attr, char **newcfg)
> {
> + int ret;
> attr->type = pmu->type;
> - return pmu_config(&pmu->format, attr, head_terms);
> + ret = pmu_config(&pmu->format, attr, head_terms);
> + if (ret == -EINVAL && newcfg)
> + ret = pmu_event(pmu, head_terms, newcfg);
> + return ret;
> }
>
> int perf_pmu__new_format(struct list_head *list, char *name,
> diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
> index 68c0db9..2052b3f 100644
> --- a/tools/perf/util/pmu.h
> +++ b/tools/perf/util/pmu.h
> @@ -19,16 +19,23 @@ struct perf_pmu__format {
> struct list_head list;
> };
>
> +struct perf_pmu__event {
> + char *name;
> + char *config;
> + struct list_head list;
> +};
> +
> struct perf_pmu {
> char *name;
> __u32 type;
> struct list_head format;
> + struct list_head events;
> 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);
> +int perf_pmu__config(struct perf_pmu *pmu, struct list_head *head_terms,
> + struct perf_event_attr *attr, char **newcfg);
>
> int perf_pmu_wrap(void);
> void perf_pmu_error(struct list_head *list, char *name, char const *msg);
> --
> 1.7.7.6
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at http://www.tux.org/lkml/
next prev parent reply other threads:[~2012-04-24 9:05 UTC|newest]
Thread overview: 12+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-04-01 1:41 [RFC PATCH V2 0/6] perf: Intel uncore pmu counting support Yan, Zheng
2012-04-01 1:41 ` [PATCH 1/6] perf: Export perf_assign_events Yan, Zheng
2012-04-01 1:41 ` [PATCH 2/6] perf: Generic intel uncore support Yan, Zheng
2012-04-01 1:41 ` [PATCH 3/6] perf: Add Nehalem and Sandy Bridge " Yan, Zheng
2012-04-01 1:41 ` [PATCH 4/6] perf tool: Parse general events from sysfs Yan, Zheng
2012-04-24 9:04 ` Jiri Olsa [this message]
2012-04-25 5:47 ` Yan, Zheng
2012-04-25 13:01 ` Jiri Olsa
2012-04-01 1:41 ` [PATCH 5/6] perf: Generic pci uncore device support Yan, Zheng
2012-04-01 1:41 ` [PATCH 6/6] perf: Add Sandy Bridge-EP uncore support Yan, Zheng
2012-04-23 15:21 ` [RFC PATCH V2 0/6] perf: Intel uncore pmu counting support Stephane Eranian
2012-04-24 8:56 ` Yan, Zheng
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=20120424090427.GA2125@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.