op_events.c

Go to the documentation of this file.
00001 
00014 #include "op_events.h"
00015 #include "op_libiberty.h"
00016 #include "op_fileio.h"
00017 #include "op_string.h"
00018 #include "op_cpufreq.h"
00019 #include "op_hw_specific.h"
00020 #include "op_parse_event.h"
00021 
00022 #include <string.h>
00023 #include <stdlib.h>
00024 #include <stdio.h>
00025 #include <ctype.h>
00026 
00027 static LIST_HEAD(events_list);
00028 static LIST_HEAD(um_list);
00029 
00030 static char const * filename;
00031 static unsigned int line_nr;
00032 
00033 static void delete_event(struct op_event * event);
00034 static void read_events(char const * file);
00035 static void read_unit_masks(char const * file);
00036 static void free_unit_mask(struct op_unit_mask * um);
00037 
00038 static char *build_fn(const char *cpu_name, const char *fn)
00039 {
00040     char *s;
00041     static const char *dir;
00042     if (dir == NULL)
00043         dir = getenv("OPROFILE_EVENTS_DIR");
00044     if (dir == NULL)
00045         dir = OP_DATADIR;
00046     s = xmalloc(strlen(dir) + strlen(cpu_name) + strlen(fn) + 5);
00047     sprintf(s, "%s/%s/%s", dir, cpu_name, fn);
00048     return s;
00049 }
00050 
00051 static void parse_error(char const * context)
00052 {
00053     fprintf(stderr, "oprofile: parse error in %s, line %u\n",
00054         filename, line_nr);
00055     fprintf(stderr, "%s\n", context);
00056     exit(EXIT_FAILURE);
00057 }
00058 
00059 
00060 static int parse_int(char const * str)
00061 {
00062     int value;
00063     if (sscanf(str, "%d", &value) != 1)
00064         parse_error("expected decimal value");
00065 
00066     return value;
00067 }
00068 
00069 
00070 static int parse_hex(char const * str)
00071 {
00072     int value;
00073     /* 0x/0X to force the use of hexa notation for field intended to
00074        be in hexadecimal */
00075     if (sscanf(str, "0x%x", &value) != 1 &&
00076         sscanf(str, "0X%x", &value) != 1)
00077         parse_error("expected hexadecimal value");
00078 
00079     return value;
00080 }
00081 
00082 
00083 static u64 parse_long_hex(char const * str)
00084 {
00085     u64 value;
00086     if (sscanf(str, "%Lx", &value) != 1)
00087         parse_error("expected long hexadecimal value");
00088 
00089     fflush(stderr);
00090     return value;
00091 }
00092 
00093 static void include_um(const char *start, const char *end)
00094 {
00095     char *s;
00096     char cpu[end - start + 1];
00097     int old_line_nr;
00098     const char *old_filename;
00099 
00100     strncpy(cpu, start, end - start);
00101     cpu[end - start] = 0;
00102     s = build_fn(cpu, "unit_masks");
00103     old_line_nr = line_nr;
00104     old_filename = filename;
00105     read_unit_masks(s);
00106     line_nr = old_line_nr;
00107     filename = old_filename;
00108     free(s);
00109 }
00110 
00111 /* extra:cmask=12,inv,edge */
00112 unsigned parse_extra(const char *s)
00113 {
00114     unsigned v, w;
00115     int o;
00116 
00117     v = 0;
00118     while (*s) {
00119         if (isspace(*s))
00120             break;
00121         if (strisprefix(s, "edge")) {
00122             v |= EXTRA_EDGE;
00123             s += 4;
00124         } else if (strisprefix(s, "inv")) {
00125             v |= EXTRA_INV;
00126             s += 3;
00127         } else if (sscanf(s, "cmask=%x%n", &w, &o) >= 1) {
00128             v |= (w & EXTRA_CMASK_MASK) << EXTRA_CMASK_SHIFT;
00129             s += o;
00130         } else if (strisprefix(s, "any")) {
00131             v |= EXTRA_ANY;
00132             s += 3;
00133         } else {
00134             parse_error("Illegal extra field modifier");
00135         }
00136         if (*s == ',')
00137             ++s;
00138     }
00139     return v;
00140 }
00141 
00142 /* name:MESI type:bitmask default:0x0f */
00143 static void parse_um(struct op_unit_mask * um, char const * line)
00144 {
00145     int seen_name = 0;
00146     int seen_type = 0;
00147         int seen_default = 0;
00148     char const * valueend = line + 1;
00149         char const * tagend = line + 1;
00150     char const * start = line;
00151 
00152     while (*valueend) {
00153         valueend = skip_nonws(valueend);
00154 
00155         while (*tagend != ':' && *tagend)
00156             ++tagend;
00157 
00158         if (valueend == tagend)
00159             break;
00160 
00161         if (!*tagend)
00162             parse_error("parse_um() expected :value");
00163 
00164         ++tagend;
00165 
00166         if (strisprefix(start, "include")) {
00167             if (seen_name + seen_type + seen_default > 0)
00168                 parse_error("include must be on its own");
00169             free_unit_mask(um);
00170             include_um(tagend, valueend);
00171             return;
00172         }
00173 
00174         if (strisprefix(start, "name")) {
00175             if (seen_name)
00176                 parse_error("duplicate name: tag");
00177             seen_name = 1;
00178             um->name = op_xstrndup(tagend, valueend - tagend);
00179         } else if (strisprefix(start, "type")) {
00180             if (seen_type)
00181                 parse_error("duplicate type: tag");
00182             seen_type = 1;
00183             if (strisprefix(tagend, "mandatory")) {
00184                 um->unit_type_mask = utm_mandatory;
00185             } else if (strisprefix(tagend, "bitmask")) {
00186                 um->unit_type_mask = utm_bitmask;
00187             } else if (strisprefix(tagend, "exclusive")) {
00188                 um->unit_type_mask = utm_exclusive;
00189             } else {
00190                 parse_error("invalid unit mask type");
00191             }
00192         } else if (strisprefix(start, "default")) {
00193             if (seen_default)
00194                 parse_error("duplicate default: tag");
00195             seen_default = 1;
00196             um->default_mask = parse_hex(tagend);
00197         } else {
00198             parse_error("invalid unit mask tag");
00199         }
00200 
00201         valueend = skip_ws(valueend);
00202         tagend = valueend;
00203         start = valueend;
00204     }
00205 
00206     if (!um->name)
00207         parse_error("Missing name for unit mask");
00208     if (!seen_type)
00209         parse_error("Missing type for unit mask");
00210 }
00211 
00212 
00213 /* \t0x08 (M)odified cache state */
00214 /* \t0x08 extra:inv,cmask=... (M)odified cache state */
00215 static void parse_um_entry(struct op_described_um * entry, char const * line)
00216 {
00217     char const * c = line;
00218 
00219     c = skip_ws(c);
00220     entry->value = parse_hex(c);
00221     c = skip_nonws(c);
00222 
00223     c = skip_ws(c);
00224     if (strisprefix(c, "extra:")) {
00225         c += 6;
00226         entry->extra = parse_extra(c);
00227         c = skip_nonws(c);
00228     } else
00229         entry->extra = 0;
00230 
00231     if (!*c)
00232         parse_error("invalid unit mask entry");
00233 
00234     c = skip_ws(c);
00235 
00236     if (!*c)
00237         parse_error("invalid unit mask entry");
00238 
00239     entry->desc = xstrdup(c);
00240 }
00241 
00242 
00243 static struct op_unit_mask * new_unit_mask(void)
00244 {
00245     struct op_unit_mask * um = xmalloc(sizeof(struct op_unit_mask));
00246     memset(um, '\0', sizeof(struct op_unit_mask));
00247     list_add_tail(&um->um_next, &um_list);
00248 
00249     return um;
00250 }
00251 
00252 static void free_unit_mask(struct op_unit_mask * um)
00253 {
00254     list_del(&um->um_next);
00255     free(um);
00256 }
00257 
00258 /*
00259  * name:zero type:mandatory default:0x0
00260  * \t0x0 No unit mask
00261  */
00262 static void read_unit_masks(char const * file)
00263 {
00264     struct op_unit_mask * um = NULL;
00265     char * line;
00266     FILE * fp = fopen(file, "r");
00267 
00268     if (!fp) {
00269         fprintf(stderr,
00270             "oprofile: could not open unit mask description file %s\n", file);
00271         exit(EXIT_FAILURE);
00272     }
00273 
00274     filename = file;
00275     line_nr = 1;
00276 
00277     line = op_get_line(fp);
00278 
00279     while (line) {
00280         if (empty_line(line) || comment_line(line))
00281             goto next;
00282 
00283         if (line[0] != '\t') {
00284             um = new_unit_mask();
00285             parse_um(um, line);
00286         } else {
00287             if (!um)
00288                 parse_error("no unit mask name line");
00289             if (um->num >= MAX_UNIT_MASK)
00290                 parse_error("oprofile: maximum unit mask entries exceeded");
00291 
00292             parse_um_entry(&um->um[um->num], line);
00293             ++(um->num);
00294         }
00295 
00296 next:
00297         free(line);
00298         line = op_get_line(fp);
00299         ++line_nr;
00300     }
00301 
00302     fclose(fp);
00303 }
00304 
00305 
00306 static u32 parse_counter_mask(char const * str)
00307 {
00308     u32 mask = 0;
00309     char const * numstart = str;
00310 
00311     while (*numstart) {
00312         mask |= 1 << parse_int(numstart);
00313 
00314         while (*numstart && *numstart != ',')
00315             ++numstart;
00316         /* skip , unless we reach eos */
00317         if (*numstart)
00318             ++numstart;
00319 
00320         numstart = skip_ws(numstart);
00321     }
00322 
00323     return mask;
00324 }
00325 
00326 static struct op_unit_mask * try_find_um(char const * value)
00327 {
00328     struct list_head * pos;
00329 
00330     list_for_each(pos, &um_list) {
00331         struct op_unit_mask * um = list_entry(pos, struct op_unit_mask, um_next);
00332         if (strcmp(value, um->name) == 0) {
00333             um->used = 1;
00334             return um;
00335         }
00336     }
00337     return NULL;
00338 }
00339 
00340 static struct op_unit_mask * find_um(char const * value)
00341 {
00342     struct op_unit_mask * um = try_find_um(value);
00343     if (um)
00344         return um;
00345     fprintf(stderr, "oprofile: could not find unit mask %s\n", value);
00346     exit(EXIT_FAILURE);
00347 }
00348 
00349 /* um:a,b,c,d merge multiple unit masks */
00350 static struct op_unit_mask * merge_um(char * value)
00351 {
00352     int num;
00353     char *s;
00354     struct op_unit_mask *new, *um;
00355     enum unit_mask_type type = -1U;
00356 
00357     um = try_find_um(value);
00358     if (um)
00359         return um;
00360 
00361     new = new_unit_mask();
00362     new->name = xstrdup(value);
00363     new->used = 1;
00364     num = 0;
00365     while ((s = strsep(&value, ",")) != NULL) {
00366         unsigned c;
00367         um = find_um(s);
00368         if (type == -1U)
00369             type = um->unit_type_mask;
00370         if (um->unit_type_mask != type)
00371             parse_error("combined unit mask must be all the same types");
00372         if (type != utm_bitmask && type != utm_exclusive)
00373             parse_error("combined unit mask must be all bitmasks or exclusive");
00374         new->default_mask |= um->default_mask;
00375         new->num += um->num;
00376         if (new->num > MAX_UNIT_MASK)
00377             parse_error("too many members in combined unit mask");
00378         for (c = 0; c < um->num; c++, num++) {
00379             new->um[num] = um->um[c];
00380             new->um[num].desc = xstrdup(new->um[num].desc);
00381         }
00382     }
00383     if (type == -1U)
00384         parse_error("Empty unit mask");
00385     new->unit_type_mask = type;
00386     return new;     
00387 }
00388 
00389 /* parse either a "tag:value" or a ": trailing description string" */
00390 static int next_token(char const ** cp, char ** name, char ** value)
00391 {
00392     size_t tag_len;
00393     size_t val_len;
00394     char const * c = *cp;
00395     char const * end;
00396     char const * colon;
00397 
00398     c = skip_ws(c);
00399     end = colon = c;
00400     end = skip_nonws(end);
00401 
00402     colon = strchr(colon, ':');
00403 
00404     if (!colon) {
00405         if (*c)
00406             parse_error("next_token(): garbage at end of line");
00407         return 0;
00408     }
00409 
00410     if (colon >= end)
00411         parse_error("next_token() expected ':'");
00412 
00413     tag_len = colon - c;
00414     val_len = end - (colon + 1);
00415 
00416     if (!tag_len) {
00417         /* : trailing description */
00418         end = skip_ws(end);
00419         *name = xstrdup("desc");
00420         *value = xstrdup(end);
00421         end += strlen(end);
00422     } else {
00423         /* tag:value */
00424         *name = op_xstrndup(c, tag_len);
00425         *value = op_xstrndup(colon + 1, val_len);
00426         end = skip_ws(end);
00427     }
00428 
00429     *cp = end;
00430     return 1;
00431 }
00432 
00433 static void include_events (char *value)
00434 {
00435     char * event_file;
00436     const char *old_filename;
00437     int old_line_nr;
00438 
00439     event_file = build_fn(value, "events");
00440     old_line_nr = line_nr;
00441     old_filename = filename;
00442     read_events(event_file);
00443     line_nr = old_line_nr;
00444     filename = old_filename;
00445     free(event_file);
00446 }
00447 
00448 static struct op_event * new_event(void)
00449 {
00450     struct op_event * event = xmalloc(sizeof(struct op_event));
00451     memset(event, '\0', sizeof(struct op_event));
00452     list_add_tail(&event->event_next, &events_list);
00453 
00454     return event;
00455 }
00456 
00457 static void free_event(struct op_event * event)
00458 {
00459     list_del(&event->event_next);
00460     free(event);
00461 }
00462 
00463 /* event:0x00 counters:0 um:zero minimum:4096 name:ISSUES : Total issues */
00464 /* event:0x00 ext:xxxxxx um:zero minimum:4096 name:ISSUES : Total issues */
00465 static void read_events(char const * file)
00466 {
00467     struct op_event * event = NULL;
00468     char * line;
00469     char * name;
00470     char * value;
00471     char const * c;
00472     int seen_event, seen_counters, seen_um, seen_minimum, seen_name, seen_ext;
00473     FILE * fp = fopen(file, "r");
00474     int tags;
00475 
00476     if (!fp) {
00477         fprintf(stderr, "oprofile: could not open event description file %s\n", file);
00478         exit(EXIT_FAILURE);
00479     }
00480 
00481     filename = file;
00482     line_nr = 1;
00483 
00484     line = op_get_line(fp);
00485 
00486     while (line) {
00487         if (empty_line(line) || comment_line(line))
00488             goto next;
00489 
00490         tags = 0;
00491         seen_name = 0;
00492         seen_event = 0;
00493         seen_counters = 0;
00494         seen_ext = 0;
00495         seen_um = 0;
00496         seen_minimum = 0;
00497         event = new_event();
00498         event->filter = -1;
00499         event->ext = NULL;
00500         
00501         c = line;
00502         while (next_token(&c, &name, &value)) {
00503             if (strcmp(name, "name") == 0) {
00504                 if (seen_name)
00505                     parse_error("duplicate name: tag");
00506                 seen_name = 1;
00507                 if (strchr(value, '/') != NULL)
00508                     parse_error("invalid event name");
00509                 if (strchr(value, '.') != NULL)
00510                     parse_error("invalid event name");
00511                 event->name = value;
00512             } else if (strcmp(name, "event") == 0) {
00513                 if (seen_event)
00514                     parse_error("duplicate event: tag");
00515                 seen_event = 1;
00516                 event->val = parse_hex(value);
00517                 free(value);
00518             } else if (strcmp(name, "counters") == 0) {
00519                 if (seen_counters)
00520                     parse_error("duplicate counters: tag");
00521                 seen_counters = 1;
00522                 if (!strcmp(value, "cpuid"))
00523                     event->counter_mask = arch_get_counter_mask();
00524                 else
00525                     event->counter_mask = parse_counter_mask(value);
00526                 free(value);
00527             } else if (strcmp(name, "ext") == 0) {
00528                 if (seen_ext)
00529                     parse_error("duplicate ext: tag");
00530                 seen_ext = 1;
00531                 event->ext = value;
00532             } else if (strcmp(name, "um") == 0) {
00533                 if (seen_um)
00534                     parse_error("duplicate um: tag");
00535                 seen_um = 1;
00536                 if (strchr(value, ','))
00537                     event->unit = merge_um(value);
00538                 else
00539                     event->unit = find_um(value);
00540                 free(value);
00541             } else if (strcmp(name, "minimum") == 0) {
00542                 if (seen_minimum)
00543                     parse_error("duplicate minimum: tag");
00544                 seen_minimum = 1;
00545                 event->min_count = parse_int(value);
00546                 free(value);
00547             } else if (strcmp(name, "desc") == 0) {
00548                 event->desc = value;
00549             } else if (strcmp(name, "filter") == 0) {
00550                 event->filter = parse_int(value);
00551                 free(value);
00552             } else if (strcmp(name, "include") == 0) {
00553                 if (tags > 0)
00554                     parse_error("tags before include:");
00555                 free_event(event);
00556                 include_events(value);
00557                 free(value);
00558                 c = skip_ws(c);
00559                 if (*c != '\0' && *c != '#')
00560                     parse_error("non whitespace after include:");
00561             } else {
00562                 parse_error("unknown tag");
00563             }
00564             tags++;
00565 
00566             free(name);
00567         }
00568 next:
00569         free(line);
00570         line = op_get_line(fp);
00571         ++line_nr;
00572     }
00573 
00574     fclose(fp);
00575 }
00576 
00577 
00578 /* usefull for make check */
00579 static int check_unit_mask(struct op_unit_mask const * um,
00580     char const * cpu_name)
00581 {
00582     u32 i;
00583     int err = 0;
00584 
00585     if (!um->used) {
00586         fprintf(stderr, "um %s is not used\n", um->name);
00587         err = EXIT_FAILURE;
00588     }
00589 
00590     if (um->unit_type_mask == utm_mandatory && um->num != 1) {
00591         fprintf(stderr, "mandatory um %s doesn't contain exactly one "
00592             "entry (%s)\n", um->name, cpu_name);
00593         err = EXIT_FAILURE;
00594     } else if (um->unit_type_mask == utm_bitmask) {
00595         u32 default_mask = um->default_mask;
00596         for (i = 0; i < um->num; ++i)
00597             default_mask &= ~um->um[i].value;
00598 
00599         if (default_mask) {
00600             fprintf(stderr, "um %s default mask is not valid "
00601                 "(%s)\n", um->name, cpu_name);
00602             err = EXIT_FAILURE;
00603         }
00604     } else {
00605         for (i = 0; i < um->num; ++i) {
00606             if (um->default_mask == um->um[i].value)
00607                 break;
00608         }
00609 
00610         if (i == um->num) {
00611             fprintf(stderr, "exclusive um %s default value is not "
00612                 "valid (%s)\n", um->name, cpu_name);
00613             err = EXIT_FAILURE;
00614         }
00615     }
00616     return err;
00617 }
00618 
00619 static void arch_filter_events(op_cpu cpu_type)
00620 {
00621     struct list_head * pos, * pos2;
00622     unsigned filter = arch_get_filter(cpu_type);
00623     if (!filter)
00624         return;
00625     list_for_each_safe (pos, pos2, &events_list) {
00626         struct op_event * event = list_entry(pos, struct op_event, event_next);
00627         if (event->filter >= 0 && ((1U << event->filter) & filter))
00628             delete_event(event);
00629     }
00630 }
00631 
00632 static void load_events_name(const char *cpu_name)
00633 {
00634     char * event_file;
00635     char * um_file;
00636 
00637     event_file = build_fn(cpu_name, "events");
00638     um_file = build_fn(cpu_name, "unit_masks");
00639 
00640     read_unit_masks(um_file);
00641     read_events(event_file);
00642     
00643     free(um_file);
00644     free(event_file);
00645 }
00646 
00647 static void load_events(op_cpu cpu_type)
00648 {
00649     const char * cpu_name = op_get_cpu_name(cpu_type);
00650     struct list_head * pos;
00651     struct op_event *event;
00652     struct op_unit_mask *unit_mask;
00653     int err = 0;
00654 
00655     if (!list_empty(&events_list))
00656         return;
00657 
00658     load_events_name(cpu_name);
00659 
00660     arch_filter_events(cpu_type);
00661 
00662     /* sanity check: all unit mask must be used */
00663     list_for_each(pos, &um_list) {
00664         struct op_unit_mask * um = list_entry(pos, struct op_unit_mask, um_next);
00665         err |= check_unit_mask(um, cpu_name);
00666     }
00667     if (err)
00668         exit(err);
00669 
00670     if (!op_cpu_has_timer_fs())
00671         return;
00672 
00673     /* sanity check: Don't use event `TIMER' since it is predefined.  */
00674     list_for_each(pos, &events_list) {
00675         struct op_event * event = list_entry(pos, struct op_event,
00676                              event_next);
00677 
00678         if (strcmp(event->name, TIMER_EVENT_NAME) == 0) {
00679             fprintf(stderr, "Error: " TIMER_EVENT_NAME
00680                 " event cannot be redefined.\n");
00681             exit(EXIT_FAILURE);
00682         }
00683         if (event->val == TIMER_EVENT_VALUE) {
00684             fprintf(stderr, "Error: Event %s uses " TIMER_EVENT_NAME
00685                 " which is reserverd for timer based sampling.\n",
00686                 event->name);
00687             exit(EXIT_FAILURE);
00688         }
00689     }
00690 
00691     list_for_each(pos, &um_list) {
00692         struct op_unit_mask * um = list_entry(pos, struct op_unit_mask,
00693                               um_next);
00694         if (strcmp(um->name, TIMER_EVENT_UNIT_MASK_NAME) == 0) {
00695             fprintf(stderr, "Error: " TIMER_EVENT_UNIT_MASK_NAME
00696                 " unit mask cannot be redefined.\n");
00697             exit(EXIT_FAILURE);
00698         }
00699     }
00700 
00701     unit_mask = new_unit_mask();
00702     unit_mask->name = xstrdup(TIMER_EVENT_UNIT_MASK_NAME);
00703     unit_mask->num = 1;
00704     unit_mask->unit_type_mask = utm_mandatory;
00705     unit_mask->um[0].extra = 0;
00706     unit_mask->um[0].value = 0;
00707     unit_mask->um[0].desc = xstrdup("No unit mask");
00708     unit_mask->used = 1;
00709 
00710     event = new_event();
00711     event->name = xstrdup(TIMER_EVENT_NAME);
00712     event->desc = xstrdup(TIMER_EVENT_DESC);
00713     event->val = TIMER_EVENT_VALUE;
00714     event->unit = unit_mask;
00715     event->min_count = 0;
00716     event->filter = 0;
00717     event->counter_mask = 1 << (op_get_nr_counters(cpu_type) - 1);
00718     event->ext = NULL;
00719     event->filter = -1;
00720 }
00721 
00722 struct list_head * op_events(op_cpu cpu_type)
00723 {
00724     load_events(cpu_type);
00725     arch_filter_events(cpu_type);
00726     return &events_list;
00727 }
00728 
00729 
00730 static void delete_unit_mask(struct op_unit_mask * unit)
00731 {
00732     u32 cur;
00733     for (cur = 0 ; cur < unit->num ; ++cur) {
00734         if (unit->um[cur].desc)
00735             free(unit->um[cur].desc);
00736     }
00737 
00738     if (unit->name)
00739         free(unit->name);
00740 
00741     list_del(&unit->um_next);
00742     free(unit);
00743 }
00744 
00745 
00746 static void delete_event(struct op_event * event)
00747 {
00748     if (event->name)
00749         free(event->name);
00750     if (event->desc)
00751         free(event->desc);
00752 
00753     list_del(&event->event_next);
00754     free(event);
00755 }
00756 
00757 
00758 void op_free_events(void)
00759 {
00760     struct list_head * pos, * pos2;
00761     list_for_each_safe(pos, pos2, &events_list) {
00762         struct op_event * event = list_entry(pos, struct op_event, event_next);
00763         delete_event(event);
00764     }
00765 
00766     list_for_each_safe(pos, pos2, &um_list) {
00767         struct op_unit_mask * unit = list_entry(pos, struct op_unit_mask, um_next);
00768         delete_unit_mask(unit);
00769     }
00770 }
00771 
00772 /* There can be actually multiple events here, so this is not quite correct */
00773 static struct op_event * find_event_any(u32 nr)
00774 {
00775     struct list_head * pos;
00776 
00777     list_for_each(pos, &events_list) {
00778         struct op_event * event = list_entry(pos, struct op_event, event_next);
00779         if (event->val == nr)
00780             return event;
00781     }
00782 
00783     return NULL;
00784 }
00785 
00786 static struct op_event * find_event_um(u32 nr, u32 um)
00787 {
00788     struct list_head * pos;
00789     unsigned int i;
00790 
00791     list_for_each(pos, &events_list) {
00792         struct op_event * event = list_entry(pos, struct op_event, event_next);
00793         if (event->val == nr) {
00794             for (i = 0; i < event->unit->num; i++) {
00795                 if (event->unit->um[i].value == um)
00796                     return event;
00797             }
00798         }
00799     }
00800 
00801     return NULL;
00802 }
00803 
00804 static FILE * open_event_mapping_file(char const * cpu_name)
00805 {
00806     char * ev_map_file;
00807     char * dir;
00808     dir = getenv("OPROFILE_EVENTS_DIR");
00809     if (dir == NULL)
00810         dir = OP_DATADIR;
00811 
00812     ev_map_file = xmalloc(strlen(dir) + strlen("/") + strlen(cpu_name) +
00813                         strlen("/") + + strlen("event_mappings") + 1);
00814     strcpy(ev_map_file, dir);
00815     strcat(ev_map_file, "/");
00816 
00817     strcat(ev_map_file, cpu_name);
00818     strcat(ev_map_file, "/");
00819     strcat(ev_map_file, "event_mappings");
00820     filename = ev_map_file;
00821     return (fopen(ev_map_file, "r"));
00822 }
00823 
00824 
00828 static char const * get_mapping(u32 nr, FILE * fp)
00829 {
00830     char * line;
00831     char * name;
00832     char * value;
00833     char const * c;
00834     char * map = NULL;
00835     int seen_event = 0, seen_mmcr0 = 0, seen_mmcr1 = 0, seen_mmcra = 0;
00836     u32 mmcr0 = 0;
00837     u64 mmcr1 = 0;
00838     u32 mmcra = 0;
00839     int event_found = 0;
00840 
00841     line_nr = 1;
00842     line = op_get_line(fp);
00843     while (line && !event_found) {
00844         if (empty_line(line) || comment_line(line))
00845             goto next;
00846 
00847         seen_event = 0;
00848         seen_mmcr0 = 0;
00849         seen_mmcr1 = 0;
00850         seen_mmcra = 0;
00851         mmcr0 = 0;
00852         mmcr1 = 0;
00853         mmcra = 0;
00854 
00855         c = line;
00856         while (next_token(&c, &name, &value)) {
00857             if (strcmp(name, "event") == 0) {
00858                 u32 evt;
00859                 if (seen_event)
00860                     parse_error("duplicate event tag");
00861                 seen_event = 1;
00862                 evt = parse_hex(value);
00863                 if (evt == nr)
00864                     event_found = 1;
00865                 free(value);
00866             } else if (strcmp(name, "mmcr0") == 0) {
00867                 if (seen_mmcr0)
00868                     parse_error("duplicate mmcr0 tag");
00869                 seen_mmcr0 = 1;
00870                 mmcr0 = parse_hex(value);
00871                 free(value);
00872             } else if (strcmp(name, "mmcr1") == 0) {
00873                 if (seen_mmcr1)
00874                     parse_error("duplicate mmcr1: tag");
00875                 seen_mmcr1 = 1;
00876                 mmcr1 = parse_long_hex(value);
00877                 free(value);
00878             } else if (strcmp(name, "mmcra") == 0) {
00879                 if (seen_mmcra)
00880                     parse_error("duplicate mmcra: tag");
00881                 seen_mmcra = 1;
00882                 mmcra = parse_hex(value);
00883                 free(value);
00884             } else {
00885                 parse_error("unknown tag");
00886             }
00887 
00888             free(name);
00889         }
00890 next:
00891         free(line);
00892         line = op_get_line(fp);
00893         ++line_nr;
00894     }
00895     if (event_found) {
00896         if (!seen_mmcr0 || !seen_mmcr1 || !seen_mmcra) {
00897             fprintf(stderr, "Error: Missing information in line %d of event mapping file %s\n", line_nr, filename);
00898             exit(EXIT_FAILURE);
00899         }
00900         map = xmalloc(70);
00901         snprintf(map, 70, "mmcr0:%u mmcr1:%Lu mmcra:%u",
00902                  mmcr0, mmcr1, mmcra);
00903     }
00904 
00905     return map;
00906 }
00907 
00908 
00909 char const * find_mapping_for_event(u32 nr, op_cpu cpu_type)
00910 {
00911     char const * cpu_name = op_get_cpu_name(cpu_type);
00912     FILE * fp = open_event_mapping_file(cpu_name);
00913     char const * map = NULL;
00914     switch (cpu_type) {
00915         case CPU_PPC64_PA6T:
00916         case CPU_PPC64_970:
00917         case CPU_PPC64_970MP:
00918         case CPU_PPC64_POWER4:
00919         case CPU_PPC64_POWER5:
00920         case CPU_PPC64_POWER5p:
00921         case CPU_PPC64_POWER5pp:
00922         case CPU_PPC64_POWER6:
00923         case CPU_PPC64_POWER7:
00924         case CPU_PPC64_IBM_COMPAT_V1:
00925             if (!fp) {
00926                 fprintf(stderr, "oprofile: could not open event mapping file %s\n", filename);
00927                 exit(EXIT_FAILURE);
00928             } else {
00929                 map = get_mapping(nr, fp);
00930             }
00931             break;          
00932         default:
00933             break;
00934     }
00935 
00936     if (fp)
00937         fclose(fp);
00938 
00939     return map;
00940 }
00941 
00942 static int match_event(int i, struct op_event *event, unsigned um)
00943 {
00944     unsigned v = event->unit->um[i].value;
00945 
00946     switch (event->unit->unit_type_mask) {
00947     case utm_exclusive:
00948     case utm_mandatory:
00949         return v == um;
00950 
00951     case utm_bitmask:
00952         return (v & um) || (!v && v == 0);
00953     }
00954 
00955     abort();
00956 }
00957 
00958 struct op_event * find_event_by_name(char const * name, unsigned um, int um_valid)
00959 {
00960     struct list_head * pos;
00961 
00962     list_for_each(pos, &events_list) {
00963         struct op_event * event = list_entry(pos, struct op_event, event_next);
00964         if (strcmp(event->name, name) == 0) {
00965             if (um_valid) {
00966                 unsigned i;
00967 
00968                 for (i = 0; i < event->unit->num; i++)
00969                     if (match_event(i, event, um))
00970                         return event;
00971                 continue;
00972             }
00973             return event;
00974         }
00975     }
00976 
00977     return NULL;
00978 }
00979 
00980 
00981 static struct op_event * find_next_event(struct op_event * e)
00982 {
00983     struct list_head * n;
00984 
00985     for (n = e->event_next.next; n != &events_list; n = n->next) {
00986         struct op_event * ne = list_entry(n, struct op_event, event_next);
00987         if (!strcmp(e->name, ne->name))
00988             return ne;
00989     }
00990     return NULL;
00991 }
00992 
00993 struct op_event * op_find_event(op_cpu cpu_type, u32 nr, u32 um)
00994 {
00995     struct op_event * event;
00996 
00997     load_events(cpu_type);
00998 
00999     event = find_event_um(nr, um);
01000 
01001     return event;
01002 }
01003 
01004 struct op_event * op_find_event_any(op_cpu cpu_type, u32 nr)
01005 {
01006     load_events(cpu_type);
01007 
01008     return find_event_any(nr);
01009 }
01010 
01011 int op_check_events(int ctr, u32 nr, u32 um, op_cpu cpu_type)
01012 {
01013     int ret = OP_INVALID_EVENT;
01014     size_t i;
01015     u32 ctr_mask = 1 << ctr;
01016     struct list_head * pos;
01017 
01018     load_events(cpu_type);
01019 
01020     list_for_each(pos, &events_list) {
01021         struct op_event * event = list_entry(pos, struct op_event, event_next);
01022         if (event->val != nr)
01023             continue;
01024 
01025         ret = OP_OK_EVENT;
01026 
01027         if ((event->counter_mask & ctr_mask) == 0)
01028             ret |= OP_INVALID_COUNTER;
01029 
01030         if (event->unit->unit_type_mask == utm_bitmask) {
01031             for (i = 0; i < event->unit->num; ++i)
01032                 um &= ~(event->unit->um[i].value);          
01033             
01034             if (um)
01035                 ret |= OP_INVALID_UM;
01036             
01037         } else {
01038             for (i = 0; i < event->unit->num; ++i) {
01039                 if (event->unit->um[i].value == um)
01040                     break;
01041             }
01042             
01043             if (i == event->unit->num)
01044                 ret |= OP_INVALID_UM;
01045 
01046         }
01047 
01048         if (ret == OP_OK_EVENT)
01049             return ret;
01050     }
01051 
01052     return ret;
01053 }
01054 
01055 
01056 void op_default_event(op_cpu cpu_type, struct op_default_event_descr * descr)
01057 {
01058     descr->name = "";
01059     descr->um = 0x0;
01060     /* A fixed value of CPU cycles; this should ensure good
01061      * granulity even on faster CPUs, though it will generate more
01062      * interrupts.
01063      */
01064     descr->count = 100000;
01065 
01066     switch (cpu_type) {
01067         case CPU_PPRO:
01068         case CPU_PII:
01069         case CPU_PIII:
01070         case CPU_P6_MOBILE:
01071         case CPU_CORE:
01072         case CPU_CORE_2:
01073         case CPU_ATHLON:
01074         case CPU_HAMMER:
01075         case CPU_FAMILY10:
01076         case CPU_ARCH_PERFMON:
01077         case CPU_FAMILY11H:
01078         case CPU_ATOM:
01079         case CPU_CORE_I7:
01080         case CPU_NEHALEM:
01081         case CPU_WESTMERE:
01082         case CPU_SANDYBRIDGE:
01083         case CPU_IVYBRIDGE:
01084         case CPU_MIPS_LOONGSON2:
01085         case CPU_FAMILY12H:
01086         case CPU_FAMILY14H:
01087         case CPU_FAMILY15H:
01088             descr->name = "CPU_CLK_UNHALTED";
01089             break;
01090 
01091         case CPU_RTC:
01092             descr->name = "RTC_INTERRUPTS";
01093             descr->count = 1024;
01094             break;
01095 
01096         case CPU_P4:
01097         case CPU_P4_HT2:
01098             descr->name = "GLOBAL_POWER_EVENTS";
01099             descr->um = 0x1;
01100             break;
01101 
01102         case CPU_IA64:
01103         case CPU_IA64_1:
01104         case CPU_IA64_2:
01105             descr->count = 1000000;
01106             descr->name = "CPU_CYCLES";
01107             break;
01108 
01109         case CPU_AXP_EV4:
01110         case CPU_AXP_EV5:
01111         case CPU_AXP_PCA56:
01112         case CPU_AXP_EV6:
01113         case CPU_AXP_EV67:
01114             descr->name = "CYCLES";
01115             break;
01116 
01117         // we could possibly use the CCNT
01118         case CPU_ARM_XSCALE1:
01119         case CPU_ARM_XSCALE2:
01120         case CPU_ARM_MPCORE:
01121         case CPU_ARM_V6:
01122         case CPU_ARM_V7:
01123         case CPU_ARM_V7_CA5:
01124         case CPU_ARM_V7_CA7:
01125         case CPU_ARM_V7_CA9:
01126         case CPU_ARM_V7_CA15:
01127         case CPU_AVR32:
01128         case CPU_ARM_SCORPION:
01129         case CPU_ARM_SCORPIONMP:
01130             descr->name = "CPU_CYCLES";
01131             break;
01132 
01133         case CPU_PPC64_PA6T:
01134         case CPU_PPC64_970:
01135         case CPU_PPC64_970MP:
01136         case CPU_PPC_7450:
01137         case CPU_PPC64_POWER4:
01138         case CPU_PPC64_POWER5:
01139         case CPU_PPC64_POWER6:
01140         case CPU_PPC64_POWER5p:
01141         case CPU_PPC64_POWER5pp:
01142         case CPU_PPC64_CELL:
01143         case CPU_PPC64_POWER7:
01144         case CPU_PPC64_IBM_COMPAT_V1:
01145             descr->name = "CYCLES";
01146             break;
01147 
01148         case CPU_MIPS_20K:
01149             descr->name = "CYCLES";
01150             break;
01151 
01152         case CPU_MIPS_24K:
01153         case CPU_MIPS_34K:
01154         case CPU_MIPS_74K:
01155         case CPU_MIPS_1004K:
01156             descr->name = "INSTRUCTIONS";
01157             break;
01158 
01159         case CPU_MIPS_5K:
01160         case CPU_MIPS_25K:
01161             descr->name = "CYCLES";
01162             break;
01163 
01164         case CPU_MIPS_R10000:
01165         case CPU_MIPS_R12000:
01166             descr->name = "INSTRUCTIONS_GRADUATED";
01167             break;
01168 
01169         case CPU_MIPS_RM7000:
01170         case CPU_MIPS_RM9000:
01171             descr->name = "INSTRUCTIONS_ISSUED";
01172             break;
01173 
01174         case CPU_MIPS_SB1:
01175             descr->name = "INSN_SURVIVED_STAGE7";
01176             break;
01177 
01178         case CPU_MIPS_VR5432:
01179         case CPU_MIPS_VR5500:
01180             descr->name = "INSTRUCTIONS_EXECUTED";
01181             break;
01182 
01183         case CPU_PPC_E500:
01184         case CPU_PPC_E500_2:
01185         case CPU_PPC_E300:
01186             descr->name = "CPU_CLK";
01187             break;
01188             case CPU_S390_Z10:
01189             case CPU_S390_Z196:
01190             if (op_get_nr_counters(cpu_type) > 1) {
01191                 descr->name = "HWSAMPLING";
01192                 descr->count = 4127518;
01193             } else {
01194                 descr->name = TIMER_EVENT_NAME;
01195                 descr->count = 10000;
01196             }
01197             break;
01198 
01199         case CPU_TILE_TILE64:
01200         case CPU_TILE_TILEPRO:
01201         case CPU_TILE_TILEGX:
01202             descr->name = "ONE";
01203             break;
01204 
01205         // don't use default, if someone add a cpu he wants a compiler
01206         // warning if he forgets to handle it here.
01207         case CPU_TIMER_INT:
01208         case CPU_NO_GOOD:
01209         case MAX_CPU_TYPE:
01210             break;
01211     }
01212 }
01213 
01214 static void extra_check(struct op_event *e, u32 unit_mask)
01215 {
01216     unsigned i;
01217     int found = 0;
01218 
01219     for (i = 0; i < e->unit->num; i++)
01220         if (e->unit->um[i].value == unit_mask)
01221             found++;
01222     if (found > 1) {
01223         fprintf(stderr,
01224 "Named unit masks not allowed for events without 'extra:' values.\n"
01225 "Please specify the numerical value for the unit mask. See 'opcontrol'"
01226 " man page for more info.\n");
01227         exit(EXIT_FAILURE);
01228     }
01229 }
01230 
01231 static void another_extra_check(struct op_event *e, char *name, unsigned w)
01232 {
01233     int found;
01234     unsigned i;
01235 
01236     if (!e->unit->um[w].extra) {
01237         fprintf(stderr,
01238 "Named unit mask (%s) not allowed for event without 'extra:' values.\n"
01239 "Please specify the numerical value for the unit mask. See 'opcontrol'"
01240 " man page for more info.\n", name);
01241         exit(EXIT_FAILURE);
01242     }
01243 
01244     found = 0;
01245     for (i = 0; i < e->unit->num; i++) {
01246         int len = strcspn(e->unit->um[i].desc, " \t");
01247         if (!strncmp(name, e->unit->um[i].desc, len) &&
01248             name[len] == '\0')
01249             found++;
01250     }
01251     if (found > 1) {
01252         fprintf(stderr,
01253     "Unit mask name `%s' not unique. Sorry please use a numerical unit mask\n", name);
01254         exit(EXIT_FAILURE);
01255     }
01256 }
01257 
01258 static void do_resolve_unit_mask(struct op_event *e, struct parsed_event *pe,
01259                  u32 *extra)
01260 {
01261     unsigned i;
01262     int found;
01263 
01264     for (;;) {
01265         if (pe->unit_mask_name == NULL) {
01266             int had_unit_mask = pe->unit_mask_valid;
01267 
01268             found = 0;
01269             for (i = 0; i < e->unit->num; i++) {
01270                 if (!pe->unit_mask_valid &&
01271                 e->unit->um[i].value == e->unit->default_mask) {
01272                     pe->unit_mask_valid = 1;
01273                     pe->unit_mask = e->unit->default_mask;
01274                     break;
01275                 }
01276             }
01277             if (found > 1 && had_unit_mask) {
01278                 fprintf(stderr,
01279     "Non unique numerical unit mask.\n"
01280     "Please specify the unit mask using the first word of the description\n");
01281                 exit(EXIT_FAILURE);
01282             }
01283             extra_check(e, pe->unit_mask);
01284             if (i == e->unit->num) {
01285                 e = find_next_event(e);
01286                 if (e != NULL)
01287                     continue;
01288             } else {
01289                 if (extra)
01290                     *extra = e->unit->um[i].extra;
01291             }
01292             return;
01293         }
01294         for (i = 0; i < e->unit->num; i++) {
01295             int len = strcspn(e->unit->um[i].desc, " \t");
01296             if (!strncmp(pe->unit_mask_name, e->unit->um[i].desc,
01297                     len) && pe->unit_mask_name[len] == '\0')
01298                 break;
01299         }
01300         if (i == e->unit->num) {
01301             e = find_next_event(e);
01302             if (e != NULL)
01303                 continue;
01304             fprintf(stderr, "Cannot find unit mask %s for %s\n",
01305                 pe->unit_mask_name, pe->name);
01306             exit(EXIT_FAILURE);
01307         }
01308         another_extra_check(e, pe->unit_mask_name, i);
01309         pe->unit_mask_valid = 1;
01310         pe->unit_mask = e->unit->um[i].value;
01311         if (extra)
01312             *extra = e->unit->um[i].extra;
01313         return;
01314     }
01315 }
01316 
01317 void op_resolve_unit_mask(struct parsed_event *pe, u32 *extra)
01318 {
01319     struct op_event *e;
01320 
01321     e = find_event_by_name(pe->name, 0, 0);
01322     if (!e) {
01323         fprintf(stderr, "Cannot find event %s\n", pe->name);
01324         exit(EXIT_FAILURE);
01325     }
01326     return do_resolve_unit_mask(e, pe, extra);
01327 }

Generated on 8 Nov 2012 for Oprofile by  doxygen 1.6.1