aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/header.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util/header.c')
-rw-r--r--tools/perf/util/header.c270
1 files changed, 270 insertions, 0 deletions
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index f50b7235ecb6..73e38e472ecd 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -23,6 +23,8 @@
23#include "strbuf.h" 23#include "strbuf.h"
24#include "build-id.h" 24#include "build-id.h"
25#include "data.h" 25#include "data.h"
26#include <api/fs/fs.h>
27#include "asm/bug.h"
26 28
27/* 29/*
28 * magic2 = "PERFILE2" 30 * magic2 = "PERFILE2"
@@ -868,6 +870,199 @@ static int write_auxtrace(int fd, struct perf_header *h,
868 return err; 870 return err;
869} 871}
870 872
873static int cpu_cache_level__sort(const void *a, const void *b)
874{
875 struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a;
876 struct cpu_cache_level *cache_b = (struct cpu_cache_level *)b;
877
878 return cache_a->level - cache_b->level;
879}
880
881static bool cpu_cache_level__cmp(struct cpu_cache_level *a, struct cpu_cache_level *b)
882{
883 if (a->level != b->level)
884 return false;
885
886 if (a->line_size != b->line_size)
887 return false;
888
889 if (a->sets != b->sets)
890 return false;
891
892 if (a->ways != b->ways)
893 return false;
894
895 if (strcmp(a->type, b->type))
896 return false;
897
898 if (strcmp(a->size, b->size))
899 return false;
900
901 if (strcmp(a->map, b->map))
902 return false;
903
904 return true;
905}
906
907static int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 level)
908{
909 char path[PATH_MAX], file[PATH_MAX];
910 struct stat st;
911 size_t len;
912
913 scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level);
914 scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path);
915
916 if (stat(file, &st))
917 return 1;
918
919 scnprintf(file, PATH_MAX, "%s/level", path);
920 if (sysfs__read_int(file, (int *) &cache->level))
921 return -1;
922
923 scnprintf(file, PATH_MAX, "%s/coherency_line_size", path);
924 if (sysfs__read_int(file, (int *) &cache->line_size))
925 return -1;
926
927 scnprintf(file, PATH_MAX, "%s/number_of_sets", path);
928 if (sysfs__read_int(file, (int *) &cache->sets))
929 return -1;
930
931 scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path);
932 if (sysfs__read_int(file, (int *) &cache->ways))
933 return -1;
934
935 scnprintf(file, PATH_MAX, "%s/type", path);
936 if (sysfs__read_str(file, &cache->type, &len))
937 return -1;
938
939 cache->type[len] = 0;
940 cache->type = rtrim(cache->type);
941
942 scnprintf(file, PATH_MAX, "%s/size", path);
943 if (sysfs__read_str(file, &cache->size, &len)) {
944 free(cache->type);
945 return -1;
946 }
947
948 cache->size[len] = 0;
949 cache->size = rtrim(cache->size);
950
951 scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path);
952 if (sysfs__read_str(file, &cache->map, &len)) {
953 free(cache->map);
954 free(cache->type);
955 return -1;
956 }
957
958 cache->map[len] = 0;
959 cache->map = rtrim(cache->map);
960 return 0;
961}
962
963static void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c)
964{
965 fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map);
966}
967
968static int build_caches(struct cpu_cache_level caches[], u32 size, u32 *cntp)
969{
970 u32 i, cnt = 0;
971 long ncpus;
972 u32 nr, cpu;
973 u16 level;
974
975 ncpus = sysconf(_SC_NPROCESSORS_CONF);
976 if (ncpus < 0)
977 return -1;
978
979 nr = (u32)(ncpus & UINT_MAX);
980
981 for (cpu = 0; cpu < nr; cpu++) {
982 for (level = 0; level < 10; level++) {
983 struct cpu_cache_level c;
984 int err;
985
986 err = cpu_cache_level__read(&c, cpu, level);
987 if (err < 0)
988 return err;
989
990 if (err == 1)
991 break;
992
993 for (i = 0; i < cnt; i++) {
994 if (cpu_cache_level__cmp(&c, &caches[i]))
995 break;
996 }
997
998 if (i == cnt)
999 caches[cnt++] = c;
1000 else
1001 cpu_cache_level__free(&c);
1002
1003 if (WARN_ONCE(cnt == size, "way too many cpu caches.."))
1004 goto out;
1005 }
1006 }
1007 out:
1008 *cntp = cnt;
1009 return 0;
1010}
1011
1012#define MAX_CACHES 2000
1013
1014static int write_cache(int fd, struct perf_header *h __maybe_unused,
1015 struct perf_evlist *evlist __maybe_unused)
1016{
1017 struct cpu_cache_level caches[MAX_CACHES];
1018 u32 cnt = 0, i, version = 1;
1019 int ret;
1020
1021 ret = build_caches(caches, MAX_CACHES, &cnt);
1022 if (ret)
1023 goto out;
1024
1025 qsort(&caches, cnt, sizeof(struct cpu_cache_level), cpu_cache_level__sort);
1026
1027 ret = do_write(fd, &version, sizeof(u32));
1028 if (ret < 0)
1029 goto out;
1030
1031 ret = do_write(fd, &cnt, sizeof(u32));
1032 if (ret < 0)
1033 goto out;
1034
1035 for (i = 0; i < cnt; i++) {
1036 struct cpu_cache_level *c = &caches[i];
1037
1038 #define _W(v) \
1039 ret = do_write(fd, &c->v, sizeof(u32)); \
1040 if (ret < 0) \
1041 goto out;
1042
1043 _W(level)
1044 _W(line_size)
1045 _W(sets)
1046 _W(ways)
1047 #undef _W
1048
1049 #define _W(v) \
1050 ret = do_write_string(fd, (const char *) c->v); \
1051 if (ret < 0) \
1052 goto out;
1053
1054 _W(type)
1055 _W(size)
1056 _W(map)
1057 #undef _W
1058 }
1059
1060out:
1061 for (i = 0; i < cnt; i++)
1062 cpu_cache_level__free(&caches[i]);
1063 return ret;
1064}
1065
871static int write_stat(int fd __maybe_unused, 1066static int write_stat(int fd __maybe_unused,
872 struct perf_header *h __maybe_unused, 1067 struct perf_header *h __maybe_unused,
873 struct perf_evlist *evlist __maybe_unused) 1068 struct perf_evlist *evlist __maybe_unused)
@@ -1172,6 +1367,18 @@ static void print_stat(struct perf_header *ph __maybe_unused,
1172 fprintf(fp, "# contains stat data\n"); 1367 fprintf(fp, "# contains stat data\n");
1173} 1368}
1174 1369
1370static void print_cache(struct perf_header *ph __maybe_unused,
1371 int fd __maybe_unused, FILE *fp __maybe_unused)
1372{
1373 int i;
1374
1375 fprintf(fp, "# CPU cache info:\n");
1376 for (i = 0; i < ph->env.caches_cnt; i++) {
1377 fprintf(fp, "# ");
1378 cpu_cache_level__fprintf(fp, &ph->env.caches[i]);
1379 }
1380}
1381
1175static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused, 1382static void print_pmu_mappings(struct perf_header *ph, int fd __maybe_unused,
1176 FILE *fp) 1383 FILE *fp)
1177{ 1384{
@@ -1920,6 +2127,68 @@ static int process_auxtrace(struct perf_file_section *section,
1920 return err; 2127 return err;
1921} 2128}
1922 2129
2130static int process_cache(struct perf_file_section *section __maybe_unused,
2131 struct perf_header *ph __maybe_unused, int fd __maybe_unused,
2132 void *data __maybe_unused)
2133{
2134 struct cpu_cache_level *caches;
2135 u32 cnt, i, version;
2136
2137 if (readn(fd, &version, sizeof(version)) != sizeof(version))
2138 return -1;
2139
2140 if (ph->needs_swap)
2141 version = bswap_32(version);
2142
2143 if (version != 1)
2144 return -1;
2145
2146 if (readn(fd, &cnt, sizeof(cnt)) != sizeof(cnt))
2147 return -1;
2148
2149 if (ph->needs_swap)
2150 cnt = bswap_32(cnt);
2151
2152 caches = zalloc(sizeof(*caches) * cnt);
2153 if (!caches)
2154 return -1;
2155
2156 for (i = 0; i < cnt; i++) {
2157 struct cpu_cache_level c;
2158
2159 #define _R(v) \
2160 if (readn(fd, &c.v, sizeof(u32)) != sizeof(u32))\
2161 goto out_free_caches; \
2162 if (ph->needs_swap) \
2163 c.v = bswap_32(c.v); \
2164
2165 _R(level)
2166 _R(line_size)
2167 _R(sets)
2168 _R(ways)
2169 #undef _R
2170
2171 #define _R(v) \
2172 c.v = do_read_string(fd, ph); \
2173 if (!c.v) \
2174 goto out_free_caches;
2175
2176 _R(type)
2177 _R(size)
2178 _R(map)
2179 #undef _R
2180
2181 caches[i] = c;
2182 }
2183
2184 ph->env.caches = caches;
2185 ph->env.caches_cnt = cnt;
2186 return 0;
2187out_free_caches:
2188 free(caches);
2189 return -1;
2190}
2191
1923struct feature_ops { 2192struct feature_ops {
1924 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist); 2193 int (*write)(int fd, struct perf_header *h, struct perf_evlist *evlist);
1925 void (*print)(struct perf_header *h, int fd, FILE *fp); 2194 void (*print)(struct perf_header *h, int fd, FILE *fp);
@@ -1962,6 +2231,7 @@ static const struct feature_ops feat_ops[HEADER_LAST_FEATURE] = {
1962 FEAT_OPP(HEADER_GROUP_DESC, group_desc), 2231 FEAT_OPP(HEADER_GROUP_DESC, group_desc),
1963 FEAT_OPP(HEADER_AUXTRACE, auxtrace), 2232 FEAT_OPP(HEADER_AUXTRACE, auxtrace),
1964 FEAT_OPA(HEADER_STAT, stat), 2233 FEAT_OPA(HEADER_STAT, stat),
2234 FEAT_OPF(HEADER_CACHE, cache),
1965}; 2235};
1966 2236
1967struct header_print_data { 2237struct header_print_data {