18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <errno.h> 38c2ecf20Sopenharmony_ci#include <inttypes.h> 48c2ecf20Sopenharmony_ci#include "string2.h" 58c2ecf20Sopenharmony_ci#include <sys/param.h> 68c2ecf20Sopenharmony_ci#include <sys/types.h> 78c2ecf20Sopenharmony_ci#include <byteswap.h> 88c2ecf20Sopenharmony_ci#include <unistd.h> 98c2ecf20Sopenharmony_ci#include <stdio.h> 108c2ecf20Sopenharmony_ci#include <stdlib.h> 118c2ecf20Sopenharmony_ci#include <linux/compiler.h> 128c2ecf20Sopenharmony_ci#include <linux/list.h> 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/bitops.h> 158c2ecf20Sopenharmony_ci#include <linux/string.h> 168c2ecf20Sopenharmony_ci#include <linux/stringify.h> 178c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 188c2ecf20Sopenharmony_ci#include <sys/stat.h> 198c2ecf20Sopenharmony_ci#include <sys/utsname.h> 208c2ecf20Sopenharmony_ci#include <linux/time64.h> 218c2ecf20Sopenharmony_ci#include <dirent.h> 228c2ecf20Sopenharmony_ci#include <bpf/libbpf.h> 238c2ecf20Sopenharmony_ci#include <perf/cpumap.h> 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#include "dso.h" 268c2ecf20Sopenharmony_ci#include "evlist.h" 278c2ecf20Sopenharmony_ci#include "evsel.h" 288c2ecf20Sopenharmony_ci#include "util/evsel_fprintf.h" 298c2ecf20Sopenharmony_ci#include "header.h" 308c2ecf20Sopenharmony_ci#include "memswap.h" 318c2ecf20Sopenharmony_ci#include "trace-event.h" 328c2ecf20Sopenharmony_ci#include "session.h" 338c2ecf20Sopenharmony_ci#include "symbol.h" 348c2ecf20Sopenharmony_ci#include "debug.h" 358c2ecf20Sopenharmony_ci#include "cpumap.h" 368c2ecf20Sopenharmony_ci#include "pmu.h" 378c2ecf20Sopenharmony_ci#include "vdso.h" 388c2ecf20Sopenharmony_ci#include "strbuf.h" 398c2ecf20Sopenharmony_ci#include "build-id.h" 408c2ecf20Sopenharmony_ci#include "data.h" 418c2ecf20Sopenharmony_ci#include <api/fs/fs.h> 428c2ecf20Sopenharmony_ci#include "asm/bug.h" 438c2ecf20Sopenharmony_ci#include "tool.h" 448c2ecf20Sopenharmony_ci#include "time-utils.h" 458c2ecf20Sopenharmony_ci#include "units.h" 468c2ecf20Sopenharmony_ci#include "util/util.h" // perf_exe() 478c2ecf20Sopenharmony_ci#include "cputopo.h" 488c2ecf20Sopenharmony_ci#include "bpf-event.h" 498c2ecf20Sopenharmony_ci#include "clockid.h" 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#include <linux/ctype.h> 528c2ecf20Sopenharmony_ci#include <internal/lib.h> 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * magic2 = "PERFILE2" 568c2ecf20Sopenharmony_ci * must be a numerical value to let the endianness 578c2ecf20Sopenharmony_ci * determine the memory layout. That way we are able 588c2ecf20Sopenharmony_ci * to detect endianness when reading the perf.data file 598c2ecf20Sopenharmony_ci * back. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * we check for legacy (PERFFILE) format. 628c2ecf20Sopenharmony_ci */ 638c2ecf20Sopenharmony_cistatic const char *__perf_magic1 = "PERFFILE"; 648c2ecf20Sopenharmony_cistatic const u64 __perf_magic2 = 0x32454c4946524550ULL; 658c2ecf20Sopenharmony_cistatic const u64 __perf_magic2_sw = 0x50455246494c4532ULL; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci#define PERF_MAGIC __perf_magic2 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_ciconst char perf_version_string[] = PERF_VERSION; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistruct perf_file_attr { 728c2ecf20Sopenharmony_ci struct perf_event_attr attr; 738c2ecf20Sopenharmony_ci struct perf_file_section ids; 748c2ecf20Sopenharmony_ci}; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_civoid perf_header__set_feat(struct perf_header *header, int feat) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci set_bit(feat, header->adds_features); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_civoid perf_header__clear_feat(struct perf_header *header, int feat) 828c2ecf20Sopenharmony_ci{ 838c2ecf20Sopenharmony_ci clear_bit(feat, header->adds_features); 848c2ecf20Sopenharmony_ci} 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cibool perf_header__has_feat(const struct perf_header *header, int feat) 878c2ecf20Sopenharmony_ci{ 888c2ecf20Sopenharmony_ci return test_bit(feat, header->adds_features); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic int __do_write_fd(struct feat_fd *ff, const void *buf, size_t size) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci ssize_t ret = writen(ff->fd, buf, size); 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci if (ret != (ssize_t)size) 968c2ecf20Sopenharmony_ci return ret < 0 ? (int)ret : -1; 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_cistatic int __do_write_buf(struct feat_fd *ff, const void *buf, size_t size) 1018c2ecf20Sopenharmony_ci{ 1028c2ecf20Sopenharmony_ci /* struct perf_event_header::size is u16 */ 1038c2ecf20Sopenharmony_ci const size_t max_size = 0xffff - sizeof(struct perf_event_header); 1048c2ecf20Sopenharmony_ci size_t new_size = ff->size; 1058c2ecf20Sopenharmony_ci void *addr; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci if (size + ff->offset > max_size) 1088c2ecf20Sopenharmony_ci return -E2BIG; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci while (size > (new_size - ff->offset)) 1118c2ecf20Sopenharmony_ci new_size <<= 1; 1128c2ecf20Sopenharmony_ci new_size = min(max_size, new_size); 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci if (ff->size < new_size) { 1158c2ecf20Sopenharmony_ci addr = realloc(ff->buf, new_size); 1168c2ecf20Sopenharmony_ci if (!addr) 1178c2ecf20Sopenharmony_ci return -ENOMEM; 1188c2ecf20Sopenharmony_ci ff->buf = addr; 1198c2ecf20Sopenharmony_ci ff->size = new_size; 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci memcpy(ff->buf + ff->offset, buf, size); 1238c2ecf20Sopenharmony_ci ff->offset += size; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci return 0; 1268c2ecf20Sopenharmony_ci} 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci/* Return: 0 if succeded, -ERR if failed. */ 1298c2ecf20Sopenharmony_ciint do_write(struct feat_fd *ff, const void *buf, size_t size) 1308c2ecf20Sopenharmony_ci{ 1318c2ecf20Sopenharmony_ci if (!ff->buf) 1328c2ecf20Sopenharmony_ci return __do_write_fd(ff, buf, size); 1338c2ecf20Sopenharmony_ci return __do_write_buf(ff, buf, size); 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/* Return: 0 if succeded, -ERR if failed. */ 1378c2ecf20Sopenharmony_cistatic int do_write_bitmap(struct feat_fd *ff, unsigned long *set, u64 size) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci u64 *p = (u64 *) set; 1408c2ecf20Sopenharmony_ci int i, ret; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci ret = do_write(ff, &size, sizeof(size)); 1438c2ecf20Sopenharmony_ci if (ret < 0) 1448c2ecf20Sopenharmony_ci return ret; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci for (i = 0; (u64) i < BITS_TO_U64(size); i++) { 1478c2ecf20Sopenharmony_ci ret = do_write(ff, p + i, sizeof(*p)); 1488c2ecf20Sopenharmony_ci if (ret < 0) 1498c2ecf20Sopenharmony_ci return ret; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci/* Return: 0 if succeded, -ERR if failed. */ 1568c2ecf20Sopenharmony_ciint write_padded(struct feat_fd *ff, const void *bf, 1578c2ecf20Sopenharmony_ci size_t count, size_t count_aligned) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci static const char zero_buf[NAME_ALIGN]; 1608c2ecf20Sopenharmony_ci int err = do_write(ff, bf, count); 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci if (!err) 1638c2ecf20Sopenharmony_ci err = do_write(ff, zero_buf, count_aligned - count); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return err; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci#define string_size(str) \ 1698c2ecf20Sopenharmony_ci (PERF_ALIGN((strlen(str) + 1), NAME_ALIGN) + sizeof(u32)) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci/* Return: 0 if succeded, -ERR if failed. */ 1728c2ecf20Sopenharmony_cistatic int do_write_string(struct feat_fd *ff, const char *str) 1738c2ecf20Sopenharmony_ci{ 1748c2ecf20Sopenharmony_ci u32 len, olen; 1758c2ecf20Sopenharmony_ci int ret; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci olen = strlen(str) + 1; 1788c2ecf20Sopenharmony_ci len = PERF_ALIGN(olen, NAME_ALIGN); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci /* write len, incl. \0 */ 1818c2ecf20Sopenharmony_ci ret = do_write(ff, &len, sizeof(len)); 1828c2ecf20Sopenharmony_ci if (ret < 0) 1838c2ecf20Sopenharmony_ci return ret; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return write_padded(ff, str, olen, len); 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int __do_read_fd(struct feat_fd *ff, void *addr, ssize_t size) 1898c2ecf20Sopenharmony_ci{ 1908c2ecf20Sopenharmony_ci ssize_t ret = readn(ff->fd, addr, size); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (ret != size) 1938c2ecf20Sopenharmony_ci return ret < 0 ? (int)ret : -1; 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int __do_read_buf(struct feat_fd *ff, void *addr, ssize_t size) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci if (size > (ssize_t)ff->size - ff->offset) 2008c2ecf20Sopenharmony_ci return -1; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci memcpy(addr, ff->buf + ff->offset, size); 2038c2ecf20Sopenharmony_ci ff->offset += size; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci return 0; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic int __do_read(struct feat_fd *ff, void *addr, ssize_t size) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci if (!ff->buf) 2128c2ecf20Sopenharmony_ci return __do_read_fd(ff, addr, size); 2138c2ecf20Sopenharmony_ci return __do_read_buf(ff, addr, size); 2148c2ecf20Sopenharmony_ci} 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_cistatic int do_read_u32(struct feat_fd *ff, u32 *addr) 2178c2ecf20Sopenharmony_ci{ 2188c2ecf20Sopenharmony_ci int ret; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci ret = __do_read(ff, addr, sizeof(*addr)); 2218c2ecf20Sopenharmony_ci if (ret) 2228c2ecf20Sopenharmony_ci return ret; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci if (ff->ph->needs_swap) 2258c2ecf20Sopenharmony_ci *addr = bswap_32(*addr); 2268c2ecf20Sopenharmony_ci return 0; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int do_read_u64(struct feat_fd *ff, u64 *addr) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci int ret; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci ret = __do_read(ff, addr, sizeof(*addr)); 2348c2ecf20Sopenharmony_ci if (ret) 2358c2ecf20Sopenharmony_ci return ret; 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (ff->ph->needs_swap) 2388c2ecf20Sopenharmony_ci *addr = bswap_64(*addr); 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_cistatic char *do_read_string(struct feat_fd *ff) 2438c2ecf20Sopenharmony_ci{ 2448c2ecf20Sopenharmony_ci u32 len; 2458c2ecf20Sopenharmony_ci char *buf; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci if (do_read_u32(ff, &len)) 2488c2ecf20Sopenharmony_ci return NULL; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci buf = malloc(len); 2518c2ecf20Sopenharmony_ci if (!buf) 2528c2ecf20Sopenharmony_ci return NULL; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci if (!__do_read(ff, buf, len)) { 2558c2ecf20Sopenharmony_ci /* 2568c2ecf20Sopenharmony_ci * strings are padded by zeroes 2578c2ecf20Sopenharmony_ci * thus the actual strlen of buf 2588c2ecf20Sopenharmony_ci * may be less than len 2598c2ecf20Sopenharmony_ci */ 2608c2ecf20Sopenharmony_ci return buf; 2618c2ecf20Sopenharmony_ci } 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci free(buf); 2648c2ecf20Sopenharmony_ci return NULL; 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci/* Return: 0 if succeded, -ERR if failed. */ 2688c2ecf20Sopenharmony_cistatic int do_read_bitmap(struct feat_fd *ff, unsigned long **pset, u64 *psize) 2698c2ecf20Sopenharmony_ci{ 2708c2ecf20Sopenharmony_ci unsigned long *set; 2718c2ecf20Sopenharmony_ci u64 size, *p; 2728c2ecf20Sopenharmony_ci int i, ret; 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci ret = do_read_u64(ff, &size); 2758c2ecf20Sopenharmony_ci if (ret) 2768c2ecf20Sopenharmony_ci return ret; 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci set = bitmap_alloc(size); 2798c2ecf20Sopenharmony_ci if (!set) 2808c2ecf20Sopenharmony_ci return -ENOMEM; 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci p = (u64 *) set; 2838c2ecf20Sopenharmony_ci 2848c2ecf20Sopenharmony_ci for (i = 0; (u64) i < BITS_TO_U64(size); i++) { 2858c2ecf20Sopenharmony_ci ret = do_read_u64(ff, p + i); 2868c2ecf20Sopenharmony_ci if (ret < 0) { 2878c2ecf20Sopenharmony_ci free(set); 2888c2ecf20Sopenharmony_ci return ret; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci *pset = set; 2938c2ecf20Sopenharmony_ci *psize = size; 2948c2ecf20Sopenharmony_ci return 0; 2958c2ecf20Sopenharmony_ci} 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_cistatic int write_tracing_data(struct feat_fd *ff, 2988c2ecf20Sopenharmony_ci struct evlist *evlist) 2998c2ecf20Sopenharmony_ci{ 3008c2ecf20Sopenharmony_ci if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) 3018c2ecf20Sopenharmony_ci return -1; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci return read_tracing_data(ff->fd, &evlist->core.entries); 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int write_build_id(struct feat_fd *ff, 3078c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct perf_session *session; 3108c2ecf20Sopenharmony_ci int err; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (!perf_session__read_build_ids(session, true)) 3158c2ecf20Sopenharmony_ci return -1; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) 3188c2ecf20Sopenharmony_ci return -1; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci err = perf_session__write_buildid_table(session, ff); 3218c2ecf20Sopenharmony_ci if (err < 0) { 3228c2ecf20Sopenharmony_ci pr_debug("failed to write buildid table\n"); 3238c2ecf20Sopenharmony_ci return err; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci perf_session__cache_build_ids(session); 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci return 0; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_cistatic int write_hostname(struct feat_fd *ff, 3318c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 3328c2ecf20Sopenharmony_ci{ 3338c2ecf20Sopenharmony_ci struct utsname uts; 3348c2ecf20Sopenharmony_ci int ret; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci ret = uname(&uts); 3378c2ecf20Sopenharmony_ci if (ret < 0) 3388c2ecf20Sopenharmony_ci return -1; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci return do_write_string(ff, uts.nodename); 3418c2ecf20Sopenharmony_ci} 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_cistatic int write_osrelease(struct feat_fd *ff, 3448c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct utsname uts; 3478c2ecf20Sopenharmony_ci int ret; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci ret = uname(&uts); 3508c2ecf20Sopenharmony_ci if (ret < 0) 3518c2ecf20Sopenharmony_ci return -1; 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci return do_write_string(ff, uts.release); 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_cistatic int write_arch(struct feat_fd *ff, 3578c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 3588c2ecf20Sopenharmony_ci{ 3598c2ecf20Sopenharmony_ci struct utsname uts; 3608c2ecf20Sopenharmony_ci int ret; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci ret = uname(&uts); 3638c2ecf20Sopenharmony_ci if (ret < 0) 3648c2ecf20Sopenharmony_ci return -1; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci return do_write_string(ff, uts.machine); 3678c2ecf20Sopenharmony_ci} 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_cistatic int write_version(struct feat_fd *ff, 3708c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci return do_write_string(ff, perf_version_string); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic int __write_cpudesc(struct feat_fd *ff, const char *cpuinfo_proc) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci FILE *file; 3788c2ecf20Sopenharmony_ci char *buf = NULL; 3798c2ecf20Sopenharmony_ci char *s, *p; 3808c2ecf20Sopenharmony_ci const char *search = cpuinfo_proc; 3818c2ecf20Sopenharmony_ci size_t len = 0; 3828c2ecf20Sopenharmony_ci int ret = -1; 3838c2ecf20Sopenharmony_ci 3848c2ecf20Sopenharmony_ci if (!search) 3858c2ecf20Sopenharmony_ci return -1; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci file = fopen("/proc/cpuinfo", "r"); 3888c2ecf20Sopenharmony_ci if (!file) 3898c2ecf20Sopenharmony_ci return -1; 3908c2ecf20Sopenharmony_ci 3918c2ecf20Sopenharmony_ci while (getline(&buf, &len, file) > 0) { 3928c2ecf20Sopenharmony_ci ret = strncmp(buf, search, strlen(search)); 3938c2ecf20Sopenharmony_ci if (!ret) 3948c2ecf20Sopenharmony_ci break; 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci if (ret) { 3988c2ecf20Sopenharmony_ci ret = -1; 3998c2ecf20Sopenharmony_ci goto done; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci s = buf; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci p = strchr(buf, ':'); 4058c2ecf20Sopenharmony_ci if (p && *(p+1) == ' ' && *(p+2)) 4068c2ecf20Sopenharmony_ci s = p + 2; 4078c2ecf20Sopenharmony_ci p = strchr(s, '\n'); 4088c2ecf20Sopenharmony_ci if (p) 4098c2ecf20Sopenharmony_ci *p = '\0'; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci /* squash extra space characters (branding string) */ 4128c2ecf20Sopenharmony_ci p = s; 4138c2ecf20Sopenharmony_ci while (*p) { 4148c2ecf20Sopenharmony_ci if (isspace(*p)) { 4158c2ecf20Sopenharmony_ci char *r = p + 1; 4168c2ecf20Sopenharmony_ci char *q = skip_spaces(r); 4178c2ecf20Sopenharmony_ci *p = ' '; 4188c2ecf20Sopenharmony_ci if (q != (p+1)) 4198c2ecf20Sopenharmony_ci while ((*r++ = *q++)); 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci p++; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci ret = do_write_string(ff, s); 4248c2ecf20Sopenharmony_cidone: 4258c2ecf20Sopenharmony_ci free(buf); 4268c2ecf20Sopenharmony_ci fclose(file); 4278c2ecf20Sopenharmony_ci return ret; 4288c2ecf20Sopenharmony_ci} 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_cistatic int write_cpudesc(struct feat_fd *ff, 4318c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci#if defined(__powerpc__) || defined(__hppa__) || defined(__sparc__) 4348c2ecf20Sopenharmony_ci#define CPUINFO_PROC { "cpu", } 4358c2ecf20Sopenharmony_ci#elif defined(__s390__) 4368c2ecf20Sopenharmony_ci#define CPUINFO_PROC { "vendor_id", } 4378c2ecf20Sopenharmony_ci#elif defined(__sh__) 4388c2ecf20Sopenharmony_ci#define CPUINFO_PROC { "cpu type", } 4398c2ecf20Sopenharmony_ci#elif defined(__alpha__) || defined(__mips__) 4408c2ecf20Sopenharmony_ci#define CPUINFO_PROC { "cpu model", } 4418c2ecf20Sopenharmony_ci#elif defined(__arm__) 4428c2ecf20Sopenharmony_ci#define CPUINFO_PROC { "model name", "Processor", } 4438c2ecf20Sopenharmony_ci#elif defined(__arc__) 4448c2ecf20Sopenharmony_ci#define CPUINFO_PROC { "Processor", } 4458c2ecf20Sopenharmony_ci#elif defined(__xtensa__) 4468c2ecf20Sopenharmony_ci#define CPUINFO_PROC { "core ID", } 4478c2ecf20Sopenharmony_ci#else 4488c2ecf20Sopenharmony_ci#define CPUINFO_PROC { "model name", } 4498c2ecf20Sopenharmony_ci#endif 4508c2ecf20Sopenharmony_ci const char *cpuinfo_procs[] = CPUINFO_PROC; 4518c2ecf20Sopenharmony_ci#undef CPUINFO_PROC 4528c2ecf20Sopenharmony_ci unsigned int i; 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(cpuinfo_procs); i++) { 4558c2ecf20Sopenharmony_ci int ret; 4568c2ecf20Sopenharmony_ci ret = __write_cpudesc(ff, cpuinfo_procs[i]); 4578c2ecf20Sopenharmony_ci if (ret >= 0) 4588c2ecf20Sopenharmony_ci return ret; 4598c2ecf20Sopenharmony_ci } 4608c2ecf20Sopenharmony_ci return -1; 4618c2ecf20Sopenharmony_ci} 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_cistatic int write_nrcpus(struct feat_fd *ff, 4658c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 4668c2ecf20Sopenharmony_ci{ 4678c2ecf20Sopenharmony_ci long nr; 4688c2ecf20Sopenharmony_ci u32 nrc, nra; 4698c2ecf20Sopenharmony_ci int ret; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci nrc = cpu__max_present_cpu(); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci nr = sysconf(_SC_NPROCESSORS_ONLN); 4748c2ecf20Sopenharmony_ci if (nr < 0) 4758c2ecf20Sopenharmony_ci return -1; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci nra = (u32)(nr & UINT_MAX); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci ret = do_write(ff, &nrc, sizeof(nrc)); 4808c2ecf20Sopenharmony_ci if (ret < 0) 4818c2ecf20Sopenharmony_ci return ret; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci return do_write(ff, &nra, sizeof(nra)); 4848c2ecf20Sopenharmony_ci} 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cistatic int write_event_desc(struct feat_fd *ff, 4878c2ecf20Sopenharmony_ci struct evlist *evlist) 4888c2ecf20Sopenharmony_ci{ 4898c2ecf20Sopenharmony_ci struct evsel *evsel; 4908c2ecf20Sopenharmony_ci u32 nre, nri, sz; 4918c2ecf20Sopenharmony_ci int ret; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci nre = evlist->core.nr_entries; 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci /* 4968c2ecf20Sopenharmony_ci * write number of events 4978c2ecf20Sopenharmony_ci */ 4988c2ecf20Sopenharmony_ci ret = do_write(ff, &nre, sizeof(nre)); 4998c2ecf20Sopenharmony_ci if (ret < 0) 5008c2ecf20Sopenharmony_ci return ret; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* 5038c2ecf20Sopenharmony_ci * size of perf_event_attr struct 5048c2ecf20Sopenharmony_ci */ 5058c2ecf20Sopenharmony_ci sz = (u32)sizeof(evsel->core.attr); 5068c2ecf20Sopenharmony_ci ret = do_write(ff, &sz, sizeof(sz)); 5078c2ecf20Sopenharmony_ci if (ret < 0) 5088c2ecf20Sopenharmony_ci return ret; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 5118c2ecf20Sopenharmony_ci ret = do_write(ff, &evsel->core.attr, sz); 5128c2ecf20Sopenharmony_ci if (ret < 0) 5138c2ecf20Sopenharmony_ci return ret; 5148c2ecf20Sopenharmony_ci /* 5158c2ecf20Sopenharmony_ci * write number of unique id per event 5168c2ecf20Sopenharmony_ci * there is one id per instance of an event 5178c2ecf20Sopenharmony_ci * 5188c2ecf20Sopenharmony_ci * copy into an nri to be independent of the 5198c2ecf20Sopenharmony_ci * type of ids, 5208c2ecf20Sopenharmony_ci */ 5218c2ecf20Sopenharmony_ci nri = evsel->core.ids; 5228c2ecf20Sopenharmony_ci ret = do_write(ff, &nri, sizeof(nri)); 5238c2ecf20Sopenharmony_ci if (ret < 0) 5248c2ecf20Sopenharmony_ci return ret; 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci /* 5278c2ecf20Sopenharmony_ci * write event string as passed on cmdline 5288c2ecf20Sopenharmony_ci */ 5298c2ecf20Sopenharmony_ci ret = do_write_string(ff, evsel__name(evsel)); 5308c2ecf20Sopenharmony_ci if (ret < 0) 5318c2ecf20Sopenharmony_ci return ret; 5328c2ecf20Sopenharmony_ci /* 5338c2ecf20Sopenharmony_ci * write unique ids for this event 5348c2ecf20Sopenharmony_ci */ 5358c2ecf20Sopenharmony_ci ret = do_write(ff, evsel->core.id, evsel->core.ids * sizeof(u64)); 5368c2ecf20Sopenharmony_ci if (ret < 0) 5378c2ecf20Sopenharmony_ci return ret; 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci return 0; 5408c2ecf20Sopenharmony_ci} 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_cistatic int write_cmdline(struct feat_fd *ff, 5438c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci char pbuf[MAXPATHLEN], *buf; 5468c2ecf20Sopenharmony_ci int i, ret, n; 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci /* actual path to perf binary */ 5498c2ecf20Sopenharmony_ci buf = perf_exe(pbuf, MAXPATHLEN); 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_ci /* account for binary path */ 5528c2ecf20Sopenharmony_ci n = perf_env.nr_cmdline + 1; 5538c2ecf20Sopenharmony_ci 5548c2ecf20Sopenharmony_ci ret = do_write(ff, &n, sizeof(n)); 5558c2ecf20Sopenharmony_ci if (ret < 0) 5568c2ecf20Sopenharmony_ci return ret; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci ret = do_write_string(ff, buf); 5598c2ecf20Sopenharmony_ci if (ret < 0) 5608c2ecf20Sopenharmony_ci return ret; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci for (i = 0 ; i < perf_env.nr_cmdline; i++) { 5638c2ecf20Sopenharmony_ci ret = do_write_string(ff, perf_env.cmdline_argv[i]); 5648c2ecf20Sopenharmony_ci if (ret < 0) 5658c2ecf20Sopenharmony_ci return ret; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci return 0; 5688c2ecf20Sopenharmony_ci} 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_cistatic int write_cpu_topology(struct feat_fd *ff, 5728c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 5738c2ecf20Sopenharmony_ci{ 5748c2ecf20Sopenharmony_ci struct cpu_topology *tp; 5758c2ecf20Sopenharmony_ci u32 i; 5768c2ecf20Sopenharmony_ci int ret, j; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci tp = cpu_topology__new(); 5798c2ecf20Sopenharmony_ci if (!tp) 5808c2ecf20Sopenharmony_ci return -1; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci ret = do_write(ff, &tp->core_sib, sizeof(tp->core_sib)); 5838c2ecf20Sopenharmony_ci if (ret < 0) 5848c2ecf20Sopenharmony_ci goto done; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci for (i = 0; i < tp->core_sib; i++) { 5878c2ecf20Sopenharmony_ci ret = do_write_string(ff, tp->core_siblings[i]); 5888c2ecf20Sopenharmony_ci if (ret < 0) 5898c2ecf20Sopenharmony_ci goto done; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci ret = do_write(ff, &tp->thread_sib, sizeof(tp->thread_sib)); 5928c2ecf20Sopenharmony_ci if (ret < 0) 5938c2ecf20Sopenharmony_ci goto done; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci for (i = 0; i < tp->thread_sib; i++) { 5968c2ecf20Sopenharmony_ci ret = do_write_string(ff, tp->thread_siblings[i]); 5978c2ecf20Sopenharmony_ci if (ret < 0) 5988c2ecf20Sopenharmony_ci break; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci ret = perf_env__read_cpu_topology_map(&perf_env); 6028c2ecf20Sopenharmony_ci if (ret < 0) 6038c2ecf20Sopenharmony_ci goto done; 6048c2ecf20Sopenharmony_ci 6058c2ecf20Sopenharmony_ci for (j = 0; j < perf_env.nr_cpus_avail; j++) { 6068c2ecf20Sopenharmony_ci ret = do_write(ff, &perf_env.cpu[j].core_id, 6078c2ecf20Sopenharmony_ci sizeof(perf_env.cpu[j].core_id)); 6088c2ecf20Sopenharmony_ci if (ret < 0) 6098c2ecf20Sopenharmony_ci return ret; 6108c2ecf20Sopenharmony_ci ret = do_write(ff, &perf_env.cpu[j].socket_id, 6118c2ecf20Sopenharmony_ci sizeof(perf_env.cpu[j].socket_id)); 6128c2ecf20Sopenharmony_ci if (ret < 0) 6138c2ecf20Sopenharmony_ci return ret; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci if (!tp->die_sib) 6178c2ecf20Sopenharmony_ci goto done; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci ret = do_write(ff, &tp->die_sib, sizeof(tp->die_sib)); 6208c2ecf20Sopenharmony_ci if (ret < 0) 6218c2ecf20Sopenharmony_ci goto done; 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci for (i = 0; i < tp->die_sib; i++) { 6248c2ecf20Sopenharmony_ci ret = do_write_string(ff, tp->die_siblings[i]); 6258c2ecf20Sopenharmony_ci if (ret < 0) 6268c2ecf20Sopenharmony_ci goto done; 6278c2ecf20Sopenharmony_ci } 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_ci for (j = 0; j < perf_env.nr_cpus_avail; j++) { 6308c2ecf20Sopenharmony_ci ret = do_write(ff, &perf_env.cpu[j].die_id, 6318c2ecf20Sopenharmony_ci sizeof(perf_env.cpu[j].die_id)); 6328c2ecf20Sopenharmony_ci if (ret < 0) 6338c2ecf20Sopenharmony_ci return ret; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cidone: 6378c2ecf20Sopenharmony_ci cpu_topology__delete(tp); 6388c2ecf20Sopenharmony_ci return ret; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_cistatic int write_total_mem(struct feat_fd *ff, 6448c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci char *buf = NULL; 6478c2ecf20Sopenharmony_ci FILE *fp; 6488c2ecf20Sopenharmony_ci size_t len = 0; 6498c2ecf20Sopenharmony_ci int ret = -1, n; 6508c2ecf20Sopenharmony_ci uint64_t mem; 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci fp = fopen("/proc/meminfo", "r"); 6538c2ecf20Sopenharmony_ci if (!fp) 6548c2ecf20Sopenharmony_ci return -1; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci while (getline(&buf, &len, fp) > 0) { 6578c2ecf20Sopenharmony_ci ret = strncmp(buf, "MemTotal:", 9); 6588c2ecf20Sopenharmony_ci if (!ret) 6598c2ecf20Sopenharmony_ci break; 6608c2ecf20Sopenharmony_ci } 6618c2ecf20Sopenharmony_ci if (!ret) { 6628c2ecf20Sopenharmony_ci n = sscanf(buf, "%*s %"PRIu64, &mem); 6638c2ecf20Sopenharmony_ci if (n == 1) 6648c2ecf20Sopenharmony_ci ret = do_write(ff, &mem, sizeof(mem)); 6658c2ecf20Sopenharmony_ci } else 6668c2ecf20Sopenharmony_ci ret = -1; 6678c2ecf20Sopenharmony_ci free(buf); 6688c2ecf20Sopenharmony_ci fclose(fp); 6698c2ecf20Sopenharmony_ci return ret; 6708c2ecf20Sopenharmony_ci} 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic int write_numa_topology(struct feat_fd *ff, 6738c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 6748c2ecf20Sopenharmony_ci{ 6758c2ecf20Sopenharmony_ci struct numa_topology *tp; 6768c2ecf20Sopenharmony_ci int ret = -1; 6778c2ecf20Sopenharmony_ci u32 i; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci tp = numa_topology__new(); 6808c2ecf20Sopenharmony_ci if (!tp) 6818c2ecf20Sopenharmony_ci return -ENOMEM; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci ret = do_write(ff, &tp->nr, sizeof(u32)); 6848c2ecf20Sopenharmony_ci if (ret < 0) 6858c2ecf20Sopenharmony_ci goto err; 6868c2ecf20Sopenharmony_ci 6878c2ecf20Sopenharmony_ci for (i = 0; i < tp->nr; i++) { 6888c2ecf20Sopenharmony_ci struct numa_topology_node *n = &tp->nodes[i]; 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci ret = do_write(ff, &n->node, sizeof(u32)); 6918c2ecf20Sopenharmony_ci if (ret < 0) 6928c2ecf20Sopenharmony_ci goto err; 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci ret = do_write(ff, &n->mem_total, sizeof(u64)); 6958c2ecf20Sopenharmony_ci if (ret) 6968c2ecf20Sopenharmony_ci goto err; 6978c2ecf20Sopenharmony_ci 6988c2ecf20Sopenharmony_ci ret = do_write(ff, &n->mem_free, sizeof(u64)); 6998c2ecf20Sopenharmony_ci if (ret) 7008c2ecf20Sopenharmony_ci goto err; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci ret = do_write_string(ff, n->cpus); 7038c2ecf20Sopenharmony_ci if (ret < 0) 7048c2ecf20Sopenharmony_ci goto err; 7058c2ecf20Sopenharmony_ci } 7068c2ecf20Sopenharmony_ci 7078c2ecf20Sopenharmony_ci ret = 0; 7088c2ecf20Sopenharmony_ci 7098c2ecf20Sopenharmony_cierr: 7108c2ecf20Sopenharmony_ci numa_topology__delete(tp); 7118c2ecf20Sopenharmony_ci return ret; 7128c2ecf20Sopenharmony_ci} 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci/* 7158c2ecf20Sopenharmony_ci * File format: 7168c2ecf20Sopenharmony_ci * 7178c2ecf20Sopenharmony_ci * struct pmu_mappings { 7188c2ecf20Sopenharmony_ci * u32 pmu_num; 7198c2ecf20Sopenharmony_ci * struct pmu_map { 7208c2ecf20Sopenharmony_ci * u32 type; 7218c2ecf20Sopenharmony_ci * char name[]; 7228c2ecf20Sopenharmony_ci * }[pmu_num]; 7238c2ecf20Sopenharmony_ci * }; 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_cistatic int write_pmu_mappings(struct feat_fd *ff, 7278c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 7288c2ecf20Sopenharmony_ci{ 7298c2ecf20Sopenharmony_ci struct perf_pmu *pmu = NULL; 7308c2ecf20Sopenharmony_ci u32 pmu_num = 0; 7318c2ecf20Sopenharmony_ci int ret; 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci /* 7348c2ecf20Sopenharmony_ci * Do a first pass to count number of pmu to avoid lseek so this 7358c2ecf20Sopenharmony_ci * works in pipe mode as well. 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_ci while ((pmu = perf_pmu__scan(pmu))) { 7388c2ecf20Sopenharmony_ci if (!pmu->name) 7398c2ecf20Sopenharmony_ci continue; 7408c2ecf20Sopenharmony_ci pmu_num++; 7418c2ecf20Sopenharmony_ci } 7428c2ecf20Sopenharmony_ci 7438c2ecf20Sopenharmony_ci ret = do_write(ff, &pmu_num, sizeof(pmu_num)); 7448c2ecf20Sopenharmony_ci if (ret < 0) 7458c2ecf20Sopenharmony_ci return ret; 7468c2ecf20Sopenharmony_ci 7478c2ecf20Sopenharmony_ci while ((pmu = perf_pmu__scan(pmu))) { 7488c2ecf20Sopenharmony_ci if (!pmu->name) 7498c2ecf20Sopenharmony_ci continue; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci ret = do_write(ff, &pmu->type, sizeof(pmu->type)); 7528c2ecf20Sopenharmony_ci if (ret < 0) 7538c2ecf20Sopenharmony_ci return ret; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci ret = do_write_string(ff, pmu->name); 7568c2ecf20Sopenharmony_ci if (ret < 0) 7578c2ecf20Sopenharmony_ci return ret; 7588c2ecf20Sopenharmony_ci } 7598c2ecf20Sopenharmony_ci 7608c2ecf20Sopenharmony_ci return 0; 7618c2ecf20Sopenharmony_ci} 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci/* 7648c2ecf20Sopenharmony_ci * File format: 7658c2ecf20Sopenharmony_ci * 7668c2ecf20Sopenharmony_ci * struct group_descs { 7678c2ecf20Sopenharmony_ci * u32 nr_groups; 7688c2ecf20Sopenharmony_ci * struct group_desc { 7698c2ecf20Sopenharmony_ci * char name[]; 7708c2ecf20Sopenharmony_ci * u32 leader_idx; 7718c2ecf20Sopenharmony_ci * u32 nr_members; 7728c2ecf20Sopenharmony_ci * }[nr_groups]; 7738c2ecf20Sopenharmony_ci * }; 7748c2ecf20Sopenharmony_ci */ 7758c2ecf20Sopenharmony_cistatic int write_group_desc(struct feat_fd *ff, 7768c2ecf20Sopenharmony_ci struct evlist *evlist) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci u32 nr_groups = evlist->nr_groups; 7798c2ecf20Sopenharmony_ci struct evsel *evsel; 7808c2ecf20Sopenharmony_ci int ret; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci ret = do_write(ff, &nr_groups, sizeof(nr_groups)); 7838c2ecf20Sopenharmony_ci if (ret < 0) 7848c2ecf20Sopenharmony_ci return ret; 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 7878c2ecf20Sopenharmony_ci if (evsel__is_group_leader(evsel) && evsel->core.nr_members > 1) { 7888c2ecf20Sopenharmony_ci const char *name = evsel->group_name ?: "{anon_group}"; 7898c2ecf20Sopenharmony_ci u32 leader_idx = evsel->idx; 7908c2ecf20Sopenharmony_ci u32 nr_members = evsel->core.nr_members; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci ret = do_write_string(ff, name); 7938c2ecf20Sopenharmony_ci if (ret < 0) 7948c2ecf20Sopenharmony_ci return ret; 7958c2ecf20Sopenharmony_ci 7968c2ecf20Sopenharmony_ci ret = do_write(ff, &leader_idx, sizeof(leader_idx)); 7978c2ecf20Sopenharmony_ci if (ret < 0) 7988c2ecf20Sopenharmony_ci return ret; 7998c2ecf20Sopenharmony_ci 8008c2ecf20Sopenharmony_ci ret = do_write(ff, &nr_members, sizeof(nr_members)); 8018c2ecf20Sopenharmony_ci if (ret < 0) 8028c2ecf20Sopenharmony_ci return ret; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci } 8058c2ecf20Sopenharmony_ci return 0; 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci/* 8098c2ecf20Sopenharmony_ci * Return the CPU id as a raw string. 8108c2ecf20Sopenharmony_ci * 8118c2ecf20Sopenharmony_ci * Each architecture should provide a more precise id string that 8128c2ecf20Sopenharmony_ci * can be use to match the architecture's "mapfile". 8138c2ecf20Sopenharmony_ci */ 8148c2ecf20Sopenharmony_cichar * __weak get_cpuid_str(struct perf_pmu *pmu __maybe_unused) 8158c2ecf20Sopenharmony_ci{ 8168c2ecf20Sopenharmony_ci return NULL; 8178c2ecf20Sopenharmony_ci} 8188c2ecf20Sopenharmony_ci 8198c2ecf20Sopenharmony_ci/* Return zero when the cpuid from the mapfile.csv matches the 8208c2ecf20Sopenharmony_ci * cpuid string generated on this platform. 8218c2ecf20Sopenharmony_ci * Otherwise return non-zero. 8228c2ecf20Sopenharmony_ci */ 8238c2ecf20Sopenharmony_ciint __weak strcmp_cpuid_str(const char *mapcpuid, const char *cpuid) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci regex_t re; 8268c2ecf20Sopenharmony_ci regmatch_t pmatch[1]; 8278c2ecf20Sopenharmony_ci int match; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (regcomp(&re, mapcpuid, REG_EXTENDED) != 0) { 8308c2ecf20Sopenharmony_ci /* Warn unable to generate match particular string. */ 8318c2ecf20Sopenharmony_ci pr_info("Invalid regular expression %s\n", mapcpuid); 8328c2ecf20Sopenharmony_ci return 1; 8338c2ecf20Sopenharmony_ci } 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci match = !regexec(&re, cpuid, 1, pmatch, 0); 8368c2ecf20Sopenharmony_ci regfree(&re); 8378c2ecf20Sopenharmony_ci if (match) { 8388c2ecf20Sopenharmony_ci size_t match_len = (pmatch[0].rm_eo - pmatch[0].rm_so); 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci /* Verify the entire string matched. */ 8418c2ecf20Sopenharmony_ci if (match_len == strlen(cpuid)) 8428c2ecf20Sopenharmony_ci return 0; 8438c2ecf20Sopenharmony_ci } 8448c2ecf20Sopenharmony_ci return 1; 8458c2ecf20Sopenharmony_ci} 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci/* 8488c2ecf20Sopenharmony_ci * default get_cpuid(): nothing gets recorded 8498c2ecf20Sopenharmony_ci * actual implementation must be in arch/$(SRCARCH)/util/header.c 8508c2ecf20Sopenharmony_ci */ 8518c2ecf20Sopenharmony_ciint __weak get_cpuid(char *buffer __maybe_unused, size_t sz __maybe_unused) 8528c2ecf20Sopenharmony_ci{ 8538c2ecf20Sopenharmony_ci return ENOSYS; /* Not implemented */ 8548c2ecf20Sopenharmony_ci} 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_cistatic int write_cpuid(struct feat_fd *ff, 8578c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 8588c2ecf20Sopenharmony_ci{ 8598c2ecf20Sopenharmony_ci char buffer[64]; 8608c2ecf20Sopenharmony_ci int ret; 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci ret = get_cpuid(buffer, sizeof(buffer)); 8638c2ecf20Sopenharmony_ci if (ret) 8648c2ecf20Sopenharmony_ci return -1; 8658c2ecf20Sopenharmony_ci 8668c2ecf20Sopenharmony_ci return do_write_string(ff, buffer); 8678c2ecf20Sopenharmony_ci} 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_cistatic int write_branch_stack(struct feat_fd *ff __maybe_unused, 8708c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 8718c2ecf20Sopenharmony_ci{ 8728c2ecf20Sopenharmony_ci return 0; 8738c2ecf20Sopenharmony_ci} 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_cistatic int write_auxtrace(struct feat_fd *ff, 8768c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 8778c2ecf20Sopenharmony_ci{ 8788c2ecf20Sopenharmony_ci struct perf_session *session; 8798c2ecf20Sopenharmony_ci int err; 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) 8828c2ecf20Sopenharmony_ci return -1; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_ci err = auxtrace_index__write(ff->fd, &session->auxtrace_index); 8878c2ecf20Sopenharmony_ci if (err < 0) 8888c2ecf20Sopenharmony_ci pr_err("Failed to write auxtrace index\n"); 8898c2ecf20Sopenharmony_ci return err; 8908c2ecf20Sopenharmony_ci} 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_cistatic int write_clockid(struct feat_fd *ff, 8938c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 8948c2ecf20Sopenharmony_ci{ 8958c2ecf20Sopenharmony_ci return do_write(ff, &ff->ph->env.clock.clockid_res_ns, 8968c2ecf20Sopenharmony_ci sizeof(ff->ph->env.clock.clockid_res_ns)); 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_cistatic int write_clock_data(struct feat_fd *ff, 9008c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 9018c2ecf20Sopenharmony_ci{ 9028c2ecf20Sopenharmony_ci u64 *data64; 9038c2ecf20Sopenharmony_ci u32 data32; 9048c2ecf20Sopenharmony_ci int ret; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci /* version */ 9078c2ecf20Sopenharmony_ci data32 = 1; 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci ret = do_write(ff, &data32, sizeof(data32)); 9108c2ecf20Sopenharmony_ci if (ret < 0) 9118c2ecf20Sopenharmony_ci return ret; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci /* clockid */ 9148c2ecf20Sopenharmony_ci data32 = ff->ph->env.clock.clockid; 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci ret = do_write(ff, &data32, sizeof(data32)); 9178c2ecf20Sopenharmony_ci if (ret < 0) 9188c2ecf20Sopenharmony_ci return ret; 9198c2ecf20Sopenharmony_ci 9208c2ecf20Sopenharmony_ci /* TOD ref time */ 9218c2ecf20Sopenharmony_ci data64 = &ff->ph->env.clock.tod_ns; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci ret = do_write(ff, data64, sizeof(*data64)); 9248c2ecf20Sopenharmony_ci if (ret < 0) 9258c2ecf20Sopenharmony_ci return ret; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci /* clockid ref time */ 9288c2ecf20Sopenharmony_ci data64 = &ff->ph->env.clock.clockid_ns; 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci return do_write(ff, data64, sizeof(*data64)); 9318c2ecf20Sopenharmony_ci} 9328c2ecf20Sopenharmony_ci 9338c2ecf20Sopenharmony_cistatic int write_dir_format(struct feat_fd *ff, 9348c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 9358c2ecf20Sopenharmony_ci{ 9368c2ecf20Sopenharmony_ci struct perf_session *session; 9378c2ecf20Sopenharmony_ci struct perf_data *data; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 9408c2ecf20Sopenharmony_ci data = session->data; 9418c2ecf20Sopenharmony_ci 9428c2ecf20Sopenharmony_ci if (WARN_ON(!perf_data__is_dir(data))) 9438c2ecf20Sopenharmony_ci return -1; 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_ci return do_write(ff, &data->dir.version, sizeof(data->dir.version)); 9468c2ecf20Sopenharmony_ci} 9478c2ecf20Sopenharmony_ci 9488c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT 9498c2ecf20Sopenharmony_cistatic int write_bpf_prog_info(struct feat_fd *ff, 9508c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 9518c2ecf20Sopenharmony_ci{ 9528c2ecf20Sopenharmony_ci struct perf_env *env = &ff->ph->env; 9538c2ecf20Sopenharmony_ci struct rb_root *root; 9548c2ecf20Sopenharmony_ci struct rb_node *next; 9558c2ecf20Sopenharmony_ci int ret; 9568c2ecf20Sopenharmony_ci 9578c2ecf20Sopenharmony_ci down_read(&env->bpf_progs.lock); 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_ci ret = do_write(ff, &env->bpf_progs.infos_cnt, 9608c2ecf20Sopenharmony_ci sizeof(env->bpf_progs.infos_cnt)); 9618c2ecf20Sopenharmony_ci if (ret < 0) 9628c2ecf20Sopenharmony_ci goto out; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci root = &env->bpf_progs.infos; 9658c2ecf20Sopenharmony_ci next = rb_first(root); 9668c2ecf20Sopenharmony_ci while (next) { 9678c2ecf20Sopenharmony_ci struct bpf_prog_info_node *node; 9688c2ecf20Sopenharmony_ci size_t len; 9698c2ecf20Sopenharmony_ci 9708c2ecf20Sopenharmony_ci node = rb_entry(next, struct bpf_prog_info_node, rb_node); 9718c2ecf20Sopenharmony_ci next = rb_next(&node->rb_node); 9728c2ecf20Sopenharmony_ci len = sizeof(struct bpf_prog_info_linear) + 9738c2ecf20Sopenharmony_ci node->info_linear->data_len; 9748c2ecf20Sopenharmony_ci 9758c2ecf20Sopenharmony_ci /* before writing to file, translate address to offset */ 9768c2ecf20Sopenharmony_ci bpf_program__bpil_addr_to_offs(node->info_linear); 9778c2ecf20Sopenharmony_ci ret = do_write(ff, node->info_linear, len); 9788c2ecf20Sopenharmony_ci /* 9798c2ecf20Sopenharmony_ci * translate back to address even when do_write() fails, 9808c2ecf20Sopenharmony_ci * so that this function never changes the data. 9818c2ecf20Sopenharmony_ci */ 9828c2ecf20Sopenharmony_ci bpf_program__bpil_offs_to_addr(node->info_linear); 9838c2ecf20Sopenharmony_ci if (ret < 0) 9848c2ecf20Sopenharmony_ci goto out; 9858c2ecf20Sopenharmony_ci } 9868c2ecf20Sopenharmony_ciout: 9878c2ecf20Sopenharmony_ci up_read(&env->bpf_progs.lock); 9888c2ecf20Sopenharmony_ci return ret; 9898c2ecf20Sopenharmony_ci} 9908c2ecf20Sopenharmony_ci#else // HAVE_LIBBPF_SUPPORT 9918c2ecf20Sopenharmony_cistatic int write_bpf_prog_info(struct feat_fd *ff __maybe_unused, 9928c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 9938c2ecf20Sopenharmony_ci{ 9948c2ecf20Sopenharmony_ci return 0; 9958c2ecf20Sopenharmony_ci} 9968c2ecf20Sopenharmony_ci#endif // HAVE_LIBBPF_SUPPORT 9978c2ecf20Sopenharmony_ci 9988c2ecf20Sopenharmony_cistatic int write_bpf_btf(struct feat_fd *ff, 9998c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci struct perf_env *env = &ff->ph->env; 10028c2ecf20Sopenharmony_ci struct rb_root *root; 10038c2ecf20Sopenharmony_ci struct rb_node *next; 10048c2ecf20Sopenharmony_ci int ret; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci down_read(&env->bpf_progs.lock); 10078c2ecf20Sopenharmony_ci 10088c2ecf20Sopenharmony_ci ret = do_write(ff, &env->bpf_progs.btfs_cnt, 10098c2ecf20Sopenharmony_ci sizeof(env->bpf_progs.btfs_cnt)); 10108c2ecf20Sopenharmony_ci 10118c2ecf20Sopenharmony_ci if (ret < 0) 10128c2ecf20Sopenharmony_ci goto out; 10138c2ecf20Sopenharmony_ci 10148c2ecf20Sopenharmony_ci root = &env->bpf_progs.btfs; 10158c2ecf20Sopenharmony_ci next = rb_first(root); 10168c2ecf20Sopenharmony_ci while (next) { 10178c2ecf20Sopenharmony_ci struct btf_node *node; 10188c2ecf20Sopenharmony_ci 10198c2ecf20Sopenharmony_ci node = rb_entry(next, struct btf_node, rb_node); 10208c2ecf20Sopenharmony_ci next = rb_next(&node->rb_node); 10218c2ecf20Sopenharmony_ci ret = do_write(ff, &node->id, 10228c2ecf20Sopenharmony_ci sizeof(u32) * 2 + node->data_size); 10238c2ecf20Sopenharmony_ci if (ret < 0) 10248c2ecf20Sopenharmony_ci goto out; 10258c2ecf20Sopenharmony_ci } 10268c2ecf20Sopenharmony_ciout: 10278c2ecf20Sopenharmony_ci up_read(&env->bpf_progs.lock); 10288c2ecf20Sopenharmony_ci return ret; 10298c2ecf20Sopenharmony_ci} 10308c2ecf20Sopenharmony_ci 10318c2ecf20Sopenharmony_cistatic int cpu_cache_level__sort(const void *a, const void *b) 10328c2ecf20Sopenharmony_ci{ 10338c2ecf20Sopenharmony_ci struct cpu_cache_level *cache_a = (struct cpu_cache_level *)a; 10348c2ecf20Sopenharmony_ci struct cpu_cache_level *cache_b = (struct cpu_cache_level *)b; 10358c2ecf20Sopenharmony_ci 10368c2ecf20Sopenharmony_ci return cache_a->level - cache_b->level; 10378c2ecf20Sopenharmony_ci} 10388c2ecf20Sopenharmony_ci 10398c2ecf20Sopenharmony_cistatic bool cpu_cache_level__cmp(struct cpu_cache_level *a, struct cpu_cache_level *b) 10408c2ecf20Sopenharmony_ci{ 10418c2ecf20Sopenharmony_ci if (a->level != b->level) 10428c2ecf20Sopenharmony_ci return false; 10438c2ecf20Sopenharmony_ci 10448c2ecf20Sopenharmony_ci if (a->line_size != b->line_size) 10458c2ecf20Sopenharmony_ci return false; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci if (a->sets != b->sets) 10488c2ecf20Sopenharmony_ci return false; 10498c2ecf20Sopenharmony_ci 10508c2ecf20Sopenharmony_ci if (a->ways != b->ways) 10518c2ecf20Sopenharmony_ci return false; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (strcmp(a->type, b->type)) 10548c2ecf20Sopenharmony_ci return false; 10558c2ecf20Sopenharmony_ci 10568c2ecf20Sopenharmony_ci if (strcmp(a->size, b->size)) 10578c2ecf20Sopenharmony_ci return false; 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (strcmp(a->map, b->map)) 10608c2ecf20Sopenharmony_ci return false; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci return true; 10638c2ecf20Sopenharmony_ci} 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_cistatic int cpu_cache_level__read(struct cpu_cache_level *cache, u32 cpu, u16 level) 10668c2ecf20Sopenharmony_ci{ 10678c2ecf20Sopenharmony_ci char path[PATH_MAX], file[PATH_MAX]; 10688c2ecf20Sopenharmony_ci struct stat st; 10698c2ecf20Sopenharmony_ci size_t len; 10708c2ecf20Sopenharmony_ci 10718c2ecf20Sopenharmony_ci scnprintf(path, PATH_MAX, "devices/system/cpu/cpu%d/cache/index%d/", cpu, level); 10728c2ecf20Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/%s", sysfs__mountpoint(), path); 10738c2ecf20Sopenharmony_ci 10748c2ecf20Sopenharmony_ci if (stat(file, &st)) 10758c2ecf20Sopenharmony_ci return 1; 10768c2ecf20Sopenharmony_ci 10778c2ecf20Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/level", path); 10788c2ecf20Sopenharmony_ci if (sysfs__read_int(file, (int *) &cache->level)) 10798c2ecf20Sopenharmony_ci return -1; 10808c2ecf20Sopenharmony_ci 10818c2ecf20Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/coherency_line_size", path); 10828c2ecf20Sopenharmony_ci if (sysfs__read_int(file, (int *) &cache->line_size)) 10838c2ecf20Sopenharmony_ci return -1; 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/number_of_sets", path); 10868c2ecf20Sopenharmony_ci if (sysfs__read_int(file, (int *) &cache->sets)) 10878c2ecf20Sopenharmony_ci return -1; 10888c2ecf20Sopenharmony_ci 10898c2ecf20Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/ways_of_associativity", path); 10908c2ecf20Sopenharmony_ci if (sysfs__read_int(file, (int *) &cache->ways)) 10918c2ecf20Sopenharmony_ci return -1; 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/type", path); 10948c2ecf20Sopenharmony_ci if (sysfs__read_str(file, &cache->type, &len)) 10958c2ecf20Sopenharmony_ci return -1; 10968c2ecf20Sopenharmony_ci 10978c2ecf20Sopenharmony_ci cache->type[len] = 0; 10988c2ecf20Sopenharmony_ci cache->type = strim(cache->type); 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/size", path); 11018c2ecf20Sopenharmony_ci if (sysfs__read_str(file, &cache->size, &len)) { 11028c2ecf20Sopenharmony_ci zfree(&cache->type); 11038c2ecf20Sopenharmony_ci return -1; 11048c2ecf20Sopenharmony_ci } 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_ci cache->size[len] = 0; 11078c2ecf20Sopenharmony_ci cache->size = strim(cache->size); 11088c2ecf20Sopenharmony_ci 11098c2ecf20Sopenharmony_ci scnprintf(file, PATH_MAX, "%s/shared_cpu_list", path); 11108c2ecf20Sopenharmony_ci if (sysfs__read_str(file, &cache->map, &len)) { 11118c2ecf20Sopenharmony_ci zfree(&cache->size); 11128c2ecf20Sopenharmony_ci zfree(&cache->type); 11138c2ecf20Sopenharmony_ci return -1; 11148c2ecf20Sopenharmony_ci } 11158c2ecf20Sopenharmony_ci 11168c2ecf20Sopenharmony_ci cache->map[len] = 0; 11178c2ecf20Sopenharmony_ci cache->map = strim(cache->map); 11188c2ecf20Sopenharmony_ci return 0; 11198c2ecf20Sopenharmony_ci} 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_cistatic void cpu_cache_level__fprintf(FILE *out, struct cpu_cache_level *c) 11228c2ecf20Sopenharmony_ci{ 11238c2ecf20Sopenharmony_ci fprintf(out, "L%d %-15s %8s [%s]\n", c->level, c->type, c->size, c->map); 11248c2ecf20Sopenharmony_ci} 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci#define MAX_CACHE_LVL 4 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_cistatic int build_caches(struct cpu_cache_level caches[], u32 *cntp) 11298c2ecf20Sopenharmony_ci{ 11308c2ecf20Sopenharmony_ci u32 i, cnt = 0; 11318c2ecf20Sopenharmony_ci u32 nr, cpu; 11328c2ecf20Sopenharmony_ci u16 level; 11338c2ecf20Sopenharmony_ci 11348c2ecf20Sopenharmony_ci nr = cpu__max_cpu(); 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci for (cpu = 0; cpu < nr; cpu++) { 11378c2ecf20Sopenharmony_ci for (level = 0; level < MAX_CACHE_LVL; level++) { 11388c2ecf20Sopenharmony_ci struct cpu_cache_level c; 11398c2ecf20Sopenharmony_ci int err; 11408c2ecf20Sopenharmony_ci 11418c2ecf20Sopenharmony_ci err = cpu_cache_level__read(&c, cpu, level); 11428c2ecf20Sopenharmony_ci if (err < 0) 11438c2ecf20Sopenharmony_ci return err; 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci if (err == 1) 11468c2ecf20Sopenharmony_ci break; 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 11498c2ecf20Sopenharmony_ci if (cpu_cache_level__cmp(&c, &caches[i])) 11508c2ecf20Sopenharmony_ci break; 11518c2ecf20Sopenharmony_ci } 11528c2ecf20Sopenharmony_ci 11538c2ecf20Sopenharmony_ci if (i == cnt) 11548c2ecf20Sopenharmony_ci caches[cnt++] = c; 11558c2ecf20Sopenharmony_ci else 11568c2ecf20Sopenharmony_ci cpu_cache_level__free(&c); 11578c2ecf20Sopenharmony_ci } 11588c2ecf20Sopenharmony_ci } 11598c2ecf20Sopenharmony_ci *cntp = cnt; 11608c2ecf20Sopenharmony_ci return 0; 11618c2ecf20Sopenharmony_ci} 11628c2ecf20Sopenharmony_ci 11638c2ecf20Sopenharmony_cistatic int write_cache(struct feat_fd *ff, 11648c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 11658c2ecf20Sopenharmony_ci{ 11668c2ecf20Sopenharmony_ci u32 max_caches = cpu__max_cpu() * MAX_CACHE_LVL; 11678c2ecf20Sopenharmony_ci struct cpu_cache_level caches[max_caches]; 11688c2ecf20Sopenharmony_ci u32 cnt = 0, i, version = 1; 11698c2ecf20Sopenharmony_ci int ret; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci ret = build_caches(caches, &cnt); 11728c2ecf20Sopenharmony_ci if (ret) 11738c2ecf20Sopenharmony_ci goto out; 11748c2ecf20Sopenharmony_ci 11758c2ecf20Sopenharmony_ci qsort(&caches, cnt, sizeof(struct cpu_cache_level), cpu_cache_level__sort); 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci ret = do_write(ff, &version, sizeof(u32)); 11788c2ecf20Sopenharmony_ci if (ret < 0) 11798c2ecf20Sopenharmony_ci goto out; 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci ret = do_write(ff, &cnt, sizeof(u32)); 11828c2ecf20Sopenharmony_ci if (ret < 0) 11838c2ecf20Sopenharmony_ci goto out; 11848c2ecf20Sopenharmony_ci 11858c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 11868c2ecf20Sopenharmony_ci struct cpu_cache_level *c = &caches[i]; 11878c2ecf20Sopenharmony_ci 11888c2ecf20Sopenharmony_ci #define _W(v) \ 11898c2ecf20Sopenharmony_ci ret = do_write(ff, &c->v, sizeof(u32)); \ 11908c2ecf20Sopenharmony_ci if (ret < 0) \ 11918c2ecf20Sopenharmony_ci goto out; 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci _W(level) 11948c2ecf20Sopenharmony_ci _W(line_size) 11958c2ecf20Sopenharmony_ci _W(sets) 11968c2ecf20Sopenharmony_ci _W(ways) 11978c2ecf20Sopenharmony_ci #undef _W 11988c2ecf20Sopenharmony_ci 11998c2ecf20Sopenharmony_ci #define _W(v) \ 12008c2ecf20Sopenharmony_ci ret = do_write_string(ff, (const char *) c->v); \ 12018c2ecf20Sopenharmony_ci if (ret < 0) \ 12028c2ecf20Sopenharmony_ci goto out; 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci _W(type) 12058c2ecf20Sopenharmony_ci _W(size) 12068c2ecf20Sopenharmony_ci _W(map) 12078c2ecf20Sopenharmony_ci #undef _W 12088c2ecf20Sopenharmony_ci } 12098c2ecf20Sopenharmony_ci 12108c2ecf20Sopenharmony_ciout: 12118c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) 12128c2ecf20Sopenharmony_ci cpu_cache_level__free(&caches[i]); 12138c2ecf20Sopenharmony_ci return ret; 12148c2ecf20Sopenharmony_ci} 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_cistatic int write_stat(struct feat_fd *ff __maybe_unused, 12178c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 12188c2ecf20Sopenharmony_ci{ 12198c2ecf20Sopenharmony_ci return 0; 12208c2ecf20Sopenharmony_ci} 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_cistatic int write_sample_time(struct feat_fd *ff, 12238c2ecf20Sopenharmony_ci struct evlist *evlist) 12248c2ecf20Sopenharmony_ci{ 12258c2ecf20Sopenharmony_ci int ret; 12268c2ecf20Sopenharmony_ci 12278c2ecf20Sopenharmony_ci ret = do_write(ff, &evlist->first_sample_time, 12288c2ecf20Sopenharmony_ci sizeof(evlist->first_sample_time)); 12298c2ecf20Sopenharmony_ci if (ret < 0) 12308c2ecf20Sopenharmony_ci return ret; 12318c2ecf20Sopenharmony_ci 12328c2ecf20Sopenharmony_ci return do_write(ff, &evlist->last_sample_time, 12338c2ecf20Sopenharmony_ci sizeof(evlist->last_sample_time)); 12348c2ecf20Sopenharmony_ci} 12358c2ecf20Sopenharmony_ci 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_cistatic int memory_node__read(struct memory_node *n, unsigned long idx) 12388c2ecf20Sopenharmony_ci{ 12398c2ecf20Sopenharmony_ci unsigned int phys, size = 0; 12408c2ecf20Sopenharmony_ci char path[PATH_MAX]; 12418c2ecf20Sopenharmony_ci struct dirent *ent; 12428c2ecf20Sopenharmony_ci DIR *dir; 12438c2ecf20Sopenharmony_ci 12448c2ecf20Sopenharmony_ci#define for_each_memory(mem, dir) \ 12458c2ecf20Sopenharmony_ci while ((ent = readdir(dir))) \ 12468c2ecf20Sopenharmony_ci if (strcmp(ent->d_name, ".") && \ 12478c2ecf20Sopenharmony_ci strcmp(ent->d_name, "..") && \ 12488c2ecf20Sopenharmony_ci sscanf(ent->d_name, "memory%u", &mem) == 1) 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci scnprintf(path, PATH_MAX, 12518c2ecf20Sopenharmony_ci "%s/devices/system/node/node%lu", 12528c2ecf20Sopenharmony_ci sysfs__mountpoint(), idx); 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_ci dir = opendir(path); 12558c2ecf20Sopenharmony_ci if (!dir) { 12568c2ecf20Sopenharmony_ci pr_warning("failed: cant' open memory sysfs data\n"); 12578c2ecf20Sopenharmony_ci return -1; 12588c2ecf20Sopenharmony_ci } 12598c2ecf20Sopenharmony_ci 12608c2ecf20Sopenharmony_ci for_each_memory(phys, dir) { 12618c2ecf20Sopenharmony_ci size = max(phys, size); 12628c2ecf20Sopenharmony_ci } 12638c2ecf20Sopenharmony_ci 12648c2ecf20Sopenharmony_ci size++; 12658c2ecf20Sopenharmony_ci 12668c2ecf20Sopenharmony_ci n->set = bitmap_alloc(size); 12678c2ecf20Sopenharmony_ci if (!n->set) { 12688c2ecf20Sopenharmony_ci closedir(dir); 12698c2ecf20Sopenharmony_ci return -ENOMEM; 12708c2ecf20Sopenharmony_ci } 12718c2ecf20Sopenharmony_ci 12728c2ecf20Sopenharmony_ci n->node = idx; 12738c2ecf20Sopenharmony_ci n->size = size; 12748c2ecf20Sopenharmony_ci 12758c2ecf20Sopenharmony_ci rewinddir(dir); 12768c2ecf20Sopenharmony_ci 12778c2ecf20Sopenharmony_ci for_each_memory(phys, dir) { 12788c2ecf20Sopenharmony_ci set_bit(phys, n->set); 12798c2ecf20Sopenharmony_ci } 12808c2ecf20Sopenharmony_ci 12818c2ecf20Sopenharmony_ci closedir(dir); 12828c2ecf20Sopenharmony_ci return 0; 12838c2ecf20Sopenharmony_ci} 12848c2ecf20Sopenharmony_ci 12858c2ecf20Sopenharmony_cistatic int memory_node__sort(const void *a, const void *b) 12868c2ecf20Sopenharmony_ci{ 12878c2ecf20Sopenharmony_ci const struct memory_node *na = a; 12888c2ecf20Sopenharmony_ci const struct memory_node *nb = b; 12898c2ecf20Sopenharmony_ci 12908c2ecf20Sopenharmony_ci return na->node - nb->node; 12918c2ecf20Sopenharmony_ci} 12928c2ecf20Sopenharmony_ci 12938c2ecf20Sopenharmony_cistatic int build_mem_topology(struct memory_node *nodes, u64 size, u64 *cntp) 12948c2ecf20Sopenharmony_ci{ 12958c2ecf20Sopenharmony_ci char path[PATH_MAX]; 12968c2ecf20Sopenharmony_ci struct dirent *ent; 12978c2ecf20Sopenharmony_ci DIR *dir; 12988c2ecf20Sopenharmony_ci u64 cnt = 0; 12998c2ecf20Sopenharmony_ci int ret = 0; 13008c2ecf20Sopenharmony_ci 13018c2ecf20Sopenharmony_ci scnprintf(path, PATH_MAX, "%s/devices/system/node/", 13028c2ecf20Sopenharmony_ci sysfs__mountpoint()); 13038c2ecf20Sopenharmony_ci 13048c2ecf20Sopenharmony_ci dir = opendir(path); 13058c2ecf20Sopenharmony_ci if (!dir) { 13068c2ecf20Sopenharmony_ci pr_debug2("%s: could't read %s, does this arch have topology information?\n", 13078c2ecf20Sopenharmony_ci __func__, path); 13088c2ecf20Sopenharmony_ci return -1; 13098c2ecf20Sopenharmony_ci } 13108c2ecf20Sopenharmony_ci 13118c2ecf20Sopenharmony_ci while (!ret && (ent = readdir(dir))) { 13128c2ecf20Sopenharmony_ci unsigned int idx; 13138c2ecf20Sopenharmony_ci int r; 13148c2ecf20Sopenharmony_ci 13158c2ecf20Sopenharmony_ci if (!strcmp(ent->d_name, ".") || 13168c2ecf20Sopenharmony_ci !strcmp(ent->d_name, "..")) 13178c2ecf20Sopenharmony_ci continue; 13188c2ecf20Sopenharmony_ci 13198c2ecf20Sopenharmony_ci r = sscanf(ent->d_name, "node%u", &idx); 13208c2ecf20Sopenharmony_ci if (r != 1) 13218c2ecf20Sopenharmony_ci continue; 13228c2ecf20Sopenharmony_ci 13238c2ecf20Sopenharmony_ci if (WARN_ONCE(cnt >= size, 13248c2ecf20Sopenharmony_ci "failed to write MEM_TOPOLOGY, way too many nodes\n")) { 13258c2ecf20Sopenharmony_ci closedir(dir); 13268c2ecf20Sopenharmony_ci return -1; 13278c2ecf20Sopenharmony_ci } 13288c2ecf20Sopenharmony_ci 13298c2ecf20Sopenharmony_ci ret = memory_node__read(&nodes[cnt++], idx); 13308c2ecf20Sopenharmony_ci } 13318c2ecf20Sopenharmony_ci 13328c2ecf20Sopenharmony_ci *cntp = cnt; 13338c2ecf20Sopenharmony_ci closedir(dir); 13348c2ecf20Sopenharmony_ci 13358c2ecf20Sopenharmony_ci if (!ret) 13368c2ecf20Sopenharmony_ci qsort(nodes, cnt, sizeof(nodes[0]), memory_node__sort); 13378c2ecf20Sopenharmony_ci 13388c2ecf20Sopenharmony_ci return ret; 13398c2ecf20Sopenharmony_ci} 13408c2ecf20Sopenharmony_ci 13418c2ecf20Sopenharmony_ci#define MAX_MEMORY_NODES 2000 13428c2ecf20Sopenharmony_ci 13438c2ecf20Sopenharmony_ci/* 13448c2ecf20Sopenharmony_ci * The MEM_TOPOLOGY holds physical memory map for every 13458c2ecf20Sopenharmony_ci * node in system. The format of data is as follows: 13468c2ecf20Sopenharmony_ci * 13478c2ecf20Sopenharmony_ci * 0 - version | for future changes 13488c2ecf20Sopenharmony_ci * 8 - block_size_bytes | /sys/devices/system/memory/block_size_bytes 13498c2ecf20Sopenharmony_ci * 16 - count | number of nodes 13508c2ecf20Sopenharmony_ci * 13518c2ecf20Sopenharmony_ci * For each node we store map of physical indexes for 13528c2ecf20Sopenharmony_ci * each node: 13538c2ecf20Sopenharmony_ci * 13548c2ecf20Sopenharmony_ci * 32 - node id | node index 13558c2ecf20Sopenharmony_ci * 40 - size | size of bitmap 13568c2ecf20Sopenharmony_ci * 48 - bitmap | bitmap of memory indexes that belongs to node 13578c2ecf20Sopenharmony_ci */ 13588c2ecf20Sopenharmony_cistatic int write_mem_topology(struct feat_fd *ff __maybe_unused, 13598c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 13608c2ecf20Sopenharmony_ci{ 13618c2ecf20Sopenharmony_ci static struct memory_node nodes[MAX_MEMORY_NODES]; 13628c2ecf20Sopenharmony_ci u64 bsize, version = 1, i, nr; 13638c2ecf20Sopenharmony_ci int ret; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci ret = sysfs__read_xll("devices/system/memory/block_size_bytes", 13668c2ecf20Sopenharmony_ci (unsigned long long *) &bsize); 13678c2ecf20Sopenharmony_ci if (ret) 13688c2ecf20Sopenharmony_ci return ret; 13698c2ecf20Sopenharmony_ci 13708c2ecf20Sopenharmony_ci ret = build_mem_topology(&nodes[0], MAX_MEMORY_NODES, &nr); 13718c2ecf20Sopenharmony_ci if (ret) 13728c2ecf20Sopenharmony_ci return ret; 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_ci ret = do_write(ff, &version, sizeof(version)); 13758c2ecf20Sopenharmony_ci if (ret < 0) 13768c2ecf20Sopenharmony_ci goto out; 13778c2ecf20Sopenharmony_ci 13788c2ecf20Sopenharmony_ci ret = do_write(ff, &bsize, sizeof(bsize)); 13798c2ecf20Sopenharmony_ci if (ret < 0) 13808c2ecf20Sopenharmony_ci goto out; 13818c2ecf20Sopenharmony_ci 13828c2ecf20Sopenharmony_ci ret = do_write(ff, &nr, sizeof(nr)); 13838c2ecf20Sopenharmony_ci if (ret < 0) 13848c2ecf20Sopenharmony_ci goto out; 13858c2ecf20Sopenharmony_ci 13868c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 13878c2ecf20Sopenharmony_ci struct memory_node *n = &nodes[i]; 13888c2ecf20Sopenharmony_ci 13898c2ecf20Sopenharmony_ci #define _W(v) \ 13908c2ecf20Sopenharmony_ci ret = do_write(ff, &n->v, sizeof(n->v)); \ 13918c2ecf20Sopenharmony_ci if (ret < 0) \ 13928c2ecf20Sopenharmony_ci goto out; 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci _W(node) 13958c2ecf20Sopenharmony_ci _W(size) 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci #undef _W 13988c2ecf20Sopenharmony_ci 13998c2ecf20Sopenharmony_ci ret = do_write_bitmap(ff, n->set, n->size); 14008c2ecf20Sopenharmony_ci if (ret < 0) 14018c2ecf20Sopenharmony_ci goto out; 14028c2ecf20Sopenharmony_ci } 14038c2ecf20Sopenharmony_ci 14048c2ecf20Sopenharmony_ciout: 14058c2ecf20Sopenharmony_ci return ret; 14068c2ecf20Sopenharmony_ci} 14078c2ecf20Sopenharmony_ci 14088c2ecf20Sopenharmony_cistatic int write_compressed(struct feat_fd *ff __maybe_unused, 14098c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 14108c2ecf20Sopenharmony_ci{ 14118c2ecf20Sopenharmony_ci int ret; 14128c2ecf20Sopenharmony_ci 14138c2ecf20Sopenharmony_ci ret = do_write(ff, &(ff->ph->env.comp_ver), sizeof(ff->ph->env.comp_ver)); 14148c2ecf20Sopenharmony_ci if (ret) 14158c2ecf20Sopenharmony_ci return ret; 14168c2ecf20Sopenharmony_ci 14178c2ecf20Sopenharmony_ci ret = do_write(ff, &(ff->ph->env.comp_type), sizeof(ff->ph->env.comp_type)); 14188c2ecf20Sopenharmony_ci if (ret) 14198c2ecf20Sopenharmony_ci return ret; 14208c2ecf20Sopenharmony_ci 14218c2ecf20Sopenharmony_ci ret = do_write(ff, &(ff->ph->env.comp_level), sizeof(ff->ph->env.comp_level)); 14228c2ecf20Sopenharmony_ci if (ret) 14238c2ecf20Sopenharmony_ci return ret; 14248c2ecf20Sopenharmony_ci 14258c2ecf20Sopenharmony_ci ret = do_write(ff, &(ff->ph->env.comp_ratio), sizeof(ff->ph->env.comp_ratio)); 14268c2ecf20Sopenharmony_ci if (ret) 14278c2ecf20Sopenharmony_ci return ret; 14288c2ecf20Sopenharmony_ci 14298c2ecf20Sopenharmony_ci return do_write(ff, &(ff->ph->env.comp_mmap_len), sizeof(ff->ph->env.comp_mmap_len)); 14308c2ecf20Sopenharmony_ci} 14318c2ecf20Sopenharmony_ci 14328c2ecf20Sopenharmony_cistatic int write_cpu_pmu_caps(struct feat_fd *ff, 14338c2ecf20Sopenharmony_ci struct evlist *evlist __maybe_unused) 14348c2ecf20Sopenharmony_ci{ 14358c2ecf20Sopenharmony_ci struct perf_pmu *cpu_pmu = perf_pmu__find("cpu"); 14368c2ecf20Sopenharmony_ci struct perf_pmu_caps *caps = NULL; 14378c2ecf20Sopenharmony_ci int nr_caps; 14388c2ecf20Sopenharmony_ci int ret; 14398c2ecf20Sopenharmony_ci 14408c2ecf20Sopenharmony_ci if (!cpu_pmu) 14418c2ecf20Sopenharmony_ci return -ENOENT; 14428c2ecf20Sopenharmony_ci 14438c2ecf20Sopenharmony_ci nr_caps = perf_pmu__caps_parse(cpu_pmu); 14448c2ecf20Sopenharmony_ci if (nr_caps < 0) 14458c2ecf20Sopenharmony_ci return nr_caps; 14468c2ecf20Sopenharmony_ci 14478c2ecf20Sopenharmony_ci ret = do_write(ff, &nr_caps, sizeof(nr_caps)); 14488c2ecf20Sopenharmony_ci if (ret < 0) 14498c2ecf20Sopenharmony_ci return ret; 14508c2ecf20Sopenharmony_ci 14518c2ecf20Sopenharmony_ci list_for_each_entry(caps, &cpu_pmu->caps, list) { 14528c2ecf20Sopenharmony_ci ret = do_write_string(ff, caps->name); 14538c2ecf20Sopenharmony_ci if (ret < 0) 14548c2ecf20Sopenharmony_ci return ret; 14558c2ecf20Sopenharmony_ci 14568c2ecf20Sopenharmony_ci ret = do_write_string(ff, caps->value); 14578c2ecf20Sopenharmony_ci if (ret < 0) 14588c2ecf20Sopenharmony_ci return ret; 14598c2ecf20Sopenharmony_ci } 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci return ret; 14628c2ecf20Sopenharmony_ci} 14638c2ecf20Sopenharmony_ci 14648c2ecf20Sopenharmony_cistatic void print_hostname(struct feat_fd *ff, FILE *fp) 14658c2ecf20Sopenharmony_ci{ 14668c2ecf20Sopenharmony_ci fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname); 14678c2ecf20Sopenharmony_ci} 14688c2ecf20Sopenharmony_ci 14698c2ecf20Sopenharmony_cistatic void print_osrelease(struct feat_fd *ff, FILE *fp) 14708c2ecf20Sopenharmony_ci{ 14718c2ecf20Sopenharmony_ci fprintf(fp, "# os release : %s\n", ff->ph->env.os_release); 14728c2ecf20Sopenharmony_ci} 14738c2ecf20Sopenharmony_ci 14748c2ecf20Sopenharmony_cistatic void print_arch(struct feat_fd *ff, FILE *fp) 14758c2ecf20Sopenharmony_ci{ 14768c2ecf20Sopenharmony_ci fprintf(fp, "# arch : %s\n", ff->ph->env.arch); 14778c2ecf20Sopenharmony_ci} 14788c2ecf20Sopenharmony_ci 14798c2ecf20Sopenharmony_cistatic void print_cpudesc(struct feat_fd *ff, FILE *fp) 14808c2ecf20Sopenharmony_ci{ 14818c2ecf20Sopenharmony_ci fprintf(fp, "# cpudesc : %s\n", ff->ph->env.cpu_desc); 14828c2ecf20Sopenharmony_ci} 14838c2ecf20Sopenharmony_ci 14848c2ecf20Sopenharmony_cistatic void print_nrcpus(struct feat_fd *ff, FILE *fp) 14858c2ecf20Sopenharmony_ci{ 14868c2ecf20Sopenharmony_ci fprintf(fp, "# nrcpus online : %u\n", ff->ph->env.nr_cpus_online); 14878c2ecf20Sopenharmony_ci fprintf(fp, "# nrcpus avail : %u\n", ff->ph->env.nr_cpus_avail); 14888c2ecf20Sopenharmony_ci} 14898c2ecf20Sopenharmony_ci 14908c2ecf20Sopenharmony_cistatic void print_version(struct feat_fd *ff, FILE *fp) 14918c2ecf20Sopenharmony_ci{ 14928c2ecf20Sopenharmony_ci fprintf(fp, "# perf version : %s\n", ff->ph->env.version); 14938c2ecf20Sopenharmony_ci} 14948c2ecf20Sopenharmony_ci 14958c2ecf20Sopenharmony_cistatic void print_cmdline(struct feat_fd *ff, FILE *fp) 14968c2ecf20Sopenharmony_ci{ 14978c2ecf20Sopenharmony_ci int nr, i; 14988c2ecf20Sopenharmony_ci 14998c2ecf20Sopenharmony_ci nr = ff->ph->env.nr_cmdline; 15008c2ecf20Sopenharmony_ci 15018c2ecf20Sopenharmony_ci fprintf(fp, "# cmdline : "); 15028c2ecf20Sopenharmony_ci 15038c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 15048c2ecf20Sopenharmony_ci char *argv_i = strdup(ff->ph->env.cmdline_argv[i]); 15058c2ecf20Sopenharmony_ci if (!argv_i) { 15068c2ecf20Sopenharmony_ci fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]); 15078c2ecf20Sopenharmony_ci } else { 15088c2ecf20Sopenharmony_ci char *mem = argv_i; 15098c2ecf20Sopenharmony_ci do { 15108c2ecf20Sopenharmony_ci char *quote = strchr(argv_i, '\''); 15118c2ecf20Sopenharmony_ci if (!quote) 15128c2ecf20Sopenharmony_ci break; 15138c2ecf20Sopenharmony_ci *quote++ = '\0'; 15148c2ecf20Sopenharmony_ci fprintf(fp, "%s\\\'", argv_i); 15158c2ecf20Sopenharmony_ci argv_i = quote; 15168c2ecf20Sopenharmony_ci } while (1); 15178c2ecf20Sopenharmony_ci fprintf(fp, "%s ", argv_i); 15188c2ecf20Sopenharmony_ci free(mem); 15198c2ecf20Sopenharmony_ci } 15208c2ecf20Sopenharmony_ci } 15218c2ecf20Sopenharmony_ci fputc('\n', fp); 15228c2ecf20Sopenharmony_ci} 15238c2ecf20Sopenharmony_ci 15248c2ecf20Sopenharmony_cistatic void print_cpu_topology(struct feat_fd *ff, FILE *fp) 15258c2ecf20Sopenharmony_ci{ 15268c2ecf20Sopenharmony_ci struct perf_header *ph = ff->ph; 15278c2ecf20Sopenharmony_ci int cpu_nr = ph->env.nr_cpus_avail; 15288c2ecf20Sopenharmony_ci int nr, i; 15298c2ecf20Sopenharmony_ci char *str; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci nr = ph->env.nr_sibling_cores; 15328c2ecf20Sopenharmony_ci str = ph->env.sibling_cores; 15338c2ecf20Sopenharmony_ci 15348c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 15358c2ecf20Sopenharmony_ci fprintf(fp, "# sibling sockets : %s\n", str); 15368c2ecf20Sopenharmony_ci str += strlen(str) + 1; 15378c2ecf20Sopenharmony_ci } 15388c2ecf20Sopenharmony_ci 15398c2ecf20Sopenharmony_ci if (ph->env.nr_sibling_dies) { 15408c2ecf20Sopenharmony_ci nr = ph->env.nr_sibling_dies; 15418c2ecf20Sopenharmony_ci str = ph->env.sibling_dies; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 15448c2ecf20Sopenharmony_ci fprintf(fp, "# sibling dies : %s\n", str); 15458c2ecf20Sopenharmony_ci str += strlen(str) + 1; 15468c2ecf20Sopenharmony_ci } 15478c2ecf20Sopenharmony_ci } 15488c2ecf20Sopenharmony_ci 15498c2ecf20Sopenharmony_ci nr = ph->env.nr_sibling_threads; 15508c2ecf20Sopenharmony_ci str = ph->env.sibling_threads; 15518c2ecf20Sopenharmony_ci 15528c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 15538c2ecf20Sopenharmony_ci fprintf(fp, "# sibling threads : %s\n", str); 15548c2ecf20Sopenharmony_ci str += strlen(str) + 1; 15558c2ecf20Sopenharmony_ci } 15568c2ecf20Sopenharmony_ci 15578c2ecf20Sopenharmony_ci if (ph->env.nr_sibling_dies) { 15588c2ecf20Sopenharmony_ci if (ph->env.cpu != NULL) { 15598c2ecf20Sopenharmony_ci for (i = 0; i < cpu_nr; i++) 15608c2ecf20Sopenharmony_ci fprintf(fp, "# CPU %d: Core ID %d, " 15618c2ecf20Sopenharmony_ci "Die ID %d, Socket ID %d\n", 15628c2ecf20Sopenharmony_ci i, ph->env.cpu[i].core_id, 15638c2ecf20Sopenharmony_ci ph->env.cpu[i].die_id, 15648c2ecf20Sopenharmony_ci ph->env.cpu[i].socket_id); 15658c2ecf20Sopenharmony_ci } else 15668c2ecf20Sopenharmony_ci fprintf(fp, "# Core ID, Die ID and Socket ID " 15678c2ecf20Sopenharmony_ci "information is not available\n"); 15688c2ecf20Sopenharmony_ci } else { 15698c2ecf20Sopenharmony_ci if (ph->env.cpu != NULL) { 15708c2ecf20Sopenharmony_ci for (i = 0; i < cpu_nr; i++) 15718c2ecf20Sopenharmony_ci fprintf(fp, "# CPU %d: Core ID %d, " 15728c2ecf20Sopenharmony_ci "Socket ID %d\n", 15738c2ecf20Sopenharmony_ci i, ph->env.cpu[i].core_id, 15748c2ecf20Sopenharmony_ci ph->env.cpu[i].socket_id); 15758c2ecf20Sopenharmony_ci } else 15768c2ecf20Sopenharmony_ci fprintf(fp, "# Core ID and Socket ID " 15778c2ecf20Sopenharmony_ci "information is not available\n"); 15788c2ecf20Sopenharmony_ci } 15798c2ecf20Sopenharmony_ci} 15808c2ecf20Sopenharmony_ci 15818c2ecf20Sopenharmony_cistatic void print_clockid(struct feat_fd *ff, FILE *fp) 15828c2ecf20Sopenharmony_ci{ 15838c2ecf20Sopenharmony_ci fprintf(fp, "# clockid frequency: %"PRIu64" MHz\n", 15848c2ecf20Sopenharmony_ci ff->ph->env.clock.clockid_res_ns * 1000); 15858c2ecf20Sopenharmony_ci} 15868c2ecf20Sopenharmony_ci 15878c2ecf20Sopenharmony_cistatic void print_clock_data(struct feat_fd *ff, FILE *fp) 15888c2ecf20Sopenharmony_ci{ 15898c2ecf20Sopenharmony_ci struct timespec clockid_ns; 15908c2ecf20Sopenharmony_ci char tstr[64], date[64]; 15918c2ecf20Sopenharmony_ci struct timeval tod_ns; 15928c2ecf20Sopenharmony_ci clockid_t clockid; 15938c2ecf20Sopenharmony_ci struct tm ltime; 15948c2ecf20Sopenharmony_ci u64 ref; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci if (!ff->ph->env.clock.enabled) { 15978c2ecf20Sopenharmony_ci fprintf(fp, "# reference time disabled\n"); 15988c2ecf20Sopenharmony_ci return; 15998c2ecf20Sopenharmony_ci } 16008c2ecf20Sopenharmony_ci 16018c2ecf20Sopenharmony_ci /* Compute TOD time. */ 16028c2ecf20Sopenharmony_ci ref = ff->ph->env.clock.tod_ns; 16038c2ecf20Sopenharmony_ci tod_ns.tv_sec = ref / NSEC_PER_SEC; 16048c2ecf20Sopenharmony_ci ref -= tod_ns.tv_sec * NSEC_PER_SEC; 16058c2ecf20Sopenharmony_ci tod_ns.tv_usec = ref / NSEC_PER_USEC; 16068c2ecf20Sopenharmony_ci 16078c2ecf20Sopenharmony_ci /* Compute clockid time. */ 16088c2ecf20Sopenharmony_ci ref = ff->ph->env.clock.clockid_ns; 16098c2ecf20Sopenharmony_ci clockid_ns.tv_sec = ref / NSEC_PER_SEC; 16108c2ecf20Sopenharmony_ci ref -= clockid_ns.tv_sec * NSEC_PER_SEC; 16118c2ecf20Sopenharmony_ci clockid_ns.tv_nsec = ref; 16128c2ecf20Sopenharmony_ci 16138c2ecf20Sopenharmony_ci clockid = ff->ph->env.clock.clockid; 16148c2ecf20Sopenharmony_ci 16158c2ecf20Sopenharmony_ci if (localtime_r(&tod_ns.tv_sec, <ime) == NULL) 16168c2ecf20Sopenharmony_ci snprintf(tstr, sizeof(tstr), "<error>"); 16178c2ecf20Sopenharmony_ci else { 16188c2ecf20Sopenharmony_ci strftime(date, sizeof(date), "%F %T", <ime); 16198c2ecf20Sopenharmony_ci scnprintf(tstr, sizeof(tstr), "%s.%06d", 16208c2ecf20Sopenharmony_ci date, (int) tod_ns.tv_usec); 16218c2ecf20Sopenharmony_ci } 16228c2ecf20Sopenharmony_ci 16238c2ecf20Sopenharmony_ci fprintf(fp, "# clockid: %s (%u)\n", clockid_name(clockid), clockid); 16248c2ecf20Sopenharmony_ci fprintf(fp, "# reference time: %s = %ld.%06d (TOD) = %ld.%09ld (%s)\n", 16258c2ecf20Sopenharmony_ci tstr, tod_ns.tv_sec, (int) tod_ns.tv_usec, 16268c2ecf20Sopenharmony_ci clockid_ns.tv_sec, clockid_ns.tv_nsec, 16278c2ecf20Sopenharmony_ci clockid_name(clockid)); 16288c2ecf20Sopenharmony_ci} 16298c2ecf20Sopenharmony_ci 16308c2ecf20Sopenharmony_cistatic void print_dir_format(struct feat_fd *ff, FILE *fp) 16318c2ecf20Sopenharmony_ci{ 16328c2ecf20Sopenharmony_ci struct perf_session *session; 16338c2ecf20Sopenharmony_ci struct perf_data *data; 16348c2ecf20Sopenharmony_ci 16358c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 16368c2ecf20Sopenharmony_ci data = session->data; 16378c2ecf20Sopenharmony_ci 16388c2ecf20Sopenharmony_ci fprintf(fp, "# directory data version : %"PRIu64"\n", data->dir.version); 16398c2ecf20Sopenharmony_ci} 16408c2ecf20Sopenharmony_ci 16418c2ecf20Sopenharmony_cistatic void print_bpf_prog_info(struct feat_fd *ff, FILE *fp) 16428c2ecf20Sopenharmony_ci{ 16438c2ecf20Sopenharmony_ci struct perf_env *env = &ff->ph->env; 16448c2ecf20Sopenharmony_ci struct rb_root *root; 16458c2ecf20Sopenharmony_ci struct rb_node *next; 16468c2ecf20Sopenharmony_ci 16478c2ecf20Sopenharmony_ci down_read(&env->bpf_progs.lock); 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci root = &env->bpf_progs.infos; 16508c2ecf20Sopenharmony_ci next = rb_first(root); 16518c2ecf20Sopenharmony_ci 16528c2ecf20Sopenharmony_ci while (next) { 16538c2ecf20Sopenharmony_ci struct bpf_prog_info_node *node; 16548c2ecf20Sopenharmony_ci 16558c2ecf20Sopenharmony_ci node = rb_entry(next, struct bpf_prog_info_node, rb_node); 16568c2ecf20Sopenharmony_ci next = rb_next(&node->rb_node); 16578c2ecf20Sopenharmony_ci 16588c2ecf20Sopenharmony_ci __bpf_event__print_bpf_prog_info(&node->info_linear->info, 16598c2ecf20Sopenharmony_ci env, fp); 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci up_read(&env->bpf_progs.lock); 16638c2ecf20Sopenharmony_ci} 16648c2ecf20Sopenharmony_ci 16658c2ecf20Sopenharmony_cistatic void print_bpf_btf(struct feat_fd *ff, FILE *fp) 16668c2ecf20Sopenharmony_ci{ 16678c2ecf20Sopenharmony_ci struct perf_env *env = &ff->ph->env; 16688c2ecf20Sopenharmony_ci struct rb_root *root; 16698c2ecf20Sopenharmony_ci struct rb_node *next; 16708c2ecf20Sopenharmony_ci 16718c2ecf20Sopenharmony_ci down_read(&env->bpf_progs.lock); 16728c2ecf20Sopenharmony_ci 16738c2ecf20Sopenharmony_ci root = &env->bpf_progs.btfs; 16748c2ecf20Sopenharmony_ci next = rb_first(root); 16758c2ecf20Sopenharmony_ci 16768c2ecf20Sopenharmony_ci while (next) { 16778c2ecf20Sopenharmony_ci struct btf_node *node; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci node = rb_entry(next, struct btf_node, rb_node); 16808c2ecf20Sopenharmony_ci next = rb_next(&node->rb_node); 16818c2ecf20Sopenharmony_ci fprintf(fp, "# btf info of id %u\n", node->id); 16828c2ecf20Sopenharmony_ci } 16838c2ecf20Sopenharmony_ci 16848c2ecf20Sopenharmony_ci up_read(&env->bpf_progs.lock); 16858c2ecf20Sopenharmony_ci} 16868c2ecf20Sopenharmony_ci 16878c2ecf20Sopenharmony_cistatic void free_event_desc(struct evsel *events) 16888c2ecf20Sopenharmony_ci{ 16898c2ecf20Sopenharmony_ci struct evsel *evsel; 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci if (!events) 16928c2ecf20Sopenharmony_ci return; 16938c2ecf20Sopenharmony_ci 16948c2ecf20Sopenharmony_ci for (evsel = events; evsel->core.attr.size; evsel++) { 16958c2ecf20Sopenharmony_ci zfree(&evsel->name); 16968c2ecf20Sopenharmony_ci zfree(&evsel->core.id); 16978c2ecf20Sopenharmony_ci } 16988c2ecf20Sopenharmony_ci 16998c2ecf20Sopenharmony_ci free(events); 17008c2ecf20Sopenharmony_ci} 17018c2ecf20Sopenharmony_ci 17028c2ecf20Sopenharmony_cistatic bool perf_attr_check(struct perf_event_attr *attr) 17038c2ecf20Sopenharmony_ci{ 17048c2ecf20Sopenharmony_ci if (attr->__reserved_1 || attr->__reserved_2 || attr->__reserved_3) { 17058c2ecf20Sopenharmony_ci pr_warning("Reserved bits are set unexpectedly. " 17068c2ecf20Sopenharmony_ci "Please update perf tool.\n"); 17078c2ecf20Sopenharmony_ci return false; 17088c2ecf20Sopenharmony_ci } 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci if (attr->sample_type & ~(PERF_SAMPLE_MAX-1)) { 17118c2ecf20Sopenharmony_ci pr_warning("Unknown sample type (0x%llx) is detected. " 17128c2ecf20Sopenharmony_ci "Please update perf tool.\n", 17138c2ecf20Sopenharmony_ci attr->sample_type); 17148c2ecf20Sopenharmony_ci return false; 17158c2ecf20Sopenharmony_ci } 17168c2ecf20Sopenharmony_ci 17178c2ecf20Sopenharmony_ci if (attr->read_format & ~(PERF_FORMAT_MAX-1)) { 17188c2ecf20Sopenharmony_ci pr_warning("Unknown read format (0x%llx) is detected. " 17198c2ecf20Sopenharmony_ci "Please update perf tool.\n", 17208c2ecf20Sopenharmony_ci attr->read_format); 17218c2ecf20Sopenharmony_ci return false; 17228c2ecf20Sopenharmony_ci } 17238c2ecf20Sopenharmony_ci 17248c2ecf20Sopenharmony_ci if ((attr->sample_type & PERF_SAMPLE_BRANCH_STACK) && 17258c2ecf20Sopenharmony_ci (attr->branch_sample_type & ~(PERF_SAMPLE_BRANCH_MAX-1))) { 17268c2ecf20Sopenharmony_ci pr_warning("Unknown branch sample type (0x%llx) is detected. " 17278c2ecf20Sopenharmony_ci "Please update perf tool.\n", 17288c2ecf20Sopenharmony_ci attr->branch_sample_type); 17298c2ecf20Sopenharmony_ci 17308c2ecf20Sopenharmony_ci return false; 17318c2ecf20Sopenharmony_ci } 17328c2ecf20Sopenharmony_ci 17338c2ecf20Sopenharmony_ci return true; 17348c2ecf20Sopenharmony_ci} 17358c2ecf20Sopenharmony_ci 17368c2ecf20Sopenharmony_cistatic struct evsel *read_event_desc(struct feat_fd *ff) 17378c2ecf20Sopenharmony_ci{ 17388c2ecf20Sopenharmony_ci struct evsel *evsel, *events = NULL; 17398c2ecf20Sopenharmony_ci u64 *id; 17408c2ecf20Sopenharmony_ci void *buf = NULL; 17418c2ecf20Sopenharmony_ci u32 nre, sz, nr, i, j; 17428c2ecf20Sopenharmony_ci size_t msz; 17438c2ecf20Sopenharmony_ci 17448c2ecf20Sopenharmony_ci /* number of events */ 17458c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nre)) 17468c2ecf20Sopenharmony_ci goto error; 17478c2ecf20Sopenharmony_ci 17488c2ecf20Sopenharmony_ci if (do_read_u32(ff, &sz)) 17498c2ecf20Sopenharmony_ci goto error; 17508c2ecf20Sopenharmony_ci 17518c2ecf20Sopenharmony_ci /* buffer to hold on file attr struct */ 17528c2ecf20Sopenharmony_ci buf = malloc(sz); 17538c2ecf20Sopenharmony_ci if (!buf) 17548c2ecf20Sopenharmony_ci goto error; 17558c2ecf20Sopenharmony_ci 17568c2ecf20Sopenharmony_ci /* the last event terminates with evsel->core.attr.size == 0: */ 17578c2ecf20Sopenharmony_ci events = calloc(nre + 1, sizeof(*events)); 17588c2ecf20Sopenharmony_ci if (!events) 17598c2ecf20Sopenharmony_ci goto error; 17608c2ecf20Sopenharmony_ci 17618c2ecf20Sopenharmony_ci msz = sizeof(evsel->core.attr); 17628c2ecf20Sopenharmony_ci if (sz < msz) 17638c2ecf20Sopenharmony_ci msz = sz; 17648c2ecf20Sopenharmony_ci 17658c2ecf20Sopenharmony_ci for (i = 0, evsel = events; i < nre; evsel++, i++) { 17668c2ecf20Sopenharmony_ci evsel->idx = i; 17678c2ecf20Sopenharmony_ci 17688c2ecf20Sopenharmony_ci /* 17698c2ecf20Sopenharmony_ci * must read entire on-file attr struct to 17708c2ecf20Sopenharmony_ci * sync up with layout. 17718c2ecf20Sopenharmony_ci */ 17728c2ecf20Sopenharmony_ci if (__do_read(ff, buf, sz)) 17738c2ecf20Sopenharmony_ci goto error; 17748c2ecf20Sopenharmony_ci 17758c2ecf20Sopenharmony_ci if (ff->ph->needs_swap) 17768c2ecf20Sopenharmony_ci perf_event__attr_swap(buf); 17778c2ecf20Sopenharmony_ci 17788c2ecf20Sopenharmony_ci memcpy(&evsel->core.attr, buf, msz); 17798c2ecf20Sopenharmony_ci 17808c2ecf20Sopenharmony_ci if (!perf_attr_check(&evsel->core.attr)) 17818c2ecf20Sopenharmony_ci goto error; 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr)) 17848c2ecf20Sopenharmony_ci goto error; 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_ci if (ff->ph->needs_swap) 17878c2ecf20Sopenharmony_ci evsel->needs_swap = true; 17888c2ecf20Sopenharmony_ci 17898c2ecf20Sopenharmony_ci evsel->name = do_read_string(ff); 17908c2ecf20Sopenharmony_ci if (!evsel->name) 17918c2ecf20Sopenharmony_ci goto error; 17928c2ecf20Sopenharmony_ci 17938c2ecf20Sopenharmony_ci if (!nr) 17948c2ecf20Sopenharmony_ci continue; 17958c2ecf20Sopenharmony_ci 17968c2ecf20Sopenharmony_ci id = calloc(nr, sizeof(*id)); 17978c2ecf20Sopenharmony_ci if (!id) 17988c2ecf20Sopenharmony_ci goto error; 17998c2ecf20Sopenharmony_ci evsel->core.ids = nr; 18008c2ecf20Sopenharmony_ci evsel->core.id = id; 18018c2ecf20Sopenharmony_ci 18028c2ecf20Sopenharmony_ci for (j = 0 ; j < nr; j++) { 18038c2ecf20Sopenharmony_ci if (do_read_u64(ff, id)) 18048c2ecf20Sopenharmony_ci goto error; 18058c2ecf20Sopenharmony_ci id++; 18068c2ecf20Sopenharmony_ci } 18078c2ecf20Sopenharmony_ci } 18088c2ecf20Sopenharmony_ciout: 18098c2ecf20Sopenharmony_ci free(buf); 18108c2ecf20Sopenharmony_ci return events; 18118c2ecf20Sopenharmony_cierror: 18128c2ecf20Sopenharmony_ci free_event_desc(events); 18138c2ecf20Sopenharmony_ci events = NULL; 18148c2ecf20Sopenharmony_ci goto out; 18158c2ecf20Sopenharmony_ci} 18168c2ecf20Sopenharmony_ci 18178c2ecf20Sopenharmony_cistatic int __desc_attr__fprintf(FILE *fp, const char *name, const char *val, 18188c2ecf20Sopenharmony_ci void *priv __maybe_unused) 18198c2ecf20Sopenharmony_ci{ 18208c2ecf20Sopenharmony_ci return fprintf(fp, ", %s = %s", name, val); 18218c2ecf20Sopenharmony_ci} 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_cistatic void print_event_desc(struct feat_fd *ff, FILE *fp) 18248c2ecf20Sopenharmony_ci{ 18258c2ecf20Sopenharmony_ci struct evsel *evsel, *events; 18268c2ecf20Sopenharmony_ci u32 j; 18278c2ecf20Sopenharmony_ci u64 *id; 18288c2ecf20Sopenharmony_ci 18298c2ecf20Sopenharmony_ci if (ff->events) 18308c2ecf20Sopenharmony_ci events = ff->events; 18318c2ecf20Sopenharmony_ci else 18328c2ecf20Sopenharmony_ci events = read_event_desc(ff); 18338c2ecf20Sopenharmony_ci 18348c2ecf20Sopenharmony_ci if (!events) { 18358c2ecf20Sopenharmony_ci fprintf(fp, "# event desc: not available or unable to read\n"); 18368c2ecf20Sopenharmony_ci return; 18378c2ecf20Sopenharmony_ci } 18388c2ecf20Sopenharmony_ci 18398c2ecf20Sopenharmony_ci for (evsel = events; evsel->core.attr.size; evsel++) { 18408c2ecf20Sopenharmony_ci fprintf(fp, "# event : name = %s, ", evsel->name); 18418c2ecf20Sopenharmony_ci 18428c2ecf20Sopenharmony_ci if (evsel->core.ids) { 18438c2ecf20Sopenharmony_ci fprintf(fp, ", id = {"); 18448c2ecf20Sopenharmony_ci for (j = 0, id = evsel->core.id; j < evsel->core.ids; j++, id++) { 18458c2ecf20Sopenharmony_ci if (j) 18468c2ecf20Sopenharmony_ci fputc(',', fp); 18478c2ecf20Sopenharmony_ci fprintf(fp, " %"PRIu64, *id); 18488c2ecf20Sopenharmony_ci } 18498c2ecf20Sopenharmony_ci fprintf(fp, " }"); 18508c2ecf20Sopenharmony_ci } 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci perf_event_attr__fprintf(fp, &evsel->core.attr, __desc_attr__fprintf, NULL); 18538c2ecf20Sopenharmony_ci 18548c2ecf20Sopenharmony_ci fputc('\n', fp); 18558c2ecf20Sopenharmony_ci } 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_ci free_event_desc(events); 18588c2ecf20Sopenharmony_ci ff->events = NULL; 18598c2ecf20Sopenharmony_ci} 18608c2ecf20Sopenharmony_ci 18618c2ecf20Sopenharmony_cistatic void print_total_mem(struct feat_fd *ff, FILE *fp) 18628c2ecf20Sopenharmony_ci{ 18638c2ecf20Sopenharmony_ci fprintf(fp, "# total memory : %llu kB\n", ff->ph->env.total_mem); 18648c2ecf20Sopenharmony_ci} 18658c2ecf20Sopenharmony_ci 18668c2ecf20Sopenharmony_cistatic void print_numa_topology(struct feat_fd *ff, FILE *fp) 18678c2ecf20Sopenharmony_ci{ 18688c2ecf20Sopenharmony_ci int i; 18698c2ecf20Sopenharmony_ci struct numa_node *n; 18708c2ecf20Sopenharmony_ci 18718c2ecf20Sopenharmony_ci for (i = 0; i < ff->ph->env.nr_numa_nodes; i++) { 18728c2ecf20Sopenharmony_ci n = &ff->ph->env.numa_nodes[i]; 18738c2ecf20Sopenharmony_ci 18748c2ecf20Sopenharmony_ci fprintf(fp, "# node%u meminfo : total = %"PRIu64" kB," 18758c2ecf20Sopenharmony_ci " free = %"PRIu64" kB\n", 18768c2ecf20Sopenharmony_ci n->node, n->mem_total, n->mem_free); 18778c2ecf20Sopenharmony_ci 18788c2ecf20Sopenharmony_ci fprintf(fp, "# node%u cpu list : ", n->node); 18798c2ecf20Sopenharmony_ci cpu_map__fprintf(n->map, fp); 18808c2ecf20Sopenharmony_ci } 18818c2ecf20Sopenharmony_ci} 18828c2ecf20Sopenharmony_ci 18838c2ecf20Sopenharmony_cistatic void print_cpuid(struct feat_fd *ff, FILE *fp) 18848c2ecf20Sopenharmony_ci{ 18858c2ecf20Sopenharmony_ci fprintf(fp, "# cpuid : %s\n", ff->ph->env.cpuid); 18868c2ecf20Sopenharmony_ci} 18878c2ecf20Sopenharmony_ci 18888c2ecf20Sopenharmony_cistatic void print_branch_stack(struct feat_fd *ff __maybe_unused, FILE *fp) 18898c2ecf20Sopenharmony_ci{ 18908c2ecf20Sopenharmony_ci fprintf(fp, "# contains samples with branch stack\n"); 18918c2ecf20Sopenharmony_ci} 18928c2ecf20Sopenharmony_ci 18938c2ecf20Sopenharmony_cistatic void print_auxtrace(struct feat_fd *ff __maybe_unused, FILE *fp) 18948c2ecf20Sopenharmony_ci{ 18958c2ecf20Sopenharmony_ci fprintf(fp, "# contains AUX area data (e.g. instruction trace)\n"); 18968c2ecf20Sopenharmony_ci} 18978c2ecf20Sopenharmony_ci 18988c2ecf20Sopenharmony_cistatic void print_stat(struct feat_fd *ff __maybe_unused, FILE *fp) 18998c2ecf20Sopenharmony_ci{ 19008c2ecf20Sopenharmony_ci fprintf(fp, "# contains stat data\n"); 19018c2ecf20Sopenharmony_ci} 19028c2ecf20Sopenharmony_ci 19038c2ecf20Sopenharmony_cistatic void print_cache(struct feat_fd *ff, FILE *fp __maybe_unused) 19048c2ecf20Sopenharmony_ci{ 19058c2ecf20Sopenharmony_ci int i; 19068c2ecf20Sopenharmony_ci 19078c2ecf20Sopenharmony_ci fprintf(fp, "# CPU cache info:\n"); 19088c2ecf20Sopenharmony_ci for (i = 0; i < ff->ph->env.caches_cnt; i++) { 19098c2ecf20Sopenharmony_ci fprintf(fp, "# "); 19108c2ecf20Sopenharmony_ci cpu_cache_level__fprintf(fp, &ff->ph->env.caches[i]); 19118c2ecf20Sopenharmony_ci } 19128c2ecf20Sopenharmony_ci} 19138c2ecf20Sopenharmony_ci 19148c2ecf20Sopenharmony_cistatic void print_compressed(struct feat_fd *ff, FILE *fp) 19158c2ecf20Sopenharmony_ci{ 19168c2ecf20Sopenharmony_ci fprintf(fp, "# compressed : %s, level = %d, ratio = %d\n", 19178c2ecf20Sopenharmony_ci ff->ph->env.comp_type == PERF_COMP_ZSTD ? "Zstd" : "Unknown", 19188c2ecf20Sopenharmony_ci ff->ph->env.comp_level, ff->ph->env.comp_ratio); 19198c2ecf20Sopenharmony_ci} 19208c2ecf20Sopenharmony_ci 19218c2ecf20Sopenharmony_cistatic void print_cpu_pmu_caps(struct feat_fd *ff, FILE *fp) 19228c2ecf20Sopenharmony_ci{ 19238c2ecf20Sopenharmony_ci const char *delimiter = "# cpu pmu capabilities: "; 19248c2ecf20Sopenharmony_ci u32 nr_caps = ff->ph->env.nr_cpu_pmu_caps; 19258c2ecf20Sopenharmony_ci char *str; 19268c2ecf20Sopenharmony_ci 19278c2ecf20Sopenharmony_ci if (!nr_caps) { 19288c2ecf20Sopenharmony_ci fprintf(fp, "# cpu pmu capabilities: not available\n"); 19298c2ecf20Sopenharmony_ci return; 19308c2ecf20Sopenharmony_ci } 19318c2ecf20Sopenharmony_ci 19328c2ecf20Sopenharmony_ci str = ff->ph->env.cpu_pmu_caps; 19338c2ecf20Sopenharmony_ci while (nr_caps--) { 19348c2ecf20Sopenharmony_ci fprintf(fp, "%s%s", delimiter, str); 19358c2ecf20Sopenharmony_ci delimiter = ", "; 19368c2ecf20Sopenharmony_ci str += strlen(str) + 1; 19378c2ecf20Sopenharmony_ci } 19388c2ecf20Sopenharmony_ci 19398c2ecf20Sopenharmony_ci fprintf(fp, "\n"); 19408c2ecf20Sopenharmony_ci} 19418c2ecf20Sopenharmony_ci 19428c2ecf20Sopenharmony_cistatic void print_pmu_mappings(struct feat_fd *ff, FILE *fp) 19438c2ecf20Sopenharmony_ci{ 19448c2ecf20Sopenharmony_ci const char *delimiter = "# pmu mappings: "; 19458c2ecf20Sopenharmony_ci char *str, *tmp; 19468c2ecf20Sopenharmony_ci u32 pmu_num; 19478c2ecf20Sopenharmony_ci u32 type; 19488c2ecf20Sopenharmony_ci 19498c2ecf20Sopenharmony_ci pmu_num = ff->ph->env.nr_pmu_mappings; 19508c2ecf20Sopenharmony_ci if (!pmu_num) { 19518c2ecf20Sopenharmony_ci fprintf(fp, "# pmu mappings: not available\n"); 19528c2ecf20Sopenharmony_ci return; 19538c2ecf20Sopenharmony_ci } 19548c2ecf20Sopenharmony_ci 19558c2ecf20Sopenharmony_ci str = ff->ph->env.pmu_mappings; 19568c2ecf20Sopenharmony_ci 19578c2ecf20Sopenharmony_ci while (pmu_num) { 19588c2ecf20Sopenharmony_ci type = strtoul(str, &tmp, 0); 19598c2ecf20Sopenharmony_ci if (*tmp != ':') 19608c2ecf20Sopenharmony_ci goto error; 19618c2ecf20Sopenharmony_ci 19628c2ecf20Sopenharmony_ci str = tmp + 1; 19638c2ecf20Sopenharmony_ci fprintf(fp, "%s%s = %" PRIu32, delimiter, str, type); 19648c2ecf20Sopenharmony_ci 19658c2ecf20Sopenharmony_ci delimiter = ", "; 19668c2ecf20Sopenharmony_ci str += strlen(str) + 1; 19678c2ecf20Sopenharmony_ci pmu_num--; 19688c2ecf20Sopenharmony_ci } 19698c2ecf20Sopenharmony_ci 19708c2ecf20Sopenharmony_ci fprintf(fp, "\n"); 19718c2ecf20Sopenharmony_ci 19728c2ecf20Sopenharmony_ci if (!pmu_num) 19738c2ecf20Sopenharmony_ci return; 19748c2ecf20Sopenharmony_cierror: 19758c2ecf20Sopenharmony_ci fprintf(fp, "# pmu mappings: unable to read\n"); 19768c2ecf20Sopenharmony_ci} 19778c2ecf20Sopenharmony_ci 19788c2ecf20Sopenharmony_cistatic void print_group_desc(struct feat_fd *ff, FILE *fp) 19798c2ecf20Sopenharmony_ci{ 19808c2ecf20Sopenharmony_ci struct perf_session *session; 19818c2ecf20Sopenharmony_ci struct evsel *evsel; 19828c2ecf20Sopenharmony_ci u32 nr = 0; 19838c2ecf20Sopenharmony_ci 19848c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 19858c2ecf20Sopenharmony_ci 19868c2ecf20Sopenharmony_ci evlist__for_each_entry(session->evlist, evsel) { 19878c2ecf20Sopenharmony_ci if (evsel__is_group_leader(evsel) && evsel->core.nr_members > 1) { 19888c2ecf20Sopenharmony_ci fprintf(fp, "# group: %s{%s", evsel->group_name ?: "", evsel__name(evsel)); 19898c2ecf20Sopenharmony_ci 19908c2ecf20Sopenharmony_ci nr = evsel->core.nr_members - 1; 19918c2ecf20Sopenharmony_ci } else if (nr) { 19928c2ecf20Sopenharmony_ci fprintf(fp, ",%s", evsel__name(evsel)); 19938c2ecf20Sopenharmony_ci 19948c2ecf20Sopenharmony_ci if (--nr == 0) 19958c2ecf20Sopenharmony_ci fprintf(fp, "}\n"); 19968c2ecf20Sopenharmony_ci } 19978c2ecf20Sopenharmony_ci } 19988c2ecf20Sopenharmony_ci} 19998c2ecf20Sopenharmony_ci 20008c2ecf20Sopenharmony_cistatic void print_sample_time(struct feat_fd *ff, FILE *fp) 20018c2ecf20Sopenharmony_ci{ 20028c2ecf20Sopenharmony_ci struct perf_session *session; 20038c2ecf20Sopenharmony_ci char time_buf[32]; 20048c2ecf20Sopenharmony_ci double d; 20058c2ecf20Sopenharmony_ci 20068c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 20078c2ecf20Sopenharmony_ci 20088c2ecf20Sopenharmony_ci timestamp__scnprintf_usec(session->evlist->first_sample_time, 20098c2ecf20Sopenharmony_ci time_buf, sizeof(time_buf)); 20108c2ecf20Sopenharmony_ci fprintf(fp, "# time of first sample : %s\n", time_buf); 20118c2ecf20Sopenharmony_ci 20128c2ecf20Sopenharmony_ci timestamp__scnprintf_usec(session->evlist->last_sample_time, 20138c2ecf20Sopenharmony_ci time_buf, sizeof(time_buf)); 20148c2ecf20Sopenharmony_ci fprintf(fp, "# time of last sample : %s\n", time_buf); 20158c2ecf20Sopenharmony_ci 20168c2ecf20Sopenharmony_ci d = (double)(session->evlist->last_sample_time - 20178c2ecf20Sopenharmony_ci session->evlist->first_sample_time) / NSEC_PER_MSEC; 20188c2ecf20Sopenharmony_ci 20198c2ecf20Sopenharmony_ci fprintf(fp, "# sample duration : %10.3f ms\n", d); 20208c2ecf20Sopenharmony_ci} 20218c2ecf20Sopenharmony_ci 20228c2ecf20Sopenharmony_cistatic void memory_node__fprintf(struct memory_node *n, 20238c2ecf20Sopenharmony_ci unsigned long long bsize, FILE *fp) 20248c2ecf20Sopenharmony_ci{ 20258c2ecf20Sopenharmony_ci char buf_map[100], buf_size[50]; 20268c2ecf20Sopenharmony_ci unsigned long long size; 20278c2ecf20Sopenharmony_ci 20288c2ecf20Sopenharmony_ci size = bsize * bitmap_weight(n->set, n->size); 20298c2ecf20Sopenharmony_ci unit_number__scnprintf(buf_size, 50, size); 20308c2ecf20Sopenharmony_ci 20318c2ecf20Sopenharmony_ci bitmap_scnprintf(n->set, n->size, buf_map, 100); 20328c2ecf20Sopenharmony_ci fprintf(fp, "# %3" PRIu64 " [%s]: %s\n", n->node, buf_size, buf_map); 20338c2ecf20Sopenharmony_ci} 20348c2ecf20Sopenharmony_ci 20358c2ecf20Sopenharmony_cistatic void print_mem_topology(struct feat_fd *ff, FILE *fp) 20368c2ecf20Sopenharmony_ci{ 20378c2ecf20Sopenharmony_ci struct memory_node *nodes; 20388c2ecf20Sopenharmony_ci int i, nr; 20398c2ecf20Sopenharmony_ci 20408c2ecf20Sopenharmony_ci nodes = ff->ph->env.memory_nodes; 20418c2ecf20Sopenharmony_ci nr = ff->ph->env.nr_memory_nodes; 20428c2ecf20Sopenharmony_ci 20438c2ecf20Sopenharmony_ci fprintf(fp, "# memory nodes (nr %d, block size 0x%llx):\n", 20448c2ecf20Sopenharmony_ci nr, ff->ph->env.memory_bsize); 20458c2ecf20Sopenharmony_ci 20468c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 20478c2ecf20Sopenharmony_ci memory_node__fprintf(&nodes[i], ff->ph->env.memory_bsize, fp); 20488c2ecf20Sopenharmony_ci } 20498c2ecf20Sopenharmony_ci} 20508c2ecf20Sopenharmony_ci 20518c2ecf20Sopenharmony_cistatic int __event_process_build_id(struct perf_record_header_build_id *bev, 20528c2ecf20Sopenharmony_ci char *filename, 20538c2ecf20Sopenharmony_ci struct perf_session *session) 20548c2ecf20Sopenharmony_ci{ 20558c2ecf20Sopenharmony_ci int err = -1; 20568c2ecf20Sopenharmony_ci struct machine *machine; 20578c2ecf20Sopenharmony_ci u16 cpumode; 20588c2ecf20Sopenharmony_ci struct dso *dso; 20598c2ecf20Sopenharmony_ci enum dso_space_type dso_space; 20608c2ecf20Sopenharmony_ci 20618c2ecf20Sopenharmony_ci machine = perf_session__findnew_machine(session, bev->pid); 20628c2ecf20Sopenharmony_ci if (!machine) 20638c2ecf20Sopenharmony_ci goto out; 20648c2ecf20Sopenharmony_ci 20658c2ecf20Sopenharmony_ci cpumode = bev->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; 20668c2ecf20Sopenharmony_ci 20678c2ecf20Sopenharmony_ci switch (cpumode) { 20688c2ecf20Sopenharmony_ci case PERF_RECORD_MISC_KERNEL: 20698c2ecf20Sopenharmony_ci dso_space = DSO_SPACE__KERNEL; 20708c2ecf20Sopenharmony_ci break; 20718c2ecf20Sopenharmony_ci case PERF_RECORD_MISC_GUEST_KERNEL: 20728c2ecf20Sopenharmony_ci dso_space = DSO_SPACE__KERNEL_GUEST; 20738c2ecf20Sopenharmony_ci break; 20748c2ecf20Sopenharmony_ci case PERF_RECORD_MISC_USER: 20758c2ecf20Sopenharmony_ci case PERF_RECORD_MISC_GUEST_USER: 20768c2ecf20Sopenharmony_ci dso_space = DSO_SPACE__USER; 20778c2ecf20Sopenharmony_ci break; 20788c2ecf20Sopenharmony_ci default: 20798c2ecf20Sopenharmony_ci goto out; 20808c2ecf20Sopenharmony_ci } 20818c2ecf20Sopenharmony_ci 20828c2ecf20Sopenharmony_ci dso = machine__findnew_dso(machine, filename); 20838c2ecf20Sopenharmony_ci if (dso != NULL) { 20848c2ecf20Sopenharmony_ci char sbuild_id[SBUILD_ID_SIZE]; 20858c2ecf20Sopenharmony_ci struct build_id bid; 20868c2ecf20Sopenharmony_ci size_t size = BUILD_ID_SIZE; 20878c2ecf20Sopenharmony_ci 20888c2ecf20Sopenharmony_ci if (bev->header.misc & PERF_RECORD_MISC_BUILD_ID_SIZE) 20898c2ecf20Sopenharmony_ci size = bev->size; 20908c2ecf20Sopenharmony_ci 20918c2ecf20Sopenharmony_ci build_id__init(&bid, bev->data, size); 20928c2ecf20Sopenharmony_ci dso__set_build_id(dso, &bid); 20938c2ecf20Sopenharmony_ci 20948c2ecf20Sopenharmony_ci if (dso_space != DSO_SPACE__USER) { 20958c2ecf20Sopenharmony_ci struct kmod_path m = { .name = NULL, }; 20968c2ecf20Sopenharmony_ci 20978c2ecf20Sopenharmony_ci if (!kmod_path__parse_name(&m, filename) && m.kmod) 20988c2ecf20Sopenharmony_ci dso__set_module_info(dso, &m, machine); 20998c2ecf20Sopenharmony_ci 21008c2ecf20Sopenharmony_ci dso->kernel = dso_space; 21018c2ecf20Sopenharmony_ci free(m.name); 21028c2ecf20Sopenharmony_ci } 21038c2ecf20Sopenharmony_ci 21048c2ecf20Sopenharmony_ci build_id__sprintf(&dso->bid, sbuild_id); 21058c2ecf20Sopenharmony_ci pr_debug("build id event received for %s: %s [%zu]\n", 21068c2ecf20Sopenharmony_ci dso->long_name, sbuild_id, size); 21078c2ecf20Sopenharmony_ci dso__put(dso); 21088c2ecf20Sopenharmony_ci } 21098c2ecf20Sopenharmony_ci 21108c2ecf20Sopenharmony_ci err = 0; 21118c2ecf20Sopenharmony_ciout: 21128c2ecf20Sopenharmony_ci return err; 21138c2ecf20Sopenharmony_ci} 21148c2ecf20Sopenharmony_ci 21158c2ecf20Sopenharmony_cistatic int perf_header__read_build_ids_abi_quirk(struct perf_header *header, 21168c2ecf20Sopenharmony_ci int input, u64 offset, u64 size) 21178c2ecf20Sopenharmony_ci{ 21188c2ecf20Sopenharmony_ci struct perf_session *session = container_of(header, struct perf_session, header); 21198c2ecf20Sopenharmony_ci struct { 21208c2ecf20Sopenharmony_ci struct perf_event_header header; 21218c2ecf20Sopenharmony_ci u8 build_id[PERF_ALIGN(BUILD_ID_SIZE, sizeof(u64))]; 21228c2ecf20Sopenharmony_ci char filename[0]; 21238c2ecf20Sopenharmony_ci } old_bev; 21248c2ecf20Sopenharmony_ci struct perf_record_header_build_id bev; 21258c2ecf20Sopenharmony_ci char filename[PATH_MAX]; 21268c2ecf20Sopenharmony_ci u64 limit = offset + size; 21278c2ecf20Sopenharmony_ci 21288c2ecf20Sopenharmony_ci while (offset < limit) { 21298c2ecf20Sopenharmony_ci ssize_t len; 21308c2ecf20Sopenharmony_ci 21318c2ecf20Sopenharmony_ci if (readn(input, &old_bev, sizeof(old_bev)) != sizeof(old_bev)) 21328c2ecf20Sopenharmony_ci return -1; 21338c2ecf20Sopenharmony_ci 21348c2ecf20Sopenharmony_ci if (header->needs_swap) 21358c2ecf20Sopenharmony_ci perf_event_header__bswap(&old_bev.header); 21368c2ecf20Sopenharmony_ci 21378c2ecf20Sopenharmony_ci len = old_bev.header.size - sizeof(old_bev); 21388c2ecf20Sopenharmony_ci if (readn(input, filename, len) != len) 21398c2ecf20Sopenharmony_ci return -1; 21408c2ecf20Sopenharmony_ci 21418c2ecf20Sopenharmony_ci bev.header = old_bev.header; 21428c2ecf20Sopenharmony_ci 21438c2ecf20Sopenharmony_ci /* 21448c2ecf20Sopenharmony_ci * As the pid is the missing value, we need to fill 21458c2ecf20Sopenharmony_ci * it properly. The header.misc value give us nice hint. 21468c2ecf20Sopenharmony_ci */ 21478c2ecf20Sopenharmony_ci bev.pid = HOST_KERNEL_ID; 21488c2ecf20Sopenharmony_ci if (bev.header.misc == PERF_RECORD_MISC_GUEST_USER || 21498c2ecf20Sopenharmony_ci bev.header.misc == PERF_RECORD_MISC_GUEST_KERNEL) 21508c2ecf20Sopenharmony_ci bev.pid = DEFAULT_GUEST_KERNEL_ID; 21518c2ecf20Sopenharmony_ci 21528c2ecf20Sopenharmony_ci memcpy(bev.build_id, old_bev.build_id, sizeof(bev.build_id)); 21538c2ecf20Sopenharmony_ci __event_process_build_id(&bev, filename, session); 21548c2ecf20Sopenharmony_ci 21558c2ecf20Sopenharmony_ci offset += bev.header.size; 21568c2ecf20Sopenharmony_ci } 21578c2ecf20Sopenharmony_ci 21588c2ecf20Sopenharmony_ci return 0; 21598c2ecf20Sopenharmony_ci} 21608c2ecf20Sopenharmony_ci 21618c2ecf20Sopenharmony_cistatic int perf_header__read_build_ids(struct perf_header *header, 21628c2ecf20Sopenharmony_ci int input, u64 offset, u64 size) 21638c2ecf20Sopenharmony_ci{ 21648c2ecf20Sopenharmony_ci struct perf_session *session = container_of(header, struct perf_session, header); 21658c2ecf20Sopenharmony_ci struct perf_record_header_build_id bev; 21668c2ecf20Sopenharmony_ci char filename[PATH_MAX]; 21678c2ecf20Sopenharmony_ci u64 limit = offset + size, orig_offset = offset; 21688c2ecf20Sopenharmony_ci int err = -1; 21698c2ecf20Sopenharmony_ci 21708c2ecf20Sopenharmony_ci while (offset < limit) { 21718c2ecf20Sopenharmony_ci ssize_t len; 21728c2ecf20Sopenharmony_ci 21738c2ecf20Sopenharmony_ci if (readn(input, &bev, sizeof(bev)) != sizeof(bev)) 21748c2ecf20Sopenharmony_ci goto out; 21758c2ecf20Sopenharmony_ci 21768c2ecf20Sopenharmony_ci if (header->needs_swap) 21778c2ecf20Sopenharmony_ci perf_event_header__bswap(&bev.header); 21788c2ecf20Sopenharmony_ci 21798c2ecf20Sopenharmony_ci len = bev.header.size - sizeof(bev); 21808c2ecf20Sopenharmony_ci if (readn(input, filename, len) != len) 21818c2ecf20Sopenharmony_ci goto out; 21828c2ecf20Sopenharmony_ci /* 21838c2ecf20Sopenharmony_ci * The a1645ce1 changeset: 21848c2ecf20Sopenharmony_ci * 21858c2ecf20Sopenharmony_ci * "perf: 'perf kvm' tool for monitoring guest performance from host" 21868c2ecf20Sopenharmony_ci * 21878c2ecf20Sopenharmony_ci * Added a field to struct perf_record_header_build_id that broke the file 21888c2ecf20Sopenharmony_ci * format. 21898c2ecf20Sopenharmony_ci * 21908c2ecf20Sopenharmony_ci * Since the kernel build-id is the first entry, process the 21918c2ecf20Sopenharmony_ci * table using the old format if the well known 21928c2ecf20Sopenharmony_ci * '[kernel.kallsyms]' string for the kernel build-id has the 21938c2ecf20Sopenharmony_ci * first 4 characters chopped off (where the pid_t sits). 21948c2ecf20Sopenharmony_ci */ 21958c2ecf20Sopenharmony_ci if (memcmp(filename, "nel.kallsyms]", 13) == 0) { 21968c2ecf20Sopenharmony_ci if (lseek(input, orig_offset, SEEK_SET) == (off_t)-1) 21978c2ecf20Sopenharmony_ci return -1; 21988c2ecf20Sopenharmony_ci return perf_header__read_build_ids_abi_quirk(header, input, offset, size); 21998c2ecf20Sopenharmony_ci } 22008c2ecf20Sopenharmony_ci 22018c2ecf20Sopenharmony_ci __event_process_build_id(&bev, filename, session); 22028c2ecf20Sopenharmony_ci 22038c2ecf20Sopenharmony_ci offset += bev.header.size; 22048c2ecf20Sopenharmony_ci } 22058c2ecf20Sopenharmony_ci err = 0; 22068c2ecf20Sopenharmony_ciout: 22078c2ecf20Sopenharmony_ci return err; 22088c2ecf20Sopenharmony_ci} 22098c2ecf20Sopenharmony_ci 22108c2ecf20Sopenharmony_ci/* Macro for features that simply need to read and store a string. */ 22118c2ecf20Sopenharmony_ci#define FEAT_PROCESS_STR_FUN(__feat, __feat_env) \ 22128c2ecf20Sopenharmony_cistatic int process_##__feat(struct feat_fd *ff, void *data __maybe_unused) \ 22138c2ecf20Sopenharmony_ci{\ 22148c2ecf20Sopenharmony_ci ff->ph->env.__feat_env = do_read_string(ff); \ 22158c2ecf20Sopenharmony_ci return ff->ph->env.__feat_env ? 0 : -ENOMEM; \ 22168c2ecf20Sopenharmony_ci} 22178c2ecf20Sopenharmony_ci 22188c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(hostname, hostname); 22198c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(osrelease, os_release); 22208c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(version, version); 22218c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(arch, arch); 22228c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(cpudesc, cpu_desc); 22238c2ecf20Sopenharmony_ciFEAT_PROCESS_STR_FUN(cpuid, cpuid); 22248c2ecf20Sopenharmony_ci 22258c2ecf20Sopenharmony_cistatic int process_tracing_data(struct feat_fd *ff, void *data) 22268c2ecf20Sopenharmony_ci{ 22278c2ecf20Sopenharmony_ci ssize_t ret = trace_report(ff->fd, data, false); 22288c2ecf20Sopenharmony_ci 22298c2ecf20Sopenharmony_ci return ret < 0 ? -1 : 0; 22308c2ecf20Sopenharmony_ci} 22318c2ecf20Sopenharmony_ci 22328c2ecf20Sopenharmony_cistatic int process_build_id(struct feat_fd *ff, void *data __maybe_unused) 22338c2ecf20Sopenharmony_ci{ 22348c2ecf20Sopenharmony_ci if (perf_header__read_build_ids(ff->ph, ff->fd, ff->offset, ff->size)) 22358c2ecf20Sopenharmony_ci pr_debug("Failed to read buildids, continuing...\n"); 22368c2ecf20Sopenharmony_ci return 0; 22378c2ecf20Sopenharmony_ci} 22388c2ecf20Sopenharmony_ci 22398c2ecf20Sopenharmony_cistatic int process_nrcpus(struct feat_fd *ff, void *data __maybe_unused) 22408c2ecf20Sopenharmony_ci{ 22418c2ecf20Sopenharmony_ci int ret; 22428c2ecf20Sopenharmony_ci u32 nr_cpus_avail, nr_cpus_online; 22438c2ecf20Sopenharmony_ci 22448c2ecf20Sopenharmony_ci ret = do_read_u32(ff, &nr_cpus_avail); 22458c2ecf20Sopenharmony_ci if (ret) 22468c2ecf20Sopenharmony_ci return ret; 22478c2ecf20Sopenharmony_ci 22488c2ecf20Sopenharmony_ci ret = do_read_u32(ff, &nr_cpus_online); 22498c2ecf20Sopenharmony_ci if (ret) 22508c2ecf20Sopenharmony_ci return ret; 22518c2ecf20Sopenharmony_ci ff->ph->env.nr_cpus_avail = (int)nr_cpus_avail; 22528c2ecf20Sopenharmony_ci ff->ph->env.nr_cpus_online = (int)nr_cpus_online; 22538c2ecf20Sopenharmony_ci return 0; 22548c2ecf20Sopenharmony_ci} 22558c2ecf20Sopenharmony_ci 22568c2ecf20Sopenharmony_cistatic int process_total_mem(struct feat_fd *ff, void *data __maybe_unused) 22578c2ecf20Sopenharmony_ci{ 22588c2ecf20Sopenharmony_ci u64 total_mem; 22598c2ecf20Sopenharmony_ci int ret; 22608c2ecf20Sopenharmony_ci 22618c2ecf20Sopenharmony_ci ret = do_read_u64(ff, &total_mem); 22628c2ecf20Sopenharmony_ci if (ret) 22638c2ecf20Sopenharmony_ci return -1; 22648c2ecf20Sopenharmony_ci ff->ph->env.total_mem = (unsigned long long)total_mem; 22658c2ecf20Sopenharmony_ci return 0; 22668c2ecf20Sopenharmony_ci} 22678c2ecf20Sopenharmony_ci 22688c2ecf20Sopenharmony_cistatic struct evsel * 22698c2ecf20Sopenharmony_ciperf_evlist__find_by_index(struct evlist *evlist, int idx) 22708c2ecf20Sopenharmony_ci{ 22718c2ecf20Sopenharmony_ci struct evsel *evsel; 22728c2ecf20Sopenharmony_ci 22738c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 22748c2ecf20Sopenharmony_ci if (evsel->idx == idx) 22758c2ecf20Sopenharmony_ci return evsel; 22768c2ecf20Sopenharmony_ci } 22778c2ecf20Sopenharmony_ci 22788c2ecf20Sopenharmony_ci return NULL; 22798c2ecf20Sopenharmony_ci} 22808c2ecf20Sopenharmony_ci 22818c2ecf20Sopenharmony_cistatic void 22828c2ecf20Sopenharmony_ciperf_evlist__set_event_name(struct evlist *evlist, 22838c2ecf20Sopenharmony_ci struct evsel *event) 22848c2ecf20Sopenharmony_ci{ 22858c2ecf20Sopenharmony_ci struct evsel *evsel; 22868c2ecf20Sopenharmony_ci 22878c2ecf20Sopenharmony_ci if (!event->name) 22888c2ecf20Sopenharmony_ci return; 22898c2ecf20Sopenharmony_ci 22908c2ecf20Sopenharmony_ci evsel = perf_evlist__find_by_index(evlist, event->idx); 22918c2ecf20Sopenharmony_ci if (!evsel) 22928c2ecf20Sopenharmony_ci return; 22938c2ecf20Sopenharmony_ci 22948c2ecf20Sopenharmony_ci if (evsel->name) 22958c2ecf20Sopenharmony_ci return; 22968c2ecf20Sopenharmony_ci 22978c2ecf20Sopenharmony_ci evsel->name = strdup(event->name); 22988c2ecf20Sopenharmony_ci} 22998c2ecf20Sopenharmony_ci 23008c2ecf20Sopenharmony_cistatic int 23018c2ecf20Sopenharmony_ciprocess_event_desc(struct feat_fd *ff, void *data __maybe_unused) 23028c2ecf20Sopenharmony_ci{ 23038c2ecf20Sopenharmony_ci struct perf_session *session; 23048c2ecf20Sopenharmony_ci struct evsel *evsel, *events = read_event_desc(ff); 23058c2ecf20Sopenharmony_ci 23068c2ecf20Sopenharmony_ci if (!events) 23078c2ecf20Sopenharmony_ci return 0; 23088c2ecf20Sopenharmony_ci 23098c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 23108c2ecf20Sopenharmony_ci 23118c2ecf20Sopenharmony_ci if (session->data->is_pipe) { 23128c2ecf20Sopenharmony_ci /* Save events for reading later by print_event_desc, 23138c2ecf20Sopenharmony_ci * since they can't be read again in pipe mode. */ 23148c2ecf20Sopenharmony_ci ff->events = events; 23158c2ecf20Sopenharmony_ci } 23168c2ecf20Sopenharmony_ci 23178c2ecf20Sopenharmony_ci for (evsel = events; evsel->core.attr.size; evsel++) 23188c2ecf20Sopenharmony_ci perf_evlist__set_event_name(session->evlist, evsel); 23198c2ecf20Sopenharmony_ci 23208c2ecf20Sopenharmony_ci if (!session->data->is_pipe) 23218c2ecf20Sopenharmony_ci free_event_desc(events); 23228c2ecf20Sopenharmony_ci 23238c2ecf20Sopenharmony_ci return 0; 23248c2ecf20Sopenharmony_ci} 23258c2ecf20Sopenharmony_ci 23268c2ecf20Sopenharmony_cistatic int process_cmdline(struct feat_fd *ff, void *data __maybe_unused) 23278c2ecf20Sopenharmony_ci{ 23288c2ecf20Sopenharmony_ci char *str, *cmdline = NULL, **argv = NULL; 23298c2ecf20Sopenharmony_ci u32 nr, i, len = 0; 23308c2ecf20Sopenharmony_ci 23318c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr)) 23328c2ecf20Sopenharmony_ci return -1; 23338c2ecf20Sopenharmony_ci 23348c2ecf20Sopenharmony_ci ff->ph->env.nr_cmdline = nr; 23358c2ecf20Sopenharmony_ci 23368c2ecf20Sopenharmony_ci cmdline = zalloc(ff->size + nr + 1); 23378c2ecf20Sopenharmony_ci if (!cmdline) 23388c2ecf20Sopenharmony_ci return -1; 23398c2ecf20Sopenharmony_ci 23408c2ecf20Sopenharmony_ci argv = zalloc(sizeof(char *) * (nr + 1)); 23418c2ecf20Sopenharmony_ci if (!argv) 23428c2ecf20Sopenharmony_ci goto error; 23438c2ecf20Sopenharmony_ci 23448c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 23458c2ecf20Sopenharmony_ci str = do_read_string(ff); 23468c2ecf20Sopenharmony_ci if (!str) 23478c2ecf20Sopenharmony_ci goto error; 23488c2ecf20Sopenharmony_ci 23498c2ecf20Sopenharmony_ci argv[i] = cmdline + len; 23508c2ecf20Sopenharmony_ci memcpy(argv[i], str, strlen(str) + 1); 23518c2ecf20Sopenharmony_ci len += strlen(str) + 1; 23528c2ecf20Sopenharmony_ci free(str); 23538c2ecf20Sopenharmony_ci } 23548c2ecf20Sopenharmony_ci ff->ph->env.cmdline = cmdline; 23558c2ecf20Sopenharmony_ci ff->ph->env.cmdline_argv = (const char **) argv; 23568c2ecf20Sopenharmony_ci return 0; 23578c2ecf20Sopenharmony_ci 23588c2ecf20Sopenharmony_cierror: 23598c2ecf20Sopenharmony_ci free(argv); 23608c2ecf20Sopenharmony_ci free(cmdline); 23618c2ecf20Sopenharmony_ci return -1; 23628c2ecf20Sopenharmony_ci} 23638c2ecf20Sopenharmony_ci 23648c2ecf20Sopenharmony_cistatic int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) 23658c2ecf20Sopenharmony_ci{ 23668c2ecf20Sopenharmony_ci u32 nr, i; 23678c2ecf20Sopenharmony_ci char *str; 23688c2ecf20Sopenharmony_ci struct strbuf sb; 23698c2ecf20Sopenharmony_ci int cpu_nr = ff->ph->env.nr_cpus_avail; 23708c2ecf20Sopenharmony_ci u64 size = 0; 23718c2ecf20Sopenharmony_ci struct perf_header *ph = ff->ph; 23728c2ecf20Sopenharmony_ci bool do_core_id_test = true; 23738c2ecf20Sopenharmony_ci 23748c2ecf20Sopenharmony_ci ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu)); 23758c2ecf20Sopenharmony_ci if (!ph->env.cpu) 23768c2ecf20Sopenharmony_ci return -1; 23778c2ecf20Sopenharmony_ci 23788c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr)) 23798c2ecf20Sopenharmony_ci goto free_cpu; 23808c2ecf20Sopenharmony_ci 23818c2ecf20Sopenharmony_ci ph->env.nr_sibling_cores = nr; 23828c2ecf20Sopenharmony_ci size += sizeof(u32); 23838c2ecf20Sopenharmony_ci if (strbuf_init(&sb, 128) < 0) 23848c2ecf20Sopenharmony_ci goto free_cpu; 23858c2ecf20Sopenharmony_ci 23868c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 23878c2ecf20Sopenharmony_ci str = do_read_string(ff); 23888c2ecf20Sopenharmony_ci if (!str) 23898c2ecf20Sopenharmony_ci goto error; 23908c2ecf20Sopenharmony_ci 23918c2ecf20Sopenharmony_ci /* include a NULL character at the end */ 23928c2ecf20Sopenharmony_ci if (strbuf_add(&sb, str, strlen(str) + 1) < 0) 23938c2ecf20Sopenharmony_ci goto error; 23948c2ecf20Sopenharmony_ci size += string_size(str); 23958c2ecf20Sopenharmony_ci free(str); 23968c2ecf20Sopenharmony_ci } 23978c2ecf20Sopenharmony_ci ph->env.sibling_cores = strbuf_detach(&sb, NULL); 23988c2ecf20Sopenharmony_ci 23998c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr)) 24008c2ecf20Sopenharmony_ci return -1; 24018c2ecf20Sopenharmony_ci 24028c2ecf20Sopenharmony_ci ph->env.nr_sibling_threads = nr; 24038c2ecf20Sopenharmony_ci size += sizeof(u32); 24048c2ecf20Sopenharmony_ci 24058c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 24068c2ecf20Sopenharmony_ci str = do_read_string(ff); 24078c2ecf20Sopenharmony_ci if (!str) 24088c2ecf20Sopenharmony_ci goto error; 24098c2ecf20Sopenharmony_ci 24108c2ecf20Sopenharmony_ci /* include a NULL character at the end */ 24118c2ecf20Sopenharmony_ci if (strbuf_add(&sb, str, strlen(str) + 1) < 0) 24128c2ecf20Sopenharmony_ci goto error; 24138c2ecf20Sopenharmony_ci size += string_size(str); 24148c2ecf20Sopenharmony_ci free(str); 24158c2ecf20Sopenharmony_ci } 24168c2ecf20Sopenharmony_ci ph->env.sibling_threads = strbuf_detach(&sb, NULL); 24178c2ecf20Sopenharmony_ci 24188c2ecf20Sopenharmony_ci /* 24198c2ecf20Sopenharmony_ci * The header may be from old perf, 24208c2ecf20Sopenharmony_ci * which doesn't include core id and socket id information. 24218c2ecf20Sopenharmony_ci */ 24228c2ecf20Sopenharmony_ci if (ff->size <= size) { 24238c2ecf20Sopenharmony_ci zfree(&ph->env.cpu); 24248c2ecf20Sopenharmony_ci return 0; 24258c2ecf20Sopenharmony_ci } 24268c2ecf20Sopenharmony_ci 24278c2ecf20Sopenharmony_ci /* On s390 the socket_id number is not related to the numbers of cpus. 24288c2ecf20Sopenharmony_ci * The socket_id number might be higher than the numbers of cpus. 24298c2ecf20Sopenharmony_ci * This depends on the configuration. 24308c2ecf20Sopenharmony_ci * AArch64 is the same. 24318c2ecf20Sopenharmony_ci */ 24328c2ecf20Sopenharmony_ci if (ph->env.arch && (!strncmp(ph->env.arch, "s390", 4) 24338c2ecf20Sopenharmony_ci || !strncmp(ph->env.arch, "aarch64", 7))) 24348c2ecf20Sopenharmony_ci do_core_id_test = false; 24358c2ecf20Sopenharmony_ci 24368c2ecf20Sopenharmony_ci for (i = 0; i < (u32)cpu_nr; i++) { 24378c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr)) 24388c2ecf20Sopenharmony_ci goto free_cpu; 24398c2ecf20Sopenharmony_ci 24408c2ecf20Sopenharmony_ci ph->env.cpu[i].core_id = nr; 24418c2ecf20Sopenharmony_ci size += sizeof(u32); 24428c2ecf20Sopenharmony_ci 24438c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr)) 24448c2ecf20Sopenharmony_ci goto free_cpu; 24458c2ecf20Sopenharmony_ci 24468c2ecf20Sopenharmony_ci if (do_core_id_test && nr != (u32)-1 && nr > (u32)cpu_nr) { 24478c2ecf20Sopenharmony_ci pr_debug("socket_id number is too big." 24488c2ecf20Sopenharmony_ci "You may need to upgrade the perf tool.\n"); 24498c2ecf20Sopenharmony_ci goto free_cpu; 24508c2ecf20Sopenharmony_ci } 24518c2ecf20Sopenharmony_ci 24528c2ecf20Sopenharmony_ci ph->env.cpu[i].socket_id = nr; 24538c2ecf20Sopenharmony_ci size += sizeof(u32); 24548c2ecf20Sopenharmony_ci } 24558c2ecf20Sopenharmony_ci 24568c2ecf20Sopenharmony_ci /* 24578c2ecf20Sopenharmony_ci * The header may be from old perf, 24588c2ecf20Sopenharmony_ci * which doesn't include die information. 24598c2ecf20Sopenharmony_ci */ 24608c2ecf20Sopenharmony_ci if (ff->size <= size) 24618c2ecf20Sopenharmony_ci return 0; 24628c2ecf20Sopenharmony_ci 24638c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr)) 24648c2ecf20Sopenharmony_ci return -1; 24658c2ecf20Sopenharmony_ci 24668c2ecf20Sopenharmony_ci ph->env.nr_sibling_dies = nr; 24678c2ecf20Sopenharmony_ci size += sizeof(u32); 24688c2ecf20Sopenharmony_ci 24698c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 24708c2ecf20Sopenharmony_ci str = do_read_string(ff); 24718c2ecf20Sopenharmony_ci if (!str) 24728c2ecf20Sopenharmony_ci goto error; 24738c2ecf20Sopenharmony_ci 24748c2ecf20Sopenharmony_ci /* include a NULL character at the end */ 24758c2ecf20Sopenharmony_ci if (strbuf_add(&sb, str, strlen(str) + 1) < 0) 24768c2ecf20Sopenharmony_ci goto error; 24778c2ecf20Sopenharmony_ci size += string_size(str); 24788c2ecf20Sopenharmony_ci free(str); 24798c2ecf20Sopenharmony_ci } 24808c2ecf20Sopenharmony_ci ph->env.sibling_dies = strbuf_detach(&sb, NULL); 24818c2ecf20Sopenharmony_ci 24828c2ecf20Sopenharmony_ci for (i = 0; i < (u32)cpu_nr; i++) { 24838c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr)) 24848c2ecf20Sopenharmony_ci goto free_cpu; 24858c2ecf20Sopenharmony_ci 24868c2ecf20Sopenharmony_ci ph->env.cpu[i].die_id = nr; 24878c2ecf20Sopenharmony_ci } 24888c2ecf20Sopenharmony_ci 24898c2ecf20Sopenharmony_ci return 0; 24908c2ecf20Sopenharmony_ci 24918c2ecf20Sopenharmony_cierror: 24928c2ecf20Sopenharmony_ci strbuf_release(&sb); 24938c2ecf20Sopenharmony_cifree_cpu: 24948c2ecf20Sopenharmony_ci zfree(&ph->env.cpu); 24958c2ecf20Sopenharmony_ci return -1; 24968c2ecf20Sopenharmony_ci} 24978c2ecf20Sopenharmony_ci 24988c2ecf20Sopenharmony_cistatic int process_numa_topology(struct feat_fd *ff, void *data __maybe_unused) 24998c2ecf20Sopenharmony_ci{ 25008c2ecf20Sopenharmony_ci struct numa_node *nodes, *n; 25018c2ecf20Sopenharmony_ci u32 nr, i; 25028c2ecf20Sopenharmony_ci char *str; 25038c2ecf20Sopenharmony_ci 25048c2ecf20Sopenharmony_ci /* nr nodes */ 25058c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr)) 25068c2ecf20Sopenharmony_ci return -1; 25078c2ecf20Sopenharmony_ci 25088c2ecf20Sopenharmony_ci nodes = zalloc(sizeof(*nodes) * nr); 25098c2ecf20Sopenharmony_ci if (!nodes) 25108c2ecf20Sopenharmony_ci return -ENOMEM; 25118c2ecf20Sopenharmony_ci 25128c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 25138c2ecf20Sopenharmony_ci n = &nodes[i]; 25148c2ecf20Sopenharmony_ci 25158c2ecf20Sopenharmony_ci /* node number */ 25168c2ecf20Sopenharmony_ci if (do_read_u32(ff, &n->node)) 25178c2ecf20Sopenharmony_ci goto error; 25188c2ecf20Sopenharmony_ci 25198c2ecf20Sopenharmony_ci if (do_read_u64(ff, &n->mem_total)) 25208c2ecf20Sopenharmony_ci goto error; 25218c2ecf20Sopenharmony_ci 25228c2ecf20Sopenharmony_ci if (do_read_u64(ff, &n->mem_free)) 25238c2ecf20Sopenharmony_ci goto error; 25248c2ecf20Sopenharmony_ci 25258c2ecf20Sopenharmony_ci str = do_read_string(ff); 25268c2ecf20Sopenharmony_ci if (!str) 25278c2ecf20Sopenharmony_ci goto error; 25288c2ecf20Sopenharmony_ci 25298c2ecf20Sopenharmony_ci n->map = perf_cpu_map__new(str); 25308c2ecf20Sopenharmony_ci if (!n->map) 25318c2ecf20Sopenharmony_ci goto error; 25328c2ecf20Sopenharmony_ci 25338c2ecf20Sopenharmony_ci free(str); 25348c2ecf20Sopenharmony_ci } 25358c2ecf20Sopenharmony_ci ff->ph->env.nr_numa_nodes = nr; 25368c2ecf20Sopenharmony_ci ff->ph->env.numa_nodes = nodes; 25378c2ecf20Sopenharmony_ci return 0; 25388c2ecf20Sopenharmony_ci 25398c2ecf20Sopenharmony_cierror: 25408c2ecf20Sopenharmony_ci free(nodes); 25418c2ecf20Sopenharmony_ci return -1; 25428c2ecf20Sopenharmony_ci} 25438c2ecf20Sopenharmony_ci 25448c2ecf20Sopenharmony_cistatic int process_pmu_mappings(struct feat_fd *ff, void *data __maybe_unused) 25458c2ecf20Sopenharmony_ci{ 25468c2ecf20Sopenharmony_ci char *name; 25478c2ecf20Sopenharmony_ci u32 pmu_num; 25488c2ecf20Sopenharmony_ci u32 type; 25498c2ecf20Sopenharmony_ci struct strbuf sb; 25508c2ecf20Sopenharmony_ci 25518c2ecf20Sopenharmony_ci if (do_read_u32(ff, &pmu_num)) 25528c2ecf20Sopenharmony_ci return -1; 25538c2ecf20Sopenharmony_ci 25548c2ecf20Sopenharmony_ci if (!pmu_num) { 25558c2ecf20Sopenharmony_ci pr_debug("pmu mappings not available\n"); 25568c2ecf20Sopenharmony_ci return 0; 25578c2ecf20Sopenharmony_ci } 25588c2ecf20Sopenharmony_ci 25598c2ecf20Sopenharmony_ci ff->ph->env.nr_pmu_mappings = pmu_num; 25608c2ecf20Sopenharmony_ci if (strbuf_init(&sb, 128) < 0) 25618c2ecf20Sopenharmony_ci return -1; 25628c2ecf20Sopenharmony_ci 25638c2ecf20Sopenharmony_ci while (pmu_num) { 25648c2ecf20Sopenharmony_ci if (do_read_u32(ff, &type)) 25658c2ecf20Sopenharmony_ci goto error; 25668c2ecf20Sopenharmony_ci 25678c2ecf20Sopenharmony_ci name = do_read_string(ff); 25688c2ecf20Sopenharmony_ci if (!name) 25698c2ecf20Sopenharmony_ci goto error; 25708c2ecf20Sopenharmony_ci 25718c2ecf20Sopenharmony_ci if (strbuf_addf(&sb, "%u:%s", type, name) < 0) 25728c2ecf20Sopenharmony_ci goto error; 25738c2ecf20Sopenharmony_ci /* include a NULL character at the end */ 25748c2ecf20Sopenharmony_ci if (strbuf_add(&sb, "", 1) < 0) 25758c2ecf20Sopenharmony_ci goto error; 25768c2ecf20Sopenharmony_ci 25778c2ecf20Sopenharmony_ci if (!strcmp(name, "msr")) 25788c2ecf20Sopenharmony_ci ff->ph->env.msr_pmu_type = type; 25798c2ecf20Sopenharmony_ci 25808c2ecf20Sopenharmony_ci free(name); 25818c2ecf20Sopenharmony_ci pmu_num--; 25828c2ecf20Sopenharmony_ci } 25838c2ecf20Sopenharmony_ci ff->ph->env.pmu_mappings = strbuf_detach(&sb, NULL); 25848c2ecf20Sopenharmony_ci return 0; 25858c2ecf20Sopenharmony_ci 25868c2ecf20Sopenharmony_cierror: 25878c2ecf20Sopenharmony_ci strbuf_release(&sb); 25888c2ecf20Sopenharmony_ci return -1; 25898c2ecf20Sopenharmony_ci} 25908c2ecf20Sopenharmony_ci 25918c2ecf20Sopenharmony_cistatic int process_group_desc(struct feat_fd *ff, void *data __maybe_unused) 25928c2ecf20Sopenharmony_ci{ 25938c2ecf20Sopenharmony_ci size_t ret = -1; 25948c2ecf20Sopenharmony_ci u32 i, nr, nr_groups; 25958c2ecf20Sopenharmony_ci struct perf_session *session; 25968c2ecf20Sopenharmony_ci struct evsel *evsel, *leader = NULL; 25978c2ecf20Sopenharmony_ci struct group_desc { 25988c2ecf20Sopenharmony_ci char *name; 25998c2ecf20Sopenharmony_ci u32 leader_idx; 26008c2ecf20Sopenharmony_ci u32 nr_members; 26018c2ecf20Sopenharmony_ci } *desc; 26028c2ecf20Sopenharmony_ci 26038c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr_groups)) 26048c2ecf20Sopenharmony_ci return -1; 26058c2ecf20Sopenharmony_ci 26068c2ecf20Sopenharmony_ci ff->ph->env.nr_groups = nr_groups; 26078c2ecf20Sopenharmony_ci if (!nr_groups) { 26088c2ecf20Sopenharmony_ci pr_debug("group desc not available\n"); 26098c2ecf20Sopenharmony_ci return 0; 26108c2ecf20Sopenharmony_ci } 26118c2ecf20Sopenharmony_ci 26128c2ecf20Sopenharmony_ci desc = calloc(nr_groups, sizeof(*desc)); 26138c2ecf20Sopenharmony_ci if (!desc) 26148c2ecf20Sopenharmony_ci return -1; 26158c2ecf20Sopenharmony_ci 26168c2ecf20Sopenharmony_ci for (i = 0; i < nr_groups; i++) { 26178c2ecf20Sopenharmony_ci desc[i].name = do_read_string(ff); 26188c2ecf20Sopenharmony_ci if (!desc[i].name) 26198c2ecf20Sopenharmony_ci goto out_free; 26208c2ecf20Sopenharmony_ci 26218c2ecf20Sopenharmony_ci if (do_read_u32(ff, &desc[i].leader_idx)) 26228c2ecf20Sopenharmony_ci goto out_free; 26238c2ecf20Sopenharmony_ci 26248c2ecf20Sopenharmony_ci if (do_read_u32(ff, &desc[i].nr_members)) 26258c2ecf20Sopenharmony_ci goto out_free; 26268c2ecf20Sopenharmony_ci } 26278c2ecf20Sopenharmony_ci 26288c2ecf20Sopenharmony_ci /* 26298c2ecf20Sopenharmony_ci * Rebuild group relationship based on the group_desc 26308c2ecf20Sopenharmony_ci */ 26318c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 26328c2ecf20Sopenharmony_ci session->evlist->nr_groups = nr_groups; 26338c2ecf20Sopenharmony_ci 26348c2ecf20Sopenharmony_ci i = nr = 0; 26358c2ecf20Sopenharmony_ci evlist__for_each_entry(session->evlist, evsel) { 26368c2ecf20Sopenharmony_ci if (evsel->idx == (int) desc[i].leader_idx) { 26378c2ecf20Sopenharmony_ci evsel->leader = evsel; 26388c2ecf20Sopenharmony_ci /* {anon_group} is a dummy name */ 26398c2ecf20Sopenharmony_ci if (strcmp(desc[i].name, "{anon_group}")) { 26408c2ecf20Sopenharmony_ci evsel->group_name = desc[i].name; 26418c2ecf20Sopenharmony_ci desc[i].name = NULL; 26428c2ecf20Sopenharmony_ci } 26438c2ecf20Sopenharmony_ci evsel->core.nr_members = desc[i].nr_members; 26448c2ecf20Sopenharmony_ci 26458c2ecf20Sopenharmony_ci if (i >= nr_groups || nr > 0) { 26468c2ecf20Sopenharmony_ci pr_debug("invalid group desc\n"); 26478c2ecf20Sopenharmony_ci goto out_free; 26488c2ecf20Sopenharmony_ci } 26498c2ecf20Sopenharmony_ci 26508c2ecf20Sopenharmony_ci leader = evsel; 26518c2ecf20Sopenharmony_ci nr = evsel->core.nr_members - 1; 26528c2ecf20Sopenharmony_ci i++; 26538c2ecf20Sopenharmony_ci } else if (nr) { 26548c2ecf20Sopenharmony_ci /* This is a group member */ 26558c2ecf20Sopenharmony_ci evsel->leader = leader; 26568c2ecf20Sopenharmony_ci 26578c2ecf20Sopenharmony_ci nr--; 26588c2ecf20Sopenharmony_ci } 26598c2ecf20Sopenharmony_ci } 26608c2ecf20Sopenharmony_ci 26618c2ecf20Sopenharmony_ci if (i != nr_groups || nr != 0) { 26628c2ecf20Sopenharmony_ci pr_debug("invalid group desc\n"); 26638c2ecf20Sopenharmony_ci goto out_free; 26648c2ecf20Sopenharmony_ci } 26658c2ecf20Sopenharmony_ci 26668c2ecf20Sopenharmony_ci ret = 0; 26678c2ecf20Sopenharmony_ciout_free: 26688c2ecf20Sopenharmony_ci for (i = 0; i < nr_groups; i++) 26698c2ecf20Sopenharmony_ci zfree(&desc[i].name); 26708c2ecf20Sopenharmony_ci free(desc); 26718c2ecf20Sopenharmony_ci 26728c2ecf20Sopenharmony_ci return ret; 26738c2ecf20Sopenharmony_ci} 26748c2ecf20Sopenharmony_ci 26758c2ecf20Sopenharmony_cistatic int process_auxtrace(struct feat_fd *ff, void *data __maybe_unused) 26768c2ecf20Sopenharmony_ci{ 26778c2ecf20Sopenharmony_ci struct perf_session *session; 26788c2ecf20Sopenharmony_ci int err; 26798c2ecf20Sopenharmony_ci 26808c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 26818c2ecf20Sopenharmony_ci 26828c2ecf20Sopenharmony_ci err = auxtrace_index__process(ff->fd, ff->size, session, 26838c2ecf20Sopenharmony_ci ff->ph->needs_swap); 26848c2ecf20Sopenharmony_ci if (err < 0) 26858c2ecf20Sopenharmony_ci pr_err("Failed to process auxtrace index\n"); 26868c2ecf20Sopenharmony_ci return err; 26878c2ecf20Sopenharmony_ci} 26888c2ecf20Sopenharmony_ci 26898c2ecf20Sopenharmony_cistatic int process_cache(struct feat_fd *ff, void *data __maybe_unused) 26908c2ecf20Sopenharmony_ci{ 26918c2ecf20Sopenharmony_ci struct cpu_cache_level *caches; 26928c2ecf20Sopenharmony_ci u32 cnt, i, version; 26938c2ecf20Sopenharmony_ci 26948c2ecf20Sopenharmony_ci if (do_read_u32(ff, &version)) 26958c2ecf20Sopenharmony_ci return -1; 26968c2ecf20Sopenharmony_ci 26978c2ecf20Sopenharmony_ci if (version != 1) 26988c2ecf20Sopenharmony_ci return -1; 26998c2ecf20Sopenharmony_ci 27008c2ecf20Sopenharmony_ci if (do_read_u32(ff, &cnt)) 27018c2ecf20Sopenharmony_ci return -1; 27028c2ecf20Sopenharmony_ci 27038c2ecf20Sopenharmony_ci caches = zalloc(sizeof(*caches) * cnt); 27048c2ecf20Sopenharmony_ci if (!caches) 27058c2ecf20Sopenharmony_ci return -1; 27068c2ecf20Sopenharmony_ci 27078c2ecf20Sopenharmony_ci for (i = 0; i < cnt; i++) { 27088c2ecf20Sopenharmony_ci struct cpu_cache_level c; 27098c2ecf20Sopenharmony_ci 27108c2ecf20Sopenharmony_ci #define _R(v) \ 27118c2ecf20Sopenharmony_ci if (do_read_u32(ff, &c.v))\ 27128c2ecf20Sopenharmony_ci goto out_free_caches; \ 27138c2ecf20Sopenharmony_ci 27148c2ecf20Sopenharmony_ci _R(level) 27158c2ecf20Sopenharmony_ci _R(line_size) 27168c2ecf20Sopenharmony_ci _R(sets) 27178c2ecf20Sopenharmony_ci _R(ways) 27188c2ecf20Sopenharmony_ci #undef _R 27198c2ecf20Sopenharmony_ci 27208c2ecf20Sopenharmony_ci #define _R(v) \ 27218c2ecf20Sopenharmony_ci c.v = do_read_string(ff); \ 27228c2ecf20Sopenharmony_ci if (!c.v) \ 27238c2ecf20Sopenharmony_ci goto out_free_caches; 27248c2ecf20Sopenharmony_ci 27258c2ecf20Sopenharmony_ci _R(type) 27268c2ecf20Sopenharmony_ci _R(size) 27278c2ecf20Sopenharmony_ci _R(map) 27288c2ecf20Sopenharmony_ci #undef _R 27298c2ecf20Sopenharmony_ci 27308c2ecf20Sopenharmony_ci caches[i] = c; 27318c2ecf20Sopenharmony_ci } 27328c2ecf20Sopenharmony_ci 27338c2ecf20Sopenharmony_ci ff->ph->env.caches = caches; 27348c2ecf20Sopenharmony_ci ff->ph->env.caches_cnt = cnt; 27358c2ecf20Sopenharmony_ci return 0; 27368c2ecf20Sopenharmony_ciout_free_caches: 27378c2ecf20Sopenharmony_ci free(caches); 27388c2ecf20Sopenharmony_ci return -1; 27398c2ecf20Sopenharmony_ci} 27408c2ecf20Sopenharmony_ci 27418c2ecf20Sopenharmony_cistatic int process_sample_time(struct feat_fd *ff, void *data __maybe_unused) 27428c2ecf20Sopenharmony_ci{ 27438c2ecf20Sopenharmony_ci struct perf_session *session; 27448c2ecf20Sopenharmony_ci u64 first_sample_time, last_sample_time; 27458c2ecf20Sopenharmony_ci int ret; 27468c2ecf20Sopenharmony_ci 27478c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 27488c2ecf20Sopenharmony_ci 27498c2ecf20Sopenharmony_ci ret = do_read_u64(ff, &first_sample_time); 27508c2ecf20Sopenharmony_ci if (ret) 27518c2ecf20Sopenharmony_ci return -1; 27528c2ecf20Sopenharmony_ci 27538c2ecf20Sopenharmony_ci ret = do_read_u64(ff, &last_sample_time); 27548c2ecf20Sopenharmony_ci if (ret) 27558c2ecf20Sopenharmony_ci return -1; 27568c2ecf20Sopenharmony_ci 27578c2ecf20Sopenharmony_ci session->evlist->first_sample_time = first_sample_time; 27588c2ecf20Sopenharmony_ci session->evlist->last_sample_time = last_sample_time; 27598c2ecf20Sopenharmony_ci return 0; 27608c2ecf20Sopenharmony_ci} 27618c2ecf20Sopenharmony_ci 27628c2ecf20Sopenharmony_cistatic int process_mem_topology(struct feat_fd *ff, 27638c2ecf20Sopenharmony_ci void *data __maybe_unused) 27648c2ecf20Sopenharmony_ci{ 27658c2ecf20Sopenharmony_ci struct memory_node *nodes; 27668c2ecf20Sopenharmony_ci u64 version, i, nr, bsize; 27678c2ecf20Sopenharmony_ci int ret = -1; 27688c2ecf20Sopenharmony_ci 27698c2ecf20Sopenharmony_ci if (do_read_u64(ff, &version)) 27708c2ecf20Sopenharmony_ci return -1; 27718c2ecf20Sopenharmony_ci 27728c2ecf20Sopenharmony_ci if (version != 1) 27738c2ecf20Sopenharmony_ci return -1; 27748c2ecf20Sopenharmony_ci 27758c2ecf20Sopenharmony_ci if (do_read_u64(ff, &bsize)) 27768c2ecf20Sopenharmony_ci return -1; 27778c2ecf20Sopenharmony_ci 27788c2ecf20Sopenharmony_ci if (do_read_u64(ff, &nr)) 27798c2ecf20Sopenharmony_ci return -1; 27808c2ecf20Sopenharmony_ci 27818c2ecf20Sopenharmony_ci nodes = zalloc(sizeof(*nodes) * nr); 27828c2ecf20Sopenharmony_ci if (!nodes) 27838c2ecf20Sopenharmony_ci return -1; 27848c2ecf20Sopenharmony_ci 27858c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) { 27868c2ecf20Sopenharmony_ci struct memory_node n; 27878c2ecf20Sopenharmony_ci 27888c2ecf20Sopenharmony_ci #define _R(v) \ 27898c2ecf20Sopenharmony_ci if (do_read_u64(ff, &n.v)) \ 27908c2ecf20Sopenharmony_ci goto out; \ 27918c2ecf20Sopenharmony_ci 27928c2ecf20Sopenharmony_ci _R(node) 27938c2ecf20Sopenharmony_ci _R(size) 27948c2ecf20Sopenharmony_ci 27958c2ecf20Sopenharmony_ci #undef _R 27968c2ecf20Sopenharmony_ci 27978c2ecf20Sopenharmony_ci if (do_read_bitmap(ff, &n.set, &n.size)) 27988c2ecf20Sopenharmony_ci goto out; 27998c2ecf20Sopenharmony_ci 28008c2ecf20Sopenharmony_ci nodes[i] = n; 28018c2ecf20Sopenharmony_ci } 28028c2ecf20Sopenharmony_ci 28038c2ecf20Sopenharmony_ci ff->ph->env.memory_bsize = bsize; 28048c2ecf20Sopenharmony_ci ff->ph->env.memory_nodes = nodes; 28058c2ecf20Sopenharmony_ci ff->ph->env.nr_memory_nodes = nr; 28068c2ecf20Sopenharmony_ci ret = 0; 28078c2ecf20Sopenharmony_ci 28088c2ecf20Sopenharmony_ciout: 28098c2ecf20Sopenharmony_ci if (ret) 28108c2ecf20Sopenharmony_ci free(nodes); 28118c2ecf20Sopenharmony_ci return ret; 28128c2ecf20Sopenharmony_ci} 28138c2ecf20Sopenharmony_ci 28148c2ecf20Sopenharmony_cistatic int process_clockid(struct feat_fd *ff, 28158c2ecf20Sopenharmony_ci void *data __maybe_unused) 28168c2ecf20Sopenharmony_ci{ 28178c2ecf20Sopenharmony_ci if (do_read_u64(ff, &ff->ph->env.clock.clockid_res_ns)) 28188c2ecf20Sopenharmony_ci return -1; 28198c2ecf20Sopenharmony_ci 28208c2ecf20Sopenharmony_ci return 0; 28218c2ecf20Sopenharmony_ci} 28228c2ecf20Sopenharmony_ci 28238c2ecf20Sopenharmony_cistatic int process_clock_data(struct feat_fd *ff, 28248c2ecf20Sopenharmony_ci void *_data __maybe_unused) 28258c2ecf20Sopenharmony_ci{ 28268c2ecf20Sopenharmony_ci u32 data32; 28278c2ecf20Sopenharmony_ci u64 data64; 28288c2ecf20Sopenharmony_ci 28298c2ecf20Sopenharmony_ci /* version */ 28308c2ecf20Sopenharmony_ci if (do_read_u32(ff, &data32)) 28318c2ecf20Sopenharmony_ci return -1; 28328c2ecf20Sopenharmony_ci 28338c2ecf20Sopenharmony_ci if (data32 != 1) 28348c2ecf20Sopenharmony_ci return -1; 28358c2ecf20Sopenharmony_ci 28368c2ecf20Sopenharmony_ci /* clockid */ 28378c2ecf20Sopenharmony_ci if (do_read_u32(ff, &data32)) 28388c2ecf20Sopenharmony_ci return -1; 28398c2ecf20Sopenharmony_ci 28408c2ecf20Sopenharmony_ci ff->ph->env.clock.clockid = data32; 28418c2ecf20Sopenharmony_ci 28428c2ecf20Sopenharmony_ci /* TOD ref time */ 28438c2ecf20Sopenharmony_ci if (do_read_u64(ff, &data64)) 28448c2ecf20Sopenharmony_ci return -1; 28458c2ecf20Sopenharmony_ci 28468c2ecf20Sopenharmony_ci ff->ph->env.clock.tod_ns = data64; 28478c2ecf20Sopenharmony_ci 28488c2ecf20Sopenharmony_ci /* clockid ref time */ 28498c2ecf20Sopenharmony_ci if (do_read_u64(ff, &data64)) 28508c2ecf20Sopenharmony_ci return -1; 28518c2ecf20Sopenharmony_ci 28528c2ecf20Sopenharmony_ci ff->ph->env.clock.clockid_ns = data64; 28538c2ecf20Sopenharmony_ci ff->ph->env.clock.enabled = true; 28548c2ecf20Sopenharmony_ci return 0; 28558c2ecf20Sopenharmony_ci} 28568c2ecf20Sopenharmony_ci 28578c2ecf20Sopenharmony_cistatic int process_dir_format(struct feat_fd *ff, 28588c2ecf20Sopenharmony_ci void *_data __maybe_unused) 28598c2ecf20Sopenharmony_ci{ 28608c2ecf20Sopenharmony_ci struct perf_session *session; 28618c2ecf20Sopenharmony_ci struct perf_data *data; 28628c2ecf20Sopenharmony_ci 28638c2ecf20Sopenharmony_ci session = container_of(ff->ph, struct perf_session, header); 28648c2ecf20Sopenharmony_ci data = session->data; 28658c2ecf20Sopenharmony_ci 28668c2ecf20Sopenharmony_ci if (WARN_ON(!perf_data__is_dir(data))) 28678c2ecf20Sopenharmony_ci return -1; 28688c2ecf20Sopenharmony_ci 28698c2ecf20Sopenharmony_ci return do_read_u64(ff, &data->dir.version); 28708c2ecf20Sopenharmony_ci} 28718c2ecf20Sopenharmony_ci 28728c2ecf20Sopenharmony_ci#ifdef HAVE_LIBBPF_SUPPORT 28738c2ecf20Sopenharmony_cistatic int process_bpf_prog_info(struct feat_fd *ff, void *data __maybe_unused) 28748c2ecf20Sopenharmony_ci{ 28758c2ecf20Sopenharmony_ci struct bpf_prog_info_linear *info_linear; 28768c2ecf20Sopenharmony_ci struct bpf_prog_info_node *info_node; 28778c2ecf20Sopenharmony_ci struct perf_env *env = &ff->ph->env; 28788c2ecf20Sopenharmony_ci u32 count, i; 28798c2ecf20Sopenharmony_ci int err = -1; 28808c2ecf20Sopenharmony_ci 28818c2ecf20Sopenharmony_ci if (ff->ph->needs_swap) { 28828c2ecf20Sopenharmony_ci pr_warning("interpreting bpf_prog_info from systems with endianity is not yet supported\n"); 28838c2ecf20Sopenharmony_ci return 0; 28848c2ecf20Sopenharmony_ci } 28858c2ecf20Sopenharmony_ci 28868c2ecf20Sopenharmony_ci if (do_read_u32(ff, &count)) 28878c2ecf20Sopenharmony_ci return -1; 28888c2ecf20Sopenharmony_ci 28898c2ecf20Sopenharmony_ci down_write(&env->bpf_progs.lock); 28908c2ecf20Sopenharmony_ci 28918c2ecf20Sopenharmony_ci for (i = 0; i < count; ++i) { 28928c2ecf20Sopenharmony_ci u32 info_len, data_len; 28938c2ecf20Sopenharmony_ci 28948c2ecf20Sopenharmony_ci info_linear = NULL; 28958c2ecf20Sopenharmony_ci info_node = NULL; 28968c2ecf20Sopenharmony_ci if (do_read_u32(ff, &info_len)) 28978c2ecf20Sopenharmony_ci goto out; 28988c2ecf20Sopenharmony_ci if (do_read_u32(ff, &data_len)) 28998c2ecf20Sopenharmony_ci goto out; 29008c2ecf20Sopenharmony_ci 29018c2ecf20Sopenharmony_ci if (info_len > sizeof(struct bpf_prog_info)) { 29028c2ecf20Sopenharmony_ci pr_warning("detected invalid bpf_prog_info\n"); 29038c2ecf20Sopenharmony_ci goto out; 29048c2ecf20Sopenharmony_ci } 29058c2ecf20Sopenharmony_ci 29068c2ecf20Sopenharmony_ci info_linear = malloc(sizeof(struct bpf_prog_info_linear) + 29078c2ecf20Sopenharmony_ci data_len); 29088c2ecf20Sopenharmony_ci if (!info_linear) 29098c2ecf20Sopenharmony_ci goto out; 29108c2ecf20Sopenharmony_ci info_linear->info_len = sizeof(struct bpf_prog_info); 29118c2ecf20Sopenharmony_ci info_linear->data_len = data_len; 29128c2ecf20Sopenharmony_ci if (do_read_u64(ff, (u64 *)(&info_linear->arrays))) 29138c2ecf20Sopenharmony_ci goto out; 29148c2ecf20Sopenharmony_ci if (__do_read(ff, &info_linear->info, info_len)) 29158c2ecf20Sopenharmony_ci goto out; 29168c2ecf20Sopenharmony_ci if (info_len < sizeof(struct bpf_prog_info)) 29178c2ecf20Sopenharmony_ci memset(((void *)(&info_linear->info)) + info_len, 0, 29188c2ecf20Sopenharmony_ci sizeof(struct bpf_prog_info) - info_len); 29198c2ecf20Sopenharmony_ci 29208c2ecf20Sopenharmony_ci if (__do_read(ff, info_linear->data, data_len)) 29218c2ecf20Sopenharmony_ci goto out; 29228c2ecf20Sopenharmony_ci 29238c2ecf20Sopenharmony_ci info_node = malloc(sizeof(struct bpf_prog_info_node)); 29248c2ecf20Sopenharmony_ci if (!info_node) 29258c2ecf20Sopenharmony_ci goto out; 29268c2ecf20Sopenharmony_ci 29278c2ecf20Sopenharmony_ci /* after reading from file, translate offset to address */ 29288c2ecf20Sopenharmony_ci bpf_program__bpil_offs_to_addr(info_linear); 29298c2ecf20Sopenharmony_ci info_node->info_linear = info_linear; 29308c2ecf20Sopenharmony_ci __perf_env__insert_bpf_prog_info(env, info_node); 29318c2ecf20Sopenharmony_ci } 29328c2ecf20Sopenharmony_ci 29338c2ecf20Sopenharmony_ci up_write(&env->bpf_progs.lock); 29348c2ecf20Sopenharmony_ci return 0; 29358c2ecf20Sopenharmony_ciout: 29368c2ecf20Sopenharmony_ci free(info_linear); 29378c2ecf20Sopenharmony_ci free(info_node); 29388c2ecf20Sopenharmony_ci up_write(&env->bpf_progs.lock); 29398c2ecf20Sopenharmony_ci return err; 29408c2ecf20Sopenharmony_ci} 29418c2ecf20Sopenharmony_ci#else // HAVE_LIBBPF_SUPPORT 29428c2ecf20Sopenharmony_cistatic int process_bpf_prog_info(struct feat_fd *ff __maybe_unused, void *data __maybe_unused) 29438c2ecf20Sopenharmony_ci{ 29448c2ecf20Sopenharmony_ci return 0; 29458c2ecf20Sopenharmony_ci} 29468c2ecf20Sopenharmony_ci#endif // HAVE_LIBBPF_SUPPORT 29478c2ecf20Sopenharmony_ci 29488c2ecf20Sopenharmony_cistatic int process_bpf_btf(struct feat_fd *ff, void *data __maybe_unused) 29498c2ecf20Sopenharmony_ci{ 29508c2ecf20Sopenharmony_ci struct perf_env *env = &ff->ph->env; 29518c2ecf20Sopenharmony_ci struct btf_node *node = NULL; 29528c2ecf20Sopenharmony_ci u32 count, i; 29538c2ecf20Sopenharmony_ci int err = -1; 29548c2ecf20Sopenharmony_ci 29558c2ecf20Sopenharmony_ci if (ff->ph->needs_swap) { 29568c2ecf20Sopenharmony_ci pr_warning("interpreting btf from systems with endianity is not yet supported\n"); 29578c2ecf20Sopenharmony_ci return 0; 29588c2ecf20Sopenharmony_ci } 29598c2ecf20Sopenharmony_ci 29608c2ecf20Sopenharmony_ci if (do_read_u32(ff, &count)) 29618c2ecf20Sopenharmony_ci return -1; 29628c2ecf20Sopenharmony_ci 29638c2ecf20Sopenharmony_ci down_write(&env->bpf_progs.lock); 29648c2ecf20Sopenharmony_ci 29658c2ecf20Sopenharmony_ci for (i = 0; i < count; ++i) { 29668c2ecf20Sopenharmony_ci u32 id, data_size; 29678c2ecf20Sopenharmony_ci 29688c2ecf20Sopenharmony_ci if (do_read_u32(ff, &id)) 29698c2ecf20Sopenharmony_ci goto out; 29708c2ecf20Sopenharmony_ci if (do_read_u32(ff, &data_size)) 29718c2ecf20Sopenharmony_ci goto out; 29728c2ecf20Sopenharmony_ci 29738c2ecf20Sopenharmony_ci node = malloc(sizeof(struct btf_node) + data_size); 29748c2ecf20Sopenharmony_ci if (!node) 29758c2ecf20Sopenharmony_ci goto out; 29768c2ecf20Sopenharmony_ci 29778c2ecf20Sopenharmony_ci node->id = id; 29788c2ecf20Sopenharmony_ci node->data_size = data_size; 29798c2ecf20Sopenharmony_ci 29808c2ecf20Sopenharmony_ci if (__do_read(ff, node->data, data_size)) 29818c2ecf20Sopenharmony_ci goto out; 29828c2ecf20Sopenharmony_ci 29838c2ecf20Sopenharmony_ci __perf_env__insert_btf(env, node); 29848c2ecf20Sopenharmony_ci node = NULL; 29858c2ecf20Sopenharmony_ci } 29868c2ecf20Sopenharmony_ci 29878c2ecf20Sopenharmony_ci err = 0; 29888c2ecf20Sopenharmony_ciout: 29898c2ecf20Sopenharmony_ci up_write(&env->bpf_progs.lock); 29908c2ecf20Sopenharmony_ci free(node); 29918c2ecf20Sopenharmony_ci return err; 29928c2ecf20Sopenharmony_ci} 29938c2ecf20Sopenharmony_ci 29948c2ecf20Sopenharmony_cistatic int process_compressed(struct feat_fd *ff, 29958c2ecf20Sopenharmony_ci void *data __maybe_unused) 29968c2ecf20Sopenharmony_ci{ 29978c2ecf20Sopenharmony_ci if (do_read_u32(ff, &(ff->ph->env.comp_ver))) 29988c2ecf20Sopenharmony_ci return -1; 29998c2ecf20Sopenharmony_ci 30008c2ecf20Sopenharmony_ci if (do_read_u32(ff, &(ff->ph->env.comp_type))) 30018c2ecf20Sopenharmony_ci return -1; 30028c2ecf20Sopenharmony_ci 30038c2ecf20Sopenharmony_ci if (do_read_u32(ff, &(ff->ph->env.comp_level))) 30048c2ecf20Sopenharmony_ci return -1; 30058c2ecf20Sopenharmony_ci 30068c2ecf20Sopenharmony_ci if (do_read_u32(ff, &(ff->ph->env.comp_ratio))) 30078c2ecf20Sopenharmony_ci return -1; 30088c2ecf20Sopenharmony_ci 30098c2ecf20Sopenharmony_ci if (do_read_u32(ff, &(ff->ph->env.comp_mmap_len))) 30108c2ecf20Sopenharmony_ci return -1; 30118c2ecf20Sopenharmony_ci 30128c2ecf20Sopenharmony_ci return 0; 30138c2ecf20Sopenharmony_ci} 30148c2ecf20Sopenharmony_ci 30158c2ecf20Sopenharmony_cistatic int process_cpu_pmu_caps(struct feat_fd *ff, 30168c2ecf20Sopenharmony_ci void *data __maybe_unused) 30178c2ecf20Sopenharmony_ci{ 30188c2ecf20Sopenharmony_ci char *name, *value; 30198c2ecf20Sopenharmony_ci struct strbuf sb; 30208c2ecf20Sopenharmony_ci u32 nr_caps; 30218c2ecf20Sopenharmony_ci 30228c2ecf20Sopenharmony_ci if (do_read_u32(ff, &nr_caps)) 30238c2ecf20Sopenharmony_ci return -1; 30248c2ecf20Sopenharmony_ci 30258c2ecf20Sopenharmony_ci if (!nr_caps) { 30268c2ecf20Sopenharmony_ci pr_debug("cpu pmu capabilities not available\n"); 30278c2ecf20Sopenharmony_ci return 0; 30288c2ecf20Sopenharmony_ci } 30298c2ecf20Sopenharmony_ci 30308c2ecf20Sopenharmony_ci ff->ph->env.nr_cpu_pmu_caps = nr_caps; 30318c2ecf20Sopenharmony_ci 30328c2ecf20Sopenharmony_ci if (strbuf_init(&sb, 128) < 0) 30338c2ecf20Sopenharmony_ci return -1; 30348c2ecf20Sopenharmony_ci 30358c2ecf20Sopenharmony_ci while (nr_caps--) { 30368c2ecf20Sopenharmony_ci name = do_read_string(ff); 30378c2ecf20Sopenharmony_ci if (!name) 30388c2ecf20Sopenharmony_ci goto error; 30398c2ecf20Sopenharmony_ci 30408c2ecf20Sopenharmony_ci value = do_read_string(ff); 30418c2ecf20Sopenharmony_ci if (!value) 30428c2ecf20Sopenharmony_ci goto free_name; 30438c2ecf20Sopenharmony_ci 30448c2ecf20Sopenharmony_ci if (strbuf_addf(&sb, "%s=%s", name, value) < 0) 30458c2ecf20Sopenharmony_ci goto free_value; 30468c2ecf20Sopenharmony_ci 30478c2ecf20Sopenharmony_ci /* include a NULL character at the end */ 30488c2ecf20Sopenharmony_ci if (strbuf_add(&sb, "", 1) < 0) 30498c2ecf20Sopenharmony_ci goto free_value; 30508c2ecf20Sopenharmony_ci 30518c2ecf20Sopenharmony_ci if (!strcmp(name, "branches")) 30528c2ecf20Sopenharmony_ci ff->ph->env.max_branches = atoi(value); 30538c2ecf20Sopenharmony_ci 30548c2ecf20Sopenharmony_ci free(value); 30558c2ecf20Sopenharmony_ci free(name); 30568c2ecf20Sopenharmony_ci } 30578c2ecf20Sopenharmony_ci ff->ph->env.cpu_pmu_caps = strbuf_detach(&sb, NULL); 30588c2ecf20Sopenharmony_ci return 0; 30598c2ecf20Sopenharmony_ci 30608c2ecf20Sopenharmony_cifree_value: 30618c2ecf20Sopenharmony_ci free(value); 30628c2ecf20Sopenharmony_cifree_name: 30638c2ecf20Sopenharmony_ci free(name); 30648c2ecf20Sopenharmony_cierror: 30658c2ecf20Sopenharmony_ci strbuf_release(&sb); 30668c2ecf20Sopenharmony_ci return -1; 30678c2ecf20Sopenharmony_ci} 30688c2ecf20Sopenharmony_ci 30698c2ecf20Sopenharmony_ci#define FEAT_OPR(n, func, __full_only) \ 30708c2ecf20Sopenharmony_ci [HEADER_##n] = { \ 30718c2ecf20Sopenharmony_ci .name = __stringify(n), \ 30728c2ecf20Sopenharmony_ci .write = write_##func, \ 30738c2ecf20Sopenharmony_ci .print = print_##func, \ 30748c2ecf20Sopenharmony_ci .full_only = __full_only, \ 30758c2ecf20Sopenharmony_ci .process = process_##func, \ 30768c2ecf20Sopenharmony_ci .synthesize = true \ 30778c2ecf20Sopenharmony_ci } 30788c2ecf20Sopenharmony_ci 30798c2ecf20Sopenharmony_ci#define FEAT_OPN(n, func, __full_only) \ 30808c2ecf20Sopenharmony_ci [HEADER_##n] = { \ 30818c2ecf20Sopenharmony_ci .name = __stringify(n), \ 30828c2ecf20Sopenharmony_ci .write = write_##func, \ 30838c2ecf20Sopenharmony_ci .print = print_##func, \ 30848c2ecf20Sopenharmony_ci .full_only = __full_only, \ 30858c2ecf20Sopenharmony_ci .process = process_##func \ 30868c2ecf20Sopenharmony_ci } 30878c2ecf20Sopenharmony_ci 30888c2ecf20Sopenharmony_ci/* feature_ops not implemented: */ 30898c2ecf20Sopenharmony_ci#define print_tracing_data NULL 30908c2ecf20Sopenharmony_ci#define print_build_id NULL 30918c2ecf20Sopenharmony_ci 30928c2ecf20Sopenharmony_ci#define process_branch_stack NULL 30938c2ecf20Sopenharmony_ci#define process_stat NULL 30948c2ecf20Sopenharmony_ci 30958c2ecf20Sopenharmony_ci// Only used in util/synthetic-events.c 30968c2ecf20Sopenharmony_ciconst struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE]; 30978c2ecf20Sopenharmony_ci 30988c2ecf20Sopenharmony_ciconst struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = { 30998c2ecf20Sopenharmony_ci FEAT_OPN(TRACING_DATA, tracing_data, false), 31008c2ecf20Sopenharmony_ci FEAT_OPN(BUILD_ID, build_id, false), 31018c2ecf20Sopenharmony_ci FEAT_OPR(HOSTNAME, hostname, false), 31028c2ecf20Sopenharmony_ci FEAT_OPR(OSRELEASE, osrelease, false), 31038c2ecf20Sopenharmony_ci FEAT_OPR(VERSION, version, false), 31048c2ecf20Sopenharmony_ci FEAT_OPR(ARCH, arch, false), 31058c2ecf20Sopenharmony_ci FEAT_OPR(NRCPUS, nrcpus, false), 31068c2ecf20Sopenharmony_ci FEAT_OPR(CPUDESC, cpudesc, false), 31078c2ecf20Sopenharmony_ci FEAT_OPR(CPUID, cpuid, false), 31088c2ecf20Sopenharmony_ci FEAT_OPR(TOTAL_MEM, total_mem, false), 31098c2ecf20Sopenharmony_ci FEAT_OPR(EVENT_DESC, event_desc, false), 31108c2ecf20Sopenharmony_ci FEAT_OPR(CMDLINE, cmdline, false), 31118c2ecf20Sopenharmony_ci FEAT_OPR(CPU_TOPOLOGY, cpu_topology, true), 31128c2ecf20Sopenharmony_ci FEAT_OPR(NUMA_TOPOLOGY, numa_topology, true), 31138c2ecf20Sopenharmony_ci FEAT_OPN(BRANCH_STACK, branch_stack, false), 31148c2ecf20Sopenharmony_ci FEAT_OPR(PMU_MAPPINGS, pmu_mappings, false), 31158c2ecf20Sopenharmony_ci FEAT_OPR(GROUP_DESC, group_desc, false), 31168c2ecf20Sopenharmony_ci FEAT_OPN(AUXTRACE, auxtrace, false), 31178c2ecf20Sopenharmony_ci FEAT_OPN(STAT, stat, false), 31188c2ecf20Sopenharmony_ci FEAT_OPN(CACHE, cache, true), 31198c2ecf20Sopenharmony_ci FEAT_OPR(SAMPLE_TIME, sample_time, false), 31208c2ecf20Sopenharmony_ci FEAT_OPR(MEM_TOPOLOGY, mem_topology, true), 31218c2ecf20Sopenharmony_ci FEAT_OPR(CLOCKID, clockid, false), 31228c2ecf20Sopenharmony_ci FEAT_OPN(DIR_FORMAT, dir_format, false), 31238c2ecf20Sopenharmony_ci FEAT_OPR(BPF_PROG_INFO, bpf_prog_info, false), 31248c2ecf20Sopenharmony_ci FEAT_OPR(BPF_BTF, bpf_btf, false), 31258c2ecf20Sopenharmony_ci FEAT_OPR(COMPRESSED, compressed, false), 31268c2ecf20Sopenharmony_ci FEAT_OPR(CPU_PMU_CAPS, cpu_pmu_caps, false), 31278c2ecf20Sopenharmony_ci FEAT_OPR(CLOCK_DATA, clock_data, false), 31288c2ecf20Sopenharmony_ci}; 31298c2ecf20Sopenharmony_ci 31308c2ecf20Sopenharmony_cistruct header_print_data { 31318c2ecf20Sopenharmony_ci FILE *fp; 31328c2ecf20Sopenharmony_ci bool full; /* extended list of headers */ 31338c2ecf20Sopenharmony_ci}; 31348c2ecf20Sopenharmony_ci 31358c2ecf20Sopenharmony_cistatic int perf_file_section__fprintf_info(struct perf_file_section *section, 31368c2ecf20Sopenharmony_ci struct perf_header *ph, 31378c2ecf20Sopenharmony_ci int feat, int fd, void *data) 31388c2ecf20Sopenharmony_ci{ 31398c2ecf20Sopenharmony_ci struct header_print_data *hd = data; 31408c2ecf20Sopenharmony_ci struct feat_fd ff; 31418c2ecf20Sopenharmony_ci 31428c2ecf20Sopenharmony_ci if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { 31438c2ecf20Sopenharmony_ci pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 31448c2ecf20Sopenharmony_ci "%d, continuing...\n", section->offset, feat); 31458c2ecf20Sopenharmony_ci return 0; 31468c2ecf20Sopenharmony_ci } 31478c2ecf20Sopenharmony_ci if (feat >= HEADER_LAST_FEATURE) { 31488c2ecf20Sopenharmony_ci pr_warning("unknown feature %d\n", feat); 31498c2ecf20Sopenharmony_ci return 0; 31508c2ecf20Sopenharmony_ci } 31518c2ecf20Sopenharmony_ci if (!feat_ops[feat].print) 31528c2ecf20Sopenharmony_ci return 0; 31538c2ecf20Sopenharmony_ci 31548c2ecf20Sopenharmony_ci ff = (struct feat_fd) { 31558c2ecf20Sopenharmony_ci .fd = fd, 31568c2ecf20Sopenharmony_ci .ph = ph, 31578c2ecf20Sopenharmony_ci }; 31588c2ecf20Sopenharmony_ci 31598c2ecf20Sopenharmony_ci if (!feat_ops[feat].full_only || hd->full) 31608c2ecf20Sopenharmony_ci feat_ops[feat].print(&ff, hd->fp); 31618c2ecf20Sopenharmony_ci else 31628c2ecf20Sopenharmony_ci fprintf(hd->fp, "# %s info available, use -I to display\n", 31638c2ecf20Sopenharmony_ci feat_ops[feat].name); 31648c2ecf20Sopenharmony_ci 31658c2ecf20Sopenharmony_ci return 0; 31668c2ecf20Sopenharmony_ci} 31678c2ecf20Sopenharmony_ci 31688c2ecf20Sopenharmony_ciint perf_header__fprintf_info(struct perf_session *session, FILE *fp, bool full) 31698c2ecf20Sopenharmony_ci{ 31708c2ecf20Sopenharmony_ci struct header_print_data hd; 31718c2ecf20Sopenharmony_ci struct perf_header *header = &session->header; 31728c2ecf20Sopenharmony_ci int fd = perf_data__fd(session->data); 31738c2ecf20Sopenharmony_ci struct stat st; 31748c2ecf20Sopenharmony_ci time_t stctime; 31758c2ecf20Sopenharmony_ci int ret, bit; 31768c2ecf20Sopenharmony_ci 31778c2ecf20Sopenharmony_ci hd.fp = fp; 31788c2ecf20Sopenharmony_ci hd.full = full; 31798c2ecf20Sopenharmony_ci 31808c2ecf20Sopenharmony_ci ret = fstat(fd, &st); 31818c2ecf20Sopenharmony_ci if (ret == -1) 31828c2ecf20Sopenharmony_ci return -1; 31838c2ecf20Sopenharmony_ci 31848c2ecf20Sopenharmony_ci stctime = st.st_mtime; 31858c2ecf20Sopenharmony_ci fprintf(fp, "# captured on : %s", ctime(&stctime)); 31868c2ecf20Sopenharmony_ci 31878c2ecf20Sopenharmony_ci fprintf(fp, "# header version : %u\n", header->version); 31888c2ecf20Sopenharmony_ci fprintf(fp, "# data offset : %" PRIu64 "\n", header->data_offset); 31898c2ecf20Sopenharmony_ci fprintf(fp, "# data size : %" PRIu64 "\n", header->data_size); 31908c2ecf20Sopenharmony_ci fprintf(fp, "# feat offset : %" PRIu64 "\n", header->feat_offset); 31918c2ecf20Sopenharmony_ci 31928c2ecf20Sopenharmony_ci perf_header__process_sections(header, fd, &hd, 31938c2ecf20Sopenharmony_ci perf_file_section__fprintf_info); 31948c2ecf20Sopenharmony_ci 31958c2ecf20Sopenharmony_ci if (session->data->is_pipe) 31968c2ecf20Sopenharmony_ci return 0; 31978c2ecf20Sopenharmony_ci 31988c2ecf20Sopenharmony_ci fprintf(fp, "# missing features: "); 31998c2ecf20Sopenharmony_ci for_each_clear_bit(bit, header->adds_features, HEADER_LAST_FEATURE) { 32008c2ecf20Sopenharmony_ci if (bit) 32018c2ecf20Sopenharmony_ci fprintf(fp, "%s ", feat_ops[bit].name); 32028c2ecf20Sopenharmony_ci } 32038c2ecf20Sopenharmony_ci 32048c2ecf20Sopenharmony_ci fprintf(fp, "\n"); 32058c2ecf20Sopenharmony_ci return 0; 32068c2ecf20Sopenharmony_ci} 32078c2ecf20Sopenharmony_ci 32088c2ecf20Sopenharmony_cistatic int do_write_feat(struct feat_fd *ff, int type, 32098c2ecf20Sopenharmony_ci struct perf_file_section **p, 32108c2ecf20Sopenharmony_ci struct evlist *evlist) 32118c2ecf20Sopenharmony_ci{ 32128c2ecf20Sopenharmony_ci int err; 32138c2ecf20Sopenharmony_ci int ret = 0; 32148c2ecf20Sopenharmony_ci 32158c2ecf20Sopenharmony_ci if (perf_header__has_feat(ff->ph, type)) { 32168c2ecf20Sopenharmony_ci if (!feat_ops[type].write) 32178c2ecf20Sopenharmony_ci return -1; 32188c2ecf20Sopenharmony_ci 32198c2ecf20Sopenharmony_ci if (WARN(ff->buf, "Error: calling %s in pipe-mode.\n", __func__)) 32208c2ecf20Sopenharmony_ci return -1; 32218c2ecf20Sopenharmony_ci 32228c2ecf20Sopenharmony_ci (*p)->offset = lseek(ff->fd, 0, SEEK_CUR); 32238c2ecf20Sopenharmony_ci 32248c2ecf20Sopenharmony_ci err = feat_ops[type].write(ff, evlist); 32258c2ecf20Sopenharmony_ci if (err < 0) { 32268c2ecf20Sopenharmony_ci pr_debug("failed to write feature %s\n", feat_ops[type].name); 32278c2ecf20Sopenharmony_ci 32288c2ecf20Sopenharmony_ci /* undo anything written */ 32298c2ecf20Sopenharmony_ci lseek(ff->fd, (*p)->offset, SEEK_SET); 32308c2ecf20Sopenharmony_ci 32318c2ecf20Sopenharmony_ci return -1; 32328c2ecf20Sopenharmony_ci } 32338c2ecf20Sopenharmony_ci (*p)->size = lseek(ff->fd, 0, SEEK_CUR) - (*p)->offset; 32348c2ecf20Sopenharmony_ci (*p)++; 32358c2ecf20Sopenharmony_ci } 32368c2ecf20Sopenharmony_ci return ret; 32378c2ecf20Sopenharmony_ci} 32388c2ecf20Sopenharmony_ci 32398c2ecf20Sopenharmony_cistatic int perf_header__adds_write(struct perf_header *header, 32408c2ecf20Sopenharmony_ci struct evlist *evlist, int fd) 32418c2ecf20Sopenharmony_ci{ 32428c2ecf20Sopenharmony_ci int nr_sections; 32438c2ecf20Sopenharmony_ci struct feat_fd ff; 32448c2ecf20Sopenharmony_ci struct perf_file_section *feat_sec, *p; 32458c2ecf20Sopenharmony_ci int sec_size; 32468c2ecf20Sopenharmony_ci u64 sec_start; 32478c2ecf20Sopenharmony_ci int feat; 32488c2ecf20Sopenharmony_ci int err; 32498c2ecf20Sopenharmony_ci 32508c2ecf20Sopenharmony_ci ff = (struct feat_fd){ 32518c2ecf20Sopenharmony_ci .fd = fd, 32528c2ecf20Sopenharmony_ci .ph = header, 32538c2ecf20Sopenharmony_ci }; 32548c2ecf20Sopenharmony_ci 32558c2ecf20Sopenharmony_ci nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); 32568c2ecf20Sopenharmony_ci if (!nr_sections) 32578c2ecf20Sopenharmony_ci return 0; 32588c2ecf20Sopenharmony_ci 32598c2ecf20Sopenharmony_ci feat_sec = p = calloc(nr_sections, sizeof(*feat_sec)); 32608c2ecf20Sopenharmony_ci if (feat_sec == NULL) 32618c2ecf20Sopenharmony_ci return -ENOMEM; 32628c2ecf20Sopenharmony_ci 32638c2ecf20Sopenharmony_ci sec_size = sizeof(*feat_sec) * nr_sections; 32648c2ecf20Sopenharmony_ci 32658c2ecf20Sopenharmony_ci sec_start = header->feat_offset; 32668c2ecf20Sopenharmony_ci lseek(fd, sec_start + sec_size, SEEK_SET); 32678c2ecf20Sopenharmony_ci 32688c2ecf20Sopenharmony_ci for_each_set_bit(feat, header->adds_features, HEADER_FEAT_BITS) { 32698c2ecf20Sopenharmony_ci if (do_write_feat(&ff, feat, &p, evlist)) 32708c2ecf20Sopenharmony_ci perf_header__clear_feat(header, feat); 32718c2ecf20Sopenharmony_ci } 32728c2ecf20Sopenharmony_ci 32738c2ecf20Sopenharmony_ci lseek(fd, sec_start, SEEK_SET); 32748c2ecf20Sopenharmony_ci /* 32758c2ecf20Sopenharmony_ci * may write more than needed due to dropped feature, but 32768c2ecf20Sopenharmony_ci * this is okay, reader will skip the missing entries 32778c2ecf20Sopenharmony_ci */ 32788c2ecf20Sopenharmony_ci err = do_write(&ff, feat_sec, sec_size); 32798c2ecf20Sopenharmony_ci if (err < 0) 32808c2ecf20Sopenharmony_ci pr_debug("failed to write feature section\n"); 32818c2ecf20Sopenharmony_ci free(feat_sec); 32828c2ecf20Sopenharmony_ci return err; 32838c2ecf20Sopenharmony_ci} 32848c2ecf20Sopenharmony_ci 32858c2ecf20Sopenharmony_ciint perf_header__write_pipe(int fd) 32868c2ecf20Sopenharmony_ci{ 32878c2ecf20Sopenharmony_ci struct perf_pipe_file_header f_header; 32888c2ecf20Sopenharmony_ci struct feat_fd ff; 32898c2ecf20Sopenharmony_ci int err; 32908c2ecf20Sopenharmony_ci 32918c2ecf20Sopenharmony_ci ff = (struct feat_fd){ .fd = fd }; 32928c2ecf20Sopenharmony_ci 32938c2ecf20Sopenharmony_ci f_header = (struct perf_pipe_file_header){ 32948c2ecf20Sopenharmony_ci .magic = PERF_MAGIC, 32958c2ecf20Sopenharmony_ci .size = sizeof(f_header), 32968c2ecf20Sopenharmony_ci }; 32978c2ecf20Sopenharmony_ci 32988c2ecf20Sopenharmony_ci err = do_write(&ff, &f_header, sizeof(f_header)); 32998c2ecf20Sopenharmony_ci if (err < 0) { 33008c2ecf20Sopenharmony_ci pr_debug("failed to write perf pipe header\n"); 33018c2ecf20Sopenharmony_ci return err; 33028c2ecf20Sopenharmony_ci } 33038c2ecf20Sopenharmony_ci 33048c2ecf20Sopenharmony_ci return 0; 33058c2ecf20Sopenharmony_ci} 33068c2ecf20Sopenharmony_ci 33078c2ecf20Sopenharmony_ciint perf_session__write_header(struct perf_session *session, 33088c2ecf20Sopenharmony_ci struct evlist *evlist, 33098c2ecf20Sopenharmony_ci int fd, bool at_exit) 33108c2ecf20Sopenharmony_ci{ 33118c2ecf20Sopenharmony_ci struct perf_file_header f_header; 33128c2ecf20Sopenharmony_ci struct perf_file_attr f_attr; 33138c2ecf20Sopenharmony_ci struct perf_header *header = &session->header; 33148c2ecf20Sopenharmony_ci struct evsel *evsel; 33158c2ecf20Sopenharmony_ci struct feat_fd ff; 33168c2ecf20Sopenharmony_ci u64 attr_offset; 33178c2ecf20Sopenharmony_ci int err; 33188c2ecf20Sopenharmony_ci 33198c2ecf20Sopenharmony_ci ff = (struct feat_fd){ .fd = fd}; 33208c2ecf20Sopenharmony_ci lseek(fd, sizeof(f_header), SEEK_SET); 33218c2ecf20Sopenharmony_ci 33228c2ecf20Sopenharmony_ci evlist__for_each_entry(session->evlist, evsel) { 33238c2ecf20Sopenharmony_ci evsel->id_offset = lseek(fd, 0, SEEK_CUR); 33248c2ecf20Sopenharmony_ci err = do_write(&ff, evsel->core.id, evsel->core.ids * sizeof(u64)); 33258c2ecf20Sopenharmony_ci if (err < 0) { 33268c2ecf20Sopenharmony_ci pr_debug("failed to write perf header\n"); 33278c2ecf20Sopenharmony_ci return err; 33288c2ecf20Sopenharmony_ci } 33298c2ecf20Sopenharmony_ci } 33308c2ecf20Sopenharmony_ci 33318c2ecf20Sopenharmony_ci attr_offset = lseek(ff.fd, 0, SEEK_CUR); 33328c2ecf20Sopenharmony_ci 33338c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 33348c2ecf20Sopenharmony_ci f_attr = (struct perf_file_attr){ 33358c2ecf20Sopenharmony_ci .attr = evsel->core.attr, 33368c2ecf20Sopenharmony_ci .ids = { 33378c2ecf20Sopenharmony_ci .offset = evsel->id_offset, 33388c2ecf20Sopenharmony_ci .size = evsel->core.ids * sizeof(u64), 33398c2ecf20Sopenharmony_ci } 33408c2ecf20Sopenharmony_ci }; 33418c2ecf20Sopenharmony_ci err = do_write(&ff, &f_attr, sizeof(f_attr)); 33428c2ecf20Sopenharmony_ci if (err < 0) { 33438c2ecf20Sopenharmony_ci pr_debug("failed to write perf header attribute\n"); 33448c2ecf20Sopenharmony_ci return err; 33458c2ecf20Sopenharmony_ci } 33468c2ecf20Sopenharmony_ci } 33478c2ecf20Sopenharmony_ci 33488c2ecf20Sopenharmony_ci if (!header->data_offset) 33498c2ecf20Sopenharmony_ci header->data_offset = lseek(fd, 0, SEEK_CUR); 33508c2ecf20Sopenharmony_ci header->feat_offset = header->data_offset + header->data_size; 33518c2ecf20Sopenharmony_ci 33528c2ecf20Sopenharmony_ci if (at_exit) { 33538c2ecf20Sopenharmony_ci err = perf_header__adds_write(header, evlist, fd); 33548c2ecf20Sopenharmony_ci if (err < 0) 33558c2ecf20Sopenharmony_ci return err; 33568c2ecf20Sopenharmony_ci } 33578c2ecf20Sopenharmony_ci 33588c2ecf20Sopenharmony_ci f_header = (struct perf_file_header){ 33598c2ecf20Sopenharmony_ci .magic = PERF_MAGIC, 33608c2ecf20Sopenharmony_ci .size = sizeof(f_header), 33618c2ecf20Sopenharmony_ci .attr_size = sizeof(f_attr), 33628c2ecf20Sopenharmony_ci .attrs = { 33638c2ecf20Sopenharmony_ci .offset = attr_offset, 33648c2ecf20Sopenharmony_ci .size = evlist->core.nr_entries * sizeof(f_attr), 33658c2ecf20Sopenharmony_ci }, 33668c2ecf20Sopenharmony_ci .data = { 33678c2ecf20Sopenharmony_ci .offset = header->data_offset, 33688c2ecf20Sopenharmony_ci .size = header->data_size, 33698c2ecf20Sopenharmony_ci }, 33708c2ecf20Sopenharmony_ci /* event_types is ignored, store zeros */ 33718c2ecf20Sopenharmony_ci }; 33728c2ecf20Sopenharmony_ci 33738c2ecf20Sopenharmony_ci memcpy(&f_header.adds_features, &header->adds_features, sizeof(header->adds_features)); 33748c2ecf20Sopenharmony_ci 33758c2ecf20Sopenharmony_ci lseek(fd, 0, SEEK_SET); 33768c2ecf20Sopenharmony_ci err = do_write(&ff, &f_header, sizeof(f_header)); 33778c2ecf20Sopenharmony_ci if (err < 0) { 33788c2ecf20Sopenharmony_ci pr_debug("failed to write perf header\n"); 33798c2ecf20Sopenharmony_ci return err; 33808c2ecf20Sopenharmony_ci } 33818c2ecf20Sopenharmony_ci lseek(fd, header->data_offset + header->data_size, SEEK_SET); 33828c2ecf20Sopenharmony_ci 33838c2ecf20Sopenharmony_ci return 0; 33848c2ecf20Sopenharmony_ci} 33858c2ecf20Sopenharmony_ci 33868c2ecf20Sopenharmony_cistatic int perf_header__getbuffer64(struct perf_header *header, 33878c2ecf20Sopenharmony_ci int fd, void *buf, size_t size) 33888c2ecf20Sopenharmony_ci{ 33898c2ecf20Sopenharmony_ci if (readn(fd, buf, size) <= 0) 33908c2ecf20Sopenharmony_ci return -1; 33918c2ecf20Sopenharmony_ci 33928c2ecf20Sopenharmony_ci if (header->needs_swap) 33938c2ecf20Sopenharmony_ci mem_bswap_64(buf, size); 33948c2ecf20Sopenharmony_ci 33958c2ecf20Sopenharmony_ci return 0; 33968c2ecf20Sopenharmony_ci} 33978c2ecf20Sopenharmony_ci 33988c2ecf20Sopenharmony_ciint perf_header__process_sections(struct perf_header *header, int fd, 33998c2ecf20Sopenharmony_ci void *data, 34008c2ecf20Sopenharmony_ci int (*process)(struct perf_file_section *section, 34018c2ecf20Sopenharmony_ci struct perf_header *ph, 34028c2ecf20Sopenharmony_ci int feat, int fd, void *data)) 34038c2ecf20Sopenharmony_ci{ 34048c2ecf20Sopenharmony_ci struct perf_file_section *feat_sec, *sec; 34058c2ecf20Sopenharmony_ci int nr_sections; 34068c2ecf20Sopenharmony_ci int sec_size; 34078c2ecf20Sopenharmony_ci int feat; 34088c2ecf20Sopenharmony_ci int err; 34098c2ecf20Sopenharmony_ci 34108c2ecf20Sopenharmony_ci nr_sections = bitmap_weight(header->adds_features, HEADER_FEAT_BITS); 34118c2ecf20Sopenharmony_ci if (!nr_sections) 34128c2ecf20Sopenharmony_ci return 0; 34138c2ecf20Sopenharmony_ci 34148c2ecf20Sopenharmony_ci feat_sec = sec = calloc(nr_sections, sizeof(*feat_sec)); 34158c2ecf20Sopenharmony_ci if (!feat_sec) 34168c2ecf20Sopenharmony_ci return -1; 34178c2ecf20Sopenharmony_ci 34188c2ecf20Sopenharmony_ci sec_size = sizeof(*feat_sec) * nr_sections; 34198c2ecf20Sopenharmony_ci 34208c2ecf20Sopenharmony_ci lseek(fd, header->feat_offset, SEEK_SET); 34218c2ecf20Sopenharmony_ci 34228c2ecf20Sopenharmony_ci err = perf_header__getbuffer64(header, fd, feat_sec, sec_size); 34238c2ecf20Sopenharmony_ci if (err < 0) 34248c2ecf20Sopenharmony_ci goto out_free; 34258c2ecf20Sopenharmony_ci 34268c2ecf20Sopenharmony_ci for_each_set_bit(feat, header->adds_features, HEADER_LAST_FEATURE) { 34278c2ecf20Sopenharmony_ci err = process(sec++, header, feat, fd, data); 34288c2ecf20Sopenharmony_ci if (err < 0) 34298c2ecf20Sopenharmony_ci goto out_free; 34308c2ecf20Sopenharmony_ci } 34318c2ecf20Sopenharmony_ci err = 0; 34328c2ecf20Sopenharmony_ciout_free: 34338c2ecf20Sopenharmony_ci free(feat_sec); 34348c2ecf20Sopenharmony_ci return err; 34358c2ecf20Sopenharmony_ci} 34368c2ecf20Sopenharmony_ci 34378c2ecf20Sopenharmony_cistatic const int attr_file_abi_sizes[] = { 34388c2ecf20Sopenharmony_ci [0] = PERF_ATTR_SIZE_VER0, 34398c2ecf20Sopenharmony_ci [1] = PERF_ATTR_SIZE_VER1, 34408c2ecf20Sopenharmony_ci [2] = PERF_ATTR_SIZE_VER2, 34418c2ecf20Sopenharmony_ci [3] = PERF_ATTR_SIZE_VER3, 34428c2ecf20Sopenharmony_ci [4] = PERF_ATTR_SIZE_VER4, 34438c2ecf20Sopenharmony_ci 0, 34448c2ecf20Sopenharmony_ci}; 34458c2ecf20Sopenharmony_ci 34468c2ecf20Sopenharmony_ci/* 34478c2ecf20Sopenharmony_ci * In the legacy file format, the magic number is not used to encode endianness. 34488c2ecf20Sopenharmony_ci * hdr_sz was used to encode endianness. But given that hdr_sz can vary based 34498c2ecf20Sopenharmony_ci * on ABI revisions, we need to try all combinations for all endianness to 34508c2ecf20Sopenharmony_ci * detect the endianness. 34518c2ecf20Sopenharmony_ci */ 34528c2ecf20Sopenharmony_cistatic int try_all_file_abis(uint64_t hdr_sz, struct perf_header *ph) 34538c2ecf20Sopenharmony_ci{ 34548c2ecf20Sopenharmony_ci uint64_t ref_size, attr_size; 34558c2ecf20Sopenharmony_ci int i; 34568c2ecf20Sopenharmony_ci 34578c2ecf20Sopenharmony_ci for (i = 0 ; attr_file_abi_sizes[i]; i++) { 34588c2ecf20Sopenharmony_ci ref_size = attr_file_abi_sizes[i] 34598c2ecf20Sopenharmony_ci + sizeof(struct perf_file_section); 34608c2ecf20Sopenharmony_ci if (hdr_sz != ref_size) { 34618c2ecf20Sopenharmony_ci attr_size = bswap_64(hdr_sz); 34628c2ecf20Sopenharmony_ci if (attr_size != ref_size) 34638c2ecf20Sopenharmony_ci continue; 34648c2ecf20Sopenharmony_ci 34658c2ecf20Sopenharmony_ci ph->needs_swap = true; 34668c2ecf20Sopenharmony_ci } 34678c2ecf20Sopenharmony_ci pr_debug("ABI%d perf.data file detected, need_swap=%d\n", 34688c2ecf20Sopenharmony_ci i, 34698c2ecf20Sopenharmony_ci ph->needs_swap); 34708c2ecf20Sopenharmony_ci return 0; 34718c2ecf20Sopenharmony_ci } 34728c2ecf20Sopenharmony_ci /* could not determine endianness */ 34738c2ecf20Sopenharmony_ci return -1; 34748c2ecf20Sopenharmony_ci} 34758c2ecf20Sopenharmony_ci 34768c2ecf20Sopenharmony_ci#define PERF_PIPE_HDR_VER0 16 34778c2ecf20Sopenharmony_ci 34788c2ecf20Sopenharmony_cistatic const size_t attr_pipe_abi_sizes[] = { 34798c2ecf20Sopenharmony_ci [0] = PERF_PIPE_HDR_VER0, 34808c2ecf20Sopenharmony_ci 0, 34818c2ecf20Sopenharmony_ci}; 34828c2ecf20Sopenharmony_ci 34838c2ecf20Sopenharmony_ci/* 34848c2ecf20Sopenharmony_ci * In the legacy pipe format, there is an implicit assumption that endiannesss 34858c2ecf20Sopenharmony_ci * between host recording the samples, and host parsing the samples is the 34868c2ecf20Sopenharmony_ci * same. This is not always the case given that the pipe output may always be 34878c2ecf20Sopenharmony_ci * redirected into a file and analyzed on a different machine with possibly a 34888c2ecf20Sopenharmony_ci * different endianness and perf_event ABI revsions in the perf tool itself. 34898c2ecf20Sopenharmony_ci */ 34908c2ecf20Sopenharmony_cistatic int try_all_pipe_abis(uint64_t hdr_sz, struct perf_header *ph) 34918c2ecf20Sopenharmony_ci{ 34928c2ecf20Sopenharmony_ci u64 attr_size; 34938c2ecf20Sopenharmony_ci int i; 34948c2ecf20Sopenharmony_ci 34958c2ecf20Sopenharmony_ci for (i = 0 ; attr_pipe_abi_sizes[i]; i++) { 34968c2ecf20Sopenharmony_ci if (hdr_sz != attr_pipe_abi_sizes[i]) { 34978c2ecf20Sopenharmony_ci attr_size = bswap_64(hdr_sz); 34988c2ecf20Sopenharmony_ci if (attr_size != hdr_sz) 34998c2ecf20Sopenharmony_ci continue; 35008c2ecf20Sopenharmony_ci 35018c2ecf20Sopenharmony_ci ph->needs_swap = true; 35028c2ecf20Sopenharmony_ci } 35038c2ecf20Sopenharmony_ci pr_debug("Pipe ABI%d perf.data file detected\n", i); 35048c2ecf20Sopenharmony_ci return 0; 35058c2ecf20Sopenharmony_ci } 35068c2ecf20Sopenharmony_ci return -1; 35078c2ecf20Sopenharmony_ci} 35088c2ecf20Sopenharmony_ci 35098c2ecf20Sopenharmony_cibool is_perf_magic(u64 magic) 35108c2ecf20Sopenharmony_ci{ 35118c2ecf20Sopenharmony_ci if (!memcmp(&magic, __perf_magic1, sizeof(magic)) 35128c2ecf20Sopenharmony_ci || magic == __perf_magic2 35138c2ecf20Sopenharmony_ci || magic == __perf_magic2_sw) 35148c2ecf20Sopenharmony_ci return true; 35158c2ecf20Sopenharmony_ci 35168c2ecf20Sopenharmony_ci return false; 35178c2ecf20Sopenharmony_ci} 35188c2ecf20Sopenharmony_ci 35198c2ecf20Sopenharmony_cistatic int check_magic_endian(u64 magic, uint64_t hdr_sz, 35208c2ecf20Sopenharmony_ci bool is_pipe, struct perf_header *ph) 35218c2ecf20Sopenharmony_ci{ 35228c2ecf20Sopenharmony_ci int ret; 35238c2ecf20Sopenharmony_ci 35248c2ecf20Sopenharmony_ci /* check for legacy format */ 35258c2ecf20Sopenharmony_ci ret = memcmp(&magic, __perf_magic1, sizeof(magic)); 35268c2ecf20Sopenharmony_ci if (ret == 0) { 35278c2ecf20Sopenharmony_ci ph->version = PERF_HEADER_VERSION_1; 35288c2ecf20Sopenharmony_ci pr_debug("legacy perf.data format\n"); 35298c2ecf20Sopenharmony_ci if (is_pipe) 35308c2ecf20Sopenharmony_ci return try_all_pipe_abis(hdr_sz, ph); 35318c2ecf20Sopenharmony_ci 35328c2ecf20Sopenharmony_ci return try_all_file_abis(hdr_sz, ph); 35338c2ecf20Sopenharmony_ci } 35348c2ecf20Sopenharmony_ci /* 35358c2ecf20Sopenharmony_ci * the new magic number serves two purposes: 35368c2ecf20Sopenharmony_ci * - unique number to identify actual perf.data files 35378c2ecf20Sopenharmony_ci * - encode endianness of file 35388c2ecf20Sopenharmony_ci */ 35398c2ecf20Sopenharmony_ci ph->version = PERF_HEADER_VERSION_2; 35408c2ecf20Sopenharmony_ci 35418c2ecf20Sopenharmony_ci /* check magic number with one endianness */ 35428c2ecf20Sopenharmony_ci if (magic == __perf_magic2) 35438c2ecf20Sopenharmony_ci return 0; 35448c2ecf20Sopenharmony_ci 35458c2ecf20Sopenharmony_ci /* check magic number with opposite endianness */ 35468c2ecf20Sopenharmony_ci if (magic != __perf_magic2_sw) 35478c2ecf20Sopenharmony_ci return -1; 35488c2ecf20Sopenharmony_ci 35498c2ecf20Sopenharmony_ci ph->needs_swap = true; 35508c2ecf20Sopenharmony_ci 35518c2ecf20Sopenharmony_ci return 0; 35528c2ecf20Sopenharmony_ci} 35538c2ecf20Sopenharmony_ci 35548c2ecf20Sopenharmony_ciint perf_file_header__read(struct perf_file_header *header, 35558c2ecf20Sopenharmony_ci struct perf_header *ph, int fd) 35568c2ecf20Sopenharmony_ci{ 35578c2ecf20Sopenharmony_ci ssize_t ret; 35588c2ecf20Sopenharmony_ci 35598c2ecf20Sopenharmony_ci lseek(fd, 0, SEEK_SET); 35608c2ecf20Sopenharmony_ci 35618c2ecf20Sopenharmony_ci ret = readn(fd, header, sizeof(*header)); 35628c2ecf20Sopenharmony_ci if (ret <= 0) 35638c2ecf20Sopenharmony_ci return -1; 35648c2ecf20Sopenharmony_ci 35658c2ecf20Sopenharmony_ci if (check_magic_endian(header->magic, 35668c2ecf20Sopenharmony_ci header->attr_size, false, ph) < 0) { 35678c2ecf20Sopenharmony_ci pr_debug("magic/endian check failed\n"); 35688c2ecf20Sopenharmony_ci return -1; 35698c2ecf20Sopenharmony_ci } 35708c2ecf20Sopenharmony_ci 35718c2ecf20Sopenharmony_ci if (ph->needs_swap) { 35728c2ecf20Sopenharmony_ci mem_bswap_64(header, offsetof(struct perf_file_header, 35738c2ecf20Sopenharmony_ci adds_features)); 35748c2ecf20Sopenharmony_ci } 35758c2ecf20Sopenharmony_ci 35768c2ecf20Sopenharmony_ci if (header->size != sizeof(*header)) { 35778c2ecf20Sopenharmony_ci /* Support the previous format */ 35788c2ecf20Sopenharmony_ci if (header->size == offsetof(typeof(*header), adds_features)) 35798c2ecf20Sopenharmony_ci bitmap_zero(header->adds_features, HEADER_FEAT_BITS); 35808c2ecf20Sopenharmony_ci else 35818c2ecf20Sopenharmony_ci return -1; 35828c2ecf20Sopenharmony_ci } else if (ph->needs_swap) { 35838c2ecf20Sopenharmony_ci /* 35848c2ecf20Sopenharmony_ci * feature bitmap is declared as an array of unsigned longs -- 35858c2ecf20Sopenharmony_ci * not good since its size can differ between the host that 35868c2ecf20Sopenharmony_ci * generated the data file and the host analyzing the file. 35878c2ecf20Sopenharmony_ci * 35888c2ecf20Sopenharmony_ci * We need to handle endianness, but we don't know the size of 35898c2ecf20Sopenharmony_ci * the unsigned long where the file was generated. Take a best 35908c2ecf20Sopenharmony_ci * guess at determining it: try 64-bit swap first (ie., file 35918c2ecf20Sopenharmony_ci * created on a 64-bit host), and check if the hostname feature 35928c2ecf20Sopenharmony_ci * bit is set (this feature bit is forced on as of fbe96f2). 35938c2ecf20Sopenharmony_ci * If the bit is not, undo the 64-bit swap and try a 32-bit 35948c2ecf20Sopenharmony_ci * swap. If the hostname bit is still not set (e.g., older data 35958c2ecf20Sopenharmony_ci * file), punt and fallback to the original behavior -- 35968c2ecf20Sopenharmony_ci * clearing all feature bits and setting buildid. 35978c2ecf20Sopenharmony_ci */ 35988c2ecf20Sopenharmony_ci mem_bswap_64(&header->adds_features, 35998c2ecf20Sopenharmony_ci BITS_TO_U64(HEADER_FEAT_BITS)); 36008c2ecf20Sopenharmony_ci 36018c2ecf20Sopenharmony_ci if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { 36028c2ecf20Sopenharmony_ci /* unswap as u64 */ 36038c2ecf20Sopenharmony_ci mem_bswap_64(&header->adds_features, 36048c2ecf20Sopenharmony_ci BITS_TO_U64(HEADER_FEAT_BITS)); 36058c2ecf20Sopenharmony_ci 36068c2ecf20Sopenharmony_ci /* unswap as u32 */ 36078c2ecf20Sopenharmony_ci mem_bswap_32(&header->adds_features, 36088c2ecf20Sopenharmony_ci BITS_TO_U32(HEADER_FEAT_BITS)); 36098c2ecf20Sopenharmony_ci } 36108c2ecf20Sopenharmony_ci 36118c2ecf20Sopenharmony_ci if (!test_bit(HEADER_HOSTNAME, header->adds_features)) { 36128c2ecf20Sopenharmony_ci bitmap_zero(header->adds_features, HEADER_FEAT_BITS); 36138c2ecf20Sopenharmony_ci set_bit(HEADER_BUILD_ID, header->adds_features); 36148c2ecf20Sopenharmony_ci } 36158c2ecf20Sopenharmony_ci } 36168c2ecf20Sopenharmony_ci 36178c2ecf20Sopenharmony_ci memcpy(&ph->adds_features, &header->adds_features, 36188c2ecf20Sopenharmony_ci sizeof(ph->adds_features)); 36198c2ecf20Sopenharmony_ci 36208c2ecf20Sopenharmony_ci ph->data_offset = header->data.offset; 36218c2ecf20Sopenharmony_ci ph->data_size = header->data.size; 36228c2ecf20Sopenharmony_ci ph->feat_offset = header->data.offset + header->data.size; 36238c2ecf20Sopenharmony_ci return 0; 36248c2ecf20Sopenharmony_ci} 36258c2ecf20Sopenharmony_ci 36268c2ecf20Sopenharmony_cistatic int perf_file_section__process(struct perf_file_section *section, 36278c2ecf20Sopenharmony_ci struct perf_header *ph, 36288c2ecf20Sopenharmony_ci int feat, int fd, void *data) 36298c2ecf20Sopenharmony_ci{ 36308c2ecf20Sopenharmony_ci struct feat_fd fdd = { 36318c2ecf20Sopenharmony_ci .fd = fd, 36328c2ecf20Sopenharmony_ci .ph = ph, 36338c2ecf20Sopenharmony_ci .size = section->size, 36348c2ecf20Sopenharmony_ci .offset = section->offset, 36358c2ecf20Sopenharmony_ci }; 36368c2ecf20Sopenharmony_ci 36378c2ecf20Sopenharmony_ci if (lseek(fd, section->offset, SEEK_SET) == (off_t)-1) { 36388c2ecf20Sopenharmony_ci pr_debug("Failed to lseek to %" PRIu64 " offset for feature " 36398c2ecf20Sopenharmony_ci "%d, continuing...\n", section->offset, feat); 36408c2ecf20Sopenharmony_ci return 0; 36418c2ecf20Sopenharmony_ci } 36428c2ecf20Sopenharmony_ci 36438c2ecf20Sopenharmony_ci if (feat >= HEADER_LAST_FEATURE) { 36448c2ecf20Sopenharmony_ci pr_debug("unknown feature %d, continuing...\n", feat); 36458c2ecf20Sopenharmony_ci return 0; 36468c2ecf20Sopenharmony_ci } 36478c2ecf20Sopenharmony_ci 36488c2ecf20Sopenharmony_ci if (!feat_ops[feat].process) 36498c2ecf20Sopenharmony_ci return 0; 36508c2ecf20Sopenharmony_ci 36518c2ecf20Sopenharmony_ci return feat_ops[feat].process(&fdd, data); 36528c2ecf20Sopenharmony_ci} 36538c2ecf20Sopenharmony_ci 36548c2ecf20Sopenharmony_cistatic int perf_file_header__read_pipe(struct perf_pipe_file_header *header, 36558c2ecf20Sopenharmony_ci struct perf_header *ph, int fd, 36568c2ecf20Sopenharmony_ci bool repipe) 36578c2ecf20Sopenharmony_ci{ 36588c2ecf20Sopenharmony_ci struct feat_fd ff = { 36598c2ecf20Sopenharmony_ci .fd = STDOUT_FILENO, 36608c2ecf20Sopenharmony_ci .ph = ph, 36618c2ecf20Sopenharmony_ci }; 36628c2ecf20Sopenharmony_ci ssize_t ret; 36638c2ecf20Sopenharmony_ci 36648c2ecf20Sopenharmony_ci ret = readn(fd, header, sizeof(*header)); 36658c2ecf20Sopenharmony_ci if (ret <= 0) 36668c2ecf20Sopenharmony_ci return -1; 36678c2ecf20Sopenharmony_ci 36688c2ecf20Sopenharmony_ci if (check_magic_endian(header->magic, header->size, true, ph) < 0) { 36698c2ecf20Sopenharmony_ci pr_debug("endian/magic failed\n"); 36708c2ecf20Sopenharmony_ci return -1; 36718c2ecf20Sopenharmony_ci } 36728c2ecf20Sopenharmony_ci 36738c2ecf20Sopenharmony_ci if (ph->needs_swap) 36748c2ecf20Sopenharmony_ci header->size = bswap_64(header->size); 36758c2ecf20Sopenharmony_ci 36768c2ecf20Sopenharmony_ci if (repipe && do_write(&ff, header, sizeof(*header)) < 0) 36778c2ecf20Sopenharmony_ci return -1; 36788c2ecf20Sopenharmony_ci 36798c2ecf20Sopenharmony_ci return 0; 36808c2ecf20Sopenharmony_ci} 36818c2ecf20Sopenharmony_ci 36828c2ecf20Sopenharmony_cistatic int perf_header__read_pipe(struct perf_session *session) 36838c2ecf20Sopenharmony_ci{ 36848c2ecf20Sopenharmony_ci struct perf_header *header = &session->header; 36858c2ecf20Sopenharmony_ci struct perf_pipe_file_header f_header; 36868c2ecf20Sopenharmony_ci 36878c2ecf20Sopenharmony_ci if (perf_file_header__read_pipe(&f_header, header, 36888c2ecf20Sopenharmony_ci perf_data__fd(session->data), 36898c2ecf20Sopenharmony_ci session->repipe) < 0) { 36908c2ecf20Sopenharmony_ci pr_debug("incompatible file format\n"); 36918c2ecf20Sopenharmony_ci return -EINVAL; 36928c2ecf20Sopenharmony_ci } 36938c2ecf20Sopenharmony_ci 36948c2ecf20Sopenharmony_ci return f_header.size == sizeof(f_header) ? 0 : -1; 36958c2ecf20Sopenharmony_ci} 36968c2ecf20Sopenharmony_ci 36978c2ecf20Sopenharmony_cistatic int read_attr(int fd, struct perf_header *ph, 36988c2ecf20Sopenharmony_ci struct perf_file_attr *f_attr) 36998c2ecf20Sopenharmony_ci{ 37008c2ecf20Sopenharmony_ci struct perf_event_attr *attr = &f_attr->attr; 37018c2ecf20Sopenharmony_ci size_t sz, left; 37028c2ecf20Sopenharmony_ci size_t our_sz = sizeof(f_attr->attr); 37038c2ecf20Sopenharmony_ci ssize_t ret; 37048c2ecf20Sopenharmony_ci 37058c2ecf20Sopenharmony_ci memset(f_attr, 0, sizeof(*f_attr)); 37068c2ecf20Sopenharmony_ci 37078c2ecf20Sopenharmony_ci /* read minimal guaranteed structure */ 37088c2ecf20Sopenharmony_ci ret = readn(fd, attr, PERF_ATTR_SIZE_VER0); 37098c2ecf20Sopenharmony_ci if (ret <= 0) { 37108c2ecf20Sopenharmony_ci pr_debug("cannot read %d bytes of header attr\n", 37118c2ecf20Sopenharmony_ci PERF_ATTR_SIZE_VER0); 37128c2ecf20Sopenharmony_ci return -1; 37138c2ecf20Sopenharmony_ci } 37148c2ecf20Sopenharmony_ci 37158c2ecf20Sopenharmony_ci /* on file perf_event_attr size */ 37168c2ecf20Sopenharmony_ci sz = attr->size; 37178c2ecf20Sopenharmony_ci 37188c2ecf20Sopenharmony_ci if (ph->needs_swap) 37198c2ecf20Sopenharmony_ci sz = bswap_32(sz); 37208c2ecf20Sopenharmony_ci 37218c2ecf20Sopenharmony_ci if (sz == 0) { 37228c2ecf20Sopenharmony_ci /* assume ABI0 */ 37238c2ecf20Sopenharmony_ci sz = PERF_ATTR_SIZE_VER0; 37248c2ecf20Sopenharmony_ci } else if (sz > our_sz) { 37258c2ecf20Sopenharmony_ci pr_debug("file uses a more recent and unsupported ABI" 37268c2ecf20Sopenharmony_ci " (%zu bytes extra)\n", sz - our_sz); 37278c2ecf20Sopenharmony_ci return -1; 37288c2ecf20Sopenharmony_ci } 37298c2ecf20Sopenharmony_ci /* what we have not yet read and that we know about */ 37308c2ecf20Sopenharmony_ci left = sz - PERF_ATTR_SIZE_VER0; 37318c2ecf20Sopenharmony_ci if (left) { 37328c2ecf20Sopenharmony_ci void *ptr = attr; 37338c2ecf20Sopenharmony_ci ptr += PERF_ATTR_SIZE_VER0; 37348c2ecf20Sopenharmony_ci 37358c2ecf20Sopenharmony_ci ret = readn(fd, ptr, left); 37368c2ecf20Sopenharmony_ci } 37378c2ecf20Sopenharmony_ci /* read perf_file_section, ids are read in caller */ 37388c2ecf20Sopenharmony_ci ret = readn(fd, &f_attr->ids, sizeof(f_attr->ids)); 37398c2ecf20Sopenharmony_ci 37408c2ecf20Sopenharmony_ci return ret <= 0 ? -1 : 0; 37418c2ecf20Sopenharmony_ci} 37428c2ecf20Sopenharmony_ci 37438c2ecf20Sopenharmony_cistatic int perf_evsel__prepare_tracepoint_event(struct evsel *evsel, 37448c2ecf20Sopenharmony_ci struct tep_handle *pevent) 37458c2ecf20Sopenharmony_ci{ 37468c2ecf20Sopenharmony_ci struct tep_event *event; 37478c2ecf20Sopenharmony_ci char bf[128]; 37488c2ecf20Sopenharmony_ci 37498c2ecf20Sopenharmony_ci /* already prepared */ 37508c2ecf20Sopenharmony_ci if (evsel->tp_format) 37518c2ecf20Sopenharmony_ci return 0; 37528c2ecf20Sopenharmony_ci 37538c2ecf20Sopenharmony_ci if (pevent == NULL) { 37548c2ecf20Sopenharmony_ci pr_debug("broken or missing trace data\n"); 37558c2ecf20Sopenharmony_ci return -1; 37568c2ecf20Sopenharmony_ci } 37578c2ecf20Sopenharmony_ci 37588c2ecf20Sopenharmony_ci event = tep_find_event(pevent, evsel->core.attr.config); 37598c2ecf20Sopenharmony_ci if (event == NULL) { 37608c2ecf20Sopenharmony_ci pr_debug("cannot find event format for %d\n", (int)evsel->core.attr.config); 37618c2ecf20Sopenharmony_ci return -1; 37628c2ecf20Sopenharmony_ci } 37638c2ecf20Sopenharmony_ci 37648c2ecf20Sopenharmony_ci if (!evsel->name) { 37658c2ecf20Sopenharmony_ci snprintf(bf, sizeof(bf), "%s:%s", event->system, event->name); 37668c2ecf20Sopenharmony_ci evsel->name = strdup(bf); 37678c2ecf20Sopenharmony_ci if (evsel->name == NULL) 37688c2ecf20Sopenharmony_ci return -1; 37698c2ecf20Sopenharmony_ci } 37708c2ecf20Sopenharmony_ci 37718c2ecf20Sopenharmony_ci evsel->tp_format = event; 37728c2ecf20Sopenharmony_ci return 0; 37738c2ecf20Sopenharmony_ci} 37748c2ecf20Sopenharmony_ci 37758c2ecf20Sopenharmony_cistatic int perf_evlist__prepare_tracepoint_events(struct evlist *evlist, 37768c2ecf20Sopenharmony_ci struct tep_handle *pevent) 37778c2ecf20Sopenharmony_ci{ 37788c2ecf20Sopenharmony_ci struct evsel *pos; 37798c2ecf20Sopenharmony_ci 37808c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, pos) { 37818c2ecf20Sopenharmony_ci if (pos->core.attr.type == PERF_TYPE_TRACEPOINT && 37828c2ecf20Sopenharmony_ci perf_evsel__prepare_tracepoint_event(pos, pevent)) 37838c2ecf20Sopenharmony_ci return -1; 37848c2ecf20Sopenharmony_ci } 37858c2ecf20Sopenharmony_ci 37868c2ecf20Sopenharmony_ci return 0; 37878c2ecf20Sopenharmony_ci} 37888c2ecf20Sopenharmony_ci 37898c2ecf20Sopenharmony_ciint perf_session__read_header(struct perf_session *session) 37908c2ecf20Sopenharmony_ci{ 37918c2ecf20Sopenharmony_ci struct perf_data *data = session->data; 37928c2ecf20Sopenharmony_ci struct perf_header *header = &session->header; 37938c2ecf20Sopenharmony_ci struct perf_file_header f_header; 37948c2ecf20Sopenharmony_ci struct perf_file_attr f_attr; 37958c2ecf20Sopenharmony_ci u64 f_id; 37968c2ecf20Sopenharmony_ci int nr_attrs, nr_ids, i, j, err; 37978c2ecf20Sopenharmony_ci int fd = perf_data__fd(data); 37988c2ecf20Sopenharmony_ci 37998c2ecf20Sopenharmony_ci session->evlist = evlist__new(); 38008c2ecf20Sopenharmony_ci if (session->evlist == NULL) 38018c2ecf20Sopenharmony_ci return -ENOMEM; 38028c2ecf20Sopenharmony_ci 38038c2ecf20Sopenharmony_ci session->evlist->env = &header->env; 38048c2ecf20Sopenharmony_ci session->machines.host.env = &header->env; 38058c2ecf20Sopenharmony_ci 38068c2ecf20Sopenharmony_ci /* 38078c2ecf20Sopenharmony_ci * We can read 'pipe' data event from regular file, 38088c2ecf20Sopenharmony_ci * check for the pipe header regardless of source. 38098c2ecf20Sopenharmony_ci */ 38108c2ecf20Sopenharmony_ci err = perf_header__read_pipe(session); 38118c2ecf20Sopenharmony_ci if (!err || (err && perf_data__is_pipe(data))) { 38128c2ecf20Sopenharmony_ci data->is_pipe = true; 38138c2ecf20Sopenharmony_ci return err; 38148c2ecf20Sopenharmony_ci } 38158c2ecf20Sopenharmony_ci 38168c2ecf20Sopenharmony_ci if (perf_file_header__read(&f_header, header, fd) < 0) 38178c2ecf20Sopenharmony_ci return -EINVAL; 38188c2ecf20Sopenharmony_ci 38198c2ecf20Sopenharmony_ci /* 38208c2ecf20Sopenharmony_ci * Sanity check that perf.data was written cleanly; data size is 38218c2ecf20Sopenharmony_ci * initialized to 0 and updated only if the on_exit function is run. 38228c2ecf20Sopenharmony_ci * If data size is still 0 then the file contains only partial 38238c2ecf20Sopenharmony_ci * information. Just warn user and process it as much as it can. 38248c2ecf20Sopenharmony_ci */ 38258c2ecf20Sopenharmony_ci if (f_header.data.size == 0) { 38268c2ecf20Sopenharmony_ci pr_warning("WARNING: The %s file's data size field is 0 which is unexpected.\n" 38278c2ecf20Sopenharmony_ci "Was the 'perf record' command properly terminated?\n", 38288c2ecf20Sopenharmony_ci data->file.path); 38298c2ecf20Sopenharmony_ci } 38308c2ecf20Sopenharmony_ci 38318c2ecf20Sopenharmony_ci if (f_header.attr_size == 0) { 38328c2ecf20Sopenharmony_ci pr_err("ERROR: The %s file's attr size field is 0 which is unexpected.\n" 38338c2ecf20Sopenharmony_ci "Was the 'perf record' command properly terminated?\n", 38348c2ecf20Sopenharmony_ci data->file.path); 38358c2ecf20Sopenharmony_ci return -EINVAL; 38368c2ecf20Sopenharmony_ci } 38378c2ecf20Sopenharmony_ci 38388c2ecf20Sopenharmony_ci nr_attrs = f_header.attrs.size / f_header.attr_size; 38398c2ecf20Sopenharmony_ci lseek(fd, f_header.attrs.offset, SEEK_SET); 38408c2ecf20Sopenharmony_ci 38418c2ecf20Sopenharmony_ci for (i = 0; i < nr_attrs; i++) { 38428c2ecf20Sopenharmony_ci struct evsel *evsel; 38438c2ecf20Sopenharmony_ci off_t tmp; 38448c2ecf20Sopenharmony_ci 38458c2ecf20Sopenharmony_ci if (read_attr(fd, header, &f_attr) < 0) 38468c2ecf20Sopenharmony_ci goto out_errno; 38478c2ecf20Sopenharmony_ci 38488c2ecf20Sopenharmony_ci if (header->needs_swap) { 38498c2ecf20Sopenharmony_ci f_attr.ids.size = bswap_64(f_attr.ids.size); 38508c2ecf20Sopenharmony_ci f_attr.ids.offset = bswap_64(f_attr.ids.offset); 38518c2ecf20Sopenharmony_ci perf_event__attr_swap(&f_attr.attr); 38528c2ecf20Sopenharmony_ci } 38538c2ecf20Sopenharmony_ci 38548c2ecf20Sopenharmony_ci tmp = lseek(fd, 0, SEEK_CUR); 38558c2ecf20Sopenharmony_ci evsel = evsel__new(&f_attr.attr); 38568c2ecf20Sopenharmony_ci 38578c2ecf20Sopenharmony_ci if (evsel == NULL) 38588c2ecf20Sopenharmony_ci goto out_delete_evlist; 38598c2ecf20Sopenharmony_ci 38608c2ecf20Sopenharmony_ci evsel->needs_swap = header->needs_swap; 38618c2ecf20Sopenharmony_ci /* 38628c2ecf20Sopenharmony_ci * Do it before so that if perf_evsel__alloc_id fails, this 38638c2ecf20Sopenharmony_ci * entry gets purged too at evlist__delete(). 38648c2ecf20Sopenharmony_ci */ 38658c2ecf20Sopenharmony_ci evlist__add(session->evlist, evsel); 38668c2ecf20Sopenharmony_ci 38678c2ecf20Sopenharmony_ci nr_ids = f_attr.ids.size / sizeof(u64); 38688c2ecf20Sopenharmony_ci /* 38698c2ecf20Sopenharmony_ci * We don't have the cpu and thread maps on the header, so 38708c2ecf20Sopenharmony_ci * for allocating the perf_sample_id table we fake 1 cpu and 38718c2ecf20Sopenharmony_ci * hattr->ids threads. 38728c2ecf20Sopenharmony_ci */ 38738c2ecf20Sopenharmony_ci if (perf_evsel__alloc_id(&evsel->core, 1, nr_ids)) 38748c2ecf20Sopenharmony_ci goto out_delete_evlist; 38758c2ecf20Sopenharmony_ci 38768c2ecf20Sopenharmony_ci lseek(fd, f_attr.ids.offset, SEEK_SET); 38778c2ecf20Sopenharmony_ci 38788c2ecf20Sopenharmony_ci for (j = 0; j < nr_ids; j++) { 38798c2ecf20Sopenharmony_ci if (perf_header__getbuffer64(header, fd, &f_id, sizeof(f_id))) 38808c2ecf20Sopenharmony_ci goto out_errno; 38818c2ecf20Sopenharmony_ci 38828c2ecf20Sopenharmony_ci perf_evlist__id_add(&session->evlist->core, &evsel->core, 0, j, f_id); 38838c2ecf20Sopenharmony_ci } 38848c2ecf20Sopenharmony_ci 38858c2ecf20Sopenharmony_ci lseek(fd, tmp, SEEK_SET); 38868c2ecf20Sopenharmony_ci } 38878c2ecf20Sopenharmony_ci 38888c2ecf20Sopenharmony_ci perf_header__process_sections(header, fd, &session->tevent, 38898c2ecf20Sopenharmony_ci perf_file_section__process); 38908c2ecf20Sopenharmony_ci 38918c2ecf20Sopenharmony_ci if (perf_evlist__prepare_tracepoint_events(session->evlist, 38928c2ecf20Sopenharmony_ci session->tevent.pevent)) 38938c2ecf20Sopenharmony_ci goto out_delete_evlist; 38948c2ecf20Sopenharmony_ci 38958c2ecf20Sopenharmony_ci return 0; 38968c2ecf20Sopenharmony_ciout_errno: 38978c2ecf20Sopenharmony_ci return -errno; 38988c2ecf20Sopenharmony_ci 38998c2ecf20Sopenharmony_ciout_delete_evlist: 39008c2ecf20Sopenharmony_ci evlist__delete(session->evlist); 39018c2ecf20Sopenharmony_ci session->evlist = NULL; 39028c2ecf20Sopenharmony_ci return -ENOMEM; 39038c2ecf20Sopenharmony_ci} 39048c2ecf20Sopenharmony_ci 39058c2ecf20Sopenharmony_ciint perf_event__process_feature(struct perf_session *session, 39068c2ecf20Sopenharmony_ci union perf_event *event) 39078c2ecf20Sopenharmony_ci{ 39088c2ecf20Sopenharmony_ci struct perf_tool *tool = session->tool; 39098c2ecf20Sopenharmony_ci struct feat_fd ff = { .fd = 0 }; 39108c2ecf20Sopenharmony_ci struct perf_record_header_feature *fe = (struct perf_record_header_feature *)event; 39118c2ecf20Sopenharmony_ci int type = fe->header.type; 39128c2ecf20Sopenharmony_ci u64 feat = fe->feat_id; 39138c2ecf20Sopenharmony_ci 39148c2ecf20Sopenharmony_ci if (type < 0 || type >= PERF_RECORD_HEADER_MAX) { 39158c2ecf20Sopenharmony_ci pr_warning("invalid record type %d in pipe-mode\n", type); 39168c2ecf20Sopenharmony_ci return 0; 39178c2ecf20Sopenharmony_ci } 39188c2ecf20Sopenharmony_ci if (feat == HEADER_RESERVED || feat >= HEADER_LAST_FEATURE) { 39198c2ecf20Sopenharmony_ci pr_warning("invalid record type %d in pipe-mode\n", type); 39208c2ecf20Sopenharmony_ci return -1; 39218c2ecf20Sopenharmony_ci } 39228c2ecf20Sopenharmony_ci 39238c2ecf20Sopenharmony_ci if (!feat_ops[feat].process) 39248c2ecf20Sopenharmony_ci return 0; 39258c2ecf20Sopenharmony_ci 39268c2ecf20Sopenharmony_ci ff.buf = (void *)fe->data; 39278c2ecf20Sopenharmony_ci ff.size = event->header.size - sizeof(*fe); 39288c2ecf20Sopenharmony_ci ff.ph = &session->header; 39298c2ecf20Sopenharmony_ci 39308c2ecf20Sopenharmony_ci if (feat_ops[feat].process(&ff, NULL)) 39318c2ecf20Sopenharmony_ci return -1; 39328c2ecf20Sopenharmony_ci 39338c2ecf20Sopenharmony_ci if (!feat_ops[feat].print || !tool->show_feat_hdr) 39348c2ecf20Sopenharmony_ci return 0; 39358c2ecf20Sopenharmony_ci 39368c2ecf20Sopenharmony_ci if (!feat_ops[feat].full_only || 39378c2ecf20Sopenharmony_ci tool->show_feat_hdr >= SHOW_FEAT_HEADER_FULL_INFO) { 39388c2ecf20Sopenharmony_ci feat_ops[feat].print(&ff, stdout); 39398c2ecf20Sopenharmony_ci } else { 39408c2ecf20Sopenharmony_ci fprintf(stdout, "# %s info available, use -I to display\n", 39418c2ecf20Sopenharmony_ci feat_ops[feat].name); 39428c2ecf20Sopenharmony_ci } 39438c2ecf20Sopenharmony_ci 39448c2ecf20Sopenharmony_ci return 0; 39458c2ecf20Sopenharmony_ci} 39468c2ecf20Sopenharmony_ci 39478c2ecf20Sopenharmony_cisize_t perf_event__fprintf_event_update(union perf_event *event, FILE *fp) 39488c2ecf20Sopenharmony_ci{ 39498c2ecf20Sopenharmony_ci struct perf_record_event_update *ev = &event->event_update; 39508c2ecf20Sopenharmony_ci struct perf_record_event_update_scale *ev_scale; 39518c2ecf20Sopenharmony_ci struct perf_record_event_update_cpus *ev_cpus; 39528c2ecf20Sopenharmony_ci struct perf_cpu_map *map; 39538c2ecf20Sopenharmony_ci size_t ret; 39548c2ecf20Sopenharmony_ci 39558c2ecf20Sopenharmony_ci ret = fprintf(fp, "\n... id: %" PRI_lu64 "\n", ev->id); 39568c2ecf20Sopenharmony_ci 39578c2ecf20Sopenharmony_ci switch (ev->type) { 39588c2ecf20Sopenharmony_ci case PERF_EVENT_UPDATE__SCALE: 39598c2ecf20Sopenharmony_ci ev_scale = (struct perf_record_event_update_scale *)ev->data; 39608c2ecf20Sopenharmony_ci ret += fprintf(fp, "... scale: %f\n", ev_scale->scale); 39618c2ecf20Sopenharmony_ci break; 39628c2ecf20Sopenharmony_ci case PERF_EVENT_UPDATE__UNIT: 39638c2ecf20Sopenharmony_ci ret += fprintf(fp, "... unit: %s\n", ev->data); 39648c2ecf20Sopenharmony_ci break; 39658c2ecf20Sopenharmony_ci case PERF_EVENT_UPDATE__NAME: 39668c2ecf20Sopenharmony_ci ret += fprintf(fp, "... name: %s\n", ev->data); 39678c2ecf20Sopenharmony_ci break; 39688c2ecf20Sopenharmony_ci case PERF_EVENT_UPDATE__CPUS: 39698c2ecf20Sopenharmony_ci ev_cpus = (struct perf_record_event_update_cpus *)ev->data; 39708c2ecf20Sopenharmony_ci ret += fprintf(fp, "... "); 39718c2ecf20Sopenharmony_ci 39728c2ecf20Sopenharmony_ci map = cpu_map__new_data(&ev_cpus->cpus); 39738c2ecf20Sopenharmony_ci if (map) 39748c2ecf20Sopenharmony_ci ret += cpu_map__fprintf(map, fp); 39758c2ecf20Sopenharmony_ci else 39768c2ecf20Sopenharmony_ci ret += fprintf(fp, "failed to get cpus\n"); 39778c2ecf20Sopenharmony_ci break; 39788c2ecf20Sopenharmony_ci default: 39798c2ecf20Sopenharmony_ci ret += fprintf(fp, "... unknown type\n"); 39808c2ecf20Sopenharmony_ci break; 39818c2ecf20Sopenharmony_ci } 39828c2ecf20Sopenharmony_ci 39838c2ecf20Sopenharmony_ci return ret; 39848c2ecf20Sopenharmony_ci} 39858c2ecf20Sopenharmony_ci 39868c2ecf20Sopenharmony_ciint perf_event__process_attr(struct perf_tool *tool __maybe_unused, 39878c2ecf20Sopenharmony_ci union perf_event *event, 39888c2ecf20Sopenharmony_ci struct evlist **pevlist) 39898c2ecf20Sopenharmony_ci{ 39908c2ecf20Sopenharmony_ci u32 i, n_ids; 39918c2ecf20Sopenharmony_ci u64 *ids; 39928c2ecf20Sopenharmony_ci struct evsel *evsel; 39938c2ecf20Sopenharmony_ci struct evlist *evlist = *pevlist; 39948c2ecf20Sopenharmony_ci 39958c2ecf20Sopenharmony_ci if (evlist == NULL) { 39968c2ecf20Sopenharmony_ci *pevlist = evlist = evlist__new(); 39978c2ecf20Sopenharmony_ci if (evlist == NULL) 39988c2ecf20Sopenharmony_ci return -ENOMEM; 39998c2ecf20Sopenharmony_ci } 40008c2ecf20Sopenharmony_ci 40018c2ecf20Sopenharmony_ci evsel = evsel__new(&event->attr.attr); 40028c2ecf20Sopenharmony_ci if (evsel == NULL) 40038c2ecf20Sopenharmony_ci return -ENOMEM; 40048c2ecf20Sopenharmony_ci 40058c2ecf20Sopenharmony_ci evlist__add(evlist, evsel); 40068c2ecf20Sopenharmony_ci 40078c2ecf20Sopenharmony_ci n_ids = event->header.size - sizeof(event->header) - event->attr.attr.size; 40088c2ecf20Sopenharmony_ci n_ids = n_ids / sizeof(u64); 40098c2ecf20Sopenharmony_ci /* 40108c2ecf20Sopenharmony_ci * We don't have the cpu and thread maps on the header, so 40118c2ecf20Sopenharmony_ci * for allocating the perf_sample_id table we fake 1 cpu and 40128c2ecf20Sopenharmony_ci * hattr->ids threads. 40138c2ecf20Sopenharmony_ci */ 40148c2ecf20Sopenharmony_ci if (perf_evsel__alloc_id(&evsel->core, 1, n_ids)) 40158c2ecf20Sopenharmony_ci return -ENOMEM; 40168c2ecf20Sopenharmony_ci 40178c2ecf20Sopenharmony_ci ids = (void *)&event->attr.attr + event->attr.attr.size; 40188c2ecf20Sopenharmony_ci for (i = 0; i < n_ids; i++) { 40198c2ecf20Sopenharmony_ci perf_evlist__id_add(&evlist->core, &evsel->core, 0, i, ids[i]); 40208c2ecf20Sopenharmony_ci } 40218c2ecf20Sopenharmony_ci 40228c2ecf20Sopenharmony_ci return 0; 40238c2ecf20Sopenharmony_ci} 40248c2ecf20Sopenharmony_ci 40258c2ecf20Sopenharmony_ciint perf_event__process_event_update(struct perf_tool *tool __maybe_unused, 40268c2ecf20Sopenharmony_ci union perf_event *event, 40278c2ecf20Sopenharmony_ci struct evlist **pevlist) 40288c2ecf20Sopenharmony_ci{ 40298c2ecf20Sopenharmony_ci struct perf_record_event_update *ev = &event->event_update; 40308c2ecf20Sopenharmony_ci struct perf_record_event_update_scale *ev_scale; 40318c2ecf20Sopenharmony_ci struct perf_record_event_update_cpus *ev_cpus; 40328c2ecf20Sopenharmony_ci struct evlist *evlist; 40338c2ecf20Sopenharmony_ci struct evsel *evsel; 40348c2ecf20Sopenharmony_ci struct perf_cpu_map *map; 40358c2ecf20Sopenharmony_ci 40368c2ecf20Sopenharmony_ci if (!pevlist || *pevlist == NULL) 40378c2ecf20Sopenharmony_ci return -EINVAL; 40388c2ecf20Sopenharmony_ci 40398c2ecf20Sopenharmony_ci evlist = *pevlist; 40408c2ecf20Sopenharmony_ci 40418c2ecf20Sopenharmony_ci evsel = perf_evlist__id2evsel(evlist, ev->id); 40428c2ecf20Sopenharmony_ci if (evsel == NULL) 40438c2ecf20Sopenharmony_ci return -EINVAL; 40448c2ecf20Sopenharmony_ci 40458c2ecf20Sopenharmony_ci switch (ev->type) { 40468c2ecf20Sopenharmony_ci case PERF_EVENT_UPDATE__UNIT: 40478c2ecf20Sopenharmony_ci evsel->unit = strdup(ev->data); 40488c2ecf20Sopenharmony_ci break; 40498c2ecf20Sopenharmony_ci case PERF_EVENT_UPDATE__NAME: 40508c2ecf20Sopenharmony_ci evsel->name = strdup(ev->data); 40518c2ecf20Sopenharmony_ci break; 40528c2ecf20Sopenharmony_ci case PERF_EVENT_UPDATE__SCALE: 40538c2ecf20Sopenharmony_ci ev_scale = (struct perf_record_event_update_scale *)ev->data; 40548c2ecf20Sopenharmony_ci evsel->scale = ev_scale->scale; 40558c2ecf20Sopenharmony_ci break; 40568c2ecf20Sopenharmony_ci case PERF_EVENT_UPDATE__CPUS: 40578c2ecf20Sopenharmony_ci ev_cpus = (struct perf_record_event_update_cpus *)ev->data; 40588c2ecf20Sopenharmony_ci 40598c2ecf20Sopenharmony_ci map = cpu_map__new_data(&ev_cpus->cpus); 40608c2ecf20Sopenharmony_ci if (map) 40618c2ecf20Sopenharmony_ci evsel->core.own_cpus = map; 40628c2ecf20Sopenharmony_ci else 40638c2ecf20Sopenharmony_ci pr_err("failed to get event_update cpus\n"); 40648c2ecf20Sopenharmony_ci default: 40658c2ecf20Sopenharmony_ci break; 40668c2ecf20Sopenharmony_ci } 40678c2ecf20Sopenharmony_ci 40688c2ecf20Sopenharmony_ci return 0; 40698c2ecf20Sopenharmony_ci} 40708c2ecf20Sopenharmony_ci 40718c2ecf20Sopenharmony_ciint perf_event__process_tracing_data(struct perf_session *session, 40728c2ecf20Sopenharmony_ci union perf_event *event) 40738c2ecf20Sopenharmony_ci{ 40748c2ecf20Sopenharmony_ci ssize_t size_read, padding, size = event->tracing_data.size; 40758c2ecf20Sopenharmony_ci int fd = perf_data__fd(session->data); 40768c2ecf20Sopenharmony_ci char buf[BUFSIZ]; 40778c2ecf20Sopenharmony_ci 40788c2ecf20Sopenharmony_ci /* 40798c2ecf20Sopenharmony_ci * The pipe fd is already in proper place and in any case 40808c2ecf20Sopenharmony_ci * we can't move it, and we'd screw the case where we read 40818c2ecf20Sopenharmony_ci * 'pipe' data from regular file. The trace_report reads 40828c2ecf20Sopenharmony_ci * data from 'fd' so we need to set it directly behind the 40838c2ecf20Sopenharmony_ci * event, where the tracing data starts. 40848c2ecf20Sopenharmony_ci */ 40858c2ecf20Sopenharmony_ci if (!perf_data__is_pipe(session->data)) { 40868c2ecf20Sopenharmony_ci off_t offset = lseek(fd, 0, SEEK_CUR); 40878c2ecf20Sopenharmony_ci 40888c2ecf20Sopenharmony_ci /* setup for reading amidst mmap */ 40898c2ecf20Sopenharmony_ci lseek(fd, offset + sizeof(struct perf_record_header_tracing_data), 40908c2ecf20Sopenharmony_ci SEEK_SET); 40918c2ecf20Sopenharmony_ci } 40928c2ecf20Sopenharmony_ci 40938c2ecf20Sopenharmony_ci size_read = trace_report(fd, &session->tevent, 40948c2ecf20Sopenharmony_ci session->repipe); 40958c2ecf20Sopenharmony_ci padding = PERF_ALIGN(size_read, sizeof(u64)) - size_read; 40968c2ecf20Sopenharmony_ci 40978c2ecf20Sopenharmony_ci if (readn(fd, buf, padding) < 0) { 40988c2ecf20Sopenharmony_ci pr_err("%s: reading input file", __func__); 40998c2ecf20Sopenharmony_ci return -1; 41008c2ecf20Sopenharmony_ci } 41018c2ecf20Sopenharmony_ci if (session->repipe) { 41028c2ecf20Sopenharmony_ci int retw = write(STDOUT_FILENO, buf, padding); 41038c2ecf20Sopenharmony_ci if (retw <= 0 || retw != padding) { 41048c2ecf20Sopenharmony_ci pr_err("%s: repiping tracing data padding", __func__); 41058c2ecf20Sopenharmony_ci return -1; 41068c2ecf20Sopenharmony_ci } 41078c2ecf20Sopenharmony_ci } 41088c2ecf20Sopenharmony_ci 41098c2ecf20Sopenharmony_ci if (size_read + padding != size) { 41108c2ecf20Sopenharmony_ci pr_err("%s: tracing data size mismatch", __func__); 41118c2ecf20Sopenharmony_ci return -1; 41128c2ecf20Sopenharmony_ci } 41138c2ecf20Sopenharmony_ci 41148c2ecf20Sopenharmony_ci perf_evlist__prepare_tracepoint_events(session->evlist, 41158c2ecf20Sopenharmony_ci session->tevent.pevent); 41168c2ecf20Sopenharmony_ci 41178c2ecf20Sopenharmony_ci return size_read + padding; 41188c2ecf20Sopenharmony_ci} 41198c2ecf20Sopenharmony_ci 41208c2ecf20Sopenharmony_ciint perf_event__process_build_id(struct perf_session *session, 41218c2ecf20Sopenharmony_ci union perf_event *event) 41228c2ecf20Sopenharmony_ci{ 41238c2ecf20Sopenharmony_ci __event_process_build_id(&event->build_id, 41248c2ecf20Sopenharmony_ci event->build_id.filename, 41258c2ecf20Sopenharmony_ci session); 41268c2ecf20Sopenharmony_ci return 0; 41278c2ecf20Sopenharmony_ci} 4128