linux/tools/perf/arch/x86/util/pmu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <string.h>
   3#include <stdio.h>
   4#include <sys/types.h>
   5#include <dirent.h>
   6#include <fcntl.h>
   7#include <linux/stddef.h>
   8#include <linux/perf_event.h>
   9#include <linux/zalloc.h>
  10#include <api/fs/fs.h>
  11#include <errno.h>
  12
  13#include "../../../util/intel-pt.h"
  14#include "../../../util/intel-bts.h"
  15#include "../../../util/pmu.h"
  16#include "../../../util/fncache.h"
  17
  18#define TEMPLATE_ALIAS  "%s/bus/event_source/devices/%s/alias"
  19
  20struct pmu_alias {
  21        char *name;
  22        char *alias;
  23        struct list_head list;
  24};
  25
  26static LIST_HEAD(pmu_alias_name_list);
  27static bool cached_list;
  28
  29struct perf_event_attr *perf_pmu__get_default_config(struct perf_pmu *pmu __maybe_unused)
  30{
  31#ifdef HAVE_AUXTRACE_SUPPORT
  32        if (!strcmp(pmu->name, INTEL_PT_PMU_NAME))
  33                return intel_pt_pmu_default_config(pmu);
  34        if (!strcmp(pmu->name, INTEL_BTS_PMU_NAME))
  35                pmu->selectable = true;
  36#endif
  37        return NULL;
  38}
  39
  40static void pmu_alias__delete(struct pmu_alias *pmu_alias)
  41{
  42        if (!pmu_alias)
  43                return;
  44
  45        zfree(&pmu_alias->name);
  46        zfree(&pmu_alias->alias);
  47        free(pmu_alias);
  48}
  49
  50static struct pmu_alias *pmu_alias__new(char *name, char *alias)
  51{
  52        struct pmu_alias *pmu_alias = zalloc(sizeof(*pmu_alias));
  53
  54        if (pmu_alias) {
  55                pmu_alias->name = strdup(name);
  56                if (!pmu_alias->name)
  57                        goto out_delete;
  58
  59                pmu_alias->alias = strdup(alias);
  60                if (!pmu_alias->alias)
  61                        goto out_delete;
  62        }
  63        return pmu_alias;
  64
  65out_delete:
  66        pmu_alias__delete(pmu_alias);
  67        return NULL;
  68}
  69
  70static int setup_pmu_alias_list(void)
  71{
  72        char path[PATH_MAX];
  73        DIR *dir;
  74        struct dirent *dent;
  75        const char *sysfs = sysfs__mountpoint();
  76        struct pmu_alias *pmu_alias;
  77        char buf[MAX_PMU_NAME_LEN];
  78        FILE *file;
  79        int ret = -ENOMEM;
  80
  81        if (!sysfs)
  82                return -1;
  83
  84        snprintf(path, PATH_MAX,
  85                 "%s" EVENT_SOURCE_DEVICE_PATH, sysfs);
  86
  87        dir = opendir(path);
  88        if (!dir)
  89                return -errno;
  90
  91        while ((dent = readdir(dir))) {
  92                if (!strcmp(dent->d_name, ".") ||
  93                    !strcmp(dent->d_name, ".."))
  94                        continue;
  95
  96                snprintf(path, PATH_MAX,
  97                         TEMPLATE_ALIAS, sysfs, dent->d_name);
  98
  99                if (!file_available(path))
 100                        continue;
 101
 102                file = fopen(path, "r");
 103                if (!file)
 104                        continue;
 105
 106                if (!fgets(buf, sizeof(buf), file)) {
 107                        fclose(file);
 108                        continue;
 109                }
 110
 111                fclose(file);
 112
 113                /* Remove the last '\n' */
 114                buf[strlen(buf) - 1] = 0;
 115
 116                pmu_alias = pmu_alias__new(dent->d_name, buf);
 117                if (!pmu_alias)
 118                        goto close_dir;
 119
 120                list_add_tail(&pmu_alias->list, &pmu_alias_name_list);
 121        }
 122
 123        ret = 0;
 124
 125close_dir:
 126        closedir(dir);
 127        return ret;
 128}
 129
 130static char *__pmu_find_real_name(const char *name)
 131{
 132        struct pmu_alias *pmu_alias;
 133
 134        list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) {
 135                if (!strcmp(name, pmu_alias->alias))
 136                        return pmu_alias->name;
 137        }
 138
 139        return (char *)name;
 140}
 141
 142char *pmu_find_real_name(const char *name)
 143{
 144        if (cached_list)
 145                return __pmu_find_real_name(name);
 146
 147        setup_pmu_alias_list();
 148        cached_list = true;
 149
 150        return __pmu_find_real_name(name);
 151}
 152
 153static char *__pmu_find_alias_name(const char *name)
 154{
 155        struct pmu_alias *pmu_alias;
 156
 157        list_for_each_entry(pmu_alias, &pmu_alias_name_list, list) {
 158                if (!strcmp(name, pmu_alias->name))
 159                        return pmu_alias->alias;
 160        }
 161        return NULL;
 162}
 163
 164char *pmu_find_alias_name(const char *name)
 165{
 166        if (cached_list)
 167                return __pmu_find_alias_name(name);
 168
 169        setup_pmu_alias_list();
 170        cached_list = true;
 171
 172        return __pmu_find_alias_name(name);
 173}
 174