| #include "cpumap.h" |
| #include "evsel.h" |
| #include "evlist.h" |
| #include "ras.h" |
| #include "debugfs.h" |
| |
| #include <regex.h> |
| |
| #define EVENT_STR_MAX_LENGTH 1024 |
| #define SYS_NAME_SEPARATOR ":" |
| #define RASD_CFG_FILE "rasd.cfg" |
| |
| unsigned int page_size; |
| struct perf_evlist *evlist; |
| struct perf_rasd rasd; |
| |
| /* Check if the read line is a valid config file line.*/ |
| static bool cfg_valid_line(char *str) |
| { |
| regex_t reg; |
| int ret; |
| |
| ret = regcomp(®, "^[:space:]*[a-z]+:[a-z_]+[:space:]*$", |
| REG_EXTENDED | |
| REG_NEWLINE); /* for matching $ */ |
| if (ret) |
| err("compiling cfg regex"); |
| |
| ret = regexec(®, str, 0, NULL, 0); |
| if (ret) { |
| if (ret != REG_NOMATCH) |
| printf("error matching %s\n", str); |
| return false; |
| } |
| return true; |
| } |
| |
| /* |
| * Extract the event subsystem and event names from the command |
| * line argument. The syntax is 'sys:name'. |
| */ |
| static int extract_sys_name(char **str, char **sys, char **name) |
| { |
| /* Look for the sys:name separator */ |
| char *sys_ptr = strsep(str, SYS_NAME_SEPARATOR); |
| |
| if (!*str || !sys_ptr) |
| return -1; |
| |
| /* Is there something after the separator? */ |
| if (!strlen(*str)) |
| return -1; |
| |
| /* Alloc and fill the sys part */ |
| *sys = strndup(sys_ptr, EVENT_STR_MAX_LENGTH); |
| |
| /* |
| * Look for the newline in the rest of the string. |
| * If found alloc and fill the name part. |
| */ |
| *name = strndup(strsep(str, "\n\r"), EVENT_STR_MAX_LENGTH); |
| |
| return 0; |
| } |
| |
| /* Add the requested tracepoint event to evlist */ |
| static int add_tp_event(char *event_str) |
| { |
| struct perf_evsel *tp; |
| char **str = &event_str; |
| int ret; |
| |
| if (extract_sys_name(str, &rasd.sys, &rasd.name)) |
| err("invalid event specified, syntax is sys:name"); |
| |
| /* Initialize tracepoint evsel */ |
| tp = perf_evsel__newtp_idx(rasd.sys, rasd.name, 0); |
| if (!tp) |
| err("init tracepoint evsel"); |
| |
| /* Add the event to the lists of events */ |
| list_add_tail(&tp->node, &evlist->entries); |
| |
| return ret; |
| } |
| |
| /* |
| * Read the config file for events to enable |
| */ |
| static int read_config_file(void) |
| { |
| FILE *file; |
| char *event_str; |
| int ret = 0; |
| |
| file = fopen(RASD_CFG_FILE, "r"); |
| if (!file) |
| return -ENODEV; |
| |
| event_str = malloc(EVENT_STR_MAX_LENGTH); |
| if (!event_str) |
| return -ENOMEM; |
| |
| /* Read config file, line by line */ |
| while (fgets(event_str, EVENT_STR_MAX_LENGTH, file)) |
| if (cfg_valid_line(event_str)) |
| add_tp_event(event_str); |
| |
| if (ferror(file)) |
| ret = -EINVAL; |
| |
| free(event_str); |
| fclose(file); |
| |
| return ret; |
| } |
| |
| int main() |
| { |
| struct perf_evsel *c; |
| |
| page_size = sysconf(_SC_PAGE_SIZE); |
| |
| /* |
| * Mount debugfs. The basepath is in debugfs_mountpoint |
| */ |
| if (!debugfs_mount(NULL)) |
| err("mounting debugfs"); |
| |
| /* Initialize evlist */ |
| evlist = perf_evlist__new(); |
| if (!evlist) |
| err("allocating evlist"); |
| |
| /* Read config file */ |
| if (read_config_file()) |
| err("error reading config file"); |
| |
| evlist__for_each(evlist, c) { |
| /* |
| * On all online cpus by default. |
| */ |
| if (perf_evsel__open(c, cpu_map__new(NULL), NULL) < 0) |
| err("opening tracepoint, are you root?"); |
| } |
| |
| if (perf_evlist__mmap(evlist, 4 /* opts->mmap_pages */, false) < 0) |
| err("Failed to mmap with %d (%s)\n", errno, strerror(errno)); |
| |
| /* mmap it and all that, consume it */ |
| |
| perf_evlist__delete(evlist); |
| |
| free(rasd.name); |
| free(rasd.sys); |
| |
| return 0; |
| } |