forked from Qortal/Brooklyn
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
3.2 KiB
173 lines
3.2 KiB
// SPDX-License-Identifier: GPL-2.0 |
|
#include <string.h> |
|
#include <stdio.h> |
|
#include <sys/types.h> |
|
#include <dirent.h> |
|
#include <fcntl.h> |
|
#include <linux/stddef.h> |
|
#include <linux/perf_event.h> |
|
#include <linux/zalloc.h> |
|
#include <api/fs/fs.h> |
|
#include <errno.h> |
|
|
|
#include "../../../util/intel-pt.h" |
|
#include "../../../util/intel-bts.h" |
|
#include "../../../util/pmu.h" |
|
#include "../../../util/fncache.h" |
|
|
|
#define TEMPLATE_ALIAS "%s/bus/event_source/devices/%s/alias" |
|
|
|
struct pmu_alias { |
|
char *name; |
|
char *alias; |
|
struct list_head list; |
|
}; |
|
|
|
static LIST_HEAD(pmu_alias_name_list); |
|
static bool cached_list; |
|
|
|
struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused) |
|
{ |
|
#ifdef HAVE_AUXTRACE_SUPPORT |
|
if (!strcmp(pmu->name, INTEL_PT_PMU_NAME)) |
|
return intel_pt_pmu_default_config(pmu); |
|
if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME)) |
|
pmu->selectable = true; |
|
#endif |
|
return NULL; |
|
} |
|
|
|
static void pmu_alias__delete(struct pmu_alias *pmu_alias) |
|
{ |
|
if (!pmu_alias) |
|
return; |
|
|
|
zfree(&pmu_alias->name); |
|
zfree(&pmu_alias->alias); |
|
free(pmu_alias); |
|
} |
|
|
|
static struct pmu_alias *pmu_alias__new(char *name, char *alias) |
|
{ |
|
struct pmu_alias *pmu_alias = zalloc(sizeof(*pmu_alias)); |
|
|
|
if (pmu_alias) { |
|
pmu_alias->name = strdup(name); |
|
if (!pmu_alias->name) |
|
goto out_delete; |
|
|
|
pmu_alias->alias = strdup(alias); |
|
if (!pmu_alias->alias) |
|
goto out_delete; |
|
} |
|
return pmu_alias; |
|
|
|
out_delete: |
|
pmu_alias__delete(pmu_alias); |
|
return NULL; |
|
} |
|
|
|
static int setup_pmu_alias_list(void) |
|
{ |
|
char path[PATH_MAX]; |
|
DIR *dir; |
|
struct dirent *dent; |
|
const char *sysfs = sysfs__mountpoint(); |
|
struct pmu_alias *pmu_alias; |
|
char buf[MAX_PMU_NAME_LEN]; |
|
FILE *file; |
|
int ret = -ENOMEM; |
|
|
|
if (!sysfs) |
|
return -1; |
|
|
|
snprintf(path, PATH_MAX, |
|
"%s" EVENT_SOURCE_DEVICE_PATH, sysfs); |
|
|
|
dir = opendir(path); |
|
if (!dir) |
|
return -errno; |
|
|
|
while ((dent = readdir(dir))) { |
|
if (!strcmp(dent->d_name, ".") || |
|
!strcmp(dent->d_name, "..")) |
|
continue; |
|
|
|
snprintf(path, PATH_MAX, |
|
TEMPLATE_ALIAS, sysfs, dent->d_name); |
|
|
|
if (!file_available(path)) |
|
continue; |
|
|
|
file = fopen(path, "r"); |
|
if (!file) |
|
continue; |
|
|
|
if (!fgets(buf, sizeof(buf), file)) { |
|
fclose(file); |
|
continue; |
|
} |
|
|
|
fclose(file); |
|
|
|
/* Remove the last '\n' */ |
|
buf[strlen(buf) - 1] = 0; |
|
|
|
pmu_alias = pmu_alias__new(dent->d_name, buf); |
|
if (!pmu_alias) |
|
goto close_dir; |
|
|
|
list_add_tail(&pmu_alias->list, &pmu_alias_name_list); |
|
} |
|
|
|
ret = 0; |
|
|
|
close_dir: |
|
closedir(dir); |
|
return ret; |
|
} |
|
|
|
static char *__pmu_find_real_name(const char *name) |
|
{ |
|
struct pmu_alias *pmu_alias; |
|
|
|
list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { |
|
if (!strcmp(name, pmu_alias->alias)) |
|
return pmu_alias->name; |
|
} |
|
|
|
return (char *)name; |
|
} |
|
|
|
char *pmu_find_real_name(const char *name) |
|
{ |
|
if (cached_list) |
|
return __pmu_find_real_name(name); |
|
|
|
setup_pmu_alias_list(); |
|
cached_list = true; |
|
|
|
return __pmu_find_real_name(name); |
|
} |
|
|
|
static char *__pmu_find_alias_name(const char *name) |
|
{ |
|
struct pmu_alias *pmu_alias; |
|
|
|
list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) { |
|
if (!strcmp(name, pmu_alias->name)) |
|
return pmu_alias->alias; |
|
} |
|
return NULL; |
|
} |
|
|
|
char *pmu_find_alias_name(const char *name) |
|
{ |
|
if (cached_list) |
|
return __pmu_find_alias_name(name); |
|
|
|
setup_pmu_alias_list(); |
|
cached_list = true; |
|
|
|
return __pmu_find_alias_name(name); |
|
}
|
|
|