162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#include <errno.h> 362306a36Sopenharmony_ci#include <inttypes.h> 462306a36Sopenharmony_ci#include "string2.h" 562306a36Sopenharmony_ci#include <sys/param.h> 662306a36Sopenharmony_ci#include <sys/types.h> 762306a36Sopenharmony_ci#include <byteswap.h> 862306a36Sopenharmony_ci#include <unistd.h> 962306a36Sopenharmony_ci#include <regex.h> 1062306a36Sopenharmony_ci#include <stdio.h> 1162306a36Sopenharmony_ci#include <stdlib.h> 1262306a36Sopenharmony_ci#include <linux/compiler.h> 1362306a36Sopenharmony_ci#include <linux/list.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/bitops.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/stringify.h> 1862306a36Sopenharmony_ci#include <linux/zalloc.h> 1962306a36Sopenharmony_ci#include <sys/stat.h> 2062306a36Sopenharmony_ci#include <sys/utsname.h> 2162306a36Sopenharmony_ci#include <linux/time64.h> 2262306a36Sopenharmony_ci#include <dirent.h> 2362306a36Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT 2462306a36Sopenharmony_ci#include <bpf/libbpf.h> 2562306a36Sopenharmony_ci#endif 2662306a36Sopenharmony_ci#include <perf/cpumap.h> 2762306a36Sopenharmony_ci#include <tools/libc_compat.h> // reallocarray 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#include "dso.h" 3062306a36Sopenharmony_ci#include "evlist.h" 3162306a36Sopenharmony_ci#include "evsel.h" 3262306a36Sopenharmony_ci#include "util/evsel_fprintf.h" 3362306a36Sopenharmony_ci#include "header.h" 3462306a36Sopenharmony_ci#include "memswap.h" 3562306a36Sopenharmony_ci#include "trace-event.h" 3662306a36Sopenharmony_ci#include "session.h" 3762306a36Sopenharmony_ci#include "symbol.h" 3862306a36Sopenharmony_ci#include "debug.h" 3962306a36Sopenharmony_ci#include "cpumap.h" 4062306a36Sopenharmony_ci#include "pmu.h" 4162306a36Sopenharmony_ci#include "pmus.h" 4262306a36Sopenharmony_ci#include "vdso.h" 4362306a36Sopenharmony_ci#include "strbuf.h" 4462306a36Sopenharmony_ci#include "build-id.h" 4562306a36Sopenharmony_ci#include "data.h" 4662306a36Sopenharmony_ci#include <api/fs/fs.h> 4762306a36Sopenharmony_ci#include "asm/bug.h" 4862306a36Sopenharmony_ci#include "tool.h" 4962306a36Sopenharmony_ci#include "time-utils.h" 5062306a36Sopenharmony_ci#include "units.h" 5162306a36Sopenharmony_ci#include "util/util.h" // perf_exe() 5262306a36Sopenharmony_ci#include "cputopo.h" 5362306a36Sopenharmony_ci#include "bpf-event.h" 5462306a36Sopenharmony_ci#include "bpf-utils.h" 5562306a36Sopenharmony_ci#include "clockid.h" 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#include <linux/ctype.h> 5862306a36Sopenharmony_ci#include <internal/lib.h> 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT 6162306a36Sopenharmony_ci#include <traceevent/event-parse.h> 6262306a36Sopenharmony_ci#endif 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* 6562306a36Sopenharmony_ci * magic2 = "PERFILE2" 6662306a36Sopenharmony_ci * must be a numerical value to let the endianness 6762306a36Sopenharmony_ci * determine the memory layout. That way we are able 6862306a36Sopenharmony_ci * to detect endianness when reading the perf.data file 6962306a36Sopenharmony_ci * back. 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * we check for legacy (PERFFILE) format. 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_cistatic const char *__perf_magic1 = "PERFFILE"; 7462306a36Sopenharmony_cistatic const u64 __perf_magic2 = 0x32454c4946524550ULL; 7562306a36Sopenharmony_cistatic const u64 __perf_magic2_sw = 0x50455246494c4532ULL; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define PERF_MAGIC __perf_magic2 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ciconst char perf_version_string[] = PERF_VERSION; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cistruct perf_file_attr { 8262306a36Sopenharmony_ci struct perf_event_attr attr; 8362306a36Sopenharmony_ci struct perf_file_section ids; 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_civoid perf_header__set_feat(struct perf_header *header, int feat) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci __set_bit(feat, header->adds_features); 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_civoid perf_header__clear_feat(struct perf_header *header, int feat) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci __clear_bit(feat, header->adds_features); 9462306a36Sopenharmony_ci} 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_cibool perf_header__has_feat(const struct perf_header *header, int feat) 9762306a36Sopenharmony_ci{ 9862306a36Sopenharmony_ci return test_bit(feat, header->adds_features); 9962306a36Sopenharmony_ci} 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_cistatic int __do_write_fd(struct feat_fd *ff, const void *buf, size_t size) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci ssize_t ret = writen(ff->fd, buf, size); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (ret != (ssize_t)size) 10662306a36Sopenharmony_ci return ret < 0 ? (int)ret : -1; 10762306a36Sopenharmony_ci return 0; 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int __do_write_buf(struct feat_fd *ff, const void *buf, size_t size) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci /* struct perf_event_header::size is u16 */ 11362306a36Sopenharmony_ci const size_t max_size = 0xffff - sizeof(struct perf_event_header); 11462306a36Sopenharmony_ci size_t new_size = ff->size; 11562306a36Sopenharmony_ci void *addr; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci if (size + ff->offset > max_size) 11862306a36Sopenharmony_ci return -E2BIG; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci while (size > (new_size - ff->offset)) 12162306a36Sopenharmony_ci new_size <<= 1; 12262306a36Sopenharmony_ci new_size = min(max_size, new_size); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (ff->size < new_size) { 12562306a36Sopenharmony_ci addr = realloc(ff->buf, new_size); 12662306a36Sopenharmony_ci if (!addr) 12762306a36Sopenharmony_ci return -ENOMEM; 12862306a36Sopenharmony_ci ff->buf = addr; 12962306a36Sopenharmony_ci ff->size = new_size; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci memcpy(ff->buf + ff->offset, buf, size); 13362306a36Sopenharmony_ci ff->offset += size; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci return 0; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* Return: 0 if succeeded, -ERR if failed. */ 13962306a36Sopenharmony_ciint do_write(struct feat_fd *ff, const void *buf, size_t size) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci if (!ff->buf) 14262306a36Sopenharmony_ci return __do_write_fd(ff, buf, size); 14362306a36Sopenharmony_ci return __do_write_buf(ff, buf, size); 14462306a36Sopenharmony_ci} 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* Return: 0 if succeeded, -ERR if failed. */ 14762306a36Sopenharmony_cistatic int do_write_bitmap(struct feat_fd *ff, unsigned long *set, u64 size) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci u64 *p = (u64 *) set; 15062306a36Sopenharmony_ci int i, ret; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci ret = do_write(ff, &size, sizeof(size)); 15362306a36Sopenharmony_ci if (ret < 0) 15462306a36Sopenharmony_ci return ret; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci for (i = 0; (u64) i < BITS_TO_U64(size); i++) { 15762306a36Sopenharmony_ci ret = do_write(ff, p + i, sizeof(*p)); 15862306a36Sopenharmony_ci if (ret < 0) 15962306a36Sopenharmony_ci return ret; 16062306a36Sopenharmony_ci } 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci return 0; 16362306a36Sopenharmony_ci} 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci/* Return: 0 if succeeded, -ERR if failed. */ 16662306a36Sopenharmony_ciint write_padded(struct feat_fd *ff, const void *bf, 16762306a36Sopenharmony_ci size_t count, size_t count_aligned) 16862306a36Sopenharmony_ci{ 16962306a36Sopenharmony_ci static const char zero_buf[NAME_ALIGN]; 17062306a36Sopenharmony_ci int err = do_write(ff, bf, count); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci if (!err) 17362306a36Sopenharmony_ci err = do_write(ff, zero_buf, count_aligned - count); 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci return err; 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci#define string_size(str) \ 17962306a36Sopenharmony_ci (PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32)) 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci/* Return: 0 if succeeded, -ERR if failed. */ 18262306a36Sopenharmony_cistatic int do_write_string(struct feat_fd *ff, const char *str) 18362306a36Sopenharmony_ci{ 18462306a36Sopenharmony_ci u32 len, olen; 18562306a36Sopenharmony_ci int ret; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci olen = strlen(str) + 1; 18862306a36Sopenharmony_ci len = PERF_ALIGN(olen, NAME_ALIGN); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci /* write len, incl. \0 */ 19162306a36Sopenharmony_ci ret = do_write(ff, &len, sizeof(len)); 19262306a36Sopenharmony_ci if (ret < 0) 19362306a36Sopenharmony_ci return ret; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return write_padded(ff, str, olen, len); 19662306a36Sopenharmony_ci} 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_cistatic int __do_read_fd(struct feat_fd *ff, void *addr, ssize_t size) 19962306a36Sopenharmony_ci{ 20062306a36Sopenharmony_ci ssize_t ret = readn(ff->fd, addr, size); 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (ret != size) 20362306a36Sopenharmony_ci return ret < 0 ? (int)ret : -1; 20462306a36Sopenharmony_ci return 0; 20562306a36Sopenharmony_ci} 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic int __do_read_buf(struct feat_fd *ff, void *addr, ssize_t size) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci if (size > (ssize_t)ff->size - ff->offset) 21062306a36Sopenharmony_ci return -1; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci memcpy(addr, ff->buf + ff->offset, size); 21362306a36Sopenharmony_ci ff->offset += size; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic int __do_read(struct feat_fd *ff, void *addr, ssize_t size) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci if (!ff->buf) 22262306a36Sopenharmony_ci return __do_read_fd(ff, addr, size); 22362306a36Sopenharmony_ci return __do_read_buf(ff, addr, size); 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic int do_read_u32(struct feat_fd *ff, u32 *addr) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci int ret; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci ret = __do_read(ff, addr, sizeof(*addr)); 23162306a36Sopenharmony_ci if (ret) 23262306a36Sopenharmony_ci return ret; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci if (ff->ph->needs_swap) 23562306a36Sopenharmony_ci *addr = bswap_32(*addr); 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_cistatic int do_read_u64(struct feat_fd *ff, u64 *addr) 24062306a36Sopenharmony_ci{ 24162306a36Sopenharmony_ci int ret; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci ret = __do_read(ff, addr, sizeof(*addr)); 24462306a36Sopenharmony_ci if (ret) 24562306a36Sopenharmony_ci return ret; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci if (ff->ph->needs_swap) 24862306a36Sopenharmony_ci *addr = bswap_64(*addr); 24962306a36Sopenharmony_ci return 0; 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_cistatic char *do_read_string(struct feat_fd *ff) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci u32 len; 25562306a36Sopenharmony_ci char *buf; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci if (do_read_u32(ff, &len)) 25862306a36Sopenharmony_ci return NULL; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci buf = malloc(len); 26162306a36Sopenharmony_ci if (!buf) 26262306a36Sopenharmony_ci return NULL; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci if (!__do_read(ff, buf, len)) { 26562306a36Sopenharmony_ci /* 26662306a36Sopenharmony_ci * strings are padded by zeroes 26762306a36Sopenharmony_ci * thus the actual strlen of buf 26862306a36Sopenharmony_ci * may be less than len 26962306a36Sopenharmony_ci */ 27062306a36Sopenharmony_ci return buf; 27162306a36Sopenharmony_ci } 27262306a36Sopenharmony_ci 27362306a36Sopenharmony_ci free(buf); 27462306a36Sopenharmony_ci return NULL; 27562306a36Sopenharmony_ci} 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci/* Return: 0 if succeeded, -ERR if failed. */ 27862306a36Sopenharmony_cistatic int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci unsigned long *set; 28162306a36Sopenharmony_ci u64 size, *p; 28262306a36Sopenharmony_ci int i, ret; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci ret = do_read_u64(ff, &size); 28562306a36Sopenharmony_ci if (ret) 28662306a36Sopenharmony_ci return ret; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci set = bitmap_zalloc(size); 28962306a36Sopenharmony_ci if (!set) 29062306a36Sopenharmony_ci return -ENOMEM; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci p = (u64 *) set; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci for (i = 0; (u64) i < BITS_TO_U64(size); i++) { 29562306a36Sopenharmony_ci ret = do_read_u64(ff, p + i); 29662306a36Sopenharmony_ci if (ret < 0) { 29762306a36Sopenharmony_ci free(set); 29862306a36Sopenharmony_ci return ret; 29962306a36Sopenharmony_ci } 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci *pset = set; 30362306a36Sopenharmony_ci *psize = size; 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT 30862306a36Sopenharmony_cistatic int write_tracing_data(struct feat_fd *ff, 30962306a36Sopenharmony_ci struct evlist *evlist) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) 31262306a36Sopenharmony_ci return -1; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return read_tracing_data(ff->fd, &evlist->core.entries); 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci#endif 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_cistatic int write_build_id(struct feat_fd *ff, 31962306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct perf_session *session; 32262306a36Sopenharmony_ci int err; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (!perf_session__read_build_ids(session, true)) 32762306a36Sopenharmony_ci return -1; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) 33062306a36Sopenharmony_ci return -1; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci err = perf_session__write_buildid_table(session, ff); 33362306a36Sopenharmony_ci if (err < 0) { 33462306a36Sopenharmony_ci pr_debug("failed to write buildid table\n"); 33562306a36Sopenharmony_ci return err; 33662306a36Sopenharmony_ci } 33762306a36Sopenharmony_ci perf_session__cache_build_ids(session); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci return 0; 34062306a36Sopenharmony_ci} 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int write_hostname(struct feat_fd *ff, 34362306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct utsname uts; 34662306a36Sopenharmony_ci int ret; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ret = uname(&uts); 34962306a36Sopenharmony_ci if (ret < 0) 35062306a36Sopenharmony_ci return -1; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return do_write_string(ff, uts.nodename); 35362306a36Sopenharmony_ci} 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_cistatic int write_osrelease(struct feat_fd *ff, 35662306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 35762306a36Sopenharmony_ci{ 35862306a36Sopenharmony_ci struct utsname uts; 35962306a36Sopenharmony_ci int ret; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci ret = uname(&uts); 36262306a36Sopenharmony_ci if (ret < 0) 36362306a36Sopenharmony_ci return -1; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci return do_write_string(ff, uts.release); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic int write_arch(struct feat_fd *ff, 36962306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci struct utsname uts; 37262306a36Sopenharmony_ci int ret; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci ret = uname(&uts); 37562306a36Sopenharmony_ci if (ret < 0) 37662306a36Sopenharmony_ci return -1; 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ci return do_write_string(ff, uts.machine); 37962306a36Sopenharmony_ci} 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_cistatic int write_version(struct feat_fd *ff, 38262306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci return do_write_string(ff, perf_version_string); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic int __write_cpudesc(struct feat_fd *ff, const char *cpuinfo_proc) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci FILE *file; 39062306a36Sopenharmony_ci char *buf = NULL; 39162306a36Sopenharmony_ci char *s, *p; 39262306a36Sopenharmony_ci const char *search = cpuinfo_proc; 39362306a36Sopenharmony_ci size_t len = 0; 39462306a36Sopenharmony_ci int ret = -1; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci if (!search) 39762306a36Sopenharmony_ci return -1; 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci file = fopen("/proc/cpuinfo", "r"); 40062306a36Sopenharmony_ci if (!file) 40162306a36Sopenharmony_ci return -1; 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci while (getline(&buf, &len, file) > 0) { 40462306a36Sopenharmony_ci ret = strncmp(buf, search, strlen(search)); 40562306a36Sopenharmony_ci if (!ret) 40662306a36Sopenharmony_ci break; 40762306a36Sopenharmony_ci } 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (ret) { 41062306a36Sopenharmony_ci ret = -1; 41162306a36Sopenharmony_ci goto done; 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci s = buf; 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci p = strchr(buf, ':'); 41762306a36Sopenharmony_ci if (p && *(p+1) == ' ' && *(p+2)) 41862306a36Sopenharmony_ci s = p + 2; 41962306a36Sopenharmony_ci p = strchr(s, '\n'); 42062306a36Sopenharmony_ci if (p) 42162306a36Sopenharmony_ci *p = '\0'; 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci /* squash extra space characters (branding string) */ 42462306a36Sopenharmony_ci p = s; 42562306a36Sopenharmony_ci while (*p) { 42662306a36Sopenharmony_ci if (isspace(*p)) { 42762306a36Sopenharmony_ci char *r = p + 1; 42862306a36Sopenharmony_ci char *q = skip_spaces(r); 42962306a36Sopenharmony_ci *p = ' '; 43062306a36Sopenharmony_ci if (q != (p+1)) 43162306a36Sopenharmony_ci while ((*r++ = *q++)); 43262306a36Sopenharmony_ci } 43362306a36Sopenharmony_ci p++; 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci ret = do_write_string(ff, s); 43662306a36Sopenharmony_cidone: 43762306a36Sopenharmony_ci free(buf); 43862306a36Sopenharmony_ci fclose(file); 43962306a36Sopenharmony_ci return ret; 44062306a36Sopenharmony_ci} 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_cistatic int write_cpudesc(struct feat_fd *ff, 44362306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci#if defined(__powerpc__) || defined(__hppa__) || defined(__sparc__) 44662306a36Sopenharmony_ci#define CPUINFO_PROC { "cpu", } 44762306a36Sopenharmony_ci#elif defined(__s390__) 44862306a36Sopenharmony_ci#define CPUINFO_PROC { "vendor_id", } 44962306a36Sopenharmony_ci#elif defined(__sh__) 45062306a36Sopenharmony_ci#define CPUINFO_PROC { "cpu type", } 45162306a36Sopenharmony_ci#elif defined(__alpha__) || defined(__mips__) 45262306a36Sopenharmony_ci#define CPUINFO_PROC { "cpu model", } 45362306a36Sopenharmony_ci#elif defined(__arm__) 45462306a36Sopenharmony_ci#define CPUINFO_PROC { "model name", "Processor", } 45562306a36Sopenharmony_ci#elif defined(__arc__) 45662306a36Sopenharmony_ci#define CPUINFO_PROC { "Processor", } 45762306a36Sopenharmony_ci#elif defined(__xtensa__) 45862306a36Sopenharmony_ci#define CPUINFO_PROC { "core ID", } 45962306a36Sopenharmony_ci#elif defined(__loongarch__) 46062306a36Sopenharmony_ci#define CPUINFO_PROC { "Model Name", } 46162306a36Sopenharmony_ci#else 46262306a36Sopenharmony_ci#define CPUINFO_PROC { "model name", } 46362306a36Sopenharmony_ci#endif 46462306a36Sopenharmony_ci const char *cpuinfo_procs[] = CPUINFO_PROC; 46562306a36Sopenharmony_ci#undef CPUINFO_PROC 46662306a36Sopenharmony_ci unsigned int i; 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) { 46962306a36Sopenharmony_ci int ret; 47062306a36Sopenharmony_ci ret = __write_cpudesc(ff, cpuinfo_procs[i]); 47162306a36Sopenharmony_ci if (ret >= 0) 47262306a36Sopenharmony_ci return ret; 47362306a36Sopenharmony_ci } 47462306a36Sopenharmony_ci return -1; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_cistatic int write_nrcpus(struct feat_fd *ff, 47962306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 48062306a36Sopenharmony_ci{ 48162306a36Sopenharmony_ci long nr; 48262306a36Sopenharmony_ci u32 nrc, nra; 48362306a36Sopenharmony_ci int ret; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci nrc = cpu__max_present_cpu().cpu; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci nr = sysconf(_SC_NPROCESSORS_ONLN); 48862306a36Sopenharmony_ci if (nr < 0) 48962306a36Sopenharmony_ci return -1; 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci nra = (u32)(nr & UINT_MAX); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci ret = do_write(ff, &nrc, sizeof(nrc)); 49462306a36Sopenharmony_ci if (ret < 0) 49562306a36Sopenharmony_ci return ret; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci return do_write(ff, &nra, sizeof(nra)); 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cistatic int write_event_desc(struct feat_fd *ff, 50162306a36Sopenharmony_ci struct evlist *evlist) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct evsel *evsel; 50462306a36Sopenharmony_ci u32 nre, nri, sz; 50562306a36Sopenharmony_ci int ret; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci nre = evlist->core.nr_entries; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci /* 51062306a36Sopenharmony_ci * write number of events 51162306a36Sopenharmony_ci */ 51262306a36Sopenharmony_ci ret = do_write(ff, &nre, sizeof(nre)); 51362306a36Sopenharmony_ci if (ret < 0) 51462306a36Sopenharmony_ci return ret; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* 51762306a36Sopenharmony_ci * size of perf_event_attr struct 51862306a36Sopenharmony_ci */ 51962306a36Sopenharmony_ci sz = (u32)sizeof(evsel->core.attr); 52062306a36Sopenharmony_ci ret = do_write(ff, &sz, sizeof(sz)); 52162306a36Sopenharmony_ci if (ret < 0) 52262306a36Sopenharmony_ci return ret; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 52562306a36Sopenharmony_ci ret = do_write(ff, &evsel->core.attr, sz); 52662306a36Sopenharmony_ci if (ret < 0) 52762306a36Sopenharmony_ci return ret; 52862306a36Sopenharmony_ci /* 52962306a36Sopenharmony_ci * write number of unique id per event 53062306a36Sopenharmony_ci * there is one id per instance of an event 53162306a36Sopenharmony_ci * 53262306a36Sopenharmony_ci * copy into an nri to be independent of the 53362306a36Sopenharmony_ci * type of ids, 53462306a36Sopenharmony_ci */ 53562306a36Sopenharmony_ci nri = evsel->core.ids; 53662306a36Sopenharmony_ci ret = do_write(ff, &nri, sizeof(nri)); 53762306a36Sopenharmony_ci if (ret < 0) 53862306a36Sopenharmony_ci return ret; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci /* 54162306a36Sopenharmony_ci * write event string as passed on cmdline 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ci ret = do_write_string(ff, evsel__name(evsel)); 54462306a36Sopenharmony_ci if (ret < 0) 54562306a36Sopenharmony_ci return ret; 54662306a36Sopenharmony_ci /* 54762306a36Sopenharmony_ci * write unique ids for this event 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_ci ret = do_write(ff, evsel->core.id, evsel->core.ids * sizeof(u64)); 55062306a36Sopenharmony_ci if (ret < 0) 55162306a36Sopenharmony_ci return ret; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci return 0; 55462306a36Sopenharmony_ci} 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_cistatic int write_cmdline(struct feat_fd *ff, 55762306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 55862306a36Sopenharmony_ci{ 55962306a36Sopenharmony_ci char pbuf[MAXPATHLEN], *buf; 56062306a36Sopenharmony_ci int i, ret, n; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci /* actual path to perf binary */ 56362306a36Sopenharmony_ci buf = perf_exe(pbuf, MAXPATHLEN); 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci /* account for binary path */ 56662306a36Sopenharmony_ci n = perf_env.nr_cmdline + 1; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci ret = do_write(ff, &n, sizeof(n)); 56962306a36Sopenharmony_ci if (ret < 0) 57062306a36Sopenharmony_ci return ret; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci ret = do_write_string(ff, buf); 57362306a36Sopenharmony_ci if (ret < 0) 57462306a36Sopenharmony_ci return ret; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci for (i = 0 ; i < perf_env.nr_cmdline; i++) { 57762306a36Sopenharmony_ci ret = do_write_string(ff, perf_env.cmdline_argv[i]); 57862306a36Sopenharmony_ci if (ret < 0) 57962306a36Sopenharmony_ci return ret; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci return 0; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int write_cpu_topology(struct feat_fd *ff, 58662306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct cpu_topology *tp; 58962306a36Sopenharmony_ci u32 i; 59062306a36Sopenharmony_ci int ret, j; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci tp = cpu_topology__new(); 59362306a36Sopenharmony_ci if (!tp) 59462306a36Sopenharmony_ci return -1; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci ret = do_write(ff, &tp->package_cpus_lists, sizeof(tp->package_cpus_lists)); 59762306a36Sopenharmony_ci if (ret < 0) 59862306a36Sopenharmony_ci goto done; 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci for (i = 0; i < tp->package_cpus_lists; i++) { 60162306a36Sopenharmony_ci ret = do_write_string(ff, tp->package_cpus_list[i]); 60262306a36Sopenharmony_ci if (ret < 0) 60362306a36Sopenharmony_ci goto done; 60462306a36Sopenharmony_ci } 60562306a36Sopenharmony_ci ret = do_write(ff, &tp->core_cpus_lists, sizeof(tp->core_cpus_lists)); 60662306a36Sopenharmony_ci if (ret < 0) 60762306a36Sopenharmony_ci goto done; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci for (i = 0; i < tp->core_cpus_lists; i++) { 61062306a36Sopenharmony_ci ret = do_write_string(ff, tp->core_cpus_list[i]); 61162306a36Sopenharmony_ci if (ret < 0) 61262306a36Sopenharmony_ci break; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci ret = perf_env__read_cpu_topology_map(&perf_env); 61662306a36Sopenharmony_ci if (ret < 0) 61762306a36Sopenharmony_ci goto done; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci for (j = 0; j < perf_env.nr_cpus_avail; j++) { 62062306a36Sopenharmony_ci ret = do_write(ff, &perf_env.cpu[j].core_id, 62162306a36Sopenharmony_ci sizeof(perf_env.cpu[j].core_id)); 62262306a36Sopenharmony_ci if (ret < 0) 62362306a36Sopenharmony_ci return ret; 62462306a36Sopenharmony_ci ret = do_write(ff, &perf_env.cpu[j].socket_id, 62562306a36Sopenharmony_ci sizeof(perf_env.cpu[j].socket_id)); 62662306a36Sopenharmony_ci if (ret < 0) 62762306a36Sopenharmony_ci return ret; 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci if (!tp->die_cpus_lists) 63162306a36Sopenharmony_ci goto done; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci ret = do_write(ff, &tp->die_cpus_lists, sizeof(tp->die_cpus_lists)); 63462306a36Sopenharmony_ci if (ret < 0) 63562306a36Sopenharmony_ci goto done; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci for (i = 0; i < tp->die_cpus_lists; i++) { 63862306a36Sopenharmony_ci ret = do_write_string(ff, tp->die_cpus_list[i]); 63962306a36Sopenharmony_ci if (ret < 0) 64062306a36Sopenharmony_ci goto done; 64162306a36Sopenharmony_ci } 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci for (j = 0; j < perf_env.nr_cpus_avail; j++) { 64462306a36Sopenharmony_ci ret = do_write(ff, &perf_env.cpu[j].die_id, 64562306a36Sopenharmony_ci sizeof(perf_env.cpu[j].die_id)); 64662306a36Sopenharmony_ci if (ret < 0) 64762306a36Sopenharmony_ci return ret; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_cidone: 65162306a36Sopenharmony_ci cpu_topology__delete(tp); 65262306a36Sopenharmony_ci return ret; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic int write_total_mem(struct feat_fd *ff, 65862306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci char *buf = NULL; 66162306a36Sopenharmony_ci FILE *fp; 66262306a36Sopenharmony_ci size_t len = 0; 66362306a36Sopenharmony_ci int ret = -1, n; 66462306a36Sopenharmony_ci uint64_t mem; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci fp = fopen("/proc/meminfo", "r"); 66762306a36Sopenharmony_ci if (!fp) 66862306a36Sopenharmony_ci return -1; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci while (getline(&buf, &len, fp) > 0) { 67162306a36Sopenharmony_ci ret = strncmp(buf, "MemTotal:", 9); 67262306a36Sopenharmony_ci if (!ret) 67362306a36Sopenharmony_ci break; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci if (!ret) { 67662306a36Sopenharmony_ci n = sscanf(buf, "%*s %"PRIu64, &mem); 67762306a36Sopenharmony_ci if (n == 1) 67862306a36Sopenharmony_ci ret = do_write(ff, &mem, sizeof(mem)); 67962306a36Sopenharmony_ci } else 68062306a36Sopenharmony_ci ret = -1; 68162306a36Sopenharmony_ci free(buf); 68262306a36Sopenharmony_ci fclose(fp); 68362306a36Sopenharmony_ci return ret; 68462306a36Sopenharmony_ci} 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_cistatic int write_numa_topology(struct feat_fd *ff, 68762306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 68862306a36Sopenharmony_ci{ 68962306a36Sopenharmony_ci struct numa_topology *tp; 69062306a36Sopenharmony_ci int ret = -1; 69162306a36Sopenharmony_ci u32 i; 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci tp = numa_topology__new(); 69462306a36Sopenharmony_ci if (!tp) 69562306a36Sopenharmony_ci return -ENOMEM; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci ret = do_write(ff, &tp->nr, sizeof(u32)); 69862306a36Sopenharmony_ci if (ret < 0) 69962306a36Sopenharmony_ci goto err; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci for (i = 0; i < tp->nr; i++) { 70262306a36Sopenharmony_ci struct numa_topology_node *n = &tp->nodes[i]; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci ret = do_write(ff, &n->node, sizeof(u32)); 70562306a36Sopenharmony_ci if (ret < 0) 70662306a36Sopenharmony_ci goto err; 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_ci ret = do_write(ff, &n->mem_total, sizeof(u64)); 70962306a36Sopenharmony_ci if (ret) 71062306a36Sopenharmony_ci goto err; 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci ret = do_write(ff, &n->mem_free, sizeof(u64)); 71362306a36Sopenharmony_ci if (ret) 71462306a36Sopenharmony_ci goto err; 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci ret = do_write_string(ff, n->cpus); 71762306a36Sopenharmony_ci if (ret < 0) 71862306a36Sopenharmony_ci goto err; 71962306a36Sopenharmony_ci } 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci ret = 0; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_cierr: 72462306a36Sopenharmony_ci numa_topology__delete(tp); 72562306a36Sopenharmony_ci return ret; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci/* 72962306a36Sopenharmony_ci * File format: 73062306a36Sopenharmony_ci * 73162306a36Sopenharmony_ci * struct pmu_mappings { 73262306a36Sopenharmony_ci * u32 pmu_num; 73362306a36Sopenharmony_ci * struct pmu_map { 73462306a36Sopenharmony_ci * u32 type; 73562306a36Sopenharmony_ci * char name[]; 73662306a36Sopenharmony_ci * }[pmu_num]; 73762306a36Sopenharmony_ci * }; 73862306a36Sopenharmony_ci */ 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_cistatic int write_pmu_mappings(struct feat_fd *ff, 74162306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci struct perf_pmu *pmu = NULL; 74462306a36Sopenharmony_ci u32 pmu_num = 0; 74562306a36Sopenharmony_ci int ret; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci /* 74862306a36Sopenharmony_ci * Do a first pass to count number of pmu to avoid lseek so this 74962306a36Sopenharmony_ci * works in pipe mode as well. 75062306a36Sopenharmony_ci */ 75162306a36Sopenharmony_ci while ((pmu = perf_pmus__scan(pmu))) 75262306a36Sopenharmony_ci pmu_num++; 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_ci ret = do_write(ff, &pmu_num, sizeof(pmu_num)); 75562306a36Sopenharmony_ci if (ret < 0) 75662306a36Sopenharmony_ci return ret; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci while ((pmu = perf_pmus__scan(pmu))) { 75962306a36Sopenharmony_ci ret = do_write(ff, &pmu->type, sizeof(pmu->type)); 76062306a36Sopenharmony_ci if (ret < 0) 76162306a36Sopenharmony_ci return ret; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci ret = do_write_string(ff, pmu->name); 76462306a36Sopenharmony_ci if (ret < 0) 76562306a36Sopenharmony_ci return ret; 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci return 0; 76962306a36Sopenharmony_ci} 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci/* 77262306a36Sopenharmony_ci * File format: 77362306a36Sopenharmony_ci * 77462306a36Sopenharmony_ci * struct group_descs { 77562306a36Sopenharmony_ci * u32 nr_groups; 77662306a36Sopenharmony_ci * struct group_desc { 77762306a36Sopenharmony_ci * char name[]; 77862306a36Sopenharmony_ci * u32 leader_idx; 77962306a36Sopenharmony_ci * u32 nr_members; 78062306a36Sopenharmony_ci * }[nr_groups]; 78162306a36Sopenharmony_ci * }; 78262306a36Sopenharmony_ci */ 78362306a36Sopenharmony_cistatic int write_group_desc(struct feat_fd *ff, 78462306a36Sopenharmony_ci struct evlist *evlist) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci u32 nr_groups = evlist__nr_groups(evlist); 78762306a36Sopenharmony_ci struct evsel *evsel; 78862306a36Sopenharmony_ci int ret; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci ret = do_write(ff, &nr_groups, sizeof(nr_groups)); 79162306a36Sopenharmony_ci if (ret < 0) 79262306a36Sopenharmony_ci return ret; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 79562306a36Sopenharmony_ci if (evsel__is_group_leader(evsel) && evsel->core.nr_members > 1) { 79662306a36Sopenharmony_ci const char *name = evsel->group_name ?: "{anon_group}"; 79762306a36Sopenharmony_ci u32 leader_idx = evsel->core.idx; 79862306a36Sopenharmony_ci u32 nr_members = evsel->core.nr_members; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci ret = do_write_string(ff, name); 80162306a36Sopenharmony_ci if (ret < 0) 80262306a36Sopenharmony_ci return ret; 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci ret = do_write(ff, &leader_idx, sizeof(leader_idx)); 80562306a36Sopenharmony_ci if (ret < 0) 80662306a36Sopenharmony_ci return ret; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci ret = do_write(ff, &nr_members, sizeof(nr_members)); 80962306a36Sopenharmony_ci if (ret < 0) 81062306a36Sopenharmony_ci return ret; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci return 0; 81462306a36Sopenharmony_ci} 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci/* 81762306a36Sopenharmony_ci * Return the CPU id as a raw string. 81862306a36Sopenharmony_ci * 81962306a36Sopenharmony_ci * Each architecture should provide a more precise id string that 82062306a36Sopenharmony_ci * can be use to match the architecture's "mapfile". 82162306a36Sopenharmony_ci */ 82262306a36Sopenharmony_cichar * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused) 82362306a36Sopenharmony_ci{ 82462306a36Sopenharmony_ci return NULL; 82562306a36Sopenharmony_ci} 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci/* Return zero when the cpuid from the mapfile.csv matches the 82862306a36Sopenharmony_ci * cpuid string generated on this platform. 82962306a36Sopenharmony_ci * Otherwise return non-zero. 83062306a36Sopenharmony_ci */ 83162306a36Sopenharmony_ciint __weak strcmp_cpuid_str(const char *mapcpuid, const char *cpuid) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci regex_t re; 83462306a36Sopenharmony_ci regmatch_t pmatch[1]; 83562306a36Sopenharmony_ci int match; 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci if (regcomp(&re, mapcpuid, REG_EXTENDED) != 0) { 83862306a36Sopenharmony_ci /* Warn unable to generate match particular string. */ 83962306a36Sopenharmony_ci pr_info("Invalid regular expression %s\n", mapcpuid); 84062306a36Sopenharmony_ci return 1; 84162306a36Sopenharmony_ci } 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci match = !regexec(&re, cpuid, 1, pmatch, 0); 84462306a36Sopenharmony_ci regfree(&re); 84562306a36Sopenharmony_ci if (match) { 84662306a36Sopenharmony_ci size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* Verify the entire string matched. */ 84962306a36Sopenharmony_ci if (match_len == strlen(cpuid)) 85062306a36Sopenharmony_ci return 0; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci return 1; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci/* 85662306a36Sopenharmony_ci * default get_cpuid(): nothing gets recorded 85762306a36Sopenharmony_ci * actual implementation must be in arch/$(SRCARCH)/util/header.c 85862306a36Sopenharmony_ci */ 85962306a36Sopenharmony_ciint __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused) 86062306a36Sopenharmony_ci{ 86162306a36Sopenharmony_ci return ENOSYS; /* Not implemented */ 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic int write_cpuid(struct feat_fd *ff, 86562306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 86662306a36Sopenharmony_ci{ 86762306a36Sopenharmony_ci char buffer[64]; 86862306a36Sopenharmony_ci int ret; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci ret = get_cpuid(buffer, sizeof(buffer)); 87162306a36Sopenharmony_ci if (ret) 87262306a36Sopenharmony_ci return -1; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci return do_write_string(ff, buffer); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic int write_branch_stack(struct feat_fd *ff __maybe_unused, 87862306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 87962306a36Sopenharmony_ci{ 88062306a36Sopenharmony_ci return 0; 88162306a36Sopenharmony_ci} 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_cistatic int write_auxtrace(struct feat_fd *ff, 88462306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct perf_session *session; 88762306a36Sopenharmony_ci int err; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) 89062306a36Sopenharmony_ci return -1; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci err = auxtrace_index__write(ff->fd, &session->auxtrace_index); 89562306a36Sopenharmony_ci if (err < 0) 89662306a36Sopenharmony_ci pr_err("Failed to write auxtrace index\n"); 89762306a36Sopenharmony_ci return err; 89862306a36Sopenharmony_ci} 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_cistatic int write_clockid(struct feat_fd *ff, 90162306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 90262306a36Sopenharmony_ci{ 90362306a36Sopenharmony_ci return do_write(ff, &ff->ph->env.clock.clockid_res_ns, 90462306a36Sopenharmony_ci sizeof(ff->ph->env.clock.clockid_res_ns)); 90562306a36Sopenharmony_ci} 90662306a36Sopenharmony_ci 90762306a36Sopenharmony_cistatic int write_clock_data(struct feat_fd *ff, 90862306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 90962306a36Sopenharmony_ci{ 91062306a36Sopenharmony_ci u64 *data64; 91162306a36Sopenharmony_ci u32 data32; 91262306a36Sopenharmony_ci int ret; 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* version */ 91562306a36Sopenharmony_ci data32 = 1; 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci ret = do_write(ff, &data32, sizeof(data32)); 91862306a36Sopenharmony_ci if (ret < 0) 91962306a36Sopenharmony_ci return ret; 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci /* clockid */ 92262306a36Sopenharmony_ci data32 = ff->ph->env.clock.clockid; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci ret = do_write(ff, &data32, sizeof(data32)); 92562306a36Sopenharmony_ci if (ret < 0) 92662306a36Sopenharmony_ci return ret; 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci /* TOD ref time */ 92962306a36Sopenharmony_ci data64 = &ff->ph->env.clock.tod_ns; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci ret = do_write(ff, data64, sizeof(*data64)); 93262306a36Sopenharmony_ci if (ret < 0) 93362306a36Sopenharmony_ci return ret; 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci /* clockid ref time */ 93662306a36Sopenharmony_ci data64 = &ff->ph->env.clock.clockid_ns; 93762306a36Sopenharmony_ci 93862306a36Sopenharmony_ci return do_write(ff, data64, sizeof(*data64)); 93962306a36Sopenharmony_ci} 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_cistatic int write_hybrid_topology(struct feat_fd *ff, 94262306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 94362306a36Sopenharmony_ci{ 94462306a36Sopenharmony_ci struct hybrid_topology *tp; 94562306a36Sopenharmony_ci int ret; 94662306a36Sopenharmony_ci u32 i; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci tp = hybrid_topology__new(); 94962306a36Sopenharmony_ci if (!tp) 95062306a36Sopenharmony_ci return -ENOENT; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci ret = do_write(ff, &tp->nr, sizeof(u32)); 95362306a36Sopenharmony_ci if (ret < 0) 95462306a36Sopenharmony_ci goto err; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci for (i = 0; i < tp->nr; i++) { 95762306a36Sopenharmony_ci struct hybrid_topology_node *n = &tp->nodes[i]; 95862306a36Sopenharmony_ci 95962306a36Sopenharmony_ci ret = do_write_string(ff, n->pmu_name); 96062306a36Sopenharmony_ci if (ret < 0) 96162306a36Sopenharmony_ci goto err; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci ret = do_write_string(ff, n->cpus); 96462306a36Sopenharmony_ci if (ret < 0) 96562306a36Sopenharmony_ci goto err; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci ret = 0; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_cierr: 97162306a36Sopenharmony_ci hybrid_topology__delete(tp); 97262306a36Sopenharmony_ci return ret; 97362306a36Sopenharmony_ci} 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_cistatic int write_dir_format(struct feat_fd *ff, 97662306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 97762306a36Sopenharmony_ci{ 97862306a36Sopenharmony_ci struct perf_session *session; 97962306a36Sopenharmony_ci struct perf_data *data; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 98262306a36Sopenharmony_ci data = session->data; 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci if (WARN_ON(!perf_data__is_dir(data))) 98562306a36Sopenharmony_ci return -1; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci return do_write(ff, &data->dir.version, sizeof(data->dir.version)); 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci/* 99162306a36Sopenharmony_ci * Check whether a CPU is online 99262306a36Sopenharmony_ci * 99362306a36Sopenharmony_ci * Returns: 99462306a36Sopenharmony_ci * 1 -> if CPU is online 99562306a36Sopenharmony_ci * 0 -> if CPU is offline 99662306a36Sopenharmony_ci * -1 -> error case 99762306a36Sopenharmony_ci */ 99862306a36Sopenharmony_ciint is_cpu_online(unsigned int cpu) 99962306a36Sopenharmony_ci{ 100062306a36Sopenharmony_ci char *str; 100162306a36Sopenharmony_ci size_t strlen; 100262306a36Sopenharmony_ci char buf[256]; 100362306a36Sopenharmony_ci int status = -1; 100462306a36Sopenharmony_ci struct stat statbuf; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci snprintf(buf, sizeof(buf), 100762306a36Sopenharmony_ci "/sys/devices/system/cpu/cpu%d", cpu); 100862306a36Sopenharmony_ci if (stat(buf, &statbuf) != 0) 100962306a36Sopenharmony_ci return 0; 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci /* 101262306a36Sopenharmony_ci * Check if /sys/devices/system/cpu/cpux/online file 101362306a36Sopenharmony_ci * exists. Some cases cpu0 won't have online file since 101462306a36Sopenharmony_ci * it is not expected to be turned off generally. 101562306a36Sopenharmony_ci * In kernels without CONFIG_HOTPLUG_CPU, this 101662306a36Sopenharmony_ci * file won't exist 101762306a36Sopenharmony_ci */ 101862306a36Sopenharmony_ci snprintf(buf, sizeof(buf), 101962306a36Sopenharmony_ci "/sys/devices/system/cpu/cpu%d/online", cpu); 102062306a36Sopenharmony_ci if (stat(buf, &statbuf) != 0) 102162306a36Sopenharmony_ci return 1; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci /* 102462306a36Sopenharmony_ci * Read online file using sysfs__read_str. 102562306a36Sopenharmony_ci * If read or open fails, return -1. 102662306a36Sopenharmony_ci * If read succeeds, return value from file 102762306a36Sopenharmony_ci * which gets stored in "str" 102862306a36Sopenharmony_ci */ 102962306a36Sopenharmony_ci snprintf(buf, sizeof(buf), 103062306a36Sopenharmony_ci "devices/system/cpu/cpu%d/online", cpu); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci if (sysfs__read_str(buf, &str, &strlen) < 0) 103362306a36Sopenharmony_ci return status; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci status = atoi(str); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci free(str); 103862306a36Sopenharmony_ci return status; 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT 104262306a36Sopenharmony_cistatic int write_bpf_prog_info(struct feat_fd *ff, 104362306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 104462306a36Sopenharmony_ci{ 104562306a36Sopenharmony_ci struct perf_env *env = &ff->ph->env; 104662306a36Sopenharmony_ci struct rb_root *root; 104762306a36Sopenharmony_ci struct rb_node *next; 104862306a36Sopenharmony_ci int ret; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci down_read(&env->bpf_progs.lock); 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci ret = do_write(ff, &env->bpf_progs.infos_cnt, 105362306a36Sopenharmony_ci sizeof(env->bpf_progs.infos_cnt)); 105462306a36Sopenharmony_ci if (ret < 0) 105562306a36Sopenharmony_ci goto out; 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci root = &env->bpf_progs.infos; 105862306a36Sopenharmony_ci next = rb_first(root); 105962306a36Sopenharmony_ci while (next) { 106062306a36Sopenharmony_ci struct bpf_prog_info_node *node; 106162306a36Sopenharmony_ci size_t len; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci node = rb_entry(next, struct bpf_prog_info_node, rb_node); 106462306a36Sopenharmony_ci next = rb_next(&node->rb_node); 106562306a36Sopenharmony_ci len = sizeof(struct perf_bpil) + 106662306a36Sopenharmony_ci node->info_linear->data_len; 106762306a36Sopenharmony_ci 106862306a36Sopenharmony_ci /* before writing to file, translate address to offset */ 106962306a36Sopenharmony_ci bpil_addr_to_offs(node->info_linear); 107062306a36Sopenharmony_ci ret = do_write(ff, node->info_linear, len); 107162306a36Sopenharmony_ci /* 107262306a36Sopenharmony_ci * translate back to address even when do_write() fails, 107362306a36Sopenharmony_ci * so that this function never changes the data. 107462306a36Sopenharmony_ci */ 107562306a36Sopenharmony_ci bpil_offs_to_addr(node->info_linear); 107662306a36Sopenharmony_ci if (ret < 0) 107762306a36Sopenharmony_ci goto out; 107862306a36Sopenharmony_ci } 107962306a36Sopenharmony_ciout: 108062306a36Sopenharmony_ci up_read(&env->bpf_progs.lock); 108162306a36Sopenharmony_ci return ret; 108262306a36Sopenharmony_ci} 108362306a36Sopenharmony_ci 108462306a36Sopenharmony_cistatic int write_bpf_btf(struct feat_fd *ff, 108562306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 108662306a36Sopenharmony_ci{ 108762306a36Sopenharmony_ci struct perf_env *env = &ff->ph->env; 108862306a36Sopenharmony_ci struct rb_root *root; 108962306a36Sopenharmony_ci struct rb_node *next; 109062306a36Sopenharmony_ci int ret; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci down_read(&env->bpf_progs.lock); 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci ret = do_write(ff, &env->bpf_progs.btfs_cnt, 109562306a36Sopenharmony_ci sizeof(env->bpf_progs.btfs_cnt)); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci if (ret < 0) 109862306a36Sopenharmony_ci goto out; 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_ci root = &env->bpf_progs.btfs; 110162306a36Sopenharmony_ci next = rb_first(root); 110262306a36Sopenharmony_ci while (next) { 110362306a36Sopenharmony_ci struct btf_node *node; 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_ci node = rb_entry(next, struct btf_node, rb_node); 110662306a36Sopenharmony_ci next = rb_next(&node->rb_node); 110762306a36Sopenharmony_ci ret = do_write(ff, &node->id, 110862306a36Sopenharmony_ci sizeof(u32) * 2 + node->data_size); 110962306a36Sopenharmony_ci if (ret < 0) 111062306a36Sopenharmony_ci goto out; 111162306a36Sopenharmony_ci } 111262306a36Sopenharmony_ciout: 111362306a36Sopenharmony_ci up_read(&env->bpf_progs.lock); 111462306a36Sopenharmony_ci return ret; 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci#endif // HAVE_LIBBPF_SUPPORT 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_cistatic int cpu_cache_level__sort(const void *a, const void *b) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a; 112162306a36Sopenharmony_ci struct cpu_cache_level *cache_b = (struct cpu_cache_level *)b; 112262306a36Sopenharmony_ci 112362306a36Sopenharmony_ci return cache_a->level - cache_b->level; 112462306a36Sopenharmony_ci} 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_cistatic bool cpu_cache_level__cmp(struct cpu_cache_level *a, struct cpu_cache_level *b) 112762306a36Sopenharmony_ci{ 112862306a36Sopenharmony_ci if (a->level != b->level) 112962306a36Sopenharmony_ci return false; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (a->line_size != b->line_size) 113262306a36Sopenharmony_ci return false; 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci if (a->sets != b->sets) 113562306a36Sopenharmony_ci return false; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci if (a->ways != b->ways) 113862306a36Sopenharmony_ci return false; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci if (strcmp(a->type, b->type)) 114162306a36Sopenharmony_ci return false; 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_ci if (strcmp(a->size, b->size)) 114462306a36Sopenharmony_ci return false; 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci if (strcmp(a->map, b->map)) 114762306a36Sopenharmony_ci return false; 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci return true; 115062306a36Sopenharmony_ci} 115162306a36Sopenharmony_ci 115262306a36Sopenharmony_cistatic int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 level) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci char path[PATH_MAX], file[PATH_MAX]; 115562306a36Sopenharmony_ci struct stat st; 115662306a36Sopenharmony_ci size_t len; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level); 115962306a36Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path); 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci if (stat(file, &st)) 116262306a36Sopenharmony_ci return 1; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/level", path); 116562306a36Sopenharmony_ci if (sysfs__read_int(file, (int *) &cache->level)) 116662306a36Sopenharmony_ci return -1; 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/coherency_line_size", path); 116962306a36Sopenharmony_ci if (sysfs__read_int(file, (int *) &cache->line_size)) 117062306a36Sopenharmony_ci return -1; 117162306a36Sopenharmony_ci 117262306a36Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/number_of_sets", path); 117362306a36Sopenharmony_ci if (sysfs__read_int(file, (int *) &cache->sets)) 117462306a36Sopenharmony_ci return -1; 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path); 117762306a36Sopenharmony_ci if (sysfs__read_int(file, (int *) &cache->ways)) 117862306a36Sopenharmony_ci return -1; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/type", path); 118162306a36Sopenharmony_ci if (sysfs__read_str(file, &cache->type, &len)) 118262306a36Sopenharmony_ci return -1; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci cache->type[len] = 0; 118562306a36Sopenharmony_ci cache->type = strim(cache->type); 118662306a36Sopenharmony_ci 118762306a36Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/size", path); 118862306a36Sopenharmony_ci if (sysfs__read_str(file, &cache->size, &len)) { 118962306a36Sopenharmony_ci zfree(&cache->type); 119062306a36Sopenharmony_ci return -1; 119162306a36Sopenharmony_ci } 119262306a36Sopenharmony_ci 119362306a36Sopenharmony_ci cache->size[len] = 0; 119462306a36Sopenharmony_ci cache->size = strim(cache->size); 119562306a36Sopenharmony_ci 119662306a36Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path); 119762306a36Sopenharmony_ci if (sysfs__read_str(file, &cache->map, &len)) { 119862306a36Sopenharmony_ci zfree(&cache->size); 119962306a36Sopenharmony_ci zfree(&cache->type); 120062306a36Sopenharmony_ci return -1; 120162306a36Sopenharmony_ci } 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci cache->map[len] = 0; 120462306a36Sopenharmony_ci cache->map = strim(cache->map); 120562306a36Sopenharmony_ci return 0; 120662306a36Sopenharmony_ci} 120762306a36Sopenharmony_ci 120862306a36Sopenharmony_cistatic void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c) 120962306a36Sopenharmony_ci{ 121062306a36Sopenharmony_ci fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map); 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_ci/* 121462306a36Sopenharmony_ci * Build caches levels for a particular CPU from the data in 121562306a36Sopenharmony_ci * /sys/devices/system/cpu/cpu<cpu>/cache/ 121662306a36Sopenharmony_ci * The cache level data is stored in caches[] from index at 121762306a36Sopenharmony_ci * *cntp. 121862306a36Sopenharmony_ci */ 121962306a36Sopenharmony_ciint build_caches_for_cpu(u32 cpu, struct cpu_cache_level caches[], u32 *cntp) 122062306a36Sopenharmony_ci{ 122162306a36Sopenharmony_ci u16 level; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci for (level = 0; level < MAX_CACHE_LVL; level++) { 122462306a36Sopenharmony_ci struct cpu_cache_level c; 122562306a36Sopenharmony_ci int err; 122662306a36Sopenharmony_ci u32 i; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci err = cpu_cache_level__read(&c, cpu, level); 122962306a36Sopenharmony_ci if (err < 0) 123062306a36Sopenharmony_ci return err; 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (err == 1) 123362306a36Sopenharmony_ci break; 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci for (i = 0; i < *cntp; i++) { 123662306a36Sopenharmony_ci if (cpu_cache_level__cmp(&c, &caches[i])) 123762306a36Sopenharmony_ci break; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (i == *cntp) { 124162306a36Sopenharmony_ci caches[*cntp] = c; 124262306a36Sopenharmony_ci *cntp = *cntp + 1; 124362306a36Sopenharmony_ci } else 124462306a36Sopenharmony_ci cpu_cache_level__free(&c); 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci return 0; 124862306a36Sopenharmony_ci} 124962306a36Sopenharmony_ci 125062306a36Sopenharmony_cistatic int build_caches(struct cpu_cache_level caches[], u32 *cntp) 125162306a36Sopenharmony_ci{ 125262306a36Sopenharmony_ci u32 nr, cpu, cnt = 0; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci nr = cpu__max_cpu().cpu; 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci for (cpu = 0; cpu < nr; cpu++) { 125762306a36Sopenharmony_ci int ret = build_caches_for_cpu(cpu, caches, &cnt); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci if (ret) 126062306a36Sopenharmony_ci return ret; 126162306a36Sopenharmony_ci } 126262306a36Sopenharmony_ci *cntp = cnt; 126362306a36Sopenharmony_ci return 0; 126462306a36Sopenharmony_ci} 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_cistatic int write_cache(struct feat_fd *ff, 126762306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 126862306a36Sopenharmony_ci{ 126962306a36Sopenharmony_ci u32 max_caches = cpu__max_cpu().cpu * MAX_CACHE_LVL; 127062306a36Sopenharmony_ci struct cpu_cache_level caches[max_caches]; 127162306a36Sopenharmony_ci u32 cnt = 0, i, version = 1; 127262306a36Sopenharmony_ci int ret; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci ret = build_caches(caches, &cnt); 127562306a36Sopenharmony_ci if (ret) 127662306a36Sopenharmony_ci goto out; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci qsort(&caches, cnt, sizeof(struct cpu_cache_level), cpu_cache_level__sort); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci ret = do_write(ff, &version, sizeof(u32)); 128162306a36Sopenharmony_ci if (ret < 0) 128262306a36Sopenharmony_ci goto out; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci ret = do_write(ff, &cnt, sizeof(u32)); 128562306a36Sopenharmony_ci if (ret < 0) 128662306a36Sopenharmony_ci goto out; 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 128962306a36Sopenharmony_ci struct cpu_cache_level *c = &caches[i]; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci #define _W(v) \ 129262306a36Sopenharmony_ci ret = do_write(ff, &c->v, sizeof(u32)); \ 129362306a36Sopenharmony_ci if (ret < 0) \ 129462306a36Sopenharmony_ci goto out; 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_ci _W(level) 129762306a36Sopenharmony_ci _W(line_size) 129862306a36Sopenharmony_ci _W(sets) 129962306a36Sopenharmony_ci _W(ways) 130062306a36Sopenharmony_ci #undef _W 130162306a36Sopenharmony_ci 130262306a36Sopenharmony_ci #define _W(v) \ 130362306a36Sopenharmony_ci ret = do_write_string(ff, (const char *) c->v); \ 130462306a36Sopenharmony_ci if (ret < 0) \ 130562306a36Sopenharmony_ci goto out; 130662306a36Sopenharmony_ci 130762306a36Sopenharmony_ci _W(type) 130862306a36Sopenharmony_ci _W(size) 130962306a36Sopenharmony_ci _W(map) 131062306a36Sopenharmony_ci #undef _W 131162306a36Sopenharmony_ci } 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ciout: 131462306a36Sopenharmony_ci for (i = 0; i < cnt; i++) 131562306a36Sopenharmony_ci cpu_cache_level__free(&caches[i]); 131662306a36Sopenharmony_ci return ret; 131762306a36Sopenharmony_ci} 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_cistatic int write_stat(struct feat_fd *ff __maybe_unused, 132062306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 132162306a36Sopenharmony_ci{ 132262306a36Sopenharmony_ci return 0; 132362306a36Sopenharmony_ci} 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_cistatic int write_sample_time(struct feat_fd *ff, 132662306a36Sopenharmony_ci struct evlist *evlist) 132762306a36Sopenharmony_ci{ 132862306a36Sopenharmony_ci int ret; 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci ret = do_write(ff, &evlist->first_sample_time, 133162306a36Sopenharmony_ci sizeof(evlist->first_sample_time)); 133262306a36Sopenharmony_ci if (ret < 0) 133362306a36Sopenharmony_ci return ret; 133462306a36Sopenharmony_ci 133562306a36Sopenharmony_ci return do_write(ff, &evlist->last_sample_time, 133662306a36Sopenharmony_ci sizeof(evlist->last_sample_time)); 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_cistatic int memory_node__read(struct memory_node *n, unsigned long idx) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci unsigned int phys, size = 0; 134362306a36Sopenharmony_ci char path[PATH_MAX]; 134462306a36Sopenharmony_ci struct dirent *ent; 134562306a36Sopenharmony_ci DIR *dir; 134662306a36Sopenharmony_ci 134762306a36Sopenharmony_ci#define for_each_memory(mem, dir) \ 134862306a36Sopenharmony_ci while ((ent = readdir(dir))) \ 134962306a36Sopenharmony_ci if (strcmp(ent->d_name, ".") && \ 135062306a36Sopenharmony_ci strcmp(ent->d_name, "..") && \ 135162306a36Sopenharmony_ci sscanf(ent->d_name, "memory%u", &mem) == 1) 135262306a36Sopenharmony_ci 135362306a36Sopenharmony_ci scnprintf(path, PATH_MAX, 135462306a36Sopenharmony_ci "%s/devices/system/node/node%lu", 135562306a36Sopenharmony_ci sysfs__mountpoint(), idx); 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_ci dir = opendir(path); 135862306a36Sopenharmony_ci if (!dir) { 135962306a36Sopenharmony_ci pr_warning("failed: can't open memory sysfs data\n"); 136062306a36Sopenharmony_ci return -1; 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci for_each_memory(phys, dir) { 136462306a36Sopenharmony_ci size = max(phys, size); 136562306a36Sopenharmony_ci } 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci size++; 136862306a36Sopenharmony_ci 136962306a36Sopenharmony_ci n->set = bitmap_zalloc(size); 137062306a36Sopenharmony_ci if (!n->set) { 137162306a36Sopenharmony_ci closedir(dir); 137262306a36Sopenharmony_ci return -ENOMEM; 137362306a36Sopenharmony_ci } 137462306a36Sopenharmony_ci 137562306a36Sopenharmony_ci n->node = idx; 137662306a36Sopenharmony_ci n->size = size; 137762306a36Sopenharmony_ci 137862306a36Sopenharmony_ci rewinddir(dir); 137962306a36Sopenharmony_ci 138062306a36Sopenharmony_ci for_each_memory(phys, dir) { 138162306a36Sopenharmony_ci __set_bit(phys, n->set); 138262306a36Sopenharmony_ci } 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_ci closedir(dir); 138562306a36Sopenharmony_ci return 0; 138662306a36Sopenharmony_ci} 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_cistatic void memory_node__delete_nodes(struct memory_node *nodesp, u64 cnt) 138962306a36Sopenharmony_ci{ 139062306a36Sopenharmony_ci for (u64 i = 0; i < cnt; i++) 139162306a36Sopenharmony_ci bitmap_free(nodesp[i].set); 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci free(nodesp); 139462306a36Sopenharmony_ci} 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_cistatic int memory_node__sort(const void *a, const void *b) 139762306a36Sopenharmony_ci{ 139862306a36Sopenharmony_ci const struct memory_node *na = a; 139962306a36Sopenharmony_ci const struct memory_node *nb = b; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci return na->node - nb->node; 140262306a36Sopenharmony_ci} 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_cistatic int build_mem_topology(struct memory_node **nodesp, u64 *cntp) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci char path[PATH_MAX]; 140762306a36Sopenharmony_ci struct dirent *ent; 140862306a36Sopenharmony_ci DIR *dir; 140962306a36Sopenharmony_ci int ret = 0; 141062306a36Sopenharmony_ci size_t cnt = 0, size = 0; 141162306a36Sopenharmony_ci struct memory_node *nodes = NULL; 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci scnprintf(path, PATH_MAX, "%s/devices/system/node/", 141462306a36Sopenharmony_ci sysfs__mountpoint()); 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci dir = opendir(path); 141762306a36Sopenharmony_ci if (!dir) { 141862306a36Sopenharmony_ci pr_debug2("%s: couldn't read %s, does this arch have topology information?\n", 141962306a36Sopenharmony_ci __func__, path); 142062306a36Sopenharmony_ci return -1; 142162306a36Sopenharmony_ci } 142262306a36Sopenharmony_ci 142362306a36Sopenharmony_ci while (!ret && (ent = readdir(dir))) { 142462306a36Sopenharmony_ci unsigned int idx; 142562306a36Sopenharmony_ci int r; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci if (!strcmp(ent->d_name, ".") || 142862306a36Sopenharmony_ci !strcmp(ent->d_name, "..")) 142962306a36Sopenharmony_ci continue; 143062306a36Sopenharmony_ci 143162306a36Sopenharmony_ci r = sscanf(ent->d_name, "node%u", &idx); 143262306a36Sopenharmony_ci if (r != 1) 143362306a36Sopenharmony_ci continue; 143462306a36Sopenharmony_ci 143562306a36Sopenharmony_ci if (cnt >= size) { 143662306a36Sopenharmony_ci struct memory_node *new_nodes = 143762306a36Sopenharmony_ci reallocarray(nodes, cnt + 4, sizeof(*nodes)); 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_ci if (!new_nodes) { 144062306a36Sopenharmony_ci pr_err("Failed to write MEM_TOPOLOGY, size %zd nodes\n", size); 144162306a36Sopenharmony_ci ret = -ENOMEM; 144262306a36Sopenharmony_ci goto out; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci nodes = new_nodes; 144562306a36Sopenharmony_ci size += 4; 144662306a36Sopenharmony_ci } 144762306a36Sopenharmony_ci ret = memory_node__read(&nodes[cnt], idx); 144862306a36Sopenharmony_ci if (!ret) 144962306a36Sopenharmony_ci cnt += 1; 145062306a36Sopenharmony_ci } 145162306a36Sopenharmony_ciout: 145262306a36Sopenharmony_ci closedir(dir); 145362306a36Sopenharmony_ci if (!ret) { 145462306a36Sopenharmony_ci *cntp = cnt; 145562306a36Sopenharmony_ci *nodesp = nodes; 145662306a36Sopenharmony_ci qsort(nodes, cnt, sizeof(nodes[0]), memory_node__sort); 145762306a36Sopenharmony_ci } else 145862306a36Sopenharmony_ci memory_node__delete_nodes(nodes, cnt); 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci return ret; 146162306a36Sopenharmony_ci} 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci/* 146462306a36Sopenharmony_ci * The MEM_TOPOLOGY holds physical memory map for every 146562306a36Sopenharmony_ci * node in system. The format of data is as follows: 146662306a36Sopenharmony_ci * 146762306a36Sopenharmony_ci * 0 - version | for future changes 146862306a36Sopenharmony_ci * 8 - block_size_bytes | /sys/devices/system/memory/block_size_bytes 146962306a36Sopenharmony_ci * 16 - count | number of nodes 147062306a36Sopenharmony_ci * 147162306a36Sopenharmony_ci * For each node we store map of physical indexes for 147262306a36Sopenharmony_ci * each node: 147362306a36Sopenharmony_ci * 147462306a36Sopenharmony_ci * 32 - node id | node index 147562306a36Sopenharmony_ci * 40 - size | size of bitmap 147662306a36Sopenharmony_ci * 48 - bitmap | bitmap of memory indexes that belongs to node 147762306a36Sopenharmony_ci */ 147862306a36Sopenharmony_cistatic int write_mem_topology(struct feat_fd *ff __maybe_unused, 147962306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 148062306a36Sopenharmony_ci{ 148162306a36Sopenharmony_ci struct memory_node *nodes = NULL; 148262306a36Sopenharmony_ci u64 bsize, version = 1, i, nr = 0; 148362306a36Sopenharmony_ci int ret; 148462306a36Sopenharmony_ci 148562306a36Sopenharmony_ci ret = sysfs__read_xll("devices/system/memory/block_size_bytes", 148662306a36Sopenharmony_ci (unsigned long long *) &bsize); 148762306a36Sopenharmony_ci if (ret) 148862306a36Sopenharmony_ci return ret; 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci ret = build_mem_topology(&nodes, &nr); 149162306a36Sopenharmony_ci if (ret) 149262306a36Sopenharmony_ci return ret; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci ret = do_write(ff, &version, sizeof(version)); 149562306a36Sopenharmony_ci if (ret < 0) 149662306a36Sopenharmony_ci goto out; 149762306a36Sopenharmony_ci 149862306a36Sopenharmony_ci ret = do_write(ff, &bsize, sizeof(bsize)); 149962306a36Sopenharmony_ci if (ret < 0) 150062306a36Sopenharmony_ci goto out; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_ci ret = do_write(ff, &nr, sizeof(nr)); 150362306a36Sopenharmony_ci if (ret < 0) 150462306a36Sopenharmony_ci goto out; 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 150762306a36Sopenharmony_ci struct memory_node *n = &nodes[i]; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci #define _W(v) \ 151062306a36Sopenharmony_ci ret = do_write(ff, &n->v, sizeof(n->v)); \ 151162306a36Sopenharmony_ci if (ret < 0) \ 151262306a36Sopenharmony_ci goto out; 151362306a36Sopenharmony_ci 151462306a36Sopenharmony_ci _W(node) 151562306a36Sopenharmony_ci _W(size) 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci #undef _W 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci ret = do_write_bitmap(ff, n->set, n->size); 152062306a36Sopenharmony_ci if (ret < 0) 152162306a36Sopenharmony_ci goto out; 152262306a36Sopenharmony_ci } 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ciout: 152562306a36Sopenharmony_ci memory_node__delete_nodes(nodes, nr); 152662306a36Sopenharmony_ci return ret; 152762306a36Sopenharmony_ci} 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_cistatic int write_compressed(struct feat_fd *ff __maybe_unused, 153062306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 153162306a36Sopenharmony_ci{ 153262306a36Sopenharmony_ci int ret; 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci ret = do_write(ff, &(ff->ph->env.comp_ver), sizeof(ff->ph->env.comp_ver)); 153562306a36Sopenharmony_ci if (ret) 153662306a36Sopenharmony_ci return ret; 153762306a36Sopenharmony_ci 153862306a36Sopenharmony_ci ret = do_write(ff, &(ff->ph->env.comp_type), sizeof(ff->ph->env.comp_type)); 153962306a36Sopenharmony_ci if (ret) 154062306a36Sopenharmony_ci return ret; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_ci ret = do_write(ff, &(ff->ph->env.comp_level), sizeof(ff->ph->env.comp_level)); 154362306a36Sopenharmony_ci if (ret) 154462306a36Sopenharmony_ci return ret; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci ret = do_write(ff, &(ff->ph->env.comp_ratio), sizeof(ff->ph->env.comp_ratio)); 154762306a36Sopenharmony_ci if (ret) 154862306a36Sopenharmony_ci return ret; 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci return do_write(ff, &(ff->ph->env.comp_mmap_len), sizeof(ff->ph->env.comp_mmap_len)); 155162306a36Sopenharmony_ci} 155262306a36Sopenharmony_ci 155362306a36Sopenharmony_cistatic int __write_pmu_caps(struct feat_fd *ff, struct perf_pmu *pmu, 155462306a36Sopenharmony_ci bool write_pmu) 155562306a36Sopenharmony_ci{ 155662306a36Sopenharmony_ci struct perf_pmu_caps *caps = NULL; 155762306a36Sopenharmony_ci int ret; 155862306a36Sopenharmony_ci 155962306a36Sopenharmony_ci ret = do_write(ff, &pmu->nr_caps, sizeof(pmu->nr_caps)); 156062306a36Sopenharmony_ci if (ret < 0) 156162306a36Sopenharmony_ci return ret; 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_ci list_for_each_entry(caps, &pmu->caps, list) { 156462306a36Sopenharmony_ci ret = do_write_string(ff, caps->name); 156562306a36Sopenharmony_ci if (ret < 0) 156662306a36Sopenharmony_ci return ret; 156762306a36Sopenharmony_ci 156862306a36Sopenharmony_ci ret = do_write_string(ff, caps->value); 156962306a36Sopenharmony_ci if (ret < 0) 157062306a36Sopenharmony_ci return ret; 157162306a36Sopenharmony_ci } 157262306a36Sopenharmony_ci 157362306a36Sopenharmony_ci if (write_pmu) { 157462306a36Sopenharmony_ci ret = do_write_string(ff, pmu->name); 157562306a36Sopenharmony_ci if (ret < 0) 157662306a36Sopenharmony_ci return ret; 157762306a36Sopenharmony_ci } 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci return ret; 158062306a36Sopenharmony_ci} 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_cistatic int write_cpu_pmu_caps(struct feat_fd *ff, 158362306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 158462306a36Sopenharmony_ci{ 158562306a36Sopenharmony_ci struct perf_pmu *cpu_pmu = perf_pmus__find("cpu"); 158662306a36Sopenharmony_ci int ret; 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci if (!cpu_pmu) 158962306a36Sopenharmony_ci return -ENOENT; 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_ci ret = perf_pmu__caps_parse(cpu_pmu); 159262306a36Sopenharmony_ci if (ret < 0) 159362306a36Sopenharmony_ci return ret; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci return __write_pmu_caps(ff, cpu_pmu, false); 159662306a36Sopenharmony_ci} 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_cistatic int write_pmu_caps(struct feat_fd *ff, 159962306a36Sopenharmony_ci struct evlist *evlist __maybe_unused) 160062306a36Sopenharmony_ci{ 160162306a36Sopenharmony_ci struct perf_pmu *pmu = NULL; 160262306a36Sopenharmony_ci int nr_pmu = 0; 160362306a36Sopenharmony_ci int ret; 160462306a36Sopenharmony_ci 160562306a36Sopenharmony_ci while ((pmu = perf_pmus__scan(pmu))) { 160662306a36Sopenharmony_ci if (!strcmp(pmu->name, "cpu")) { 160762306a36Sopenharmony_ci /* 160862306a36Sopenharmony_ci * The "cpu" PMU is special and covered by 160962306a36Sopenharmony_ci * HEADER_CPU_PMU_CAPS. Note, core PMUs are 161062306a36Sopenharmony_ci * counted/written here for ARM, s390 and Intel hybrid. 161162306a36Sopenharmony_ci */ 161262306a36Sopenharmony_ci continue; 161362306a36Sopenharmony_ci } 161462306a36Sopenharmony_ci if (perf_pmu__caps_parse(pmu) <= 0) 161562306a36Sopenharmony_ci continue; 161662306a36Sopenharmony_ci nr_pmu++; 161762306a36Sopenharmony_ci } 161862306a36Sopenharmony_ci 161962306a36Sopenharmony_ci ret = do_write(ff, &nr_pmu, sizeof(nr_pmu)); 162062306a36Sopenharmony_ci if (ret < 0) 162162306a36Sopenharmony_ci return ret; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci if (!nr_pmu) 162462306a36Sopenharmony_ci return 0; 162562306a36Sopenharmony_ci 162662306a36Sopenharmony_ci /* 162762306a36Sopenharmony_ci * Note older perf tools assume core PMUs come first, this is a property 162862306a36Sopenharmony_ci * of perf_pmus__scan. 162962306a36Sopenharmony_ci */ 163062306a36Sopenharmony_ci pmu = NULL; 163162306a36Sopenharmony_ci while ((pmu = perf_pmus__scan(pmu))) { 163262306a36Sopenharmony_ci if (!strcmp(pmu->name, "cpu")) { 163362306a36Sopenharmony_ci /* Skip as above. */ 163462306a36Sopenharmony_ci continue; 163562306a36Sopenharmony_ci } 163662306a36Sopenharmony_ci if (perf_pmu__caps_parse(pmu) <= 0) 163762306a36Sopenharmony_ci continue; 163862306a36Sopenharmony_ci ret = __write_pmu_caps(ff, pmu, true); 163962306a36Sopenharmony_ci if (ret < 0) 164062306a36Sopenharmony_ci return ret; 164162306a36Sopenharmony_ci } 164262306a36Sopenharmony_ci return 0; 164362306a36Sopenharmony_ci} 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_cistatic void print_hostname(struct feat_fd *ff, FILE *fp) 164662306a36Sopenharmony_ci{ 164762306a36Sopenharmony_ci fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname); 164862306a36Sopenharmony_ci} 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_cistatic void print_osrelease(struct feat_fd *ff, FILE *fp) 165162306a36Sopenharmony_ci{ 165262306a36Sopenharmony_ci fprintf(fp, "# os release : %s\n", ff->ph->env.os_release); 165362306a36Sopenharmony_ci} 165462306a36Sopenharmony_ci 165562306a36Sopenharmony_cistatic void print_arch(struct feat_fd *ff, FILE *fp) 165662306a36Sopenharmony_ci{ 165762306a36Sopenharmony_ci fprintf(fp, "# arch : %s\n", ff->ph->env.arch); 165862306a36Sopenharmony_ci} 165962306a36Sopenharmony_ci 166062306a36Sopenharmony_cistatic void print_cpudesc(struct feat_fd *ff, FILE *fp) 166162306a36Sopenharmony_ci{ 166262306a36Sopenharmony_ci fprintf(fp, "# cpudesc : %s\n", ff->ph->env.cpu_desc); 166362306a36Sopenharmony_ci} 166462306a36Sopenharmony_ci 166562306a36Sopenharmony_cistatic void print_nrcpus(struct feat_fd *ff, FILE *fp) 166662306a36Sopenharmony_ci{ 166762306a36Sopenharmony_ci fprintf(fp, "# nrcpus online : %u\n", ff->ph->env.nr_cpus_online); 166862306a36Sopenharmony_ci fprintf(fp, "# nrcpus avail : %u\n", ff->ph->env.nr_cpus_avail); 166962306a36Sopenharmony_ci} 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_cistatic void print_version(struct feat_fd *ff, FILE *fp) 167262306a36Sopenharmony_ci{ 167362306a36Sopenharmony_ci fprintf(fp, "# perf version : %s\n", ff->ph->env.version); 167462306a36Sopenharmony_ci} 167562306a36Sopenharmony_ci 167662306a36Sopenharmony_cistatic void print_cmdline(struct feat_fd *ff, FILE *fp) 167762306a36Sopenharmony_ci{ 167862306a36Sopenharmony_ci int nr, i; 167962306a36Sopenharmony_ci 168062306a36Sopenharmony_ci nr = ff->ph->env.nr_cmdline; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci fprintf(fp, "# cmdline : "); 168362306a36Sopenharmony_ci 168462306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 168562306a36Sopenharmony_ci char *argv_i = strdup(ff->ph->env.cmdline_argv[i]); 168662306a36Sopenharmony_ci if (!argv_i) { 168762306a36Sopenharmony_ci fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]); 168862306a36Sopenharmony_ci } else { 168962306a36Sopenharmony_ci char *mem = argv_i; 169062306a36Sopenharmony_ci do { 169162306a36Sopenharmony_ci char *quote = strchr(argv_i, '\''); 169262306a36Sopenharmony_ci if (!quote) 169362306a36Sopenharmony_ci break; 169462306a36Sopenharmony_ci *quote++ = '\0'; 169562306a36Sopenharmony_ci fprintf(fp, "%s\\\'", argv_i); 169662306a36Sopenharmony_ci argv_i = quote; 169762306a36Sopenharmony_ci } while (1); 169862306a36Sopenharmony_ci fprintf(fp, "%s ", argv_i); 169962306a36Sopenharmony_ci free(mem); 170062306a36Sopenharmony_ci } 170162306a36Sopenharmony_ci } 170262306a36Sopenharmony_ci fputc('\n', fp); 170362306a36Sopenharmony_ci} 170462306a36Sopenharmony_ci 170562306a36Sopenharmony_cistatic void print_cpu_topology(struct feat_fd *ff, FILE *fp) 170662306a36Sopenharmony_ci{ 170762306a36Sopenharmony_ci struct perf_header *ph = ff->ph; 170862306a36Sopenharmony_ci int cpu_nr = ph->env.nr_cpus_avail; 170962306a36Sopenharmony_ci int nr, i; 171062306a36Sopenharmony_ci char *str; 171162306a36Sopenharmony_ci 171262306a36Sopenharmony_ci nr = ph->env.nr_sibling_cores; 171362306a36Sopenharmony_ci str = ph->env.sibling_cores; 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 171662306a36Sopenharmony_ci fprintf(fp, "# sibling sockets : %s\n", str); 171762306a36Sopenharmony_ci str += strlen(str) + 1; 171862306a36Sopenharmony_ci } 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci if (ph->env.nr_sibling_dies) { 172162306a36Sopenharmony_ci nr = ph->env.nr_sibling_dies; 172262306a36Sopenharmony_ci str = ph->env.sibling_dies; 172362306a36Sopenharmony_ci 172462306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 172562306a36Sopenharmony_ci fprintf(fp, "# sibling dies : %s\n", str); 172662306a36Sopenharmony_ci str += strlen(str) + 1; 172762306a36Sopenharmony_ci } 172862306a36Sopenharmony_ci } 172962306a36Sopenharmony_ci 173062306a36Sopenharmony_ci nr = ph->env.nr_sibling_threads; 173162306a36Sopenharmony_ci str = ph->env.sibling_threads; 173262306a36Sopenharmony_ci 173362306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 173462306a36Sopenharmony_ci fprintf(fp, "# sibling threads : %s\n", str); 173562306a36Sopenharmony_ci str += strlen(str) + 1; 173662306a36Sopenharmony_ci } 173762306a36Sopenharmony_ci 173862306a36Sopenharmony_ci if (ph->env.nr_sibling_dies) { 173962306a36Sopenharmony_ci if (ph->env.cpu != NULL) { 174062306a36Sopenharmony_ci for (i = 0; i < cpu_nr; i++) 174162306a36Sopenharmony_ci fprintf(fp, "# CPU %d: Core ID %d, " 174262306a36Sopenharmony_ci "Die ID %d, Socket ID %d\n", 174362306a36Sopenharmony_ci i, ph->env.cpu[i].core_id, 174462306a36Sopenharmony_ci ph->env.cpu[i].die_id, 174562306a36Sopenharmony_ci ph->env.cpu[i].socket_id); 174662306a36Sopenharmony_ci } else 174762306a36Sopenharmony_ci fprintf(fp, "# Core ID, Die ID and Socket ID " 174862306a36Sopenharmony_ci "information is not available\n"); 174962306a36Sopenharmony_ci } else { 175062306a36Sopenharmony_ci if (ph->env.cpu != NULL) { 175162306a36Sopenharmony_ci for (i = 0; i < cpu_nr; i++) 175262306a36Sopenharmony_ci fprintf(fp, "# CPU %d: Core ID %d, " 175362306a36Sopenharmony_ci "Socket ID %d\n", 175462306a36Sopenharmony_ci i, ph->env.cpu[i].core_id, 175562306a36Sopenharmony_ci ph->env.cpu[i].socket_id); 175662306a36Sopenharmony_ci } else 175762306a36Sopenharmony_ci fprintf(fp, "# Core ID and Socket ID " 175862306a36Sopenharmony_ci "information is not available\n"); 175962306a36Sopenharmony_ci } 176062306a36Sopenharmony_ci} 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_cistatic void print_clockid(struct feat_fd *ff, FILE *fp) 176362306a36Sopenharmony_ci{ 176462306a36Sopenharmony_ci fprintf(fp, "# clockid frequency: %"PRIu64" MHz\n", 176562306a36Sopenharmony_ci ff->ph->env.clock.clockid_res_ns * 1000); 176662306a36Sopenharmony_ci} 176762306a36Sopenharmony_ci 176862306a36Sopenharmony_cistatic void print_clock_data(struct feat_fd *ff, FILE *fp) 176962306a36Sopenharmony_ci{ 177062306a36Sopenharmony_ci struct timespec clockid_ns; 177162306a36Sopenharmony_ci char tstr[64], date[64]; 177262306a36Sopenharmony_ci struct timeval tod_ns; 177362306a36Sopenharmony_ci clockid_t clockid; 177462306a36Sopenharmony_ci struct tm ltime; 177562306a36Sopenharmony_ci u64 ref; 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci if (!ff->ph->env.clock.enabled) { 177862306a36Sopenharmony_ci fprintf(fp, "# reference time disabled\n"); 177962306a36Sopenharmony_ci return; 178062306a36Sopenharmony_ci } 178162306a36Sopenharmony_ci 178262306a36Sopenharmony_ci /* Compute TOD time. */ 178362306a36Sopenharmony_ci ref = ff->ph->env.clock.tod_ns; 178462306a36Sopenharmony_ci tod_ns.tv_sec = ref / NSEC_PER_SEC; 178562306a36Sopenharmony_ci ref -= tod_ns.tv_sec * NSEC_PER_SEC; 178662306a36Sopenharmony_ci tod_ns.tv_usec = ref / NSEC_PER_USEC; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci /* Compute clockid time. */ 178962306a36Sopenharmony_ci ref = ff->ph->env.clock.clockid_ns; 179062306a36Sopenharmony_ci clockid_ns.tv_sec = ref / NSEC_PER_SEC; 179162306a36Sopenharmony_ci ref -= clockid_ns.tv_sec * NSEC_PER_SEC; 179262306a36Sopenharmony_ci clockid_ns.tv_nsec = ref; 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci clockid = ff->ph->env.clock.clockid; 179562306a36Sopenharmony_ci 179662306a36Sopenharmony_ci if (localtime_r(&tod_ns.tv_sec, <ime) == NULL) 179762306a36Sopenharmony_ci snprintf(tstr, sizeof(tstr), "<error>"); 179862306a36Sopenharmony_ci else { 179962306a36Sopenharmony_ci strftime(date, sizeof(date), "%F %T", <ime); 180062306a36Sopenharmony_ci scnprintf(tstr, sizeof(tstr), "%s.%06d", 180162306a36Sopenharmony_ci date, (int) tod_ns.tv_usec); 180262306a36Sopenharmony_ci } 180362306a36Sopenharmony_ci 180462306a36Sopenharmony_ci fprintf(fp, "# clockid: %s (%u)\n", clockid_name(clockid), clockid); 180562306a36Sopenharmony_ci fprintf(fp, "# reference time: %s = %ld.%06d (TOD) = %ld.%09ld (%s)\n", 180662306a36Sopenharmony_ci tstr, (long) tod_ns.tv_sec, (int) tod_ns.tv_usec, 180762306a36Sopenharmony_ci (long) clockid_ns.tv_sec, clockid_ns.tv_nsec, 180862306a36Sopenharmony_ci clockid_name(clockid)); 180962306a36Sopenharmony_ci} 181062306a36Sopenharmony_ci 181162306a36Sopenharmony_cistatic void print_hybrid_topology(struct feat_fd *ff, FILE *fp) 181262306a36Sopenharmony_ci{ 181362306a36Sopenharmony_ci int i; 181462306a36Sopenharmony_ci struct hybrid_node *n; 181562306a36Sopenharmony_ci 181662306a36Sopenharmony_ci fprintf(fp, "# hybrid cpu system:\n"); 181762306a36Sopenharmony_ci for (i = 0; i < ff->ph->env.nr_hybrid_nodes; i++) { 181862306a36Sopenharmony_ci n = &ff->ph->env.hybrid_nodes[i]; 181962306a36Sopenharmony_ci fprintf(fp, "# %s cpu list : %s\n", n->pmu_name, n->cpus); 182062306a36Sopenharmony_ci } 182162306a36Sopenharmony_ci} 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_cistatic void print_dir_format(struct feat_fd *ff, FILE *fp) 182462306a36Sopenharmony_ci{ 182562306a36Sopenharmony_ci struct perf_session *session; 182662306a36Sopenharmony_ci struct perf_data *data; 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 182962306a36Sopenharmony_ci data = session->data; 183062306a36Sopenharmony_ci 183162306a36Sopenharmony_ci fprintf(fp, "# directory data version : %"PRIu64"\n", data->dir.version); 183262306a36Sopenharmony_ci} 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT 183562306a36Sopenharmony_cistatic void print_bpf_prog_info(struct feat_fd *ff, FILE *fp) 183662306a36Sopenharmony_ci{ 183762306a36Sopenharmony_ci struct perf_env *env = &ff->ph->env; 183862306a36Sopenharmony_ci struct rb_root *root; 183962306a36Sopenharmony_ci struct rb_node *next; 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci down_read(&env->bpf_progs.lock); 184262306a36Sopenharmony_ci 184362306a36Sopenharmony_ci root = &env->bpf_progs.infos; 184462306a36Sopenharmony_ci next = rb_first(root); 184562306a36Sopenharmony_ci 184662306a36Sopenharmony_ci while (next) { 184762306a36Sopenharmony_ci struct bpf_prog_info_node *node; 184862306a36Sopenharmony_ci 184962306a36Sopenharmony_ci node = rb_entry(next, struct bpf_prog_info_node, rb_node); 185062306a36Sopenharmony_ci next = rb_next(&node->rb_node); 185162306a36Sopenharmony_ci 185262306a36Sopenharmony_ci __bpf_event__print_bpf_prog_info(&node->info_linear->info, 185362306a36Sopenharmony_ci env, fp); 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci up_read(&env->bpf_progs.lock); 185762306a36Sopenharmony_ci} 185862306a36Sopenharmony_ci 185962306a36Sopenharmony_cistatic void print_bpf_btf(struct feat_fd *ff, FILE *fp) 186062306a36Sopenharmony_ci{ 186162306a36Sopenharmony_ci struct perf_env *env = &ff->ph->env; 186262306a36Sopenharmony_ci struct rb_root *root; 186362306a36Sopenharmony_ci struct rb_node *next; 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci down_read(&env->bpf_progs.lock); 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci root = &env->bpf_progs.btfs; 186862306a36Sopenharmony_ci next = rb_first(root); 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_ci while (next) { 187162306a36Sopenharmony_ci struct btf_node *node; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci node = rb_entry(next, struct btf_node, rb_node); 187462306a36Sopenharmony_ci next = rb_next(&node->rb_node); 187562306a36Sopenharmony_ci fprintf(fp, "# btf info of id %u\n", node->id); 187662306a36Sopenharmony_ci } 187762306a36Sopenharmony_ci 187862306a36Sopenharmony_ci up_read(&env->bpf_progs.lock); 187962306a36Sopenharmony_ci} 188062306a36Sopenharmony_ci#endif // HAVE_LIBBPF_SUPPORT 188162306a36Sopenharmony_ci 188262306a36Sopenharmony_cistatic void free_event_desc(struct evsel *events) 188362306a36Sopenharmony_ci{ 188462306a36Sopenharmony_ci struct evsel *evsel; 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci if (!events) 188762306a36Sopenharmony_ci return; 188862306a36Sopenharmony_ci 188962306a36Sopenharmony_ci for (evsel = events; evsel->core.attr.size; evsel++) { 189062306a36Sopenharmony_ci zfree(&evsel->name); 189162306a36Sopenharmony_ci zfree(&evsel->core.id); 189262306a36Sopenharmony_ci } 189362306a36Sopenharmony_ci 189462306a36Sopenharmony_ci free(events); 189562306a36Sopenharmony_ci} 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_cistatic bool perf_attr_check(struct perf_event_attr *attr) 189862306a36Sopenharmony_ci{ 189962306a36Sopenharmony_ci if (attr->__reserved_1 || attr->__reserved_2 || attr->__reserved_3) { 190062306a36Sopenharmony_ci pr_warning("Reserved bits are set unexpectedly. " 190162306a36Sopenharmony_ci "Please update perf tool.\n"); 190262306a36Sopenharmony_ci return false; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci if (attr->sample_type & ~(PERF_SAMPLE_MAX-1)) { 190662306a36Sopenharmony_ci pr_warning("Unknown sample type (0x%llx) is detected. " 190762306a36Sopenharmony_ci "Please update perf tool.\n", 190862306a36Sopenharmony_ci attr->sample_type); 190962306a36Sopenharmony_ci return false; 191062306a36Sopenharmony_ci } 191162306a36Sopenharmony_ci 191262306a36Sopenharmony_ci if (attr->read_format & ~(PERF_FORMAT_MAX-1)) { 191362306a36Sopenharmony_ci pr_warning("Unknown read format (0x%llx) is detected. " 191462306a36Sopenharmony_ci "Please update perf tool.\n", 191562306a36Sopenharmony_ci attr->read_format); 191662306a36Sopenharmony_ci return false; 191762306a36Sopenharmony_ci } 191862306a36Sopenharmony_ci 191962306a36Sopenharmony_ci if ((attr->sample_type & PERF_SAMPLE_BRANCH_STACK) && 192062306a36Sopenharmony_ci (attr->branch_sample_type & ~(PERF_SAMPLE_BRANCH_MAX-1))) { 192162306a36Sopenharmony_ci pr_warning("Unknown branch sample type (0x%llx) is detected. " 192262306a36Sopenharmony_ci "Please update perf tool.\n", 192362306a36Sopenharmony_ci attr->branch_sample_type); 192462306a36Sopenharmony_ci 192562306a36Sopenharmony_ci return false; 192662306a36Sopenharmony_ci } 192762306a36Sopenharmony_ci 192862306a36Sopenharmony_ci return true; 192962306a36Sopenharmony_ci} 193062306a36Sopenharmony_ci 193162306a36Sopenharmony_cistatic struct evsel *read_event_desc(struct feat_fd *ff) 193262306a36Sopenharmony_ci{ 193362306a36Sopenharmony_ci struct evsel *evsel, *events = NULL; 193462306a36Sopenharmony_ci u64 *id; 193562306a36Sopenharmony_ci void *buf = NULL; 193662306a36Sopenharmony_ci u32 nre, sz, nr, i, j; 193762306a36Sopenharmony_ci size_t msz; 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_ci /* number of events */ 194062306a36Sopenharmony_ci if (do_read_u32(ff, &nre)) 194162306a36Sopenharmony_ci goto error; 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci if (do_read_u32(ff, &sz)) 194462306a36Sopenharmony_ci goto error; 194562306a36Sopenharmony_ci 194662306a36Sopenharmony_ci /* buffer to hold on file attr struct */ 194762306a36Sopenharmony_ci buf = malloc(sz); 194862306a36Sopenharmony_ci if (!buf) 194962306a36Sopenharmony_ci goto error; 195062306a36Sopenharmony_ci 195162306a36Sopenharmony_ci /* the last event terminates with evsel->core.attr.size == 0: */ 195262306a36Sopenharmony_ci events = calloc(nre + 1, sizeof(*events)); 195362306a36Sopenharmony_ci if (!events) 195462306a36Sopenharmony_ci goto error; 195562306a36Sopenharmony_ci 195662306a36Sopenharmony_ci msz = sizeof(evsel->core.attr); 195762306a36Sopenharmony_ci if (sz < msz) 195862306a36Sopenharmony_ci msz = sz; 195962306a36Sopenharmony_ci 196062306a36Sopenharmony_ci for (i = 0, evsel = events; i < nre; evsel++, i++) { 196162306a36Sopenharmony_ci evsel->core.idx = i; 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci /* 196462306a36Sopenharmony_ci * must read entire on-file attr struct to 196562306a36Sopenharmony_ci * sync up with layout. 196662306a36Sopenharmony_ci */ 196762306a36Sopenharmony_ci if (__do_read(ff, buf, sz)) 196862306a36Sopenharmony_ci goto error; 196962306a36Sopenharmony_ci 197062306a36Sopenharmony_ci if (ff->ph->needs_swap) 197162306a36Sopenharmony_ci perf_event__attr_swap(buf); 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci memcpy(&evsel->core.attr, buf, msz); 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci if (!perf_attr_check(&evsel->core.attr)) 197662306a36Sopenharmony_ci goto error; 197762306a36Sopenharmony_ci 197862306a36Sopenharmony_ci if (do_read_u32(ff, &nr)) 197962306a36Sopenharmony_ci goto error; 198062306a36Sopenharmony_ci 198162306a36Sopenharmony_ci if (ff->ph->needs_swap) 198262306a36Sopenharmony_ci evsel->needs_swap = true; 198362306a36Sopenharmony_ci 198462306a36Sopenharmony_ci evsel->name = do_read_string(ff); 198562306a36Sopenharmony_ci if (!evsel->name) 198662306a36Sopenharmony_ci goto error; 198762306a36Sopenharmony_ci 198862306a36Sopenharmony_ci if (!nr) 198962306a36Sopenharmony_ci continue; 199062306a36Sopenharmony_ci 199162306a36Sopenharmony_ci id = calloc(nr, sizeof(*id)); 199262306a36Sopenharmony_ci if (!id) 199362306a36Sopenharmony_ci goto error; 199462306a36Sopenharmony_ci evsel->core.ids = nr; 199562306a36Sopenharmony_ci evsel->core.id = id; 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci for (j = 0 ; j < nr; j++) { 199862306a36Sopenharmony_ci if (do_read_u64(ff, id)) 199962306a36Sopenharmony_ci goto error; 200062306a36Sopenharmony_ci id++; 200162306a36Sopenharmony_ci } 200262306a36Sopenharmony_ci } 200362306a36Sopenharmony_ciout: 200462306a36Sopenharmony_ci free(buf); 200562306a36Sopenharmony_ci return events; 200662306a36Sopenharmony_cierror: 200762306a36Sopenharmony_ci free_event_desc(events); 200862306a36Sopenharmony_ci events = NULL; 200962306a36Sopenharmony_ci goto out; 201062306a36Sopenharmony_ci} 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_cistatic int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, 201362306a36Sopenharmony_ci void *priv __maybe_unused) 201462306a36Sopenharmony_ci{ 201562306a36Sopenharmony_ci return fprintf(fp, ", %s = %s", name, val); 201662306a36Sopenharmony_ci} 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_cistatic void print_event_desc(struct feat_fd *ff, FILE *fp) 201962306a36Sopenharmony_ci{ 202062306a36Sopenharmony_ci struct evsel *evsel, *events; 202162306a36Sopenharmony_ci u32 j; 202262306a36Sopenharmony_ci u64 *id; 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci if (ff->events) 202562306a36Sopenharmony_ci events = ff->events; 202662306a36Sopenharmony_ci else 202762306a36Sopenharmony_ci events = read_event_desc(ff); 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_ci if (!events) { 203062306a36Sopenharmony_ci fprintf(fp, "# event desc: not available or unable to read\n"); 203162306a36Sopenharmony_ci return; 203262306a36Sopenharmony_ci } 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci for (evsel = events; evsel->core.attr.size; evsel++) { 203562306a36Sopenharmony_ci fprintf(fp, "# event : name = %s, ", evsel->name); 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci if (evsel->core.ids) { 203862306a36Sopenharmony_ci fprintf(fp, ", id = {"); 203962306a36Sopenharmony_ci for (j = 0, id = evsel->core.id; j < evsel->core.ids; j++, id++) { 204062306a36Sopenharmony_ci if (j) 204162306a36Sopenharmony_ci fputc(',', fp); 204262306a36Sopenharmony_ci fprintf(fp, " %"PRIu64, *id); 204362306a36Sopenharmony_ci } 204462306a36Sopenharmony_ci fprintf(fp, " }"); 204562306a36Sopenharmony_ci } 204662306a36Sopenharmony_ci 204762306a36Sopenharmony_ci perf_event_attr__fprintf(fp, &evsel->core.attr, __desc_attr__fprintf, NULL); 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci fputc('\n', fp); 205062306a36Sopenharmony_ci } 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci free_event_desc(events); 205362306a36Sopenharmony_ci ff->events = NULL; 205462306a36Sopenharmony_ci} 205562306a36Sopenharmony_ci 205662306a36Sopenharmony_cistatic void print_total_mem(struct feat_fd *ff, FILE *fp) 205762306a36Sopenharmony_ci{ 205862306a36Sopenharmony_ci fprintf(fp, "# total memory : %llu kB\n", ff->ph->env.total_mem); 205962306a36Sopenharmony_ci} 206062306a36Sopenharmony_ci 206162306a36Sopenharmony_cistatic void print_numa_topology(struct feat_fd *ff, FILE *fp) 206262306a36Sopenharmony_ci{ 206362306a36Sopenharmony_ci int i; 206462306a36Sopenharmony_ci struct numa_node *n; 206562306a36Sopenharmony_ci 206662306a36Sopenharmony_ci for (i = 0; i < ff->ph->env.nr_numa_nodes; i++) { 206762306a36Sopenharmony_ci n = &ff->ph->env.numa_nodes[i]; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci fprintf(fp, "# node%u meminfo : total = %"PRIu64" kB," 207062306a36Sopenharmony_ci " free = %"PRIu64" kB\n", 207162306a36Sopenharmony_ci n->node, n->mem_total, n->mem_free); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci fprintf(fp, "# node%u cpu list : ", n->node); 207462306a36Sopenharmony_ci cpu_map__fprintf(n->map, fp); 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci} 207762306a36Sopenharmony_ci 207862306a36Sopenharmony_cistatic void print_cpuid(struct feat_fd *ff, FILE *fp) 207962306a36Sopenharmony_ci{ 208062306a36Sopenharmony_ci fprintf(fp, "# cpuid : %s\n", ff->ph->env.cpuid); 208162306a36Sopenharmony_ci} 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_cistatic void print_branch_stack(struct feat_fd *ff __maybe_unused, FILE *fp) 208462306a36Sopenharmony_ci{ 208562306a36Sopenharmony_ci fprintf(fp, "# contains samples with branch stack\n"); 208662306a36Sopenharmony_ci} 208762306a36Sopenharmony_ci 208862306a36Sopenharmony_cistatic void print_auxtrace(struct feat_fd *ff __maybe_unused, FILE *fp) 208962306a36Sopenharmony_ci{ 209062306a36Sopenharmony_ci fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n"); 209162306a36Sopenharmony_ci} 209262306a36Sopenharmony_ci 209362306a36Sopenharmony_cistatic void print_stat(struct feat_fd *ff __maybe_unused, FILE *fp) 209462306a36Sopenharmony_ci{ 209562306a36Sopenharmony_ci fprintf(fp, "# contains stat data\n"); 209662306a36Sopenharmony_ci} 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_cistatic void print_cache(struct feat_fd *ff, FILE *fp __maybe_unused) 209962306a36Sopenharmony_ci{ 210062306a36Sopenharmony_ci int i; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci fprintf(fp, "# CPU cache info:\n"); 210362306a36Sopenharmony_ci for (i = 0; i < ff->ph->env.caches_cnt; i++) { 210462306a36Sopenharmony_ci fprintf(fp, "# "); 210562306a36Sopenharmony_ci cpu_cache_level__fprintf(fp, &ff->ph->env.caches[i]); 210662306a36Sopenharmony_ci } 210762306a36Sopenharmony_ci} 210862306a36Sopenharmony_ci 210962306a36Sopenharmony_cistatic void print_compressed(struct feat_fd *ff, FILE *fp) 211062306a36Sopenharmony_ci{ 211162306a36Sopenharmony_ci fprintf(fp, "# compressed : %s, level = %d, ratio = %d\n", 211262306a36Sopenharmony_ci ff->ph->env.comp_type == PERF_COMP_ZSTD ? "Zstd" : "Unknown", 211362306a36Sopenharmony_ci ff->ph->env.comp_level, ff->ph->env.comp_ratio); 211462306a36Sopenharmony_ci} 211562306a36Sopenharmony_ci 211662306a36Sopenharmony_cistatic void __print_pmu_caps(FILE *fp, int nr_caps, char **caps, char *pmu_name) 211762306a36Sopenharmony_ci{ 211862306a36Sopenharmony_ci const char *delimiter = ""; 211962306a36Sopenharmony_ci int i; 212062306a36Sopenharmony_ci 212162306a36Sopenharmony_ci if (!nr_caps) { 212262306a36Sopenharmony_ci fprintf(fp, "# %s pmu capabilities: not available\n", pmu_name); 212362306a36Sopenharmony_ci return; 212462306a36Sopenharmony_ci } 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci fprintf(fp, "# %s pmu capabilities: ", pmu_name); 212762306a36Sopenharmony_ci for (i = 0; i < nr_caps; i++) { 212862306a36Sopenharmony_ci fprintf(fp, "%s%s", delimiter, caps[i]); 212962306a36Sopenharmony_ci delimiter = ", "; 213062306a36Sopenharmony_ci } 213162306a36Sopenharmony_ci 213262306a36Sopenharmony_ci fprintf(fp, "\n"); 213362306a36Sopenharmony_ci} 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_cistatic void print_cpu_pmu_caps(struct feat_fd *ff, FILE *fp) 213662306a36Sopenharmony_ci{ 213762306a36Sopenharmony_ci __print_pmu_caps(fp, ff->ph->env.nr_cpu_pmu_caps, 213862306a36Sopenharmony_ci ff->ph->env.cpu_pmu_caps, (char *)"cpu"); 213962306a36Sopenharmony_ci} 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_cistatic void print_pmu_caps(struct feat_fd *ff, FILE *fp) 214262306a36Sopenharmony_ci{ 214362306a36Sopenharmony_ci struct pmu_caps *pmu_caps; 214462306a36Sopenharmony_ci 214562306a36Sopenharmony_ci for (int i = 0; i < ff->ph->env.nr_pmus_with_caps; i++) { 214662306a36Sopenharmony_ci pmu_caps = &ff->ph->env.pmu_caps[i]; 214762306a36Sopenharmony_ci __print_pmu_caps(fp, pmu_caps->nr_caps, pmu_caps->caps, 214862306a36Sopenharmony_ci pmu_caps->pmu_name); 214962306a36Sopenharmony_ci } 215062306a36Sopenharmony_ci} 215162306a36Sopenharmony_ci 215262306a36Sopenharmony_cistatic void print_pmu_mappings(struct feat_fd *ff, FILE *fp) 215362306a36Sopenharmony_ci{ 215462306a36Sopenharmony_ci const char *delimiter = "# pmu mappings: "; 215562306a36Sopenharmony_ci char *str, *tmp; 215662306a36Sopenharmony_ci u32 pmu_num; 215762306a36Sopenharmony_ci u32 type; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci pmu_num = ff->ph->env.nr_pmu_mappings; 216062306a36Sopenharmony_ci if (!pmu_num) { 216162306a36Sopenharmony_ci fprintf(fp, "# pmu mappings: not available\n"); 216262306a36Sopenharmony_ci return; 216362306a36Sopenharmony_ci } 216462306a36Sopenharmony_ci 216562306a36Sopenharmony_ci str = ff->ph->env.pmu_mappings; 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci while (pmu_num) { 216862306a36Sopenharmony_ci type = strtoul(str, &tmp, 0); 216962306a36Sopenharmony_ci if (*tmp != ':') 217062306a36Sopenharmony_ci goto error; 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci str = tmp + 1; 217362306a36Sopenharmony_ci fprintf(fp, "%s%s = %" PRIu32, delimiter, str, type); 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci delimiter = ", "; 217662306a36Sopenharmony_ci str += strlen(str) + 1; 217762306a36Sopenharmony_ci pmu_num--; 217862306a36Sopenharmony_ci } 217962306a36Sopenharmony_ci 218062306a36Sopenharmony_ci fprintf(fp, "\n"); 218162306a36Sopenharmony_ci 218262306a36Sopenharmony_ci if (!pmu_num) 218362306a36Sopenharmony_ci return; 218462306a36Sopenharmony_cierror: 218562306a36Sopenharmony_ci fprintf(fp, "# pmu mappings: unable to read\n"); 218662306a36Sopenharmony_ci} 218762306a36Sopenharmony_ci 218862306a36Sopenharmony_cistatic void print_group_desc(struct feat_fd *ff, FILE *fp) 218962306a36Sopenharmony_ci{ 219062306a36Sopenharmony_ci struct perf_session *session; 219162306a36Sopenharmony_ci struct evsel *evsel; 219262306a36Sopenharmony_ci u32 nr = 0; 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 219562306a36Sopenharmony_ci 219662306a36Sopenharmony_ci evlist__for_each_entry(session->evlist, evsel) { 219762306a36Sopenharmony_ci if (evsel__is_group_leader(evsel) && evsel->core.nr_members > 1) { 219862306a36Sopenharmony_ci fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", evsel__name(evsel)); 219962306a36Sopenharmony_ci 220062306a36Sopenharmony_ci nr = evsel->core.nr_members - 1; 220162306a36Sopenharmony_ci } else if (nr) { 220262306a36Sopenharmony_ci fprintf(fp, ",%s", evsel__name(evsel)); 220362306a36Sopenharmony_ci 220462306a36Sopenharmony_ci if (--nr == 0) 220562306a36Sopenharmony_ci fprintf(fp, "}\n"); 220662306a36Sopenharmony_ci } 220762306a36Sopenharmony_ci } 220862306a36Sopenharmony_ci} 220962306a36Sopenharmony_ci 221062306a36Sopenharmony_cistatic void print_sample_time(struct feat_fd *ff, FILE *fp) 221162306a36Sopenharmony_ci{ 221262306a36Sopenharmony_ci struct perf_session *session; 221362306a36Sopenharmony_ci char time_buf[32]; 221462306a36Sopenharmony_ci double d; 221562306a36Sopenharmony_ci 221662306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_ci timestamp__scnprintf_usec(session->evlist->first_sample_time, 221962306a36Sopenharmony_ci time_buf, sizeof(time_buf)); 222062306a36Sopenharmony_ci fprintf(fp, "# time of first sample : %s\n", time_buf); 222162306a36Sopenharmony_ci 222262306a36Sopenharmony_ci timestamp__scnprintf_usec(session->evlist->last_sample_time, 222362306a36Sopenharmony_ci time_buf, sizeof(time_buf)); 222462306a36Sopenharmony_ci fprintf(fp, "# time of last sample : %s\n", time_buf); 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci d = (double)(session->evlist->last_sample_time - 222762306a36Sopenharmony_ci session->evlist->first_sample_time) / NSEC_PER_MSEC; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci fprintf(fp, "# sample duration : %10.3f ms\n", d); 223062306a36Sopenharmony_ci} 223162306a36Sopenharmony_ci 223262306a36Sopenharmony_cistatic void memory_node__fprintf(struct memory_node *n, 223362306a36Sopenharmony_ci unsigned long long bsize, FILE *fp) 223462306a36Sopenharmony_ci{ 223562306a36Sopenharmony_ci char buf_map[100], buf_size[50]; 223662306a36Sopenharmony_ci unsigned long long size; 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci size = bsize * bitmap_weight(n->set, n->size); 223962306a36Sopenharmony_ci unit_number__scnprintf(buf_size, 50, size); 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci bitmap_scnprintf(n->set, n->size, buf_map, 100); 224262306a36Sopenharmony_ci fprintf(fp, "# %3" PRIu64 " [%s]: %s\n", n->node, buf_size, buf_map); 224362306a36Sopenharmony_ci} 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_cistatic void print_mem_topology(struct feat_fd *ff, FILE *fp) 224662306a36Sopenharmony_ci{ 224762306a36Sopenharmony_ci struct memory_node *nodes; 224862306a36Sopenharmony_ci int i, nr; 224962306a36Sopenharmony_ci 225062306a36Sopenharmony_ci nodes = ff->ph->env.memory_nodes; 225162306a36Sopenharmony_ci nr = ff->ph->env.nr_memory_nodes; 225262306a36Sopenharmony_ci 225362306a36Sopenharmony_ci fprintf(fp, "# memory nodes (nr %d, block size 0x%llx):\n", 225462306a36Sopenharmony_ci nr, ff->ph->env.memory_bsize); 225562306a36Sopenharmony_ci 225662306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 225762306a36Sopenharmony_ci memory_node__fprintf(&nodes[i], ff->ph->env.memory_bsize, fp); 225862306a36Sopenharmony_ci } 225962306a36Sopenharmony_ci} 226062306a36Sopenharmony_ci 226162306a36Sopenharmony_cistatic int __event_process_build_id(struct perf_record_header_build_id *bev, 226262306a36Sopenharmony_ci char *filename, 226362306a36Sopenharmony_ci struct perf_session *session) 226462306a36Sopenharmony_ci{ 226562306a36Sopenharmony_ci int err = -1; 226662306a36Sopenharmony_ci struct machine *machine; 226762306a36Sopenharmony_ci u16 cpumode; 226862306a36Sopenharmony_ci struct dso *dso; 226962306a36Sopenharmony_ci enum dso_space_type dso_space; 227062306a36Sopenharmony_ci 227162306a36Sopenharmony_ci machine = perf_session__findnew_machine(session, bev->pid); 227262306a36Sopenharmony_ci if (!machine) 227362306a36Sopenharmony_ci goto out; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci cpumode = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci switch (cpumode) { 227862306a36Sopenharmony_ci case PERF_RECORD_MISC_KERNEL: 227962306a36Sopenharmony_ci dso_space = DSO_SPACE__KERNEL; 228062306a36Sopenharmony_ci break; 228162306a36Sopenharmony_ci case PERF_RECORD_MISC_GUEST_KERNEL: 228262306a36Sopenharmony_ci dso_space = DSO_SPACE__KERNEL_GUEST; 228362306a36Sopenharmony_ci break; 228462306a36Sopenharmony_ci case PERF_RECORD_MISC_USER: 228562306a36Sopenharmony_ci case PERF_RECORD_MISC_GUEST_USER: 228662306a36Sopenharmony_ci dso_space = DSO_SPACE__USER; 228762306a36Sopenharmony_ci break; 228862306a36Sopenharmony_ci default: 228962306a36Sopenharmony_ci goto out; 229062306a36Sopenharmony_ci } 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci dso = machine__findnew_dso(machine, filename); 229362306a36Sopenharmony_ci if (dso != NULL) { 229462306a36Sopenharmony_ci char sbuild_id[SBUILD_ID_SIZE]; 229562306a36Sopenharmony_ci struct build_id bid; 229662306a36Sopenharmony_ci size_t size = BUILD_ID_SIZE; 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci if (bev->header.misc & PERF_RECORD_MISC_BUILD_ID_SIZE) 229962306a36Sopenharmony_ci size = bev->size; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci build_id__init(&bid, bev->data, size); 230262306a36Sopenharmony_ci dso__set_build_id(dso, &bid); 230362306a36Sopenharmony_ci dso->header_build_id = 1; 230462306a36Sopenharmony_ci 230562306a36Sopenharmony_ci if (dso_space != DSO_SPACE__USER) { 230662306a36Sopenharmony_ci struct kmod_path m = { .name = NULL, }; 230762306a36Sopenharmony_ci 230862306a36Sopenharmony_ci if (!kmod_path__parse_name(&m, filename) && m.kmod) 230962306a36Sopenharmony_ci dso__set_module_info(dso, &m, machine); 231062306a36Sopenharmony_ci 231162306a36Sopenharmony_ci dso->kernel = dso_space; 231262306a36Sopenharmony_ci free(m.name); 231362306a36Sopenharmony_ci } 231462306a36Sopenharmony_ci 231562306a36Sopenharmony_ci build_id__sprintf(&dso->bid, sbuild_id); 231662306a36Sopenharmony_ci pr_debug("build id event received for %s: %s [%zu]\n", 231762306a36Sopenharmony_ci dso->long_name, sbuild_id, size); 231862306a36Sopenharmony_ci dso__put(dso); 231962306a36Sopenharmony_ci } 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci err = 0; 232262306a36Sopenharmony_ciout: 232362306a36Sopenharmony_ci return err; 232462306a36Sopenharmony_ci} 232562306a36Sopenharmony_ci 232662306a36Sopenharmony_cistatic int perf_header__read_build_ids_abi_quirk(struct perf_header *header, 232762306a36Sopenharmony_ci int input, u64 offset, u64 size) 232862306a36Sopenharmony_ci{ 232962306a36Sopenharmony_ci struct perf_session *session = container_of(header, struct perf_session, header); 233062306a36Sopenharmony_ci struct { 233162306a36Sopenharmony_ci struct perf_event_header header; 233262306a36Sopenharmony_ci u8 build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))]; 233362306a36Sopenharmony_ci char filename[0]; 233462306a36Sopenharmony_ci } old_bev; 233562306a36Sopenharmony_ci struct perf_record_header_build_id bev; 233662306a36Sopenharmony_ci char filename[PATH_MAX]; 233762306a36Sopenharmony_ci u64 limit = offset + size; 233862306a36Sopenharmony_ci 233962306a36Sopenharmony_ci while (offset < limit) { 234062306a36Sopenharmony_ci ssize_t len; 234162306a36Sopenharmony_ci 234262306a36Sopenharmony_ci if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) 234362306a36Sopenharmony_ci return -1; 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci if (header->needs_swap) 234662306a36Sopenharmony_ci perf_event_header__bswap(&old_bev.header); 234762306a36Sopenharmony_ci 234862306a36Sopenharmony_ci len = old_bev.header.size - sizeof(old_bev); 234962306a36Sopenharmony_ci if (readn(input, filename, len) != len) 235062306a36Sopenharmony_ci return -1; 235162306a36Sopenharmony_ci 235262306a36Sopenharmony_ci bev.header = old_bev.header; 235362306a36Sopenharmony_ci 235462306a36Sopenharmony_ci /* 235562306a36Sopenharmony_ci * As the pid is the missing value, we need to fill 235662306a36Sopenharmony_ci * it properly. The header.misc value give us nice hint. 235762306a36Sopenharmony_ci */ 235862306a36Sopenharmony_ci bev.pid = HOST_KERNEL_ID; 235962306a36Sopenharmony_ci if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER || 236062306a36Sopenharmony_ci bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL) 236162306a36Sopenharmony_ci bev.pid = DEFAULT_GUEST_KERNEL_ID; 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); 236462306a36Sopenharmony_ci __event_process_build_id(&bev, filename, session); 236562306a36Sopenharmony_ci 236662306a36Sopenharmony_ci offset += bev.header.size; 236762306a36Sopenharmony_ci } 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci return 0; 237062306a36Sopenharmony_ci} 237162306a36Sopenharmony_ci 237262306a36Sopenharmony_cistatic int perf_header__read_build_ids(struct perf_header *header, 237362306a36Sopenharmony_ci int input, u64 offset, u64 size) 237462306a36Sopenharmony_ci{ 237562306a36Sopenharmony_ci struct perf_session *session = container_of(header, struct perf_session, header); 237662306a36Sopenharmony_ci struct perf_record_header_build_id bev; 237762306a36Sopenharmony_ci char filename[PATH_MAX]; 237862306a36Sopenharmony_ci u64 limit = offset + size, orig_offset = offset; 237962306a36Sopenharmony_ci int err = -1; 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci while (offset < limit) { 238262306a36Sopenharmony_ci ssize_t len; 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci if (readn(input, &bev, sizeof(bev)) != sizeof(bev)) 238562306a36Sopenharmony_ci goto out; 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci if (header->needs_swap) 238862306a36Sopenharmony_ci perf_event_header__bswap(&bev.header); 238962306a36Sopenharmony_ci 239062306a36Sopenharmony_ci len = bev.header.size - sizeof(bev); 239162306a36Sopenharmony_ci if (readn(input, filename, len) != len) 239262306a36Sopenharmony_ci goto out; 239362306a36Sopenharmony_ci /* 239462306a36Sopenharmony_ci * The a1645ce1 changeset: 239562306a36Sopenharmony_ci * 239662306a36Sopenharmony_ci * "perf: 'perf kvm' tool for monitoring guest performance from host" 239762306a36Sopenharmony_ci * 239862306a36Sopenharmony_ci * Added a field to struct perf_record_header_build_id that broke the file 239962306a36Sopenharmony_ci * format. 240062306a36Sopenharmony_ci * 240162306a36Sopenharmony_ci * Since the kernel build-id is the first entry, process the 240262306a36Sopenharmony_ci * table using the old format if the well known 240362306a36Sopenharmony_ci * '[kernel.kallsyms]' string for the kernel build-id has the 240462306a36Sopenharmony_ci * first 4 characters chopped off (where the pid_t sits). 240562306a36Sopenharmony_ci */ 240662306a36Sopenharmony_ci if (memcmp(filename, "nel.kallsyms]", 13) == 0) { 240762306a36Sopenharmony_ci if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1) 240862306a36Sopenharmony_ci return -1; 240962306a36Sopenharmony_ci return perf_header__read_build_ids_abi_quirk(header, input, offset, size); 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci __event_process_build_id(&bev, filename, session); 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci offset += bev.header.size; 241562306a36Sopenharmony_ci } 241662306a36Sopenharmony_ci err = 0; 241762306a36Sopenharmony_ciout: 241862306a36Sopenharmony_ci return err; 241962306a36Sopenharmony_ci} 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci/* Macro for features that simply need to read and store a string. */ 242262306a36Sopenharmony_ci#define FEAT_PROCESS_STR_FUN(__feat, __feat_env) \ 242362306a36Sopenharmony_cistatic int process_##__feat(struct feat_fd *ff, void *data __maybe_unused) \ 242462306a36Sopenharmony_ci{\ 242562306a36Sopenharmony_ci free(ff->ph->env.__feat_env); \ 242662306a36Sopenharmony_ci ff->ph->env.__feat_env = do_read_string(ff); \ 242762306a36Sopenharmony_ci return ff->ph->env.__feat_env ? 0 : -ENOMEM; \ 242862306a36Sopenharmony_ci} 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(hostname, hostname); 243162306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(osrelease, os_release); 243262306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(version, version); 243362306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(arch, arch); 243462306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(cpudesc, cpu_desc); 243562306a36Sopenharmony_ciFEAT_PROCESS_STR_FUN(cpuid, cpuid); 243662306a36Sopenharmony_ci 243762306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT 243862306a36Sopenharmony_cistatic int process_tracing_data(struct feat_fd *ff, void *data) 243962306a36Sopenharmony_ci{ 244062306a36Sopenharmony_ci ssize_t ret = trace_report(ff->fd, data, false); 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci return ret < 0 ? -1 : 0; 244362306a36Sopenharmony_ci} 244462306a36Sopenharmony_ci#endif 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_cistatic int process_build_id(struct feat_fd *ff, void *data __maybe_unused) 244762306a36Sopenharmony_ci{ 244862306a36Sopenharmony_ci if (perf_header__read_build_ids(ff->ph, ff->fd, ff->offset, ff->size)) 244962306a36Sopenharmony_ci pr_debug("Failed to read buildids, continuing...\n"); 245062306a36Sopenharmony_ci return 0; 245162306a36Sopenharmony_ci} 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_cistatic int process_nrcpus(struct feat_fd *ff, void *data __maybe_unused) 245462306a36Sopenharmony_ci{ 245562306a36Sopenharmony_ci int ret; 245662306a36Sopenharmony_ci u32 nr_cpus_avail, nr_cpus_online; 245762306a36Sopenharmony_ci 245862306a36Sopenharmony_ci ret = do_read_u32(ff, &nr_cpus_avail); 245962306a36Sopenharmony_ci if (ret) 246062306a36Sopenharmony_ci return ret; 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci ret = do_read_u32(ff, &nr_cpus_online); 246362306a36Sopenharmony_ci if (ret) 246462306a36Sopenharmony_ci return ret; 246562306a36Sopenharmony_ci ff->ph->env.nr_cpus_avail = (int)nr_cpus_avail; 246662306a36Sopenharmony_ci ff->ph->env.nr_cpus_online = (int)nr_cpus_online; 246762306a36Sopenharmony_ci return 0; 246862306a36Sopenharmony_ci} 246962306a36Sopenharmony_ci 247062306a36Sopenharmony_cistatic int process_total_mem(struct feat_fd *ff, void *data __maybe_unused) 247162306a36Sopenharmony_ci{ 247262306a36Sopenharmony_ci u64 total_mem; 247362306a36Sopenharmony_ci int ret; 247462306a36Sopenharmony_ci 247562306a36Sopenharmony_ci ret = do_read_u64(ff, &total_mem); 247662306a36Sopenharmony_ci if (ret) 247762306a36Sopenharmony_ci return -1; 247862306a36Sopenharmony_ci ff->ph->env.total_mem = (unsigned long long)total_mem; 247962306a36Sopenharmony_ci return 0; 248062306a36Sopenharmony_ci} 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_cistatic struct evsel *evlist__find_by_index(struct evlist *evlist, int idx) 248362306a36Sopenharmony_ci{ 248462306a36Sopenharmony_ci struct evsel *evsel; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 248762306a36Sopenharmony_ci if (evsel->core.idx == idx) 248862306a36Sopenharmony_ci return evsel; 248962306a36Sopenharmony_ci } 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci return NULL; 249262306a36Sopenharmony_ci} 249362306a36Sopenharmony_ci 249462306a36Sopenharmony_cistatic void evlist__set_event_name(struct evlist *evlist, struct evsel *event) 249562306a36Sopenharmony_ci{ 249662306a36Sopenharmony_ci struct evsel *evsel; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci if (!event->name) 249962306a36Sopenharmony_ci return; 250062306a36Sopenharmony_ci 250162306a36Sopenharmony_ci evsel = evlist__find_by_index(evlist, event->core.idx); 250262306a36Sopenharmony_ci if (!evsel) 250362306a36Sopenharmony_ci return; 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci if (evsel->name) 250662306a36Sopenharmony_ci return; 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci evsel->name = strdup(event->name); 250962306a36Sopenharmony_ci} 251062306a36Sopenharmony_ci 251162306a36Sopenharmony_cistatic int 251262306a36Sopenharmony_ciprocess_event_desc(struct feat_fd *ff, void *data __maybe_unused) 251362306a36Sopenharmony_ci{ 251462306a36Sopenharmony_ci struct perf_session *session; 251562306a36Sopenharmony_ci struct evsel *evsel, *events = read_event_desc(ff); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci if (!events) 251862306a36Sopenharmony_ci return 0; 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 252162306a36Sopenharmony_ci 252262306a36Sopenharmony_ci if (session->data->is_pipe) { 252362306a36Sopenharmony_ci /* Save events for reading later by print_event_desc, 252462306a36Sopenharmony_ci * since they can't be read again in pipe mode. */ 252562306a36Sopenharmony_ci ff->events = events; 252662306a36Sopenharmony_ci } 252762306a36Sopenharmony_ci 252862306a36Sopenharmony_ci for (evsel = events; evsel->core.attr.size; evsel++) 252962306a36Sopenharmony_ci evlist__set_event_name(session->evlist, evsel); 253062306a36Sopenharmony_ci 253162306a36Sopenharmony_ci if (!session->data->is_pipe) 253262306a36Sopenharmony_ci free_event_desc(events); 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci return 0; 253562306a36Sopenharmony_ci} 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_cistatic int process_cmdline(struct feat_fd *ff, void *data __maybe_unused) 253862306a36Sopenharmony_ci{ 253962306a36Sopenharmony_ci char *str, *cmdline = NULL, **argv = NULL; 254062306a36Sopenharmony_ci u32 nr, i, len = 0; 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci if (do_read_u32(ff, &nr)) 254362306a36Sopenharmony_ci return -1; 254462306a36Sopenharmony_ci 254562306a36Sopenharmony_ci ff->ph->env.nr_cmdline = nr; 254662306a36Sopenharmony_ci 254762306a36Sopenharmony_ci cmdline = zalloc(ff->size + nr + 1); 254862306a36Sopenharmony_ci if (!cmdline) 254962306a36Sopenharmony_ci return -1; 255062306a36Sopenharmony_ci 255162306a36Sopenharmony_ci argv = zalloc(sizeof(char *) * (nr + 1)); 255262306a36Sopenharmony_ci if (!argv) 255362306a36Sopenharmony_ci goto error; 255462306a36Sopenharmony_ci 255562306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 255662306a36Sopenharmony_ci str = do_read_string(ff); 255762306a36Sopenharmony_ci if (!str) 255862306a36Sopenharmony_ci goto error; 255962306a36Sopenharmony_ci 256062306a36Sopenharmony_ci argv[i] = cmdline + len; 256162306a36Sopenharmony_ci memcpy(argv[i], str, strlen(str) + 1); 256262306a36Sopenharmony_ci len += strlen(str) + 1; 256362306a36Sopenharmony_ci free(str); 256462306a36Sopenharmony_ci } 256562306a36Sopenharmony_ci ff->ph->env.cmdline = cmdline; 256662306a36Sopenharmony_ci ff->ph->env.cmdline_argv = (const char **) argv; 256762306a36Sopenharmony_ci return 0; 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_cierror: 257062306a36Sopenharmony_ci free(argv); 257162306a36Sopenharmony_ci free(cmdline); 257262306a36Sopenharmony_ci return -1; 257362306a36Sopenharmony_ci} 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_cistatic int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) 257662306a36Sopenharmony_ci{ 257762306a36Sopenharmony_ci u32 nr, i; 257862306a36Sopenharmony_ci char *str; 257962306a36Sopenharmony_ci struct strbuf sb; 258062306a36Sopenharmony_ci int cpu_nr = ff->ph->env.nr_cpus_avail; 258162306a36Sopenharmony_ci u64 size = 0; 258262306a36Sopenharmony_ci struct perf_header *ph = ff->ph; 258362306a36Sopenharmony_ci bool do_core_id_test = true; 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu)); 258662306a36Sopenharmony_ci if (!ph->env.cpu) 258762306a36Sopenharmony_ci return -1; 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci if (do_read_u32(ff, &nr)) 259062306a36Sopenharmony_ci goto free_cpu; 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_ci ph->env.nr_sibling_cores = nr; 259362306a36Sopenharmony_ci size += sizeof(u32); 259462306a36Sopenharmony_ci if (strbuf_init(&sb, 128) < 0) 259562306a36Sopenharmony_ci goto free_cpu; 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 259862306a36Sopenharmony_ci str = do_read_string(ff); 259962306a36Sopenharmony_ci if (!str) 260062306a36Sopenharmony_ci goto error; 260162306a36Sopenharmony_ci 260262306a36Sopenharmony_ci /* include a NULL character at the end */ 260362306a36Sopenharmony_ci if (strbuf_add(&sb, str, strlen(str) + 1) < 0) 260462306a36Sopenharmony_ci goto error; 260562306a36Sopenharmony_ci size += string_size(str); 260662306a36Sopenharmony_ci free(str); 260762306a36Sopenharmony_ci } 260862306a36Sopenharmony_ci ph->env.sibling_cores = strbuf_detach(&sb, NULL); 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci if (do_read_u32(ff, &nr)) 261162306a36Sopenharmony_ci return -1; 261262306a36Sopenharmony_ci 261362306a36Sopenharmony_ci ph->env.nr_sibling_threads = nr; 261462306a36Sopenharmony_ci size += sizeof(u32); 261562306a36Sopenharmony_ci 261662306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 261762306a36Sopenharmony_ci str = do_read_string(ff); 261862306a36Sopenharmony_ci if (!str) 261962306a36Sopenharmony_ci goto error; 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci /* include a NULL character at the end */ 262262306a36Sopenharmony_ci if (strbuf_add(&sb, str, strlen(str) + 1) < 0) 262362306a36Sopenharmony_ci goto error; 262462306a36Sopenharmony_ci size += string_size(str); 262562306a36Sopenharmony_ci free(str); 262662306a36Sopenharmony_ci } 262762306a36Sopenharmony_ci ph->env.sibling_threads = strbuf_detach(&sb, NULL); 262862306a36Sopenharmony_ci 262962306a36Sopenharmony_ci /* 263062306a36Sopenharmony_ci * The header may be from old perf, 263162306a36Sopenharmony_ci * which doesn't include core id and socket id information. 263262306a36Sopenharmony_ci */ 263362306a36Sopenharmony_ci if (ff->size <= size) { 263462306a36Sopenharmony_ci zfree(&ph->env.cpu); 263562306a36Sopenharmony_ci return 0; 263662306a36Sopenharmony_ci } 263762306a36Sopenharmony_ci 263862306a36Sopenharmony_ci /* On s390 the socket_id number is not related to the numbers of cpus. 263962306a36Sopenharmony_ci * The socket_id number might be higher than the numbers of cpus. 264062306a36Sopenharmony_ci * This depends on the configuration. 264162306a36Sopenharmony_ci * AArch64 is the same. 264262306a36Sopenharmony_ci */ 264362306a36Sopenharmony_ci if (ph->env.arch && (!strncmp(ph->env.arch, "s390", 4) 264462306a36Sopenharmony_ci || !strncmp(ph->env.arch, "aarch64", 7))) 264562306a36Sopenharmony_ci do_core_id_test = false; 264662306a36Sopenharmony_ci 264762306a36Sopenharmony_ci for (i = 0; i < (u32)cpu_nr; i++) { 264862306a36Sopenharmony_ci if (do_read_u32(ff, &nr)) 264962306a36Sopenharmony_ci goto free_cpu; 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci ph->env.cpu[i].core_id = nr; 265262306a36Sopenharmony_ci size += sizeof(u32); 265362306a36Sopenharmony_ci 265462306a36Sopenharmony_ci if (do_read_u32(ff, &nr)) 265562306a36Sopenharmony_ci goto free_cpu; 265662306a36Sopenharmony_ci 265762306a36Sopenharmony_ci if (do_core_id_test && nr != (u32)-1 && nr > (u32)cpu_nr) { 265862306a36Sopenharmony_ci pr_debug("socket_id number is too big." 265962306a36Sopenharmony_ci "You may need to upgrade the perf tool.\n"); 266062306a36Sopenharmony_ci goto free_cpu; 266162306a36Sopenharmony_ci } 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_ci ph->env.cpu[i].socket_id = nr; 266462306a36Sopenharmony_ci size += sizeof(u32); 266562306a36Sopenharmony_ci } 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci /* 266862306a36Sopenharmony_ci * The header may be from old perf, 266962306a36Sopenharmony_ci * which doesn't include die information. 267062306a36Sopenharmony_ci */ 267162306a36Sopenharmony_ci if (ff->size <= size) 267262306a36Sopenharmony_ci return 0; 267362306a36Sopenharmony_ci 267462306a36Sopenharmony_ci if (do_read_u32(ff, &nr)) 267562306a36Sopenharmony_ci return -1; 267662306a36Sopenharmony_ci 267762306a36Sopenharmony_ci ph->env.nr_sibling_dies = nr; 267862306a36Sopenharmony_ci size += sizeof(u32); 267962306a36Sopenharmony_ci 268062306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 268162306a36Sopenharmony_ci str = do_read_string(ff); 268262306a36Sopenharmony_ci if (!str) 268362306a36Sopenharmony_ci goto error; 268462306a36Sopenharmony_ci 268562306a36Sopenharmony_ci /* include a NULL character at the end */ 268662306a36Sopenharmony_ci if (strbuf_add(&sb, str, strlen(str) + 1) < 0) 268762306a36Sopenharmony_ci goto error; 268862306a36Sopenharmony_ci size += string_size(str); 268962306a36Sopenharmony_ci free(str); 269062306a36Sopenharmony_ci } 269162306a36Sopenharmony_ci ph->env.sibling_dies = strbuf_detach(&sb, NULL); 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci for (i = 0; i < (u32)cpu_nr; i++) { 269462306a36Sopenharmony_ci if (do_read_u32(ff, &nr)) 269562306a36Sopenharmony_ci goto free_cpu; 269662306a36Sopenharmony_ci 269762306a36Sopenharmony_ci ph->env.cpu[i].die_id = nr; 269862306a36Sopenharmony_ci } 269962306a36Sopenharmony_ci 270062306a36Sopenharmony_ci return 0; 270162306a36Sopenharmony_ci 270262306a36Sopenharmony_cierror: 270362306a36Sopenharmony_ci strbuf_release(&sb); 270462306a36Sopenharmony_cifree_cpu: 270562306a36Sopenharmony_ci zfree(&ph->env.cpu); 270662306a36Sopenharmony_ci return -1; 270762306a36Sopenharmony_ci} 270862306a36Sopenharmony_ci 270962306a36Sopenharmony_cistatic int process_numa_topology(struct feat_fd *ff, void *data __maybe_unused) 271062306a36Sopenharmony_ci{ 271162306a36Sopenharmony_ci struct numa_node *nodes, *n; 271262306a36Sopenharmony_ci u32 nr, i; 271362306a36Sopenharmony_ci char *str; 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci /* nr nodes */ 271662306a36Sopenharmony_ci if (do_read_u32(ff, &nr)) 271762306a36Sopenharmony_ci return -1; 271862306a36Sopenharmony_ci 271962306a36Sopenharmony_ci nodes = zalloc(sizeof(*nodes) * nr); 272062306a36Sopenharmony_ci if (!nodes) 272162306a36Sopenharmony_ci return -ENOMEM; 272262306a36Sopenharmony_ci 272362306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 272462306a36Sopenharmony_ci n = &nodes[i]; 272562306a36Sopenharmony_ci 272662306a36Sopenharmony_ci /* node number */ 272762306a36Sopenharmony_ci if (do_read_u32(ff, &n->node)) 272862306a36Sopenharmony_ci goto error; 272962306a36Sopenharmony_ci 273062306a36Sopenharmony_ci if (do_read_u64(ff, &n->mem_total)) 273162306a36Sopenharmony_ci goto error; 273262306a36Sopenharmony_ci 273362306a36Sopenharmony_ci if (do_read_u64(ff, &n->mem_free)) 273462306a36Sopenharmony_ci goto error; 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci str = do_read_string(ff); 273762306a36Sopenharmony_ci if (!str) 273862306a36Sopenharmony_ci goto error; 273962306a36Sopenharmony_ci 274062306a36Sopenharmony_ci n->map = perf_cpu_map__new(str); 274162306a36Sopenharmony_ci if (!n->map) 274262306a36Sopenharmony_ci goto error; 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_ci free(str); 274562306a36Sopenharmony_ci } 274662306a36Sopenharmony_ci ff->ph->env.nr_numa_nodes = nr; 274762306a36Sopenharmony_ci ff->ph->env.numa_nodes = nodes; 274862306a36Sopenharmony_ci return 0; 274962306a36Sopenharmony_ci 275062306a36Sopenharmony_cierror: 275162306a36Sopenharmony_ci free(nodes); 275262306a36Sopenharmony_ci return -1; 275362306a36Sopenharmony_ci} 275462306a36Sopenharmony_ci 275562306a36Sopenharmony_cistatic int process_pmu_mappings(struct feat_fd *ff, void *data __maybe_unused) 275662306a36Sopenharmony_ci{ 275762306a36Sopenharmony_ci char *name; 275862306a36Sopenharmony_ci u32 pmu_num; 275962306a36Sopenharmony_ci u32 type; 276062306a36Sopenharmony_ci struct strbuf sb; 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci if (do_read_u32(ff, &pmu_num)) 276362306a36Sopenharmony_ci return -1; 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci if (!pmu_num) { 276662306a36Sopenharmony_ci pr_debug("pmu mappings not available\n"); 276762306a36Sopenharmony_ci return 0; 276862306a36Sopenharmony_ci } 276962306a36Sopenharmony_ci 277062306a36Sopenharmony_ci ff->ph->env.nr_pmu_mappings = pmu_num; 277162306a36Sopenharmony_ci if (strbuf_init(&sb, 128) < 0) 277262306a36Sopenharmony_ci return -1; 277362306a36Sopenharmony_ci 277462306a36Sopenharmony_ci while (pmu_num) { 277562306a36Sopenharmony_ci if (do_read_u32(ff, &type)) 277662306a36Sopenharmony_ci goto error; 277762306a36Sopenharmony_ci 277862306a36Sopenharmony_ci name = do_read_string(ff); 277962306a36Sopenharmony_ci if (!name) 278062306a36Sopenharmony_ci goto error; 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci if (strbuf_addf(&sb, "%u:%s", type, name) < 0) 278362306a36Sopenharmony_ci goto error; 278462306a36Sopenharmony_ci /* include a NULL character at the end */ 278562306a36Sopenharmony_ci if (strbuf_add(&sb, "", 1) < 0) 278662306a36Sopenharmony_ci goto error; 278762306a36Sopenharmony_ci 278862306a36Sopenharmony_ci if (!strcmp(name, "msr")) 278962306a36Sopenharmony_ci ff->ph->env.msr_pmu_type = type; 279062306a36Sopenharmony_ci 279162306a36Sopenharmony_ci free(name); 279262306a36Sopenharmony_ci pmu_num--; 279362306a36Sopenharmony_ci } 279462306a36Sopenharmony_ci ff->ph->env.pmu_mappings = strbuf_detach(&sb, NULL); 279562306a36Sopenharmony_ci return 0; 279662306a36Sopenharmony_ci 279762306a36Sopenharmony_cierror: 279862306a36Sopenharmony_ci strbuf_release(&sb); 279962306a36Sopenharmony_ci return -1; 280062306a36Sopenharmony_ci} 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_cistatic int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) 280362306a36Sopenharmony_ci{ 280462306a36Sopenharmony_ci size_t ret = -1; 280562306a36Sopenharmony_ci u32 i, nr, nr_groups; 280662306a36Sopenharmony_ci struct perf_session *session; 280762306a36Sopenharmony_ci struct evsel *evsel, *leader = NULL; 280862306a36Sopenharmony_ci struct group_desc { 280962306a36Sopenharmony_ci char *name; 281062306a36Sopenharmony_ci u32 leader_idx; 281162306a36Sopenharmony_ci u32 nr_members; 281262306a36Sopenharmony_ci } *desc; 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_ci if (do_read_u32(ff, &nr_groups)) 281562306a36Sopenharmony_ci return -1; 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci ff->ph->env.nr_groups = nr_groups; 281862306a36Sopenharmony_ci if (!nr_groups) { 281962306a36Sopenharmony_ci pr_debug("group desc not available\n"); 282062306a36Sopenharmony_ci return 0; 282162306a36Sopenharmony_ci } 282262306a36Sopenharmony_ci 282362306a36Sopenharmony_ci desc = calloc(nr_groups, sizeof(*desc)); 282462306a36Sopenharmony_ci if (!desc) 282562306a36Sopenharmony_ci return -1; 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci for (i = 0; i < nr_groups; i++) { 282862306a36Sopenharmony_ci desc[i].name = do_read_string(ff); 282962306a36Sopenharmony_ci if (!desc[i].name) 283062306a36Sopenharmony_ci goto out_free; 283162306a36Sopenharmony_ci 283262306a36Sopenharmony_ci if (do_read_u32(ff, &desc[i].leader_idx)) 283362306a36Sopenharmony_ci goto out_free; 283462306a36Sopenharmony_ci 283562306a36Sopenharmony_ci if (do_read_u32(ff, &desc[i].nr_members)) 283662306a36Sopenharmony_ci goto out_free; 283762306a36Sopenharmony_ci } 283862306a36Sopenharmony_ci 283962306a36Sopenharmony_ci /* 284062306a36Sopenharmony_ci * Rebuild group relationship based on the group_desc 284162306a36Sopenharmony_ci */ 284262306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_ci i = nr = 0; 284562306a36Sopenharmony_ci evlist__for_each_entry(session->evlist, evsel) { 284662306a36Sopenharmony_ci if (i < nr_groups && evsel->core.idx == (int) desc[i].leader_idx) { 284762306a36Sopenharmony_ci evsel__set_leader(evsel, evsel); 284862306a36Sopenharmony_ci /* {anon_group} is a dummy name */ 284962306a36Sopenharmony_ci if (strcmp(desc[i].name, "{anon_group}")) { 285062306a36Sopenharmony_ci evsel->group_name = desc[i].name; 285162306a36Sopenharmony_ci desc[i].name = NULL; 285262306a36Sopenharmony_ci } 285362306a36Sopenharmony_ci evsel->core.nr_members = desc[i].nr_members; 285462306a36Sopenharmony_ci 285562306a36Sopenharmony_ci if (i >= nr_groups || nr > 0) { 285662306a36Sopenharmony_ci pr_debug("invalid group desc\n"); 285762306a36Sopenharmony_ci goto out_free; 285862306a36Sopenharmony_ci } 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci leader = evsel; 286162306a36Sopenharmony_ci nr = evsel->core.nr_members - 1; 286262306a36Sopenharmony_ci i++; 286362306a36Sopenharmony_ci } else if (nr) { 286462306a36Sopenharmony_ci /* This is a group member */ 286562306a36Sopenharmony_ci evsel__set_leader(evsel, leader); 286662306a36Sopenharmony_ci 286762306a36Sopenharmony_ci nr--; 286862306a36Sopenharmony_ci } 286962306a36Sopenharmony_ci } 287062306a36Sopenharmony_ci 287162306a36Sopenharmony_ci if (i != nr_groups || nr != 0) { 287262306a36Sopenharmony_ci pr_debug("invalid group desc\n"); 287362306a36Sopenharmony_ci goto out_free; 287462306a36Sopenharmony_ci } 287562306a36Sopenharmony_ci 287662306a36Sopenharmony_ci ret = 0; 287762306a36Sopenharmony_ciout_free: 287862306a36Sopenharmony_ci for (i = 0; i < nr_groups; i++) 287962306a36Sopenharmony_ci zfree(&desc[i].name); 288062306a36Sopenharmony_ci free(desc); 288162306a36Sopenharmony_ci 288262306a36Sopenharmony_ci return ret; 288362306a36Sopenharmony_ci} 288462306a36Sopenharmony_ci 288562306a36Sopenharmony_cistatic int process_auxtrace(struct feat_fd *ff, void *data __maybe_unused) 288662306a36Sopenharmony_ci{ 288762306a36Sopenharmony_ci struct perf_session *session; 288862306a36Sopenharmony_ci int err; 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_ci err = auxtrace_index__process(ff->fd, ff->size, session, 289362306a36Sopenharmony_ci ff->ph->needs_swap); 289462306a36Sopenharmony_ci if (err < 0) 289562306a36Sopenharmony_ci pr_err("Failed to process auxtrace index\n"); 289662306a36Sopenharmony_ci return err; 289762306a36Sopenharmony_ci} 289862306a36Sopenharmony_ci 289962306a36Sopenharmony_cistatic int process_cache(struct feat_fd *ff, void *data __maybe_unused) 290062306a36Sopenharmony_ci{ 290162306a36Sopenharmony_ci struct cpu_cache_level *caches; 290262306a36Sopenharmony_ci u32 cnt, i, version; 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci if (do_read_u32(ff, &version)) 290562306a36Sopenharmony_ci return -1; 290662306a36Sopenharmony_ci 290762306a36Sopenharmony_ci if (version != 1) 290862306a36Sopenharmony_ci return -1; 290962306a36Sopenharmony_ci 291062306a36Sopenharmony_ci if (do_read_u32(ff, &cnt)) 291162306a36Sopenharmony_ci return -1; 291262306a36Sopenharmony_ci 291362306a36Sopenharmony_ci caches = zalloc(sizeof(*caches) * cnt); 291462306a36Sopenharmony_ci if (!caches) 291562306a36Sopenharmony_ci return -1; 291662306a36Sopenharmony_ci 291762306a36Sopenharmony_ci for (i = 0; i < cnt; i++) { 291862306a36Sopenharmony_ci struct cpu_cache_level c; 291962306a36Sopenharmony_ci 292062306a36Sopenharmony_ci #define _R(v) \ 292162306a36Sopenharmony_ci if (do_read_u32(ff, &c.v))\ 292262306a36Sopenharmony_ci goto out_free_caches; \ 292362306a36Sopenharmony_ci 292462306a36Sopenharmony_ci _R(level) 292562306a36Sopenharmony_ci _R(line_size) 292662306a36Sopenharmony_ci _R(sets) 292762306a36Sopenharmony_ci _R(ways) 292862306a36Sopenharmony_ci #undef _R 292962306a36Sopenharmony_ci 293062306a36Sopenharmony_ci #define _R(v) \ 293162306a36Sopenharmony_ci c.v = do_read_string(ff); \ 293262306a36Sopenharmony_ci if (!c.v) \ 293362306a36Sopenharmony_ci goto out_free_caches; 293462306a36Sopenharmony_ci 293562306a36Sopenharmony_ci _R(type) 293662306a36Sopenharmony_ci _R(size) 293762306a36Sopenharmony_ci _R(map) 293862306a36Sopenharmony_ci #undef _R 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci caches[i] = c; 294162306a36Sopenharmony_ci } 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci ff->ph->env.caches = caches; 294462306a36Sopenharmony_ci ff->ph->env.caches_cnt = cnt; 294562306a36Sopenharmony_ci return 0; 294662306a36Sopenharmony_ciout_free_caches: 294762306a36Sopenharmony_ci free(caches); 294862306a36Sopenharmony_ci return -1; 294962306a36Sopenharmony_ci} 295062306a36Sopenharmony_ci 295162306a36Sopenharmony_cistatic int process_sample_time(struct feat_fd *ff, void *data __maybe_unused) 295262306a36Sopenharmony_ci{ 295362306a36Sopenharmony_ci struct perf_session *session; 295462306a36Sopenharmony_ci u64 first_sample_time, last_sample_time; 295562306a36Sopenharmony_ci int ret; 295662306a36Sopenharmony_ci 295762306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_ci ret = do_read_u64(ff, &first_sample_time); 296062306a36Sopenharmony_ci if (ret) 296162306a36Sopenharmony_ci return -1; 296262306a36Sopenharmony_ci 296362306a36Sopenharmony_ci ret = do_read_u64(ff, &last_sample_time); 296462306a36Sopenharmony_ci if (ret) 296562306a36Sopenharmony_ci return -1; 296662306a36Sopenharmony_ci 296762306a36Sopenharmony_ci session->evlist->first_sample_time = first_sample_time; 296862306a36Sopenharmony_ci session->evlist->last_sample_time = last_sample_time; 296962306a36Sopenharmony_ci return 0; 297062306a36Sopenharmony_ci} 297162306a36Sopenharmony_ci 297262306a36Sopenharmony_cistatic int process_mem_topology(struct feat_fd *ff, 297362306a36Sopenharmony_ci void *data __maybe_unused) 297462306a36Sopenharmony_ci{ 297562306a36Sopenharmony_ci struct memory_node *nodes; 297662306a36Sopenharmony_ci u64 version, i, nr, bsize; 297762306a36Sopenharmony_ci int ret = -1; 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci if (do_read_u64(ff, &version)) 298062306a36Sopenharmony_ci return -1; 298162306a36Sopenharmony_ci 298262306a36Sopenharmony_ci if (version != 1) 298362306a36Sopenharmony_ci return -1; 298462306a36Sopenharmony_ci 298562306a36Sopenharmony_ci if (do_read_u64(ff, &bsize)) 298662306a36Sopenharmony_ci return -1; 298762306a36Sopenharmony_ci 298862306a36Sopenharmony_ci if (do_read_u64(ff, &nr)) 298962306a36Sopenharmony_ci return -1; 299062306a36Sopenharmony_ci 299162306a36Sopenharmony_ci nodes = zalloc(sizeof(*nodes) * nr); 299262306a36Sopenharmony_ci if (!nodes) 299362306a36Sopenharmony_ci return -1; 299462306a36Sopenharmony_ci 299562306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 299662306a36Sopenharmony_ci struct memory_node n; 299762306a36Sopenharmony_ci 299862306a36Sopenharmony_ci #define _R(v) \ 299962306a36Sopenharmony_ci if (do_read_u64(ff, &n.v)) \ 300062306a36Sopenharmony_ci goto out; \ 300162306a36Sopenharmony_ci 300262306a36Sopenharmony_ci _R(node) 300362306a36Sopenharmony_ci _R(size) 300462306a36Sopenharmony_ci 300562306a36Sopenharmony_ci #undef _R 300662306a36Sopenharmony_ci 300762306a36Sopenharmony_ci if (do_read_bitmap(ff, &n.set, &n.size)) 300862306a36Sopenharmony_ci goto out; 300962306a36Sopenharmony_ci 301062306a36Sopenharmony_ci nodes[i] = n; 301162306a36Sopenharmony_ci } 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci ff->ph->env.memory_bsize = bsize; 301462306a36Sopenharmony_ci ff->ph->env.memory_nodes = nodes; 301562306a36Sopenharmony_ci ff->ph->env.nr_memory_nodes = nr; 301662306a36Sopenharmony_ci ret = 0; 301762306a36Sopenharmony_ci 301862306a36Sopenharmony_ciout: 301962306a36Sopenharmony_ci if (ret) 302062306a36Sopenharmony_ci free(nodes); 302162306a36Sopenharmony_ci return ret; 302262306a36Sopenharmony_ci} 302362306a36Sopenharmony_ci 302462306a36Sopenharmony_cistatic int process_clockid(struct feat_fd *ff, 302562306a36Sopenharmony_ci void *data __maybe_unused) 302662306a36Sopenharmony_ci{ 302762306a36Sopenharmony_ci if (do_read_u64(ff, &ff->ph->env.clock.clockid_res_ns)) 302862306a36Sopenharmony_ci return -1; 302962306a36Sopenharmony_ci 303062306a36Sopenharmony_ci return 0; 303162306a36Sopenharmony_ci} 303262306a36Sopenharmony_ci 303362306a36Sopenharmony_cistatic int process_clock_data(struct feat_fd *ff, 303462306a36Sopenharmony_ci void *_data __maybe_unused) 303562306a36Sopenharmony_ci{ 303662306a36Sopenharmony_ci u32 data32; 303762306a36Sopenharmony_ci u64 data64; 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci /* version */ 304062306a36Sopenharmony_ci if (do_read_u32(ff, &data32)) 304162306a36Sopenharmony_ci return -1; 304262306a36Sopenharmony_ci 304362306a36Sopenharmony_ci if (data32 != 1) 304462306a36Sopenharmony_ci return -1; 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci /* clockid */ 304762306a36Sopenharmony_ci if (do_read_u32(ff, &data32)) 304862306a36Sopenharmony_ci return -1; 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci ff->ph->env.clock.clockid = data32; 305162306a36Sopenharmony_ci 305262306a36Sopenharmony_ci /* TOD ref time */ 305362306a36Sopenharmony_ci if (do_read_u64(ff, &data64)) 305462306a36Sopenharmony_ci return -1; 305562306a36Sopenharmony_ci 305662306a36Sopenharmony_ci ff->ph->env.clock.tod_ns = data64; 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci /* clockid ref time */ 305962306a36Sopenharmony_ci if (do_read_u64(ff, &data64)) 306062306a36Sopenharmony_ci return -1; 306162306a36Sopenharmony_ci 306262306a36Sopenharmony_ci ff->ph->env.clock.clockid_ns = data64; 306362306a36Sopenharmony_ci ff->ph->env.clock.enabled = true; 306462306a36Sopenharmony_ci return 0; 306562306a36Sopenharmony_ci} 306662306a36Sopenharmony_ci 306762306a36Sopenharmony_cistatic int process_hybrid_topology(struct feat_fd *ff, 306862306a36Sopenharmony_ci void *data __maybe_unused) 306962306a36Sopenharmony_ci{ 307062306a36Sopenharmony_ci struct hybrid_node *nodes, *n; 307162306a36Sopenharmony_ci u32 nr, i; 307262306a36Sopenharmony_ci 307362306a36Sopenharmony_ci /* nr nodes */ 307462306a36Sopenharmony_ci if (do_read_u32(ff, &nr)) 307562306a36Sopenharmony_ci return -1; 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_ci nodes = zalloc(sizeof(*nodes) * nr); 307862306a36Sopenharmony_ci if (!nodes) 307962306a36Sopenharmony_ci return -ENOMEM; 308062306a36Sopenharmony_ci 308162306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 308262306a36Sopenharmony_ci n = &nodes[i]; 308362306a36Sopenharmony_ci 308462306a36Sopenharmony_ci n->pmu_name = do_read_string(ff); 308562306a36Sopenharmony_ci if (!n->pmu_name) 308662306a36Sopenharmony_ci goto error; 308762306a36Sopenharmony_ci 308862306a36Sopenharmony_ci n->cpus = do_read_string(ff); 308962306a36Sopenharmony_ci if (!n->cpus) 309062306a36Sopenharmony_ci goto error; 309162306a36Sopenharmony_ci } 309262306a36Sopenharmony_ci 309362306a36Sopenharmony_ci ff->ph->env.nr_hybrid_nodes = nr; 309462306a36Sopenharmony_ci ff->ph->env.hybrid_nodes = nodes; 309562306a36Sopenharmony_ci return 0; 309662306a36Sopenharmony_ci 309762306a36Sopenharmony_cierror: 309862306a36Sopenharmony_ci for (i = 0; i < nr; i++) { 309962306a36Sopenharmony_ci free(nodes[i].pmu_name); 310062306a36Sopenharmony_ci free(nodes[i].cpus); 310162306a36Sopenharmony_ci } 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci free(nodes); 310462306a36Sopenharmony_ci return -1; 310562306a36Sopenharmony_ci} 310662306a36Sopenharmony_ci 310762306a36Sopenharmony_cistatic int process_dir_format(struct feat_fd *ff, 310862306a36Sopenharmony_ci void *_data __maybe_unused) 310962306a36Sopenharmony_ci{ 311062306a36Sopenharmony_ci struct perf_session *session; 311162306a36Sopenharmony_ci struct perf_data *data; 311262306a36Sopenharmony_ci 311362306a36Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 311462306a36Sopenharmony_ci data = session->data; 311562306a36Sopenharmony_ci 311662306a36Sopenharmony_ci if (WARN_ON(!perf_data__is_dir(data))) 311762306a36Sopenharmony_ci return -1; 311862306a36Sopenharmony_ci 311962306a36Sopenharmony_ci return do_read_u64(ff, &data->dir.version); 312062306a36Sopenharmony_ci} 312162306a36Sopenharmony_ci 312262306a36Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT 312362306a36Sopenharmony_cistatic int process_bpf_prog_info(struct feat_fd *ff, void *data __maybe_unused) 312462306a36Sopenharmony_ci{ 312562306a36Sopenharmony_ci struct bpf_prog_info_node *info_node; 312662306a36Sopenharmony_ci struct perf_env *env = &ff->ph->env; 312762306a36Sopenharmony_ci struct perf_bpil *info_linear; 312862306a36Sopenharmony_ci u32 count, i; 312962306a36Sopenharmony_ci int err = -1; 313062306a36Sopenharmony_ci 313162306a36Sopenharmony_ci if (ff->ph->needs_swap) { 313262306a36Sopenharmony_ci pr_warning("interpreting bpf_prog_info from systems with endianness is not yet supported\n"); 313362306a36Sopenharmony_ci return 0; 313462306a36Sopenharmony_ci } 313562306a36Sopenharmony_ci 313662306a36Sopenharmony_ci if (do_read_u32(ff, &count)) 313762306a36Sopenharmony_ci return -1; 313862306a36Sopenharmony_ci 313962306a36Sopenharmony_ci down_write(&env->bpf_progs.lock); 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ci for (i = 0; i < count; ++i) { 314262306a36Sopenharmony_ci u32 info_len, data_len; 314362306a36Sopenharmony_ci 314462306a36Sopenharmony_ci info_linear = NULL; 314562306a36Sopenharmony_ci info_node = NULL; 314662306a36Sopenharmony_ci if (do_read_u32(ff, &info_len)) 314762306a36Sopenharmony_ci goto out; 314862306a36Sopenharmony_ci if (do_read_u32(ff, &data_len)) 314962306a36Sopenharmony_ci goto out; 315062306a36Sopenharmony_ci 315162306a36Sopenharmony_ci if (info_len > sizeof(struct bpf_prog_info)) { 315262306a36Sopenharmony_ci pr_warning("detected invalid bpf_prog_info\n"); 315362306a36Sopenharmony_ci goto out; 315462306a36Sopenharmony_ci } 315562306a36Sopenharmony_ci 315662306a36Sopenharmony_ci info_linear = malloc(sizeof(struct perf_bpil) + 315762306a36Sopenharmony_ci data_len); 315862306a36Sopenharmony_ci if (!info_linear) 315962306a36Sopenharmony_ci goto out; 316062306a36Sopenharmony_ci info_linear->info_len = sizeof(struct bpf_prog_info); 316162306a36Sopenharmony_ci info_linear->data_len = data_len; 316262306a36Sopenharmony_ci if (do_read_u64(ff, (u64 *)(&info_linear->arrays))) 316362306a36Sopenharmony_ci goto out; 316462306a36Sopenharmony_ci if (__do_read(ff, &info_linear->info, info_len)) 316562306a36Sopenharmony_ci goto out; 316662306a36Sopenharmony_ci if (info_len < sizeof(struct bpf_prog_info)) 316762306a36Sopenharmony_ci memset(((void *)(&info_linear->info)) + info_len, 0, 316862306a36Sopenharmony_ci sizeof(struct bpf_prog_info) - info_len); 316962306a36Sopenharmony_ci 317062306a36Sopenharmony_ci if (__do_read(ff, info_linear->data, data_len)) 317162306a36Sopenharmony_ci goto out; 317262306a36Sopenharmony_ci 317362306a36Sopenharmony_ci info_node = malloc(sizeof(struct bpf_prog_info_node)); 317462306a36Sopenharmony_ci if (!info_node) 317562306a36Sopenharmony_ci goto out; 317662306a36Sopenharmony_ci 317762306a36Sopenharmony_ci /* after reading from file, translate offset to address */ 317862306a36Sopenharmony_ci bpil_offs_to_addr(info_linear); 317962306a36Sopenharmony_ci info_node->info_linear = info_linear; 318062306a36Sopenharmony_ci __perf_env__insert_bpf_prog_info(env, info_node); 318162306a36Sopenharmony_ci } 318262306a36Sopenharmony_ci 318362306a36Sopenharmony_ci up_write(&env->bpf_progs.lock); 318462306a36Sopenharmony_ci return 0; 318562306a36Sopenharmony_ciout: 318662306a36Sopenharmony_ci free(info_linear); 318762306a36Sopenharmony_ci free(info_node); 318862306a36Sopenharmony_ci up_write(&env->bpf_progs.lock); 318962306a36Sopenharmony_ci return err; 319062306a36Sopenharmony_ci} 319162306a36Sopenharmony_ci 319262306a36Sopenharmony_cistatic int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused) 319362306a36Sopenharmony_ci{ 319462306a36Sopenharmony_ci struct perf_env *env = &ff->ph->env; 319562306a36Sopenharmony_ci struct btf_node *node = NULL; 319662306a36Sopenharmony_ci u32 count, i; 319762306a36Sopenharmony_ci int err = -1; 319862306a36Sopenharmony_ci 319962306a36Sopenharmony_ci if (ff->ph->needs_swap) { 320062306a36Sopenharmony_ci pr_warning("interpreting btf from systems with endianness is not yet supported\n"); 320162306a36Sopenharmony_ci return 0; 320262306a36Sopenharmony_ci } 320362306a36Sopenharmony_ci 320462306a36Sopenharmony_ci if (do_read_u32(ff, &count)) 320562306a36Sopenharmony_ci return -1; 320662306a36Sopenharmony_ci 320762306a36Sopenharmony_ci down_write(&env->bpf_progs.lock); 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci for (i = 0; i < count; ++i) { 321062306a36Sopenharmony_ci u32 id, data_size; 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_ci if (do_read_u32(ff, &id)) 321362306a36Sopenharmony_ci goto out; 321462306a36Sopenharmony_ci if (do_read_u32(ff, &data_size)) 321562306a36Sopenharmony_ci goto out; 321662306a36Sopenharmony_ci 321762306a36Sopenharmony_ci node = malloc(sizeof(struct btf_node) + data_size); 321862306a36Sopenharmony_ci if (!node) 321962306a36Sopenharmony_ci goto out; 322062306a36Sopenharmony_ci 322162306a36Sopenharmony_ci node->id = id; 322262306a36Sopenharmony_ci node->data_size = data_size; 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci if (__do_read(ff, node->data, data_size)) 322562306a36Sopenharmony_ci goto out; 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci __perf_env__insert_btf(env, node); 322862306a36Sopenharmony_ci node = NULL; 322962306a36Sopenharmony_ci } 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci err = 0; 323262306a36Sopenharmony_ciout: 323362306a36Sopenharmony_ci up_write(&env->bpf_progs.lock); 323462306a36Sopenharmony_ci free(node); 323562306a36Sopenharmony_ci return err; 323662306a36Sopenharmony_ci} 323762306a36Sopenharmony_ci#endif // HAVE_LIBBPF_SUPPORT 323862306a36Sopenharmony_ci 323962306a36Sopenharmony_cistatic int process_compressed(struct feat_fd *ff, 324062306a36Sopenharmony_ci void *data __maybe_unused) 324162306a36Sopenharmony_ci{ 324262306a36Sopenharmony_ci if (do_read_u32(ff, &(ff->ph->env.comp_ver))) 324362306a36Sopenharmony_ci return -1; 324462306a36Sopenharmony_ci 324562306a36Sopenharmony_ci if (do_read_u32(ff, &(ff->ph->env.comp_type))) 324662306a36Sopenharmony_ci return -1; 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci if (do_read_u32(ff, &(ff->ph->env.comp_level))) 324962306a36Sopenharmony_ci return -1; 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci if (do_read_u32(ff, &(ff->ph->env.comp_ratio))) 325262306a36Sopenharmony_ci return -1; 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci if (do_read_u32(ff, &(ff->ph->env.comp_mmap_len))) 325562306a36Sopenharmony_ci return -1; 325662306a36Sopenharmony_ci 325762306a36Sopenharmony_ci return 0; 325862306a36Sopenharmony_ci} 325962306a36Sopenharmony_ci 326062306a36Sopenharmony_cistatic int __process_pmu_caps(struct feat_fd *ff, int *nr_caps, 326162306a36Sopenharmony_ci char ***caps, unsigned int *max_branches) 326262306a36Sopenharmony_ci{ 326362306a36Sopenharmony_ci char *name, *value, *ptr; 326462306a36Sopenharmony_ci u32 nr_pmu_caps, i; 326562306a36Sopenharmony_ci 326662306a36Sopenharmony_ci *nr_caps = 0; 326762306a36Sopenharmony_ci *caps = NULL; 326862306a36Sopenharmony_ci 326962306a36Sopenharmony_ci if (do_read_u32(ff, &nr_pmu_caps)) 327062306a36Sopenharmony_ci return -1; 327162306a36Sopenharmony_ci 327262306a36Sopenharmony_ci if (!nr_pmu_caps) 327362306a36Sopenharmony_ci return 0; 327462306a36Sopenharmony_ci 327562306a36Sopenharmony_ci *caps = zalloc(sizeof(char *) * nr_pmu_caps); 327662306a36Sopenharmony_ci if (!*caps) 327762306a36Sopenharmony_ci return -1; 327862306a36Sopenharmony_ci 327962306a36Sopenharmony_ci for (i = 0; i < nr_pmu_caps; i++) { 328062306a36Sopenharmony_ci name = do_read_string(ff); 328162306a36Sopenharmony_ci if (!name) 328262306a36Sopenharmony_ci goto error; 328362306a36Sopenharmony_ci 328462306a36Sopenharmony_ci value = do_read_string(ff); 328562306a36Sopenharmony_ci if (!value) 328662306a36Sopenharmony_ci goto free_name; 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci if (asprintf(&ptr, "%s=%s", name, value) < 0) 328962306a36Sopenharmony_ci goto free_value; 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci (*caps)[i] = ptr; 329262306a36Sopenharmony_ci 329362306a36Sopenharmony_ci if (!strcmp(name, "branches")) 329462306a36Sopenharmony_ci *max_branches = atoi(value); 329562306a36Sopenharmony_ci 329662306a36Sopenharmony_ci free(value); 329762306a36Sopenharmony_ci free(name); 329862306a36Sopenharmony_ci } 329962306a36Sopenharmony_ci *nr_caps = nr_pmu_caps; 330062306a36Sopenharmony_ci return 0; 330162306a36Sopenharmony_ci 330262306a36Sopenharmony_cifree_value: 330362306a36Sopenharmony_ci free(value); 330462306a36Sopenharmony_cifree_name: 330562306a36Sopenharmony_ci free(name); 330662306a36Sopenharmony_cierror: 330762306a36Sopenharmony_ci for (; i > 0; i--) 330862306a36Sopenharmony_ci free((*caps)[i - 1]); 330962306a36Sopenharmony_ci free(*caps); 331062306a36Sopenharmony_ci *caps = NULL; 331162306a36Sopenharmony_ci *nr_caps = 0; 331262306a36Sopenharmony_ci return -1; 331362306a36Sopenharmony_ci} 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_cistatic int process_cpu_pmu_caps(struct feat_fd *ff, 331662306a36Sopenharmony_ci void *data __maybe_unused) 331762306a36Sopenharmony_ci{ 331862306a36Sopenharmony_ci int ret = __process_pmu_caps(ff, &ff->ph->env.nr_cpu_pmu_caps, 331962306a36Sopenharmony_ci &ff->ph->env.cpu_pmu_caps, 332062306a36Sopenharmony_ci &ff->ph->env.max_branches); 332162306a36Sopenharmony_ci 332262306a36Sopenharmony_ci if (!ret && !ff->ph->env.cpu_pmu_caps) 332362306a36Sopenharmony_ci pr_debug("cpu pmu capabilities not available\n"); 332462306a36Sopenharmony_ci return ret; 332562306a36Sopenharmony_ci} 332662306a36Sopenharmony_ci 332762306a36Sopenharmony_cistatic int process_pmu_caps(struct feat_fd *ff, void *data __maybe_unused) 332862306a36Sopenharmony_ci{ 332962306a36Sopenharmony_ci struct pmu_caps *pmu_caps; 333062306a36Sopenharmony_ci u32 nr_pmu, i; 333162306a36Sopenharmony_ci int ret; 333262306a36Sopenharmony_ci int j; 333362306a36Sopenharmony_ci 333462306a36Sopenharmony_ci if (do_read_u32(ff, &nr_pmu)) 333562306a36Sopenharmony_ci return -1; 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci if (!nr_pmu) { 333862306a36Sopenharmony_ci pr_debug("pmu capabilities not available\n"); 333962306a36Sopenharmony_ci return 0; 334062306a36Sopenharmony_ci } 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci pmu_caps = zalloc(sizeof(*pmu_caps) * nr_pmu); 334362306a36Sopenharmony_ci if (!pmu_caps) 334462306a36Sopenharmony_ci return -ENOMEM; 334562306a36Sopenharmony_ci 334662306a36Sopenharmony_ci for (i = 0; i < nr_pmu; i++) { 334762306a36Sopenharmony_ci ret = __process_pmu_caps(ff, &pmu_caps[i].nr_caps, 334862306a36Sopenharmony_ci &pmu_caps[i].caps, 334962306a36Sopenharmony_ci &pmu_caps[i].max_branches); 335062306a36Sopenharmony_ci if (ret) 335162306a36Sopenharmony_ci goto err; 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci pmu_caps[i].pmu_name = do_read_string(ff); 335462306a36Sopenharmony_ci if (!pmu_caps[i].pmu_name) { 335562306a36Sopenharmony_ci ret = -1; 335662306a36Sopenharmony_ci goto err; 335762306a36Sopenharmony_ci } 335862306a36Sopenharmony_ci if (!pmu_caps[i].nr_caps) { 335962306a36Sopenharmony_ci pr_debug("%s pmu capabilities not available\n", 336062306a36Sopenharmony_ci pmu_caps[i].pmu_name); 336162306a36Sopenharmony_ci } 336262306a36Sopenharmony_ci } 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci ff->ph->env.nr_pmus_with_caps = nr_pmu; 336562306a36Sopenharmony_ci ff->ph->env.pmu_caps = pmu_caps; 336662306a36Sopenharmony_ci return 0; 336762306a36Sopenharmony_ci 336862306a36Sopenharmony_cierr: 336962306a36Sopenharmony_ci for (i = 0; i < nr_pmu; i++) { 337062306a36Sopenharmony_ci for (j = 0; j < pmu_caps[i].nr_caps; j++) 337162306a36Sopenharmony_ci free(pmu_caps[i].caps[j]); 337262306a36Sopenharmony_ci free(pmu_caps[i].caps); 337362306a36Sopenharmony_ci free(pmu_caps[i].pmu_name); 337462306a36Sopenharmony_ci } 337562306a36Sopenharmony_ci 337662306a36Sopenharmony_ci free(pmu_caps); 337762306a36Sopenharmony_ci return ret; 337862306a36Sopenharmony_ci} 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci#define FEAT_OPR(n, func, __full_only) \ 338162306a36Sopenharmony_ci [HEADER_##n] = { \ 338262306a36Sopenharmony_ci .name = __stringify(n), \ 338362306a36Sopenharmony_ci .write = write_##func, \ 338462306a36Sopenharmony_ci .print = print_##func, \ 338562306a36Sopenharmony_ci .full_only = __full_only, \ 338662306a36Sopenharmony_ci .process = process_##func, \ 338762306a36Sopenharmony_ci .synthesize = true \ 338862306a36Sopenharmony_ci } 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci#define FEAT_OPN(n, func, __full_only) \ 339162306a36Sopenharmony_ci [HEADER_##n] = { \ 339262306a36Sopenharmony_ci .name = __stringify(n), \ 339362306a36Sopenharmony_ci .write = write_##func, \ 339462306a36Sopenharmony_ci .print = print_##func, \ 339562306a36Sopenharmony_ci .full_only = __full_only, \ 339662306a36Sopenharmony_ci .process = process_##func \ 339762306a36Sopenharmony_ci } 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_ci/* feature_ops not implemented: */ 340062306a36Sopenharmony_ci#define print_tracing_data NULL 340162306a36Sopenharmony_ci#define print_build_id NULL 340262306a36Sopenharmony_ci 340362306a36Sopenharmony_ci#define process_branch_stack NULL 340462306a36Sopenharmony_ci#define process_stat NULL 340562306a36Sopenharmony_ci 340662306a36Sopenharmony_ci// Only used in util/synthetic-events.c 340762306a36Sopenharmony_ciconst struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; 340862306a36Sopenharmony_ci 340962306a36Sopenharmony_ciconst struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = { 341062306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT 341162306a36Sopenharmony_ci FEAT_OPN(TRACING_DATA, tracing_data, false), 341262306a36Sopenharmony_ci#endif 341362306a36Sopenharmony_ci FEAT_OPN(BUILD_ID, build_id, false), 341462306a36Sopenharmony_ci FEAT_OPR(HOSTNAME, hostname, false), 341562306a36Sopenharmony_ci FEAT_OPR(OSRELEASE, osrelease, false), 341662306a36Sopenharmony_ci FEAT_OPR(VERSION, version, false), 341762306a36Sopenharmony_ci FEAT_OPR(ARCH, arch, false), 341862306a36Sopenharmony_ci FEAT_OPR(NRCPUS, nrcpus, false), 341962306a36Sopenharmony_ci FEAT_OPR(CPUDESC, cpudesc, false), 342062306a36Sopenharmony_ci FEAT_OPR(CPUID, cpuid, false), 342162306a36Sopenharmony_ci FEAT_OPR(TOTAL_MEM, total_mem, false), 342262306a36Sopenharmony_ci FEAT_OPR(EVENT_DESC, event_desc, false), 342362306a36Sopenharmony_ci FEAT_OPR(CMDLINE, cmdline, false), 342462306a36Sopenharmony_ci FEAT_OPR(CPU_TOPOLOGY, cpu_topology, true), 342562306a36Sopenharmony_ci FEAT_OPR(NUMA_TOPOLOGY, numa_topology, true), 342662306a36Sopenharmony_ci FEAT_OPN(BRANCH_STACK, branch_stack, false), 342762306a36Sopenharmony_ci FEAT_OPR(PMU_MAPPINGS, pmu_mappings, false), 342862306a36Sopenharmony_ci FEAT_OPR(GROUP_DESC, group_desc, false), 342962306a36Sopenharmony_ci FEAT_OPN(AUXTRACE, auxtrace, false), 343062306a36Sopenharmony_ci FEAT_OPN(STAT, stat, false), 343162306a36Sopenharmony_ci FEAT_OPN(CACHE, cache, true), 343262306a36Sopenharmony_ci FEAT_OPR(SAMPLE_TIME, sample_time, false), 343362306a36Sopenharmony_ci FEAT_OPR(MEM_TOPOLOGY, mem_topology, true), 343462306a36Sopenharmony_ci FEAT_OPR(CLOCKID, clockid, false), 343562306a36Sopenharmony_ci FEAT_OPN(DIR_FORMAT, dir_format, false), 343662306a36Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT 343762306a36Sopenharmony_ci FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false), 343862306a36Sopenharmony_ci FEAT_OPR(BPF_BTF, bpf_btf, false), 343962306a36Sopenharmony_ci#endif 344062306a36Sopenharmony_ci FEAT_OPR(COMPRESSED, compressed, false), 344162306a36Sopenharmony_ci FEAT_OPR(CPU_PMU_CAPS, cpu_pmu_caps, false), 344262306a36Sopenharmony_ci FEAT_OPR(CLOCK_DATA, clock_data, false), 344362306a36Sopenharmony_ci FEAT_OPN(HYBRID_TOPOLOGY, hybrid_topology, true), 344462306a36Sopenharmony_ci FEAT_OPR(PMU_CAPS, pmu_caps, false), 344562306a36Sopenharmony_ci}; 344662306a36Sopenharmony_ci 344762306a36Sopenharmony_cistruct header_print_data { 344862306a36Sopenharmony_ci FILE *fp; 344962306a36Sopenharmony_ci bool full; /* extended list of headers */ 345062306a36Sopenharmony_ci}; 345162306a36Sopenharmony_ci 345262306a36Sopenharmony_cistatic int perf_file_section__fprintf_info(struct perf_file_section *section, 345362306a36Sopenharmony_ci struct perf_header *ph, 345462306a36Sopenharmony_ci int feat, int fd, void *data) 345562306a36Sopenharmony_ci{ 345662306a36Sopenharmony_ci struct header_print_data *hd = data; 345762306a36Sopenharmony_ci struct feat_fd ff; 345862306a36Sopenharmony_ci 345962306a36Sopenharmony_ci if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { 346062306a36Sopenharmony_ci pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 346162306a36Sopenharmony_ci "%d, continuing...\n", section->offset, feat); 346262306a36Sopenharmony_ci return 0; 346362306a36Sopenharmony_ci } 346462306a36Sopenharmony_ci if (feat >= HEADER_LAST_FEATURE) { 346562306a36Sopenharmony_ci pr_warning("unknown feature %d\n", feat); 346662306a36Sopenharmony_ci return 0; 346762306a36Sopenharmony_ci } 346862306a36Sopenharmony_ci if (!feat_ops[feat].print) 346962306a36Sopenharmony_ci return 0; 347062306a36Sopenharmony_ci 347162306a36Sopenharmony_ci ff = (struct feat_fd) { 347262306a36Sopenharmony_ci .fd = fd, 347362306a36Sopenharmony_ci .ph = ph, 347462306a36Sopenharmony_ci }; 347562306a36Sopenharmony_ci 347662306a36Sopenharmony_ci if (!feat_ops[feat].full_only || hd->full) 347762306a36Sopenharmony_ci feat_ops[feat].print(&ff, hd->fp); 347862306a36Sopenharmony_ci else 347962306a36Sopenharmony_ci fprintf(hd->fp, "# %s info available, use -I to display\n", 348062306a36Sopenharmony_ci feat_ops[feat].name); 348162306a36Sopenharmony_ci 348262306a36Sopenharmony_ci return 0; 348362306a36Sopenharmony_ci} 348462306a36Sopenharmony_ci 348562306a36Sopenharmony_ciint perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) 348662306a36Sopenharmony_ci{ 348762306a36Sopenharmony_ci struct header_print_data hd; 348862306a36Sopenharmony_ci struct perf_header *header = &session->header; 348962306a36Sopenharmony_ci int fd = perf_data__fd(session->data); 349062306a36Sopenharmony_ci struct stat st; 349162306a36Sopenharmony_ci time_t stctime; 349262306a36Sopenharmony_ci int ret, bit; 349362306a36Sopenharmony_ci 349462306a36Sopenharmony_ci hd.fp = fp; 349562306a36Sopenharmony_ci hd.full = full; 349662306a36Sopenharmony_ci 349762306a36Sopenharmony_ci ret = fstat(fd, &st); 349862306a36Sopenharmony_ci if (ret == -1) 349962306a36Sopenharmony_ci return -1; 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_ci stctime = st.st_mtime; 350262306a36Sopenharmony_ci fprintf(fp, "# captured on : %s", ctime(&stctime)); 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci fprintf(fp, "# header version : %u\n", header->version); 350562306a36Sopenharmony_ci fprintf(fp, "# data offset : %" PRIu64 "\n", header->data_offset); 350662306a36Sopenharmony_ci fprintf(fp, "# data size : %" PRIu64 "\n", header->data_size); 350762306a36Sopenharmony_ci fprintf(fp, "# feat offset : %" PRIu64 "\n", header->feat_offset); 350862306a36Sopenharmony_ci 350962306a36Sopenharmony_ci perf_header__process_sections(header, fd, &hd, 351062306a36Sopenharmony_ci perf_file_section__fprintf_info); 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci if (session->data->is_pipe) 351362306a36Sopenharmony_ci return 0; 351462306a36Sopenharmony_ci 351562306a36Sopenharmony_ci fprintf(fp, "# missing features: "); 351662306a36Sopenharmony_ci for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) { 351762306a36Sopenharmony_ci if (bit) 351862306a36Sopenharmony_ci fprintf(fp, "%s ", feat_ops[bit].name); 351962306a36Sopenharmony_ci } 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci fprintf(fp, "\n"); 352262306a36Sopenharmony_ci return 0; 352362306a36Sopenharmony_ci} 352462306a36Sopenharmony_ci 352562306a36Sopenharmony_cistruct header_fw { 352662306a36Sopenharmony_ci struct feat_writer fw; 352762306a36Sopenharmony_ci struct feat_fd *ff; 352862306a36Sopenharmony_ci}; 352962306a36Sopenharmony_ci 353062306a36Sopenharmony_cistatic int feat_writer_cb(struct feat_writer *fw, void *buf, size_t sz) 353162306a36Sopenharmony_ci{ 353262306a36Sopenharmony_ci struct header_fw *h = container_of(fw, struct header_fw, fw); 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci return do_write(h->ff, buf, sz); 353562306a36Sopenharmony_ci} 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_cistatic int do_write_feat(struct feat_fd *ff, int type, 353862306a36Sopenharmony_ci struct perf_file_section **p, 353962306a36Sopenharmony_ci struct evlist *evlist, 354062306a36Sopenharmony_ci struct feat_copier *fc) 354162306a36Sopenharmony_ci{ 354262306a36Sopenharmony_ci int err; 354362306a36Sopenharmony_ci int ret = 0; 354462306a36Sopenharmony_ci 354562306a36Sopenharmony_ci if (perf_header__has_feat(ff->ph, type)) { 354662306a36Sopenharmony_ci if (!feat_ops[type].write) 354762306a36Sopenharmony_ci return -1; 354862306a36Sopenharmony_ci 354962306a36Sopenharmony_ci if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) 355062306a36Sopenharmony_ci return -1; 355162306a36Sopenharmony_ci 355262306a36Sopenharmony_ci (*p)->offset = lseek(ff->fd, 0, SEEK_CUR); 355362306a36Sopenharmony_ci 355462306a36Sopenharmony_ci /* 355562306a36Sopenharmony_ci * Hook to let perf inject copy features sections from the input 355662306a36Sopenharmony_ci * file. 355762306a36Sopenharmony_ci */ 355862306a36Sopenharmony_ci if (fc && fc->copy) { 355962306a36Sopenharmony_ci struct header_fw h = { 356062306a36Sopenharmony_ci .fw.write = feat_writer_cb, 356162306a36Sopenharmony_ci .ff = ff, 356262306a36Sopenharmony_ci }; 356362306a36Sopenharmony_ci 356462306a36Sopenharmony_ci /* ->copy() returns 0 if the feature was not copied */ 356562306a36Sopenharmony_ci err = fc->copy(fc, type, &h.fw); 356662306a36Sopenharmony_ci } else { 356762306a36Sopenharmony_ci err = 0; 356862306a36Sopenharmony_ci } 356962306a36Sopenharmony_ci if (!err) 357062306a36Sopenharmony_ci err = feat_ops[type].write(ff, evlist); 357162306a36Sopenharmony_ci if (err < 0) { 357262306a36Sopenharmony_ci pr_debug("failed to write feature %s\n", feat_ops[type].name); 357362306a36Sopenharmony_ci 357462306a36Sopenharmony_ci /* undo anything written */ 357562306a36Sopenharmony_ci lseek(ff->fd, (*p)->offset, SEEK_SET); 357662306a36Sopenharmony_ci 357762306a36Sopenharmony_ci return -1; 357862306a36Sopenharmony_ci } 357962306a36Sopenharmony_ci (*p)->size = lseek(ff->fd, 0, SEEK_CUR) - (*p)->offset; 358062306a36Sopenharmony_ci (*p)++; 358162306a36Sopenharmony_ci } 358262306a36Sopenharmony_ci return ret; 358362306a36Sopenharmony_ci} 358462306a36Sopenharmony_ci 358562306a36Sopenharmony_cistatic int perf_header__adds_write(struct perf_header *header, 358662306a36Sopenharmony_ci struct evlist *evlist, int fd, 358762306a36Sopenharmony_ci struct feat_copier *fc) 358862306a36Sopenharmony_ci{ 358962306a36Sopenharmony_ci int nr_sections; 359062306a36Sopenharmony_ci struct feat_fd ff; 359162306a36Sopenharmony_ci struct perf_file_section *feat_sec, *p; 359262306a36Sopenharmony_ci int sec_size; 359362306a36Sopenharmony_ci u64 sec_start; 359462306a36Sopenharmony_ci int feat; 359562306a36Sopenharmony_ci int err; 359662306a36Sopenharmony_ci 359762306a36Sopenharmony_ci ff = (struct feat_fd){ 359862306a36Sopenharmony_ci .fd = fd, 359962306a36Sopenharmony_ci .ph = header, 360062306a36Sopenharmony_ci }; 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); 360362306a36Sopenharmony_ci if (!nr_sections) 360462306a36Sopenharmony_ci return 0; 360562306a36Sopenharmony_ci 360662306a36Sopenharmony_ci feat_sec = p = calloc(nr_sections, sizeof(*feat_sec)); 360762306a36Sopenharmony_ci if (feat_sec == NULL) 360862306a36Sopenharmony_ci return -ENOMEM; 360962306a36Sopenharmony_ci 361062306a36Sopenharmony_ci sec_size = sizeof(*feat_sec) * nr_sections; 361162306a36Sopenharmony_ci 361262306a36Sopenharmony_ci sec_start = header->feat_offset; 361362306a36Sopenharmony_ci lseek(fd, sec_start + sec_size, SEEK_SET); 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ci for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { 361662306a36Sopenharmony_ci if (do_write_feat(&ff, feat, &p, evlist, fc)) 361762306a36Sopenharmony_ci perf_header__clear_feat(header, feat); 361862306a36Sopenharmony_ci } 361962306a36Sopenharmony_ci 362062306a36Sopenharmony_ci lseek(fd, sec_start, SEEK_SET); 362162306a36Sopenharmony_ci /* 362262306a36Sopenharmony_ci * may write more than needed due to dropped feature, but 362362306a36Sopenharmony_ci * this is okay, reader will skip the missing entries 362462306a36Sopenharmony_ci */ 362562306a36Sopenharmony_ci err = do_write(&ff, feat_sec, sec_size); 362662306a36Sopenharmony_ci if (err < 0) 362762306a36Sopenharmony_ci pr_debug("failed to write feature section\n"); 362862306a36Sopenharmony_ci free(feat_sec); 362962306a36Sopenharmony_ci return err; 363062306a36Sopenharmony_ci} 363162306a36Sopenharmony_ci 363262306a36Sopenharmony_ciint perf_header__write_pipe(int fd) 363362306a36Sopenharmony_ci{ 363462306a36Sopenharmony_ci struct perf_pipe_file_header f_header; 363562306a36Sopenharmony_ci struct feat_fd ff; 363662306a36Sopenharmony_ci int err; 363762306a36Sopenharmony_ci 363862306a36Sopenharmony_ci ff = (struct feat_fd){ .fd = fd }; 363962306a36Sopenharmony_ci 364062306a36Sopenharmony_ci f_header = (struct perf_pipe_file_header){ 364162306a36Sopenharmony_ci .magic = PERF_MAGIC, 364262306a36Sopenharmony_ci .size = sizeof(f_header), 364362306a36Sopenharmony_ci }; 364462306a36Sopenharmony_ci 364562306a36Sopenharmony_ci err = do_write(&ff, &f_header, sizeof(f_header)); 364662306a36Sopenharmony_ci if (err < 0) { 364762306a36Sopenharmony_ci pr_debug("failed to write perf pipe header\n"); 364862306a36Sopenharmony_ci return err; 364962306a36Sopenharmony_ci } 365062306a36Sopenharmony_ci 365162306a36Sopenharmony_ci return 0; 365262306a36Sopenharmony_ci} 365362306a36Sopenharmony_ci 365462306a36Sopenharmony_cistatic int perf_session__do_write_header(struct perf_session *session, 365562306a36Sopenharmony_ci struct evlist *evlist, 365662306a36Sopenharmony_ci int fd, bool at_exit, 365762306a36Sopenharmony_ci struct feat_copier *fc) 365862306a36Sopenharmony_ci{ 365962306a36Sopenharmony_ci struct perf_file_header f_header; 366062306a36Sopenharmony_ci struct perf_file_attr f_attr; 366162306a36Sopenharmony_ci struct perf_header *header = &session->header; 366262306a36Sopenharmony_ci struct evsel *evsel; 366362306a36Sopenharmony_ci struct feat_fd ff; 366462306a36Sopenharmony_ci u64 attr_offset; 366562306a36Sopenharmony_ci int err; 366662306a36Sopenharmony_ci 366762306a36Sopenharmony_ci ff = (struct feat_fd){ .fd = fd}; 366862306a36Sopenharmony_ci lseek(fd, sizeof(f_header), SEEK_SET); 366962306a36Sopenharmony_ci 367062306a36Sopenharmony_ci evlist__for_each_entry(session->evlist, evsel) { 367162306a36Sopenharmony_ci evsel->id_offset = lseek(fd, 0, SEEK_CUR); 367262306a36Sopenharmony_ci err = do_write(&ff, evsel->core.id, evsel->core.ids * sizeof(u64)); 367362306a36Sopenharmony_ci if (err < 0) { 367462306a36Sopenharmony_ci pr_debug("failed to write perf header\n"); 367562306a36Sopenharmony_ci return err; 367662306a36Sopenharmony_ci } 367762306a36Sopenharmony_ci } 367862306a36Sopenharmony_ci 367962306a36Sopenharmony_ci attr_offset = lseek(ff.fd, 0, SEEK_CUR); 368062306a36Sopenharmony_ci 368162306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 368262306a36Sopenharmony_ci if (evsel->core.attr.size < sizeof(evsel->core.attr)) { 368362306a36Sopenharmony_ci /* 368462306a36Sopenharmony_ci * We are likely in "perf inject" and have read 368562306a36Sopenharmony_ci * from an older file. Update attr size so that 368662306a36Sopenharmony_ci * reader gets the right offset to the ids. 368762306a36Sopenharmony_ci */ 368862306a36Sopenharmony_ci evsel->core.attr.size = sizeof(evsel->core.attr); 368962306a36Sopenharmony_ci } 369062306a36Sopenharmony_ci f_attr = (struct perf_file_attr){ 369162306a36Sopenharmony_ci .attr = evsel->core.attr, 369262306a36Sopenharmony_ci .ids = { 369362306a36Sopenharmony_ci .offset = evsel->id_offset, 369462306a36Sopenharmony_ci .size = evsel->core.ids * sizeof(u64), 369562306a36Sopenharmony_ci } 369662306a36Sopenharmony_ci }; 369762306a36Sopenharmony_ci err = do_write(&ff, &f_attr, sizeof(f_attr)); 369862306a36Sopenharmony_ci if (err < 0) { 369962306a36Sopenharmony_ci pr_debug("failed to write perf header attribute\n"); 370062306a36Sopenharmony_ci return err; 370162306a36Sopenharmony_ci } 370262306a36Sopenharmony_ci } 370362306a36Sopenharmony_ci 370462306a36Sopenharmony_ci if (!header->data_offset) 370562306a36Sopenharmony_ci header->data_offset = lseek(fd, 0, SEEK_CUR); 370662306a36Sopenharmony_ci header->feat_offset = header->data_offset + header->data_size; 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci if (at_exit) { 370962306a36Sopenharmony_ci err = perf_header__adds_write(header, evlist, fd, fc); 371062306a36Sopenharmony_ci if (err < 0) 371162306a36Sopenharmony_ci return err; 371262306a36Sopenharmony_ci } 371362306a36Sopenharmony_ci 371462306a36Sopenharmony_ci f_header = (struct perf_file_header){ 371562306a36Sopenharmony_ci .magic = PERF_MAGIC, 371662306a36Sopenharmony_ci .size = sizeof(f_header), 371762306a36Sopenharmony_ci .attr_size = sizeof(f_attr), 371862306a36Sopenharmony_ci .attrs = { 371962306a36Sopenharmony_ci .offset = attr_offset, 372062306a36Sopenharmony_ci .size = evlist->core.nr_entries * sizeof(f_attr), 372162306a36Sopenharmony_ci }, 372262306a36Sopenharmony_ci .data = { 372362306a36Sopenharmony_ci .offset = header->data_offset, 372462306a36Sopenharmony_ci .size = header->data_size, 372562306a36Sopenharmony_ci }, 372662306a36Sopenharmony_ci /* event_types is ignored, store zeros */ 372762306a36Sopenharmony_ci }; 372862306a36Sopenharmony_ci 372962306a36Sopenharmony_ci memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci lseek(fd, 0, SEEK_SET); 373262306a36Sopenharmony_ci err = do_write(&ff, &f_header, sizeof(f_header)); 373362306a36Sopenharmony_ci if (err < 0) { 373462306a36Sopenharmony_ci pr_debug("failed to write perf header\n"); 373562306a36Sopenharmony_ci return err; 373662306a36Sopenharmony_ci } 373762306a36Sopenharmony_ci lseek(fd, header->data_offset + header->data_size, SEEK_SET); 373862306a36Sopenharmony_ci 373962306a36Sopenharmony_ci return 0; 374062306a36Sopenharmony_ci} 374162306a36Sopenharmony_ci 374262306a36Sopenharmony_ciint perf_session__write_header(struct perf_session *session, 374362306a36Sopenharmony_ci struct evlist *evlist, 374462306a36Sopenharmony_ci int fd, bool at_exit) 374562306a36Sopenharmony_ci{ 374662306a36Sopenharmony_ci return perf_session__do_write_header(session, evlist, fd, at_exit, NULL); 374762306a36Sopenharmony_ci} 374862306a36Sopenharmony_ci 374962306a36Sopenharmony_cisize_t perf_session__data_offset(const struct evlist *evlist) 375062306a36Sopenharmony_ci{ 375162306a36Sopenharmony_ci struct evsel *evsel; 375262306a36Sopenharmony_ci size_t data_offset; 375362306a36Sopenharmony_ci 375462306a36Sopenharmony_ci data_offset = sizeof(struct perf_file_header); 375562306a36Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 375662306a36Sopenharmony_ci data_offset += evsel->core.ids * sizeof(u64); 375762306a36Sopenharmony_ci } 375862306a36Sopenharmony_ci data_offset += evlist->core.nr_entries * sizeof(struct perf_file_attr); 375962306a36Sopenharmony_ci 376062306a36Sopenharmony_ci return data_offset; 376162306a36Sopenharmony_ci} 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_ciint perf_session__inject_header(struct perf_session *session, 376462306a36Sopenharmony_ci struct evlist *evlist, 376562306a36Sopenharmony_ci int fd, 376662306a36Sopenharmony_ci struct feat_copier *fc) 376762306a36Sopenharmony_ci{ 376862306a36Sopenharmony_ci return perf_session__do_write_header(session, evlist, fd, true, fc); 376962306a36Sopenharmony_ci} 377062306a36Sopenharmony_ci 377162306a36Sopenharmony_cistatic int perf_header__getbuffer64(struct perf_header *header, 377262306a36Sopenharmony_ci int fd, void *buf, size_t size) 377362306a36Sopenharmony_ci{ 377462306a36Sopenharmony_ci if (readn(fd, buf, size) <= 0) 377562306a36Sopenharmony_ci return -1; 377662306a36Sopenharmony_ci 377762306a36Sopenharmony_ci if (header->needs_swap) 377862306a36Sopenharmony_ci mem_bswap_64(buf, size); 377962306a36Sopenharmony_ci 378062306a36Sopenharmony_ci return 0; 378162306a36Sopenharmony_ci} 378262306a36Sopenharmony_ci 378362306a36Sopenharmony_ciint perf_header__process_sections(struct perf_header *header, int fd, 378462306a36Sopenharmony_ci void *data, 378562306a36Sopenharmony_ci int (*process)(struct perf_file_section *section, 378662306a36Sopenharmony_ci struct perf_header *ph, 378762306a36Sopenharmony_ci int feat, int fd, void *data)) 378862306a36Sopenharmony_ci{ 378962306a36Sopenharmony_ci struct perf_file_section *feat_sec, *sec; 379062306a36Sopenharmony_ci int nr_sections; 379162306a36Sopenharmony_ci int sec_size; 379262306a36Sopenharmony_ci int feat; 379362306a36Sopenharmony_ci int err; 379462306a36Sopenharmony_ci 379562306a36Sopenharmony_ci nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); 379662306a36Sopenharmony_ci if (!nr_sections) 379762306a36Sopenharmony_ci return 0; 379862306a36Sopenharmony_ci 379962306a36Sopenharmony_ci feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec)); 380062306a36Sopenharmony_ci if (!feat_sec) 380162306a36Sopenharmony_ci return -1; 380262306a36Sopenharmony_ci 380362306a36Sopenharmony_ci sec_size = sizeof(*feat_sec) * nr_sections; 380462306a36Sopenharmony_ci 380562306a36Sopenharmony_ci lseek(fd, header->feat_offset, SEEK_SET); 380662306a36Sopenharmony_ci 380762306a36Sopenharmony_ci err = perf_header__getbuffer64(header, fd, feat_sec, sec_size); 380862306a36Sopenharmony_ci if (err < 0) 380962306a36Sopenharmony_ci goto out_free; 381062306a36Sopenharmony_ci 381162306a36Sopenharmony_ci for_each_set_bit(feat, header->adds_features, HEADER_LAST_FEATURE) { 381262306a36Sopenharmony_ci err = process(sec++, header, feat, fd, data); 381362306a36Sopenharmony_ci if (err < 0) 381462306a36Sopenharmony_ci goto out_free; 381562306a36Sopenharmony_ci } 381662306a36Sopenharmony_ci err = 0; 381762306a36Sopenharmony_ciout_free: 381862306a36Sopenharmony_ci free(feat_sec); 381962306a36Sopenharmony_ci return err; 382062306a36Sopenharmony_ci} 382162306a36Sopenharmony_ci 382262306a36Sopenharmony_cistatic const int attr_file_abi_sizes[] = { 382362306a36Sopenharmony_ci [0] = PERF_ATTR_SIZE_VER0, 382462306a36Sopenharmony_ci [1] = PERF_ATTR_SIZE_VER1, 382562306a36Sopenharmony_ci [2] = PERF_ATTR_SIZE_VER2, 382662306a36Sopenharmony_ci [3] = PERF_ATTR_SIZE_VER3, 382762306a36Sopenharmony_ci [4] = PERF_ATTR_SIZE_VER4, 382862306a36Sopenharmony_ci 0, 382962306a36Sopenharmony_ci}; 383062306a36Sopenharmony_ci 383162306a36Sopenharmony_ci/* 383262306a36Sopenharmony_ci * In the legacy file format, the magic number is not used to encode endianness. 383362306a36Sopenharmony_ci * hdr_sz was used to encode endianness. But given that hdr_sz can vary based 383462306a36Sopenharmony_ci * on ABI revisions, we need to try all combinations for all endianness to 383562306a36Sopenharmony_ci * detect the endianness. 383662306a36Sopenharmony_ci */ 383762306a36Sopenharmony_cistatic int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph) 383862306a36Sopenharmony_ci{ 383962306a36Sopenharmony_ci uint64_t ref_size, attr_size; 384062306a36Sopenharmony_ci int i; 384162306a36Sopenharmony_ci 384262306a36Sopenharmony_ci for (i = 0 ; attr_file_abi_sizes[i]; i++) { 384362306a36Sopenharmony_ci ref_size = attr_file_abi_sizes[i] 384462306a36Sopenharmony_ci + sizeof(struct perf_file_section); 384562306a36Sopenharmony_ci if (hdr_sz != ref_size) { 384662306a36Sopenharmony_ci attr_size = bswap_64(hdr_sz); 384762306a36Sopenharmony_ci if (attr_size != ref_size) 384862306a36Sopenharmony_ci continue; 384962306a36Sopenharmony_ci 385062306a36Sopenharmony_ci ph->needs_swap = true; 385162306a36Sopenharmony_ci } 385262306a36Sopenharmony_ci pr_debug("ABI%d perf.data file detected, need_swap=%d\n", 385362306a36Sopenharmony_ci i, 385462306a36Sopenharmony_ci ph->needs_swap); 385562306a36Sopenharmony_ci return 0; 385662306a36Sopenharmony_ci } 385762306a36Sopenharmony_ci /* could not determine endianness */ 385862306a36Sopenharmony_ci return -1; 385962306a36Sopenharmony_ci} 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_ci#define PERF_PIPE_HDR_VER0 16 386262306a36Sopenharmony_ci 386362306a36Sopenharmony_cistatic const size_t attr_pipe_abi_sizes[] = { 386462306a36Sopenharmony_ci [0] = PERF_PIPE_HDR_VER0, 386562306a36Sopenharmony_ci 0, 386662306a36Sopenharmony_ci}; 386762306a36Sopenharmony_ci 386862306a36Sopenharmony_ci/* 386962306a36Sopenharmony_ci * In the legacy pipe format, there is an implicit assumption that endianness 387062306a36Sopenharmony_ci * between host recording the samples, and host parsing the samples is the 387162306a36Sopenharmony_ci * same. This is not always the case given that the pipe output may always be 387262306a36Sopenharmony_ci * redirected into a file and analyzed on a different machine with possibly a 387362306a36Sopenharmony_ci * different endianness and perf_event ABI revisions in the perf tool itself. 387462306a36Sopenharmony_ci */ 387562306a36Sopenharmony_cistatic int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph) 387662306a36Sopenharmony_ci{ 387762306a36Sopenharmony_ci u64 attr_size; 387862306a36Sopenharmony_ci int i; 387962306a36Sopenharmony_ci 388062306a36Sopenharmony_ci for (i = 0 ; attr_pipe_abi_sizes[i]; i++) { 388162306a36Sopenharmony_ci if (hdr_sz != attr_pipe_abi_sizes[i]) { 388262306a36Sopenharmony_ci attr_size = bswap_64(hdr_sz); 388362306a36Sopenharmony_ci if (attr_size != hdr_sz) 388462306a36Sopenharmony_ci continue; 388562306a36Sopenharmony_ci 388662306a36Sopenharmony_ci ph->needs_swap = true; 388762306a36Sopenharmony_ci } 388862306a36Sopenharmony_ci pr_debug("Pipe ABI%d perf.data file detected\n", i); 388962306a36Sopenharmony_ci return 0; 389062306a36Sopenharmony_ci } 389162306a36Sopenharmony_ci return -1; 389262306a36Sopenharmony_ci} 389362306a36Sopenharmony_ci 389462306a36Sopenharmony_cibool is_perf_magic(u64 magic) 389562306a36Sopenharmony_ci{ 389662306a36Sopenharmony_ci if (!memcmp(&magic, __perf_magic1, sizeof(magic)) 389762306a36Sopenharmony_ci || magic == __perf_magic2 389862306a36Sopenharmony_ci || magic == __perf_magic2_sw) 389962306a36Sopenharmony_ci return true; 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci return false; 390262306a36Sopenharmony_ci} 390362306a36Sopenharmony_ci 390462306a36Sopenharmony_cistatic int check_magic_endian(u64 magic, uint64_t hdr_sz, 390562306a36Sopenharmony_ci bool is_pipe, struct perf_header *ph) 390662306a36Sopenharmony_ci{ 390762306a36Sopenharmony_ci int ret; 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci /* check for legacy format */ 391062306a36Sopenharmony_ci ret = memcmp(&magic, __perf_magic1, sizeof(magic)); 391162306a36Sopenharmony_ci if (ret == 0) { 391262306a36Sopenharmony_ci ph->version = PERF_HEADER_VERSION_1; 391362306a36Sopenharmony_ci pr_debug("legacy perf.data format\n"); 391462306a36Sopenharmony_ci if (is_pipe) 391562306a36Sopenharmony_ci return try_all_pipe_abis(hdr_sz, ph); 391662306a36Sopenharmony_ci 391762306a36Sopenharmony_ci return try_all_file_abis(hdr_sz, ph); 391862306a36Sopenharmony_ci } 391962306a36Sopenharmony_ci /* 392062306a36Sopenharmony_ci * the new magic number serves two purposes: 392162306a36Sopenharmony_ci * - unique number to identify actual perf.data files 392262306a36Sopenharmony_ci * - encode endianness of file 392362306a36Sopenharmony_ci */ 392462306a36Sopenharmony_ci ph->version = PERF_HEADER_VERSION_2; 392562306a36Sopenharmony_ci 392662306a36Sopenharmony_ci /* check magic number with one endianness */ 392762306a36Sopenharmony_ci if (magic == __perf_magic2) 392862306a36Sopenharmony_ci return 0; 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci /* check magic number with opposite endianness */ 393162306a36Sopenharmony_ci if (magic != __perf_magic2_sw) 393262306a36Sopenharmony_ci return -1; 393362306a36Sopenharmony_ci 393462306a36Sopenharmony_ci ph->needs_swap = true; 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci return 0; 393762306a36Sopenharmony_ci} 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_ciint perf_file_header__read(struct perf_file_header *header, 394062306a36Sopenharmony_ci struct perf_header *ph, int fd) 394162306a36Sopenharmony_ci{ 394262306a36Sopenharmony_ci ssize_t ret; 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci lseek(fd, 0, SEEK_SET); 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ci ret = readn(fd, header, sizeof(*header)); 394762306a36Sopenharmony_ci if (ret <= 0) 394862306a36Sopenharmony_ci return -1; 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_ci if (check_magic_endian(header->magic, 395162306a36Sopenharmony_ci header->attr_size, false, ph) < 0) { 395262306a36Sopenharmony_ci pr_debug("magic/endian check failed\n"); 395362306a36Sopenharmony_ci return -1; 395462306a36Sopenharmony_ci } 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_ci if (ph->needs_swap) { 395762306a36Sopenharmony_ci mem_bswap_64(header, offsetof(struct perf_file_header, 395862306a36Sopenharmony_ci adds_features)); 395962306a36Sopenharmony_ci } 396062306a36Sopenharmony_ci 396162306a36Sopenharmony_ci if (header->size != sizeof(*header)) { 396262306a36Sopenharmony_ci /* Support the previous format */ 396362306a36Sopenharmony_ci if (header->size == offsetof(typeof(*header), adds_features)) 396462306a36Sopenharmony_ci bitmap_zero(header->adds_features, HEADER_FEAT_BITS); 396562306a36Sopenharmony_ci else 396662306a36Sopenharmony_ci return -1; 396762306a36Sopenharmony_ci } else if (ph->needs_swap) { 396862306a36Sopenharmony_ci /* 396962306a36Sopenharmony_ci * feature bitmap is declared as an array of unsigned longs -- 397062306a36Sopenharmony_ci * not good since its size can differ between the host that 397162306a36Sopenharmony_ci * generated the data file and the host analyzing the file. 397262306a36Sopenharmony_ci * 397362306a36Sopenharmony_ci * We need to handle endianness, but we don't know the size of 397462306a36Sopenharmony_ci * the unsigned long where the file was generated. Take a best 397562306a36Sopenharmony_ci * guess at determining it: try 64-bit swap first (ie., file 397662306a36Sopenharmony_ci * created on a 64-bit host), and check if the hostname feature 397762306a36Sopenharmony_ci * bit is set (this feature bit is forced on as of fbe96f2). 397862306a36Sopenharmony_ci * If the bit is not, undo the 64-bit swap and try a 32-bit 397962306a36Sopenharmony_ci * swap. If the hostname bit is still not set (e.g., older data 398062306a36Sopenharmony_ci * file), punt and fallback to the original behavior -- 398162306a36Sopenharmony_ci * clearing all feature bits and setting buildid. 398262306a36Sopenharmony_ci */ 398362306a36Sopenharmony_ci mem_bswap_64(&header->adds_features, 398462306a36Sopenharmony_ci BITS_TO_U64(HEADER_FEAT_BITS)); 398562306a36Sopenharmony_ci 398662306a36Sopenharmony_ci if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { 398762306a36Sopenharmony_ci /* unswap as u64 */ 398862306a36Sopenharmony_ci mem_bswap_64(&header->adds_features, 398962306a36Sopenharmony_ci BITS_TO_U64(HEADER_FEAT_BITS)); 399062306a36Sopenharmony_ci 399162306a36Sopenharmony_ci /* unswap as u32 */ 399262306a36Sopenharmony_ci mem_bswap_32(&header->adds_features, 399362306a36Sopenharmony_ci BITS_TO_U32(HEADER_FEAT_BITS)); 399462306a36Sopenharmony_ci } 399562306a36Sopenharmony_ci 399662306a36Sopenharmony_ci if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { 399762306a36Sopenharmony_ci bitmap_zero(header->adds_features, HEADER_FEAT_BITS); 399862306a36Sopenharmony_ci __set_bit(HEADER_BUILD_ID, header->adds_features); 399962306a36Sopenharmony_ci } 400062306a36Sopenharmony_ci } 400162306a36Sopenharmony_ci 400262306a36Sopenharmony_ci memcpy(&ph->adds_features, &header->adds_features, 400362306a36Sopenharmony_ci sizeof(ph->adds_features)); 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci ph->data_offset = header->data.offset; 400662306a36Sopenharmony_ci ph->data_size = header->data.size; 400762306a36Sopenharmony_ci ph->feat_offset = header->data.offset + header->data.size; 400862306a36Sopenharmony_ci return 0; 400962306a36Sopenharmony_ci} 401062306a36Sopenharmony_ci 401162306a36Sopenharmony_cistatic int perf_file_section__process(struct perf_file_section *section, 401262306a36Sopenharmony_ci struct perf_header *ph, 401362306a36Sopenharmony_ci int feat, int fd, void *data) 401462306a36Sopenharmony_ci{ 401562306a36Sopenharmony_ci struct feat_fd fdd = { 401662306a36Sopenharmony_ci .fd = fd, 401762306a36Sopenharmony_ci .ph = ph, 401862306a36Sopenharmony_ci .size = section->size, 401962306a36Sopenharmony_ci .offset = section->offset, 402062306a36Sopenharmony_ci }; 402162306a36Sopenharmony_ci 402262306a36Sopenharmony_ci if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { 402362306a36Sopenharmony_ci pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 402462306a36Sopenharmony_ci "%d, continuing...\n", section->offset, feat); 402562306a36Sopenharmony_ci return 0; 402662306a36Sopenharmony_ci } 402762306a36Sopenharmony_ci 402862306a36Sopenharmony_ci if (feat >= HEADER_LAST_FEATURE) { 402962306a36Sopenharmony_ci pr_debug("unknown feature %d, continuing...\n", feat); 403062306a36Sopenharmony_ci return 0; 403162306a36Sopenharmony_ci } 403262306a36Sopenharmony_ci 403362306a36Sopenharmony_ci if (!feat_ops[feat].process) 403462306a36Sopenharmony_ci return 0; 403562306a36Sopenharmony_ci 403662306a36Sopenharmony_ci return feat_ops[feat].process(&fdd, data); 403762306a36Sopenharmony_ci} 403862306a36Sopenharmony_ci 403962306a36Sopenharmony_cistatic int perf_file_header__read_pipe(struct perf_pipe_file_header *header, 404062306a36Sopenharmony_ci struct perf_header *ph, 404162306a36Sopenharmony_ci struct perf_data* data, 404262306a36Sopenharmony_ci bool repipe, int repipe_fd) 404362306a36Sopenharmony_ci{ 404462306a36Sopenharmony_ci struct feat_fd ff = { 404562306a36Sopenharmony_ci .fd = repipe_fd, 404662306a36Sopenharmony_ci .ph = ph, 404762306a36Sopenharmony_ci }; 404862306a36Sopenharmony_ci ssize_t ret; 404962306a36Sopenharmony_ci 405062306a36Sopenharmony_ci ret = perf_data__read(data, header, sizeof(*header)); 405162306a36Sopenharmony_ci if (ret <= 0) 405262306a36Sopenharmony_ci return -1; 405362306a36Sopenharmony_ci 405462306a36Sopenharmony_ci if (check_magic_endian(header->magic, header->size, true, ph) < 0) { 405562306a36Sopenharmony_ci pr_debug("endian/magic failed\n"); 405662306a36Sopenharmony_ci return -1; 405762306a36Sopenharmony_ci } 405862306a36Sopenharmony_ci 405962306a36Sopenharmony_ci if (ph->needs_swap) 406062306a36Sopenharmony_ci header->size = bswap_64(header->size); 406162306a36Sopenharmony_ci 406262306a36Sopenharmony_ci if (repipe && do_write(&ff, header, sizeof(*header)) < 0) 406362306a36Sopenharmony_ci return -1; 406462306a36Sopenharmony_ci 406562306a36Sopenharmony_ci return 0; 406662306a36Sopenharmony_ci} 406762306a36Sopenharmony_ci 406862306a36Sopenharmony_cistatic int perf_header__read_pipe(struct perf_session *session, int repipe_fd) 406962306a36Sopenharmony_ci{ 407062306a36Sopenharmony_ci struct perf_header *header = &session->header; 407162306a36Sopenharmony_ci struct perf_pipe_file_header f_header; 407262306a36Sopenharmony_ci 407362306a36Sopenharmony_ci if (perf_file_header__read_pipe(&f_header, header, session->data, 407462306a36Sopenharmony_ci session->repipe, repipe_fd) < 0) { 407562306a36Sopenharmony_ci pr_debug("incompatible file format\n"); 407662306a36Sopenharmony_ci return -EINVAL; 407762306a36Sopenharmony_ci } 407862306a36Sopenharmony_ci 407962306a36Sopenharmony_ci return f_header.size == sizeof(f_header) ? 0 : -1; 408062306a36Sopenharmony_ci} 408162306a36Sopenharmony_ci 408262306a36Sopenharmony_cistatic int read_attr(int fd, struct perf_header *ph, 408362306a36Sopenharmony_ci struct perf_file_attr *f_attr) 408462306a36Sopenharmony_ci{ 408562306a36Sopenharmony_ci struct perf_event_attr *attr = &f_attr->attr; 408662306a36Sopenharmony_ci size_t sz, left; 408762306a36Sopenharmony_ci size_t our_sz = sizeof(f_attr->attr); 408862306a36Sopenharmony_ci ssize_t ret; 408962306a36Sopenharmony_ci 409062306a36Sopenharmony_ci memset(f_attr, 0, sizeof(*f_attr)); 409162306a36Sopenharmony_ci 409262306a36Sopenharmony_ci /* read minimal guaranteed structure */ 409362306a36Sopenharmony_ci ret = readn(fd, attr, PERF_ATTR_SIZE_VER0); 409462306a36Sopenharmony_ci if (ret <= 0) { 409562306a36Sopenharmony_ci pr_debug("cannot read %d bytes of header attr\n", 409662306a36Sopenharmony_ci PERF_ATTR_SIZE_VER0); 409762306a36Sopenharmony_ci return -1; 409862306a36Sopenharmony_ci } 409962306a36Sopenharmony_ci 410062306a36Sopenharmony_ci /* on file perf_event_attr size */ 410162306a36Sopenharmony_ci sz = attr->size; 410262306a36Sopenharmony_ci 410362306a36Sopenharmony_ci if (ph->needs_swap) 410462306a36Sopenharmony_ci sz = bswap_32(sz); 410562306a36Sopenharmony_ci 410662306a36Sopenharmony_ci if (sz == 0) { 410762306a36Sopenharmony_ci /* assume ABI0 */ 410862306a36Sopenharmony_ci sz = PERF_ATTR_SIZE_VER0; 410962306a36Sopenharmony_ci } else if (sz > our_sz) { 411062306a36Sopenharmony_ci pr_debug("file uses a more recent and unsupported ABI" 411162306a36Sopenharmony_ci " (%zu bytes extra)\n", sz - our_sz); 411262306a36Sopenharmony_ci return -1; 411362306a36Sopenharmony_ci } 411462306a36Sopenharmony_ci /* what we have not yet read and that we know about */ 411562306a36Sopenharmony_ci left = sz - PERF_ATTR_SIZE_VER0; 411662306a36Sopenharmony_ci if (left) { 411762306a36Sopenharmony_ci void *ptr = attr; 411862306a36Sopenharmony_ci ptr += PERF_ATTR_SIZE_VER0; 411962306a36Sopenharmony_ci 412062306a36Sopenharmony_ci ret = readn(fd, ptr, left); 412162306a36Sopenharmony_ci } 412262306a36Sopenharmony_ci /* read perf_file_section, ids are read in caller */ 412362306a36Sopenharmony_ci ret = readn(fd, &f_attr->ids, sizeof(f_attr->ids)); 412462306a36Sopenharmony_ci 412562306a36Sopenharmony_ci return ret <= 0 ? -1 : 0; 412662306a36Sopenharmony_ci} 412762306a36Sopenharmony_ci 412862306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT 412962306a36Sopenharmony_cistatic int evsel__prepare_tracepoint_event(struct evsel *evsel, struct tep_handle *pevent) 413062306a36Sopenharmony_ci{ 413162306a36Sopenharmony_ci struct tep_event *event; 413262306a36Sopenharmony_ci char bf[128]; 413362306a36Sopenharmony_ci 413462306a36Sopenharmony_ci /* already prepared */ 413562306a36Sopenharmony_ci if (evsel->tp_format) 413662306a36Sopenharmony_ci return 0; 413762306a36Sopenharmony_ci 413862306a36Sopenharmony_ci if (pevent == NULL) { 413962306a36Sopenharmony_ci pr_debug("broken or missing trace data\n"); 414062306a36Sopenharmony_ci return -1; 414162306a36Sopenharmony_ci } 414262306a36Sopenharmony_ci 414362306a36Sopenharmony_ci event = tep_find_event(pevent, evsel->core.attr.config); 414462306a36Sopenharmony_ci if (event == NULL) { 414562306a36Sopenharmony_ci pr_debug("cannot find event format for %d\n", (int)evsel->core.attr.config); 414662306a36Sopenharmony_ci return -1; 414762306a36Sopenharmony_ci } 414862306a36Sopenharmony_ci 414962306a36Sopenharmony_ci if (!evsel->name) { 415062306a36Sopenharmony_ci snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name); 415162306a36Sopenharmony_ci evsel->name = strdup(bf); 415262306a36Sopenharmony_ci if (evsel->name == NULL) 415362306a36Sopenharmony_ci return -1; 415462306a36Sopenharmony_ci } 415562306a36Sopenharmony_ci 415662306a36Sopenharmony_ci evsel->tp_format = event; 415762306a36Sopenharmony_ci return 0; 415862306a36Sopenharmony_ci} 415962306a36Sopenharmony_ci 416062306a36Sopenharmony_cistatic int evlist__prepare_tracepoint_events(struct evlist *evlist, struct tep_handle *pevent) 416162306a36Sopenharmony_ci{ 416262306a36Sopenharmony_ci struct evsel *pos; 416362306a36Sopenharmony_ci 416462306a36Sopenharmony_ci evlist__for_each_entry(evlist, pos) { 416562306a36Sopenharmony_ci if (pos->core.attr.type == PERF_TYPE_TRACEPOINT && 416662306a36Sopenharmony_ci evsel__prepare_tracepoint_event(pos, pevent)) 416762306a36Sopenharmony_ci return -1; 416862306a36Sopenharmony_ci } 416962306a36Sopenharmony_ci 417062306a36Sopenharmony_ci return 0; 417162306a36Sopenharmony_ci} 417262306a36Sopenharmony_ci#endif 417362306a36Sopenharmony_ci 417462306a36Sopenharmony_ciint perf_session__read_header(struct perf_session *session, int repipe_fd) 417562306a36Sopenharmony_ci{ 417662306a36Sopenharmony_ci struct perf_data *data = session->data; 417762306a36Sopenharmony_ci struct perf_header *header = &session->header; 417862306a36Sopenharmony_ci struct perf_file_header f_header; 417962306a36Sopenharmony_ci struct perf_file_attr f_attr; 418062306a36Sopenharmony_ci u64 f_id; 418162306a36Sopenharmony_ci int nr_attrs, nr_ids, i, j, err; 418262306a36Sopenharmony_ci int fd = perf_data__fd(data); 418362306a36Sopenharmony_ci 418462306a36Sopenharmony_ci session->evlist = evlist__new(); 418562306a36Sopenharmony_ci if (session->evlist == NULL) 418662306a36Sopenharmony_ci return -ENOMEM; 418762306a36Sopenharmony_ci 418862306a36Sopenharmony_ci session->evlist->env = &header->env; 418962306a36Sopenharmony_ci session->machines.host.env = &header->env; 419062306a36Sopenharmony_ci 419162306a36Sopenharmony_ci /* 419262306a36Sopenharmony_ci * We can read 'pipe' data event from regular file, 419362306a36Sopenharmony_ci * check for the pipe header regardless of source. 419462306a36Sopenharmony_ci */ 419562306a36Sopenharmony_ci err = perf_header__read_pipe(session, repipe_fd); 419662306a36Sopenharmony_ci if (!err || perf_data__is_pipe(data)) { 419762306a36Sopenharmony_ci data->is_pipe = true; 419862306a36Sopenharmony_ci return err; 419962306a36Sopenharmony_ci } 420062306a36Sopenharmony_ci 420162306a36Sopenharmony_ci if (perf_file_header__read(&f_header, header, fd) < 0) 420262306a36Sopenharmony_ci return -EINVAL; 420362306a36Sopenharmony_ci 420462306a36Sopenharmony_ci if (header->needs_swap && data->in_place_update) { 420562306a36Sopenharmony_ci pr_err("In-place update not supported when byte-swapping is required\n"); 420662306a36Sopenharmony_ci return -EINVAL; 420762306a36Sopenharmony_ci } 420862306a36Sopenharmony_ci 420962306a36Sopenharmony_ci /* 421062306a36Sopenharmony_ci * Sanity check that perf.data was written cleanly; data size is 421162306a36Sopenharmony_ci * initialized to 0 and updated only if the on_exit function is run. 421262306a36Sopenharmony_ci * If data size is still 0 then the file contains only partial 421362306a36Sopenharmony_ci * information. Just warn user and process it as much as it can. 421462306a36Sopenharmony_ci */ 421562306a36Sopenharmony_ci if (f_header.data.size == 0) { 421662306a36Sopenharmony_ci pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n" 421762306a36Sopenharmony_ci "Was the 'perf record' command properly terminated?\n", 421862306a36Sopenharmony_ci data->file.path); 421962306a36Sopenharmony_ci } 422062306a36Sopenharmony_ci 422162306a36Sopenharmony_ci if (f_header.attr_size == 0) { 422262306a36Sopenharmony_ci pr_err("ERROR: The %s file's attr size field is 0 which is unexpected.\n" 422362306a36Sopenharmony_ci "Was the 'perf record' command properly terminated?\n", 422462306a36Sopenharmony_ci data->file.path); 422562306a36Sopenharmony_ci return -EINVAL; 422662306a36Sopenharmony_ci } 422762306a36Sopenharmony_ci 422862306a36Sopenharmony_ci nr_attrs = f_header.attrs.size / f_header.attr_size; 422962306a36Sopenharmony_ci lseek(fd, f_header.attrs.offset, SEEK_SET); 423062306a36Sopenharmony_ci 423162306a36Sopenharmony_ci for (i = 0; i < nr_attrs; i++) { 423262306a36Sopenharmony_ci struct evsel *evsel; 423362306a36Sopenharmony_ci off_t tmp; 423462306a36Sopenharmony_ci 423562306a36Sopenharmony_ci if (read_attr(fd, header, &f_attr) < 0) 423662306a36Sopenharmony_ci goto out_errno; 423762306a36Sopenharmony_ci 423862306a36Sopenharmony_ci if (header->needs_swap) { 423962306a36Sopenharmony_ci f_attr.ids.size = bswap_64(f_attr.ids.size); 424062306a36Sopenharmony_ci f_attr.ids.offset = bswap_64(f_attr.ids.offset); 424162306a36Sopenharmony_ci perf_event__attr_swap(&f_attr.attr); 424262306a36Sopenharmony_ci } 424362306a36Sopenharmony_ci 424462306a36Sopenharmony_ci tmp = lseek(fd, 0, SEEK_CUR); 424562306a36Sopenharmony_ci evsel = evsel__new(&f_attr.attr); 424662306a36Sopenharmony_ci 424762306a36Sopenharmony_ci if (evsel == NULL) 424862306a36Sopenharmony_ci goto out_delete_evlist; 424962306a36Sopenharmony_ci 425062306a36Sopenharmony_ci evsel->needs_swap = header->needs_swap; 425162306a36Sopenharmony_ci /* 425262306a36Sopenharmony_ci * Do it before so that if perf_evsel__alloc_id fails, this 425362306a36Sopenharmony_ci * entry gets purged too at evlist__delete(). 425462306a36Sopenharmony_ci */ 425562306a36Sopenharmony_ci evlist__add(session->evlist, evsel); 425662306a36Sopenharmony_ci 425762306a36Sopenharmony_ci nr_ids = f_attr.ids.size / sizeof(u64); 425862306a36Sopenharmony_ci /* 425962306a36Sopenharmony_ci * We don't have the cpu and thread maps on the header, so 426062306a36Sopenharmony_ci * for allocating the perf_sample_id table we fake 1 cpu and 426162306a36Sopenharmony_ci * hattr->ids threads. 426262306a36Sopenharmony_ci */ 426362306a36Sopenharmony_ci if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids)) 426462306a36Sopenharmony_ci goto out_delete_evlist; 426562306a36Sopenharmony_ci 426662306a36Sopenharmony_ci lseek(fd, f_attr.ids.offset, SEEK_SET); 426762306a36Sopenharmony_ci 426862306a36Sopenharmony_ci for (j = 0; j < nr_ids; j++) { 426962306a36Sopenharmony_ci if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id))) 427062306a36Sopenharmony_ci goto out_errno; 427162306a36Sopenharmony_ci 427262306a36Sopenharmony_ci perf_evlist__id_add(&session->evlist->core, &evsel->core, 0, j, f_id); 427362306a36Sopenharmony_ci } 427462306a36Sopenharmony_ci 427562306a36Sopenharmony_ci lseek(fd, tmp, SEEK_SET); 427662306a36Sopenharmony_ci } 427762306a36Sopenharmony_ci 427862306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT 427962306a36Sopenharmony_ci perf_header__process_sections(header, fd, &session->tevent, 428062306a36Sopenharmony_ci perf_file_section__process); 428162306a36Sopenharmony_ci 428262306a36Sopenharmony_ci if (evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent)) 428362306a36Sopenharmony_ci goto out_delete_evlist; 428462306a36Sopenharmony_ci#else 428562306a36Sopenharmony_ci perf_header__process_sections(header, fd, NULL, perf_file_section__process); 428662306a36Sopenharmony_ci#endif 428762306a36Sopenharmony_ci 428862306a36Sopenharmony_ci return 0; 428962306a36Sopenharmony_ciout_errno: 429062306a36Sopenharmony_ci return -errno; 429162306a36Sopenharmony_ci 429262306a36Sopenharmony_ciout_delete_evlist: 429362306a36Sopenharmony_ci evlist__delete(session->evlist); 429462306a36Sopenharmony_ci session->evlist = NULL; 429562306a36Sopenharmony_ci return -ENOMEM; 429662306a36Sopenharmony_ci} 429762306a36Sopenharmony_ci 429862306a36Sopenharmony_ciint perf_event__process_feature(struct perf_session *session, 429962306a36Sopenharmony_ci union perf_event *event) 430062306a36Sopenharmony_ci{ 430162306a36Sopenharmony_ci struct perf_tool *tool = session->tool; 430262306a36Sopenharmony_ci struct feat_fd ff = { .fd = 0 }; 430362306a36Sopenharmony_ci struct perf_record_header_feature *fe = (struct perf_record_header_feature *)event; 430462306a36Sopenharmony_ci int type = fe->header.type; 430562306a36Sopenharmony_ci u64 feat = fe->feat_id; 430662306a36Sopenharmony_ci int ret = 0; 430762306a36Sopenharmony_ci 430862306a36Sopenharmony_ci if (type < 0 || type >= PERF_RECORD_HEADER_MAX) { 430962306a36Sopenharmony_ci pr_warning("invalid record type %d in pipe-mode\n", type); 431062306a36Sopenharmony_ci return 0; 431162306a36Sopenharmony_ci } 431262306a36Sopenharmony_ci if (feat == HEADER_RESERVED || feat >= HEADER_LAST_FEATURE) { 431362306a36Sopenharmony_ci pr_warning("invalid record type %d in pipe-mode\n", type); 431462306a36Sopenharmony_ci return -1; 431562306a36Sopenharmony_ci } 431662306a36Sopenharmony_ci 431762306a36Sopenharmony_ci if (!feat_ops[feat].process) 431862306a36Sopenharmony_ci return 0; 431962306a36Sopenharmony_ci 432062306a36Sopenharmony_ci ff.buf = (void *)fe->data; 432162306a36Sopenharmony_ci ff.size = event->header.size - sizeof(*fe); 432262306a36Sopenharmony_ci ff.ph = &session->header; 432362306a36Sopenharmony_ci 432462306a36Sopenharmony_ci if (feat_ops[feat].process(&ff, NULL)) { 432562306a36Sopenharmony_ci ret = -1; 432662306a36Sopenharmony_ci goto out; 432762306a36Sopenharmony_ci } 432862306a36Sopenharmony_ci 432962306a36Sopenharmony_ci if (!feat_ops[feat].print || !tool->show_feat_hdr) 433062306a36Sopenharmony_ci goto out; 433162306a36Sopenharmony_ci 433262306a36Sopenharmony_ci if (!feat_ops[feat].full_only || 433362306a36Sopenharmony_ci tool->show_feat_hdr >= SHOW_FEAT_HEADER_FULL_INFO) { 433462306a36Sopenharmony_ci feat_ops[feat].print(&ff, stdout); 433562306a36Sopenharmony_ci } else { 433662306a36Sopenharmony_ci fprintf(stdout, "# %s info available, use -I to display\n", 433762306a36Sopenharmony_ci feat_ops[feat].name); 433862306a36Sopenharmony_ci } 433962306a36Sopenharmony_ciout: 434062306a36Sopenharmony_ci free_event_desc(ff.events); 434162306a36Sopenharmony_ci return ret; 434262306a36Sopenharmony_ci} 434362306a36Sopenharmony_ci 434462306a36Sopenharmony_cisize_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) 434562306a36Sopenharmony_ci{ 434662306a36Sopenharmony_ci struct perf_record_event_update *ev = &event->event_update; 434762306a36Sopenharmony_ci struct perf_cpu_map *map; 434862306a36Sopenharmony_ci size_t ret; 434962306a36Sopenharmony_ci 435062306a36Sopenharmony_ci ret = fprintf(fp, "\n... id: %" PRI_lu64 "\n", ev->id); 435162306a36Sopenharmony_ci 435262306a36Sopenharmony_ci switch (ev->type) { 435362306a36Sopenharmony_ci case PERF_EVENT_UPDATE__SCALE: 435462306a36Sopenharmony_ci ret += fprintf(fp, "... scale: %f\n", ev->scale.scale); 435562306a36Sopenharmony_ci break; 435662306a36Sopenharmony_ci case PERF_EVENT_UPDATE__UNIT: 435762306a36Sopenharmony_ci ret += fprintf(fp, "... unit: %s\n", ev->unit); 435862306a36Sopenharmony_ci break; 435962306a36Sopenharmony_ci case PERF_EVENT_UPDATE__NAME: 436062306a36Sopenharmony_ci ret += fprintf(fp, "... name: %s\n", ev->name); 436162306a36Sopenharmony_ci break; 436262306a36Sopenharmony_ci case PERF_EVENT_UPDATE__CPUS: 436362306a36Sopenharmony_ci ret += fprintf(fp, "... "); 436462306a36Sopenharmony_ci 436562306a36Sopenharmony_ci map = cpu_map__new_data(&ev->cpus.cpus); 436662306a36Sopenharmony_ci if (map) { 436762306a36Sopenharmony_ci ret += cpu_map__fprintf(map, fp); 436862306a36Sopenharmony_ci perf_cpu_map__put(map); 436962306a36Sopenharmony_ci } else 437062306a36Sopenharmony_ci ret += fprintf(fp, "failed to get cpus\n"); 437162306a36Sopenharmony_ci break; 437262306a36Sopenharmony_ci default: 437362306a36Sopenharmony_ci ret += fprintf(fp, "... unknown type\n"); 437462306a36Sopenharmony_ci break; 437562306a36Sopenharmony_ci } 437662306a36Sopenharmony_ci 437762306a36Sopenharmony_ci return ret; 437862306a36Sopenharmony_ci} 437962306a36Sopenharmony_ci 438062306a36Sopenharmony_ciint perf_event__process_attr(struct perf_tool *tool __maybe_unused, 438162306a36Sopenharmony_ci union perf_event *event, 438262306a36Sopenharmony_ci struct evlist **pevlist) 438362306a36Sopenharmony_ci{ 438462306a36Sopenharmony_ci u32 i, n_ids; 438562306a36Sopenharmony_ci u64 *ids; 438662306a36Sopenharmony_ci struct evsel *evsel; 438762306a36Sopenharmony_ci struct evlist *evlist = *pevlist; 438862306a36Sopenharmony_ci 438962306a36Sopenharmony_ci if (evlist == NULL) { 439062306a36Sopenharmony_ci *pevlist = evlist = evlist__new(); 439162306a36Sopenharmony_ci if (evlist == NULL) 439262306a36Sopenharmony_ci return -ENOMEM; 439362306a36Sopenharmony_ci } 439462306a36Sopenharmony_ci 439562306a36Sopenharmony_ci evsel = evsel__new(&event->attr.attr); 439662306a36Sopenharmony_ci if (evsel == NULL) 439762306a36Sopenharmony_ci return -ENOMEM; 439862306a36Sopenharmony_ci 439962306a36Sopenharmony_ci evlist__add(evlist, evsel); 440062306a36Sopenharmony_ci 440162306a36Sopenharmony_ci n_ids = event->header.size - sizeof(event->header) - event->attr.attr.size; 440262306a36Sopenharmony_ci n_ids = n_ids / sizeof(u64); 440362306a36Sopenharmony_ci /* 440462306a36Sopenharmony_ci * We don't have the cpu and thread maps on the header, so 440562306a36Sopenharmony_ci * for allocating the perf_sample_id table we fake 1 cpu and 440662306a36Sopenharmony_ci * hattr->ids threads. 440762306a36Sopenharmony_ci */ 440862306a36Sopenharmony_ci if (perf_evsel__alloc_id(&evsel->core, 1, n_ids)) 440962306a36Sopenharmony_ci return -ENOMEM; 441062306a36Sopenharmony_ci 441162306a36Sopenharmony_ci ids = perf_record_header_attr_id(event); 441262306a36Sopenharmony_ci for (i = 0; i < n_ids; i++) { 441362306a36Sopenharmony_ci perf_evlist__id_add(&evlist->core, &evsel->core, 0, i, ids[i]); 441462306a36Sopenharmony_ci } 441562306a36Sopenharmony_ci 441662306a36Sopenharmony_ci return 0; 441762306a36Sopenharmony_ci} 441862306a36Sopenharmony_ci 441962306a36Sopenharmony_ciint perf_event__process_event_update(struct perf_tool *tool __maybe_unused, 442062306a36Sopenharmony_ci union perf_event *event, 442162306a36Sopenharmony_ci struct evlist **pevlist) 442262306a36Sopenharmony_ci{ 442362306a36Sopenharmony_ci struct perf_record_event_update *ev = &event->event_update; 442462306a36Sopenharmony_ci struct evlist *evlist; 442562306a36Sopenharmony_ci struct evsel *evsel; 442662306a36Sopenharmony_ci struct perf_cpu_map *map; 442762306a36Sopenharmony_ci 442862306a36Sopenharmony_ci if (dump_trace) 442962306a36Sopenharmony_ci perf_event__fprintf_event_update(event, stdout); 443062306a36Sopenharmony_ci 443162306a36Sopenharmony_ci if (!pevlist || *pevlist == NULL) 443262306a36Sopenharmony_ci return -EINVAL; 443362306a36Sopenharmony_ci 443462306a36Sopenharmony_ci evlist = *pevlist; 443562306a36Sopenharmony_ci 443662306a36Sopenharmony_ci evsel = evlist__id2evsel(evlist, ev->id); 443762306a36Sopenharmony_ci if (evsel == NULL) 443862306a36Sopenharmony_ci return -EINVAL; 443962306a36Sopenharmony_ci 444062306a36Sopenharmony_ci switch (ev->type) { 444162306a36Sopenharmony_ci case PERF_EVENT_UPDATE__UNIT: 444262306a36Sopenharmony_ci free((char *)evsel->unit); 444362306a36Sopenharmony_ci evsel->unit = strdup(ev->unit); 444462306a36Sopenharmony_ci break; 444562306a36Sopenharmony_ci case PERF_EVENT_UPDATE__NAME: 444662306a36Sopenharmony_ci free(evsel->name); 444762306a36Sopenharmony_ci evsel->name = strdup(ev->name); 444862306a36Sopenharmony_ci break; 444962306a36Sopenharmony_ci case PERF_EVENT_UPDATE__SCALE: 445062306a36Sopenharmony_ci evsel->scale = ev->scale.scale; 445162306a36Sopenharmony_ci break; 445262306a36Sopenharmony_ci case PERF_EVENT_UPDATE__CPUS: 445362306a36Sopenharmony_ci map = cpu_map__new_data(&ev->cpus.cpus); 445462306a36Sopenharmony_ci if (map) { 445562306a36Sopenharmony_ci perf_cpu_map__put(evsel->core.own_cpus); 445662306a36Sopenharmony_ci evsel->core.own_cpus = map; 445762306a36Sopenharmony_ci } else 445862306a36Sopenharmony_ci pr_err("failed to get event_update cpus\n"); 445962306a36Sopenharmony_ci default: 446062306a36Sopenharmony_ci break; 446162306a36Sopenharmony_ci } 446262306a36Sopenharmony_ci 446362306a36Sopenharmony_ci return 0; 446462306a36Sopenharmony_ci} 446562306a36Sopenharmony_ci 446662306a36Sopenharmony_ci#ifdef HAVE_LIBTRACEEVENT 446762306a36Sopenharmony_ciint perf_event__process_tracing_data(struct perf_session *session, 446862306a36Sopenharmony_ci union perf_event *event) 446962306a36Sopenharmony_ci{ 447062306a36Sopenharmony_ci ssize_t size_read, padding, size = event->tracing_data.size; 447162306a36Sopenharmony_ci int fd = perf_data__fd(session->data); 447262306a36Sopenharmony_ci char buf[BUFSIZ]; 447362306a36Sopenharmony_ci 447462306a36Sopenharmony_ci /* 447562306a36Sopenharmony_ci * The pipe fd is already in proper place and in any case 447662306a36Sopenharmony_ci * we can't move it, and we'd screw the case where we read 447762306a36Sopenharmony_ci * 'pipe' data from regular file. The trace_report reads 447862306a36Sopenharmony_ci * data from 'fd' so we need to set it directly behind the 447962306a36Sopenharmony_ci * event, where the tracing data starts. 448062306a36Sopenharmony_ci */ 448162306a36Sopenharmony_ci if (!perf_data__is_pipe(session->data)) { 448262306a36Sopenharmony_ci off_t offset = lseek(fd, 0, SEEK_CUR); 448362306a36Sopenharmony_ci 448462306a36Sopenharmony_ci /* setup for reading amidst mmap */ 448562306a36Sopenharmony_ci lseek(fd, offset + sizeof(struct perf_record_header_tracing_data), 448662306a36Sopenharmony_ci SEEK_SET); 448762306a36Sopenharmony_ci } 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci size_read = trace_report(fd, &session->tevent, 449062306a36Sopenharmony_ci session->repipe); 449162306a36Sopenharmony_ci padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 449262306a36Sopenharmony_ci 449362306a36Sopenharmony_ci if (readn(fd, buf, padding) < 0) { 449462306a36Sopenharmony_ci pr_err("%s: reading input file", __func__); 449562306a36Sopenharmony_ci return -1; 449662306a36Sopenharmony_ci } 449762306a36Sopenharmony_ci if (session->repipe) { 449862306a36Sopenharmony_ci int retw = write(STDOUT_FILENO, buf, padding); 449962306a36Sopenharmony_ci if (retw <= 0 || retw != padding) { 450062306a36Sopenharmony_ci pr_err("%s: repiping tracing data padding", __func__); 450162306a36Sopenharmony_ci return -1; 450262306a36Sopenharmony_ci } 450362306a36Sopenharmony_ci } 450462306a36Sopenharmony_ci 450562306a36Sopenharmony_ci if (size_read + padding != size) { 450662306a36Sopenharmony_ci pr_err("%s: tracing data size mismatch", __func__); 450762306a36Sopenharmony_ci return -1; 450862306a36Sopenharmony_ci } 450962306a36Sopenharmony_ci 451062306a36Sopenharmony_ci evlist__prepare_tracepoint_events(session->evlist, session->tevent.pevent); 451162306a36Sopenharmony_ci 451262306a36Sopenharmony_ci return size_read + padding; 451362306a36Sopenharmony_ci} 451462306a36Sopenharmony_ci#endif 451562306a36Sopenharmony_ci 451662306a36Sopenharmony_ciint perf_event__process_build_id(struct perf_session *session, 451762306a36Sopenharmony_ci union perf_event *event) 451862306a36Sopenharmony_ci{ 451962306a36Sopenharmony_ci __event_process_build_id(&event->build_id, 452062306a36Sopenharmony_ci event->build_id.filename, 452162306a36Sopenharmony_ci session); 452262306a36Sopenharmony_ci return 0; 452362306a36Sopenharmony_ci} 4524