From: Andi K. <an...@fi...> - 2011-05-15 04:34:27
|
From: Andi Kleen <ak...@li...> With extra fields available just specifying the numerical unit_mask is often not enough to select the right event. This patch allows to specify unitmasks by name (first word in the description) in the event description. This also makes many unit masks easier to use because names are easier to remember than numbers. v2: Fixed review feedback, fix regression tester v3: Add unit mask name uniqueness check v4: Add another check Signed-off-by: Andi Kleen <ak...@li...> --- doc/opcontrol.1.in | 5 +- doc/oprofile.xml | 2 +- libop/op_events.c | 134 +++++++++++++++++++++++++++++++++++++++ libop/op_events.h | 11 +++ libop/op_parse_event.c | 9 ++- libop/op_parse_event.h | 1 + libop/tests/parse_event_tests.c | 8 +- utils/opcontrol | 13 ++-- utils/ophelp.c | 40 ++++-------- 9 files changed, 180 insertions(+), 43 deletions(-) diff --git a/doc/opcontrol.1.in b/doc/opcontrol.1.in index 5a78aa6..931d877 100644 --- a/doc/opcontrol.1.in +++ b/doc/opcontrol.1.in @@ -107,7 +107,10 @@ or "default" for the default event. The event is of the form count, unit mask, kernel-space counting, user-space counting, respectively. Note that this over-rides all previous events selected; if you want two or more counters used simultaneously, you must specify -them on the same opcontrol invocation. +them on the same opcontrol invocation. The numerical unit mask +can also be a string which matches the first word in the unit mask +description, but only for events with extra parameters shown. +Events with extra parameters must be specified by first word. .br .TP .BI "--separate="[none,lib,kernel,thread,cpu,all] diff --git a/doc/oprofile.xml b/doc/oprofile.xml index 0d6407c..843d96b 100644 --- a/doc/oprofile.xml +++ b/doc/oprofile.xml @@ -877,7 +877,7 @@ of the form <option><emphasis>name</emphasis>:<emphasis>count</emphasis>:<emphas <tbody> <row><entry><option>name</option></entry><entry>The symbolic event name, e.g. <constant>CPU_CLK_UNHALTED</constant></entry></row> <row><entry><option>count</option></entry><entry>The counter reset value, e.g. 100000</entry></row> -<row><entry><option>unitmask</option></entry><entry>The unit mask, as given in the events list, e.g. 0x0f</entry></row> +<row><entry><option>unitmask</option></entry><entry>The unit mask, as given in the events list, e.g. 0x0f or a symbolic name (first word of the description if unique)</entry></row> <row><entry><option>kernel</option></entry><entry>Whether to profile kernel code</entry></row> <row><entry><option>user</option></entry><entry>Whether to profile userspace code</entry></row> </tbody> diff --git a/libop/op_events.c b/libop/op_events.c index 8da023b..502ff01 100644 --- a/libop/op_events.c +++ b/libop/op_events.c @@ -17,6 +17,7 @@ #include "op_string.h" #include "op_cpufreq.h" #include "op_hw_specific.h" +#include "op_parse_event.h" #include <string.h> #include <stdlib.h> @@ -921,6 +922,18 @@ struct op_event * find_event_by_name(char const * name, unsigned um, int um_vali } +static struct op_event * find_next_event(struct op_event * e) +{ + struct list_head * n; + + for (n = e->event_next.next; n != &events_list; n = n->next) { + struct op_event * ne = list_entry(n, struct op_event, event_next); + if (!strcmp(e->name, ne->name)) + return ne; + } + return NULL; +} + struct op_event * op_find_event(op_cpu cpu_type, u32 nr, u32 um) { struct op_event * event; @@ -1120,3 +1133,124 @@ void op_default_event(op_cpu cpu_type, struct op_default_event_descr * descr) break; } } + +static void extra_check(struct op_event *e, u32 unit_mask) +{ + unsigned i; + int found = 0; + + for (i = 0; i < e->unit->num; i++) + if (e->unit->um[i].value == unit_mask) + found++; + if (found > 1) { + fprintf(stderr, +"Unfortunately you are not allowed to use named unit masks on events\n" +"without extra values. Please specify the magic numbers for the unit mask\n" +"instead\n"); + exit(EXIT_FAILURE); + } +} + +static void another_extra_check(struct op_event *e, char *name, unsigned w) +{ + int found; + unsigned i; + + if (!e->unit->um[w].extra) { + fprintf(stderr, +"Named unit mask `%s' has no extra parameter. Please use a numerical\n" +"unit mask; names would be too easy.\n", name); + exit(EXIT_FAILURE); + } + + found = 0; + for (i = 0; i < e->unit->num; i++) { + int len = strcspn(e->unit->um[i].desc, " \t"); + if (!strncmp(name, e->unit->um[i].desc, len) && + name[len] == '\0') + found++; + } + if (found > 1) { + fprintf(stderr, + "Unit mask name `%s' not unique. Sorry please use a numerical unit mask\n", name); + exit(EXIT_FAILURE); + } +} + +static void do_resolve_unit_mask(struct op_event *e, struct parsed_event *pe, + u32 *extra) +{ + unsigned i; + int found; + + for (;;) { + if (pe->unit_mask_name == NULL) { + int fi = 0; + unsigned um = pe->unit_mask; + int had_unit_mask = pe->unit_mask_valid; + + found = 0; + for (i = 0; i < e->unit->num; i++) { + if (pe->unit_mask_valid && + e->unit->um[i].value == um) { + if (found++ == 0) + fi = i; + } + if (!pe->unit_mask_valid && + e->unit->um[i].value == e->unit->default_mask) { + pe->unit_mask_valid = 1; + pe->unit_mask = e->unit->default_mask; + break; + } + } + if (found > 1 && had_unit_mask) { + fprintf(stderr, + "Non unique numerical unit mask.\n" + "Please specify the unit mask using the first word of the description\n"); + exit(EXIT_FAILURE); + } + extra_check(e, pe->unit_mask); + if (i == e->unit->num) { + e = find_next_event(e); + if (e != NULL) + continue; + } else { + if (extra) + *extra = e->unit->um[i].extra; + } + return; + } + for (i = 0; i < e->unit->num; i++) { + int len = strcspn(e->unit->um[i].desc, " \t"); + if (!strncmp(pe->unit_mask_name, e->unit->um[i].desc, + len) && pe->unit_mask_name[len] == '\0') + break; + } + if (i == e->unit->num) { + e = find_next_event(e); + if (e != NULL) + continue; + fprintf(stderr, "Cannot find unit mask %s for %s\n", + pe->unit_mask_name, pe->name); + exit(EXIT_FAILURE); + } + another_extra_check(e, pe->unit_mask_name, i); + pe->unit_mask_valid = 1; + pe->unit_mask = e->unit->um[i].value; + if (extra) + *extra = e->unit->um[i].extra; + return; + } +} + +void op_resolve_unit_mask(struct parsed_event *pe, u32 *extra) +{ + struct op_event *e; + + e = find_event_by_name(pe->name, 0, 0); + if (!e) { + fprintf(stderr, "Cannot find event %s\n", pe->name); + exit(EXIT_FAILURE); + } + return do_resolve_unit_mask(e, pe, extra); +} diff --git a/libop/op_events.h b/libop/op_events.h index 3aaaba2..58d39da 100644 --- a/libop/op_events.h +++ b/libop/op_events.h @@ -128,6 +128,17 @@ struct op_default_event_descr { */ void op_default_event(op_cpu cpu_type, struct op_default_event_descr * descr); +/** + * op_resolve_unit_mask - resolve a unit mask in a parsed event. + * @pe parsed event + * @extra pointer to extra mask or NULL. + * + * Fills in the extra mask for the unit mask. + */ + +struct parsed_event; +void op_resolve_unit_mask(struct parsed_event *pe, u32 *extra); + #ifdef __cplusplus } #endif diff --git a/libop/op_parse_event.c b/libop/op_parse_event.c index eb99a20..949730b 100644 --- a/libop/op_parse_event.c +++ b/libop/op_parse_event.c @@ -13,6 +13,7 @@ #include <stdio.h> #include <stdlib.h> +#include <ctype.h> #include "op_parse_event.h" #include "op_string.h" @@ -94,8 +95,12 @@ size_t parse_events(struct parsed_event * parsed_events, size_t max_events, if (part) { parsed_events[i].unit_mask_valid = 1; - parsed_events[i].unit_mask = parse_ulong(part); - free(part); + if (!isdigit(*part)) + parsed_events[i].unit_mask_name = part; + else { + parsed_events[i].unit_mask = parse_ulong(part); + free(part); + } } parsed_events[i].kernel = 1; diff --git a/libop/op_parse_event.h b/libop/op_parse_event.h index c8d4144..2519b0d 100644 --- a/libop/op_parse_event.h +++ b/libop/op_parse_event.h @@ -20,6 +20,7 @@ struct parsed_event { char * name; int count; int unit_mask; + char * unit_mask_name; int kernel; int user; int unit_mask_valid; diff --git a/libop/tests/parse_event_tests.c b/libop/tests/parse_event_tests.c index b2fda3b..8e9dabe 100644 --- a/libop/tests/parse_event_tests.c +++ b/libop/tests/parse_event_tests.c @@ -22,10 +22,10 @@ struct events_test { static struct events_test const events[] = { - { { "FOO:3000:0:0:0", 0 }, { "FOO", 3000, 0, 0, 0, 0 } }, - { { "BAR:3000", 0 }, { "BAR", 3000, 0, 1, 1, 0 } }, - { { "FOOBAR:3000:1:1:1", 0 }, { "FOOBAR", 3000, 1, 1, 1, 0 } }, - { { NULL, NULL }, { 0, 0, 0, 0, 0, 0 } } + { { "FOO:3000:0:0:0", 0 }, { "FOO", 3000, 0, NULL, 0, 0, 0 } }, + { { "BAR:3000", 0 }, { "BAR", 3000, 0, NULL, 1, 1, 0 } }, + { { "FOOBAR:3000:1:1:1", 0 }, { "FOOBAR", 3000, 1, NULL, 1, 1, 0 } }, + { { NULL, NULL }, { 0, 0, 0, NULL, 0, 0, 0 } } }; static void do_test(struct events_test const * ev) diff --git a/utils/opcontrol b/utils/opcontrol index 603172d..dfe70f0 100644 --- a/utils/opcontrol +++ b/utils/opcontrol @@ -638,12 +638,11 @@ normalise_events() UNIT_MASK=`echo $GOTEVENT | awk -F: '{print $3}'` KERNEL=`echo $GOTEVENT | awk -F: '{print $4}'` USER=`echo $GOTEVENT | awk -F: '{print $5}'` - if test -z "$UNIT_MASK"; then - TMPEVENT="$EVENT:$COUNT" - UNIT_MASK=`$OPHELP --unit-mask $TMPEVENT` - if test "$?" != 0; then - exit 1 - fi + TMPEVENT="$EVENT:$COUNT:$UNIT_MASK" + UNIT_MASK_NAMED="$UNIT_MASK" + UNIT_MASK=`$OPHELP --unit-mask $TMPEVENT` + if test "$?" != 0; then + exit 1 fi if test -z "$KERNEL"; then KERNEL=1 @@ -1442,7 +1441,7 @@ do_param_setup() set_ctr_param $CTR user $USER set_ctr_param $CTR unit_mask $UNIT_MASK - EXTRA=`$OPHELP --extra-mask $GOTEVENT` + EXTRA=`$OPHELP --extra-mask $EVENT:$COUNT:$UNIT_MASK_NAMED` if test "$EXTRA" -ne 0 ; then if ! test -d $MOUNT/$CTR/extra ; then echo >&2 "Warning: $GOTEVENT has extra mask, but kernel does not support extra field" diff --git a/utils/ophelp.c b/utils/ophelp.c index 60b1662..b3aebde 100644 --- a/utils/ophelp.c +++ b/utils/ophelp.c @@ -182,6 +182,8 @@ static void check_event(struct parsed_event * pev, exit(EXIT_FAILURE); } + op_resolve_unit_mask(pev, NULL); + ret = op_check_events(0, event->val, pev->unit_mask, cpu_type); if (ret & OP_INVALID_UM) { @@ -212,6 +214,7 @@ static void resolve_events(void) count = parse_events(parsed_events, num_chosen_events, chosen_events); for (i = 0; i < count; ++i) { + op_resolve_unit_mask(&parsed_events[i], NULL); for (j = i + 1; j < count; ++j) { struct parsed_event * pev1 = &parsed_events[i]; struct parsed_event * pev2 = &parsed_events[j]; @@ -270,7 +273,6 @@ static void resolve_events(void) static void show_unit_mask(void) { - struct op_event * event; size_t count; count = parse_events(parsed_events, num_chosen_events, chosen_events); @@ -279,20 +281,15 @@ static void show_unit_mask(void) exit(EXIT_FAILURE); } - event = find_event_by_name(parsed_events[0].name, 0, 0); - - if (!event) { - fprintf(stderr, "No such event found.\n"); - exit(EXIT_FAILURE); - } - - printf("%d\n", event->unit->default_mask); + op_resolve_unit_mask(parsed_events, NULL); + if (parsed_events[0].unit_mask_name) + printf("%s\n", parsed_events[0].unit_mask_name); + else + printf("%d\n", parsed_events[0].unit_mask); } static void show_extra_mask(void) { - unsigned i; - struct op_event * event; size_t count; unsigned extra; @@ -302,22 +299,7 @@ static void show_extra_mask(void) exit(EXIT_FAILURE); } - event = find_event_by_name(parsed_events[0].name, - parsed_events[0].unit_mask, - 1); - if (!event) { - fprintf(stderr, "No such event found.\n"); - exit(EXIT_FAILURE); - } - - /* Not exact match is nothing */ - extra = 0; - for (i = 0; i < event->unit->num; i++) - if (event->unit->um[i].value == (unsigned)parsed_events[0].unit_mask) { - extra = event->unit->um[i].extra; - break; - } - + op_resolve_unit_mask(parsed_events, &extra); printf ("%d\n", extra); } @@ -761,8 +743,10 @@ int main(int argc, char const * argv[]) sprintf(title, "oprofile: available events for CPU type \"%s\"\n\n", pretty); if (want_xml) open_xml_events(title, event_doc, cpu_type); - else + else { printf("%s%s", title, event_doc); + printf("You can use named events by specifying the first word of the description if unique\n\n"); + } list_for_each(pos, events) { struct op_event * event = list_entry(pos, struct op_event, event_next); -- 1.7.4.4 |