lkml.org 
[lkml]   [2012]   [Apr]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectRe: [PATCH 4/6] perf tool: Parse general events from sysfs
On 04/24/2012 05:04 PM, Jiri Olsa wrote:
> 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..
>
Thank you very much for reviewing this.
> - 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..
>
For this point, how about making the parser re-entrantable like the patch
attached below does.

Regards
Yan, Zheng

---
diff --git a/tools/perf/Makefile b/tools/perf/Makefile
index e98e14c..a8b47d2 100644
--- a/tools/perf/Makefile
+++ b/tools/perf/Makefile
@@ -728,11 +728,13 @@ $(OUTPUT)perf.o perf.spec \
# These two need to be here so that when O= is not used they take precedence
# over the general rule for .o

+ALL_CFLAGS_NO_WERROR = $(shell echo $(ALL_CFLAGS) | sed "s/-Werror //g")
+
$(OUTPUT)util/%-flex.o: $(OUTPUT)util/%-flex.c $(OUTPUT)PERF-CFLAGS
- $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
+ $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS_NO_WERROR) -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<

$(OUTPUT)util/%-bison.o: $(OUTPUT)util/%-bison.c $(OUTPUT)PERF-CFLAGS
- $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<
+ $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS_NO_WERROR) -DYYENABLE_NLS=0 -DYYLTYPE_IS_TRIVIAL=0 -Iutil/ -Wno-redundant-decls -Wno-switch-default -Wno-unused-function $<

$(OUTPUT)%.o: %.c $(OUTPUT)PERF-CFLAGS
$(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $<
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 5b3a0ef..b776c2e 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -11,6 +11,7 @@
#include "cache.h"
#include "header.h"
#include "debugfs.h"
+#include "parse-events-bison.h"
#include "parse-events-flex.h"
#include "pmu.h"

@@ -24,7 +25,8 @@ struct event_symbol {
};

int parse_events_parse(struct list_head *list, struct list_head *list_tmp,
- int *idx);
+ int *idx, void *scanner);
+static int __parse_events(const char *str, int *idx, struct list_head *list);

#define CHW(x) .type = PERF_TYPE_HARDWARE, .config = PERF_COUNT_HW_##x
#define CSW(x) .type = PERF_TYPE_SOFTWARE, .config = PERF_COUNT_SW_##x
@@ -651,8 +653,11 @@ int parse_events_add_numeric(struct list_head *list, int *idx,
int parse_events_add_pmu(struct list_head *list, int *idx,
char *name, struct list_head *head_config)
{
+ LIST_HEAD(event);
struct perf_event_attr attr;
struct perf_pmu *pmu;
+ char *config;
+ int ret;

pmu = perf_pmu__find(name);
if (!pmu)
@@ -666,10 +671,21 @@ 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))
- return -EINVAL;
+ ret = perf_pmu__config(pmu, &attr, head_config);
+ if (!ret)
+ return add_event(list, idx, &attr, (char *) "pmu");
+
+ ret = perf_pmu__alias(pmu, &config, head_config);
+ if (ret)
+ return ret;
+
+ ret = __parse_events(config, idx, &event);
+ free(config);
+ if (ret)
+ return ret;

- return add_event(list, idx, &attr, (char *) "pmu");
+ list_splice_tail(&event, list);
+ return 0;
}

void parse_events_update_lists(struct list_head *list_event,
@@ -747,20 +763,34 @@ int parse_events_modifier(struct list_head *list, char *str)
return 0;
}

-int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
+static int __parse_events(const char *str, int *idx, struct list_head *list)
{
- LIST_HEAD(list);
LIST_HEAD(list_tmp);
YY_BUFFER_STATE buffer;
- int ret, idx = evlist->nr_entries;
+ void *scanner;
+ int ret;
+
+ ret = parse_events_lex_init(&scanner);
+ if (ret)
+ return ret;
+
+ buffer = parse_events__scan_string(str, scanner);
+
+ ret = parse_events_parse(list, &list_tmp, idx, scanner);

- buffer = parse_events__scan_string(str);
+ parse_events__flush_buffer(buffer, scanner);
+ parse_events__delete_buffer(buffer, scanner);
+ parse_events_lex_destroy(scanner);

- ret = parse_events_parse(&list, &list_tmp, &idx);
+ return ret;
+}

- parse_events__flush_buffer(buffer);
- parse_events__delete_buffer(buffer);
+int parse_events(struct perf_evlist *evlist, const char *str, int unset __used)
+{
+ LIST_HEAD(list);
+ int ret, idx = evlist->nr_entries;

+ ret = __parse_events(str, &idx, &list);
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..e1ffeb7 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -80,7 +80,7 @@ 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, void *scanner, char const *msg);

void print_events(const char *event_glob);
void print_events_type(u8 type);
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 05d766e..72066d2 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -1,4 +1,6 @@

+%option reentrant
+%option bison-bridge
%option prefix="parse_events_"

%{
@@ -7,7 +9,7 @@
#include "parse-events-bison.h"
#include "parse-events.h"

-static int __value(char *str, int base, int token)
+static int __value(YYSTYPE *yylval, char *str, int base, int token)
{
long num;

@@ -16,35 +18,35 @@ static int __value(char *str, int base, int token)
if (errno)
return PE_ERROR;

- parse_events_lval.num = num;
+ yylval->num = num;
return token;
}

-static int value(int base)
+static int value(YYSTYPE *yylval, char *text, int base)
{
- return __value(parse_events_text, base, PE_VALUE);
+ return __value(yylval, text, base, PE_VALUE);
}

-static int raw(void)
+static int raw(YYSTYPE *yylval, char *text)
{
- return __value(parse_events_text + 1, 16, PE_RAW);
+ return __value(yylval, text + 1, 16, PE_RAW);
}

-static int str(int token)
+static int str(YYSTYPE *yylval, char *text, int token)
{
- parse_events_lval.str = strdup(parse_events_text);
+ yylval->str = strdup(text);
return token;
}

-static int sym(int type, int config)
+static int sym(YYSTYPE *yylval, int type, int config)
{
- parse_events_lval.num = (type << 16) + config;
+ yylval->num = (type << 16) + config;
return PE_VALUE_SYM;
}

-static int term(int type)
+static int term(YYSTYPE *yylval, int type)
{
- parse_events_lval.num = type;
+ yylval->num = type;
return PE_TERM;
}

@@ -58,25 +60,25 @@ modifier_event [ukhp]{1,5}
modifier_bp [rwx]

%%
-cpu-cycles|cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
-stalled-cycles-frontend|idle-cycles-frontend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
-stalled-cycles-backend|idle-cycles-backend { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
-instructions { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
-cache-references { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
-cache-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
-branch-instructions|branches { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
-branch-misses { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
-bus-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
-ref-cycles { return sym(PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
-cpu-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
-task-clock { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
-page-faults|faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
-minor-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
-major-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
-context-switches|cs { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
-cpu-migrations|migrations { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
-alignment-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
-emulation-faults { return sym(PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }
+cpu-cycles|cycles { return sym(yylval, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CPU_CYCLES); }
+stalled-cycles-frontend|idle-cycles-frontend { return sym(yylval, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_FRONTEND); }
+stalled-cycles-backend|idle-cycles-backend { return sym(yylval, PERF_TYPE_HARDWARE, PERF_COUNT_HW_STALLED_CYCLES_BACKEND); }
+instructions { return sym(yylval, PERF_TYPE_HARDWARE, PERF_COUNT_HW_INSTRUCTIONS); }
+cache-references { return sym(yylval, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_REFERENCES); }
+cache-misses { return sym(yylval, PERF_TYPE_HARDWARE, PERF_COUNT_HW_CACHE_MISSES); }
+branch-instructions|branches { return sym(yylval, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_INSTRUCTIONS); }
+branch-misses { return sym(yylval, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BRANCH_MISSES); }
+bus-cycles { return sym(yylval, PERF_TYPE_HARDWARE, PERF_COUNT_HW_BUS_CYCLES); }
+ref-cycles { return sym(yylval, PERF_TYPE_HARDWARE, PERF_COUNT_HW_REF_CPU_CYCLES); }
+cpu-clock { return sym(yylval, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_CLOCK); }
+task-clock { return sym(yylval, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_TASK_CLOCK); }
+page-faults|faults { return sym(yylval, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS); }
+minor-faults { return sym(yylval, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MIN); }
+major-faults { return sym(yylval, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_PAGE_FAULTS_MAJ); }
+context-switches|cs { return sym(yylval, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CONTEXT_SWITCHES); }
+cpu-migrations|migrations { return sym(yylval, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_CPU_MIGRATIONS); }
+alignment-faults { return sym(yylval, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_ALIGNMENT_FAULTS); }
+emulation-faults { return sym(yylval, PERF_TYPE_SOFTWARE, PERF_COUNT_SW_EMULATION_FAULTS); }

L1-dcache|l1-d|l1d|L1-data |
L1-icache|l1-i|l1i|L1-instruction |
@@ -84,14 +86,14 @@ LLC|L2 |
dTLB|d-tlb|Data-TLB |
iTLB|i-tlb|Instruction-TLB |
branch|branches|bpu|btb|bpc |
-node { return str(PE_NAME_CACHE_TYPE); }
+node { return str(yylval, yytext, PE_NAME_CACHE_TYPE); }

load|loads|read |
store|stores|write |
prefetch|prefetches |
speculative-read|speculative-load |
refs|Reference|ops|access |
-misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
+misses|miss { return str(yylval, yytext, PE_NAME_CACHE_OP_RESULT); }

/*
* These are event config hardcoded term names to be specified
@@ -99,20 +101,20 @@ misses|miss { return str(PE_NAME_CACHE_OP_RESULT); }
* so we can put them here directly. In case the we have a conflict
* in future, this needs to go into '//' condition block.
*/
-config { return term(PARSE_EVENTS__TERM_TYPE_CONFIG); }
-config1 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG1); }
-config2 { return term(PARSE_EVENTS__TERM_TYPE_CONFIG2); }
-period { return term(PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
-branch_type { return term(PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }
+config { return term(yylval, PARSE_EVENTS__TERM_TYPE_CONFIG); }
+config1 { return term(yylval, PARSE_EVENTS__TERM_TYPE_CONFIG1); }
+config2 { return term(yylval, PARSE_EVENTS__TERM_TYPE_CONFIG2); }
+period { return term(yylval, PARSE_EVENTS__TERM_TYPE_SAMPLE_PERIOD); }
+branch_type { return term(yylval, PARSE_EVENTS__TERM_TYPE_BRANCH_SAMPLE_TYPE); }

mem: { return PE_PREFIX_MEM; }
-r{num_raw_hex} { return raw(); }
-{num_dec} { return value(10); }
-{num_hex} { return value(16); }
+r{num_raw_hex} { return raw(yylval, yytext); }
+{num_dec} { return value(yylval, yytext, 10); }
+{num_hex} { return value(yylval, yytext, 16); }

-{modifier_event} { return str(PE_MODIFIER_EVENT); }
-{modifier_bp} { return str(PE_MODIFIER_BP); }
-{name} { return str(PE_NAME); }
+{modifier_event} { return str(yylval, yytext, PE_MODIFIER_EVENT); }
+{modifier_bp} { return str(yylval, yytext, PE_MODIFIER_BP); }
+{name} { return str(yylval, yytext, PE_NAME); }
"/" { return '/'; }
- { return '-'; }
, { return ','; }
@@ -121,7 +123,7 @@ r{num_raw_hex} { return raw(); }

%%

-int parse_events_wrap(void)
+int parse_events_wrap(void *scanner __used)
{
return 1;
}
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d9637da..8a26f3d 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -1,8 +1,10 @@
-
+%pure-parser
%name-prefix "parse_events_"
%parse-param {struct list_head *list_all}
%parse-param {struct list_head *list_event}
%parse-param {int *idx}
+%parse-param {void *scanner}
+%lex-param {void* scanner}

%{

@@ -13,8 +15,9 @@
#include "types.h"
#include "util.h"
#include "parse-events.h"
+#include "parse-events-bison.h"

-extern int parse_events_lex (void);
+extern int parse_events_lex (YYSTYPE* lvalp, void* scanner);

#define ABORT_ON(val) \
do { \
@@ -194,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;
}
@@ -223,7 +226,7 @@ sep_slash_dc: '/' | ':' |

void parse_events_error(struct list_head *list_all __used,
struct list_head *list_event __used,
- int *idx __used,
+ int *idx __used, void *scanner __used,
char const *msg __used)
{
}
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index cb08a11..3daf828 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,6 +350,47 @@ 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 **config)
+{
+ 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);
+ *config = buf;
+ return 0;
+}
+
/*
* Configures event's 'attr' parameter based on the:
* 1) users input - specified in terms parameter
@@ -274,6 +403,12 @@ int perf_pmu__config(struct perf_pmu *pmu, struct perf_event_attr *attr,
return pmu_config(&pmu->format, attr, head_terms);
}

+int perf_pmu__alias(struct perf_pmu *pmu, char **config,
+ struct list_head *head_terms)
+{
+ return pmu_event(pmu, head_terms, config);
+}
+
int perf_pmu__new_format(struct list_head *list, char *name,
int config, unsigned long *bits)
{
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index 68c0db9..3656b42 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -19,16 +19,25 @@ 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__alias(struct perf_pmu *pmu, char **config,
+ struct list_head *head_terms);

int perf_pmu_wrap(void);
void perf_pmu_error(struct list_head *list, char *name, char const *msg);

\
 
 \ /
  Last update: 2012-04-25 07:51    [W:0.063 / U:0.120 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site