diff --git a/repos/libports/lib/import/import-libpfm4.mk b/repos/libports/lib/import/import-libpfm4.mk new file mode 100644 index 0000000000..ba6094e1cf --- /dev/null +++ b/repos/libports/lib/import/import-libpfm4.mk @@ -0,0 +1 @@ +INC_DIR += $(call select_from_ports,libpfm4)/include \ No newline at end of file diff --git a/repos/libports/lib/mk/libpfm4.mk b/repos/libports/lib/mk/libpfm4.mk new file mode 100644 index 0000000000..c998bfad52 --- /dev/null +++ b/repos/libports/lib/mk/libpfm4.mk @@ -0,0 +1,204 @@ +LIBPFM4_DIR := $(call select_from_ports,libpfm4)/src/lib/libpfm4 + +CC_OPT += -D_REENTRANT -fvisibility=hidden + +SRC_CC = $(LIBPFM4_DIR)/lib/pfmlib_common.c + +# build libpfm only for x86_64 for now +CONFIG_PFMLIB_ARCH_X86_64=y +CONFIG_PFMLIB_ARCH_X86=y + +CONFIG_PFMLIB_SHARED?=n +CONFIG_PFMLIB_DEBUG?=y +CONFIG_PFMLIB_NOPYTHON?=y + +# +# list all library support modules +# +ifeq ($(CONFIG_PFMLIB_ARCH_IA64),y) +INCARCH = $(INC_IA64) +#SRCS += pfmlib_gen_ia64.c pfmlib_itanium.c pfmlib_itanium2.c pfmlib_montecito.c +CFLAGS += -DCONFIG_PFMLIB_ARCH_IA64 +endif + +ifeq ($(CONFIG_PFMLIB_ARCH_X86),y) + +ifeq ($(SYS),Linux) +SRCS += pfmlib_intel_x86_perf_event.c pfmlib_amd64_perf_event.c \ + pfmlib_intel_netburst_perf_event.c \ + pfmlib_intel_snbep_unc_perf_event.c +endif + +INCARCH = $(INC_X86) +SRCS += pfmlib_amd64.c pfmlib_intel_core.c pfmlib_intel_x86.c \ + pfmlib_intel_x86_arch.c pfmlib_intel_atom.c \ + pfmlib_intel_nhm_unc.c pfmlib_intel_nhm.c \ + pfmlib_intel_wsm.c \ + pfmlib_intel_snb.c pfmlib_intel_snb_unc.c \ + pfmlib_intel_ivb.c pfmlib_intel_ivb_unc.c \ + pfmlib_intel_hsw.c \ + pfmlib_intel_bdw.c \ + pfmlib_intel_skl.c \ + pfmlib_intel_icl.c \ + pfmlib_intel_spr.c \ + pfmlib_intel_rapl.c \ + pfmlib_intel_snbep_unc.c \ + pfmlib_intel_snbep_unc_cbo.c \ + pfmlib_intel_snbep_unc_ha.c \ + pfmlib_intel_snbep_unc_imc.c \ + pfmlib_intel_snbep_unc_pcu.c \ + pfmlib_intel_snbep_unc_qpi.c \ + pfmlib_intel_snbep_unc_ubo.c \ + pfmlib_intel_snbep_unc_r2pcie.c \ + pfmlib_intel_snbep_unc_r3qpi.c \ + pfmlib_intel_ivbep_unc_cbo.c \ + pfmlib_intel_ivbep_unc_ha.c \ + pfmlib_intel_ivbep_unc_imc.c \ + pfmlib_intel_ivbep_unc_pcu.c \ + pfmlib_intel_ivbep_unc_qpi.c \ + pfmlib_intel_ivbep_unc_ubo.c \ + pfmlib_intel_ivbep_unc_r2pcie.c \ + pfmlib_intel_ivbep_unc_r3qpi.c \ + pfmlib_intel_ivbep_unc_irp.c \ + pfmlib_intel_hswep_unc_cbo.c \ + pfmlib_intel_hswep_unc_ha.c \ + pfmlib_intel_hswep_unc_imc.c \ + pfmlib_intel_hswep_unc_pcu.c \ + pfmlib_intel_hswep_unc_qpi.c \ + pfmlib_intel_hswep_unc_ubo.c \ + pfmlib_intel_hswep_unc_r2pcie.c \ + pfmlib_intel_hswep_unc_r3qpi.c \ + pfmlib_intel_hswep_unc_irp.c \ + pfmlib_intel_hswep_unc_sbo.c \ + pfmlib_intel_bdx_unc_cbo.c \ + pfmlib_intel_bdx_unc_ubo.c \ + pfmlib_intel_bdx_unc_sbo.c \ + pfmlib_intel_bdx_unc_ha.c \ + pfmlib_intel_bdx_unc_imc.c \ + pfmlib_intel_bdx_unc_irp.c \ + pfmlib_intel_bdx_unc_pcu.c \ + pfmlib_intel_bdx_unc_qpi.c \ + pfmlib_intel_bdx_unc_r2pcie.c \ + pfmlib_intel_bdx_unc_r3qpi.c \ + pfmlib_intel_skx_unc_cha.c \ + pfmlib_intel_skx_unc_iio.c \ + pfmlib_intel_skx_unc_imc.c \ + pfmlib_intel_skx_unc_irp.c \ + pfmlib_intel_skx_unc_m2m.c \ + pfmlib_intel_skx_unc_m3upi.c \ + pfmlib_intel_skx_unc_pcu.c \ + pfmlib_intel_skx_unc_ubo.c \ + pfmlib_intel_skx_unc_upi.c \ + pfmlib_intel_knc.c \ + pfmlib_intel_slm.c \ + pfmlib_intel_tmt.c \ + pfmlib_intel_knl.c \ + pfmlib_intel_knl_unc_imc.c \ + pfmlib_intel_knl_unc_edc.c \ + pfmlib_intel_knl_unc_cha.c \ + pfmlib_intel_knl_unc_m2pcie.c \ + pfmlib_intel_glm.c \ + pfmlib_intel_netburst.c \ + pfmlib_amd64_k7.c pfmlib_amd64_k8.c pfmlib_amd64_fam10h.c \ + pfmlib_amd64_fam11h.c pfmlib_amd64_fam12h.c \ + pfmlib_amd64_fam14h.c pfmlib_amd64_fam15h.c \ + pfmlib_amd64_fam17h.c pfmlib_amd64_fam16h.c \ + pfmlib_amd64_fam19h.c pfmlib_amd64_rapl.c \ + pfmlib_amd64_fam19h_l3.c + +CFLAGS += -DCONFIG_PFMLIB_ARCH_X86 + +ifeq ($(CONFIG_PFMLIB_ARCH_I386),y) +SRCS += pfmlib_intel_coreduo.c pfmlib_intel_p6.c +CFLAGS += -DCONFIG_PFMLIB_ARCH_I386 +endif + +ifeq ($(CONFIG_PFMLIB_ARCH_X86_64),y) +CFLAGS += -DCONFIG_PFMLIB_ARCH_X86_64 +endif + +endif + +ifeq ($(CONFIG_PFMLIB_ARCH_POWERPC),y) + +ifeq ($(SYS),Linux) +SRCS += pfmlib_powerpc_perf_event.c +endif + +INCARCH = $(INC_POWERPC) +SRCS += pfmlib_powerpc.c pfmlib_power4.c pfmlib_ppc970.c pfmlib_power5.c \ + pfmlib_power6.c pfmlib_power7.c pfmlib_torrent.c pfmlib_power8.c \ + pfmlib_power9.c pfmlib_powerpc_nest.c pfmlib_power10.c +CFLAGS += -DCONFIG_PFMLIB_ARCH_POWERPC +endif + +ifeq ($(CONFIG_PFMLIB_ARCH_S390X),y) + +ifeq ($(SYS),Linux) +SRCS += pfmlib_s390x_perf_event.c +endif + +INCARCH = $(INC_S390X) +SRCS += pfmlib_s390x_cpumf.c +CFLAGS += -DCONFIG_PFMLIB_ARCH_S390X +endif + +ifeq ($(CONFIG_PFMLIB_ARCH_SPARC),y) + +ifeq ($(SYS),Linux) +SRCS += pfmlib_sparc_perf_event.c +endif + +INCARCH = $(INC_SPARC) +SRCS += pfmlib_sparc.c pfmlib_sparc_ultra12.c pfmlib_sparc_ultra3.c pfmlib_sparc_ultra4.c pfmlib_sparc_niagara.c +CFLAGS += -DCONFIG_PFMLIB_ARCH_SPARC +endif + +ifeq ($(CONFIG_PFMLIB_ARCH_ARM),y) + +ifeq ($(SYS),Linux) +SRCS += pfmlib_arm_perf_event.c +endif + +INCARCH = $(INC_ARM) +SRCS += pfmlib_arm.c pfmlib_arm_armv7_pmuv1.c pfmlib_arm_armv6.c pfmlib_arm_armv8.c pfmlib_tx2_unc_perf_event.c pfmlib_kunpeng_unc_perf_event.c +CFLAGS += -DCONFIG_PFMLIB_ARCH_ARM +endif + +ifeq ($(CONFIG_PFMLIB_ARCH_ARM64),y) + +ifeq ($(SYS),Linux) +SRCS += pfmlib_arm_perf_event.c +endif + +INCARCH = $(INC_ARM64) +SRCS += pfmlib_arm.c pfmlib_arm_armv8.c pfmlib_tx2_unc_perf_event.c pfmlib_kunpeng_unc_perf_event.c +CFLAGS += -DCONFIG_PFMLIB_ARCH_ARM64 +endif + +ifeq ($(CONFIG_PFMLIB_ARCH_MIPS),y) + +ifeq ($(SYS),Linux) +SRCS += pfmlib_mips_perf_event.c +endif + +INCARCH = $(INC_MIPS) +SRCS += pfmlib_mips.c pfmlib_mips_74k.c +CFLAGS += -DCONFIG_PFMLIB_ARCH_MIPS +endif + +ifeq ($(CONFIG_PFMLIB_CELL),y) +INCARCH = $(INC_CELL) +#SRCS += pfmlib_cell.c +CFLAGS += -DCONFIG_PFMLIB_CELL +endif + +SRC_CC += $(addprefix $(LIBPFM4_DIR)/lib/,$(SRCS)) +vpath %.c $(LIBPFM4_DIR)/lib + +CC_OPT += $(CFLAGS) + +INC_DIR += $(LIBPFM4_DIR)/include $(LIBPFM4_DIR)/lib/events +vpath %.h $(INC_DIR) + +LIBS += base libm libc diff --git a/repos/libports/ports/libpfm4.hash b/repos/libports/ports/libpfm4.hash new file mode 100644 index 0000000000..6eeb6653d7 --- /dev/null +++ b/repos/libports/ports/libpfm4.hash @@ -0,0 +1 @@ +b0ec09148c2be9f4a96203a3d2de4ebed6ce2da0 diff --git a/repos/libports/ports/libpfm4.port b/repos/libports/ports/libpfm4.port new file mode 100644 index 0000000000..f0d7542ca3 --- /dev/null +++ b/repos/libports/ports/libpfm4.port @@ -0,0 +1,13 @@ +LICENSE := PD +DOWNLOADS := libpfm4.git +VERSION := git + +URL(libpfm4) := https://github.com/wcohen/libpfm4.git +REV(libpfm4) := 8aaaf1747e96031a47ed6bd9337ff61a21f8cc64 +DIR(libpfm4) := src/lib/libpfm4 + +DIRS += include +DIRS += include/perfmon + +DIR_CONTENT(include) += src/lib/libpfm4/include/perfmon +DIR_CONTENT(include/perfmon) += src/lib/libpfm4/include/perfmon/*.h \ No newline at end of file diff --git a/repos/libports/recipes/src/libpfm4/api b/repos/libports/recipes/src/libpfm4/api new file mode 100644 index 0000000000..954b4ab6ae --- /dev/null +++ b/repos/libports/recipes/src/libpfm4/api @@ -0,0 +1 @@ +libpfm4 \ No newline at end of file diff --git a/repos/libports/recipes/src/libpfm4/content.mk b/repos/libports/recipes/src/libpfm4/content.mk new file mode 100644 index 0000000000..1301d4f0ba --- /dev/null +++ b/repos/libports/recipes/src/libpfm4/content.mk @@ -0,0 +1,17 @@ +MIRROR_FROM_REP_DIR := lib/mk/libpfm4.mk lib/import/import-libpfm4.mk + +content: src/lib/libpfm4 COPYING $(MIRROR_FROM_REP_DIR) + +PORT_DIR := $(call port_dir,$(REP_DIR)/ports/libpfm4) + +src/lib/libpfm4: + mkdir -p $@ + cp -r $(PORT_DIR)/src/lib/libpfm4/* $@ + rm -rf $@/.git + echo "LIBS = libpfm4" > $@/target.mk + +$(MIRROR_FROM_REP_DIR): + $(mirror_from_rep_dir) + +LICENSE: + echo "libpfm license, see src/lib/libpfm4/COPYING" > $@ \ No newline at end of file diff --git a/repos/libports/recipes/src/libpfm4/used_api b/repos/libports/recipes/src/libpfm4/used_api new file mode 100644 index 0000000000..186e29c4c6 --- /dev/null +++ b/repos/libports/recipes/src/libpfm4/used_api @@ -0,0 +1,3 @@ +base +libm +libc \ No newline at end of file diff --git a/repos/mml/run/libpfm_test.run b/repos/mml/run/libpfm_test.run new file mode 100644 index 0000000000..12d1aec044 --- /dev/null +++ b/repos/mml/run/libpfm_test.run @@ -0,0 +1,68 @@ +set build_components { + core init timer app/libpfm_test +} + +source ${genode_dir}/repos/base/run/platform_drv.inc +append_platform_drv_build_components + +build $build_components + +create_boot_directory + +set config { + + + + + + + + + + + + + + + + + + + + + + + + + + + +} + +append config { + + + + 2022-07-20 14:30 + + + + + + + + +} + +install_config $config + +set boot_modules { + core init timer vfs.lib.so ld.lib.so posix.lib.so libc.lib.so libm.lib.so stdcxx.lib.so libpfm_test +} + +append_platform_drv_boot_modules + +build_boot_image $boot_modules +append qemu_args "-nographic " + +run_genode_until forever \ No newline at end of file diff --git a/repos/mml/src/app/libpfm_test/check_events.c b/repos/mml/src/app/libpfm_test/check_events.c new file mode 100644 index 0000000000..9edaebd7e1 --- /dev/null +++ b/repos/mml/src/app/libpfm_test/check_events.c @@ -0,0 +1,174 @@ +/* + * check_events.c - show event encoding + * + * Copyright (c) 2009 Google, Inc + * Contributed by Stephane Eranian + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * This file is part of libpfm, a performance monitoring support library for + * applications on Linux. + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +int pmu_is_present(pfm_pmu_t p) +{ + pfm_pmu_info_t pinfo; + int ret; + + memset(&pinfo, 0, sizeof(pinfo)); + ret = pfm_get_pmu_info(p, &pinfo); + return ret == PFM_SUCCESS ? pinfo.is_present : 0; +} + +int main(int argc, const char **argv) +{ + pfm_pmu_info_t pinfo; + pfm_pmu_encode_arg_t e; + const char *arg[3]; + const char **p; + char *fqstr; + pfm_event_info_t info; + int j, ret; + pfm_pmu_t i; + int total_supported_events = 0; + int total_available_events = 0; + + unsigned long low, high, msr; + msr = 0xc0010200; + + asm volatile("rdmsr" + : "=a"(low), "=d"(high) + : "c"(msr)); /* + * Initialize pfm library (required before we can use it) + */ + ret = pfm_initialize(); + if (ret != PFM_SUCCESS) + errx(1, "cannot initialize library: %s\n", pfm_strerror(ret)); + + memset(&pinfo, 0, sizeof(pinfo)); + memset(&info, 0, sizeof(info)); + + printf("Supported PMU models:\n"); + for (i = PFM_PMU_NONE; i < PFM_PMU_MAX; i++) + { + ret = pfm_get_pmu_info(i, &pinfo); + if (ret != PFM_SUCCESS) + continue; + + printf("\t[%d, %s, \"%s\"]\n", i, pinfo.name, pinfo.desc); + } + + printf("Detected PMU models:\n"); + for (i = PFM_PMU_NONE; i < PFM_PMU_MAX; i++) + { + ret = pfm_get_pmu_info(i, &pinfo); + if (ret != PFM_SUCCESS) + continue; + if (pinfo.is_present) + { + printf("\t[%d, %s, \"%s\"]\n", i, pinfo.name, pinfo.desc); + total_supported_events += pinfo.nevents; + } + total_available_events += pinfo.nevents; + } + + printf("Total events: %d available, %d supported\n", total_available_events, total_supported_events); + + /* + * be nice to user! + */ + if (argc < 2 && pmu_is_present(PFM_PMU_PERF_EVENT)) + { + arg[0] = "PERF_COUNT_HW_CPU_CYCLES"; + arg[1] = "PERF_COUNT_HW_INSTRUCTIONS"; + arg[2] = NULL; + p = arg; + } + else + { + p = argv + 1; + } + + if (!*p) + errx(1, "you must pass at least one event"); + + memset(&e, 0, sizeof(e)); + while (*p) + { + /* + * extract raw event encoding + * + * For perf_event encoding, use + * #include + * and the function: + * pfm_get_perf_event_encoding() + */ + fqstr = NULL; + e.fstr = &fqstr; + ret = pfm_get_os_event_encoding(*p, PFM_PLM0 | PFM_PLM3, PFM_OS_NONE, &e); + if (ret != PFM_SUCCESS) + { + /* + * codes is too small for this event + * free and let the library resize + */ + if (ret == PFM_ERR_TOOSMALL) + { + free(e.codes); + e.codes = NULL; + e.count = 0; + free(fqstr); + continue; + } + if (ret == PFM_ERR_NOTFOUND && strstr(*p, "::")) + errx(1, "%s: try setting LIBPFM_ENCODE_INACTIVE=1", pfm_strerror(ret)); + errx(1, "cannot encode event %s: %s", *p, pfm_strerror(ret)); + } + ret = pfm_get_event_info(e.idx, PFM_OS_NONE, &info); + if (ret != PFM_SUCCESS) + errx(1, "cannot get event info: %s", pfm_strerror(ret)); + + ret = pfm_get_pmu_info(info.pmu, &pinfo); + if (ret != PFM_SUCCESS) + errx(1, "cannot get PMU info: %s", pfm_strerror(ret)); + + printf("Requested Event: %s\n", *p); + printf("Actual Event: %s\n", fqstr); + printf("PMU : %s\n", pinfo.desc); + printf("IDX : %d\n", e.idx); + printf("Codes :"); + for (j = 0; j < e.count; j++) + printf(" 0x%" PRIx64, e.codes[j]); + putchar('\n'); + + free(fqstr); + p++; + } + if (e.codes) + free(e.codes); + return 0; +} \ No newline at end of file diff --git a/repos/mml/src/app/libpfm_test/showevtinfo.c b/repos/mml/src/app/libpfm_test/showevtinfo.c new file mode 100644 index 0000000000..3c775c8da0 --- /dev/null +++ b/repos/mml/src/app/libpfm_test/showevtinfo.c @@ -0,0 +1,1020 @@ +/* + * showevtinfo.c - show event information + * + * Copyright (c) 2010 Google, Inc + * Contributed by Stephane Eranian + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * This file is part of libpfm, a performance monitoring support library for + * applications on Linux. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define MAXBUF 1024 +#define COMBO_MAX 18 + +static struct +{ + int compact; + int sort; + uint8_t encode; + uint8_t combo; + uint8_t combo_lim; + uint8_t name_only; + uint8_t desc; + char *csv_sep; + pfm_event_info_t efilter; + pfm_event_attr_info_t ufilter; + pfm_os_t os; + uint64_t mask; +} options; + +typedef struct +{ + uint64_t code; + int idx; +} code_info_t; + +static void show_event_info_compact(pfm_event_info_t *info); + +static const char *srcs[PFM_ATTR_CTRL_MAX] = { + [PFM_ATTR_CTRL_UNKNOWN] = "???", + [PFM_ATTR_CTRL_PMU] = "PMU", + [PFM_ATTR_CTRL_PERF_EVENT] = "perf_event", +}; + +#ifdef PFMLIB_WINDOWS +int set_env_var(const char *var, const char *value, int ov) +{ + size_t len; + char *str; + int ret; + + len = strlen(var) + 1 + strlen(value) + 1; + + str = malloc(len); + if (!str) + return PFM_ERR_NOMEM; + + sprintf(str, "%s=%s", var, value); + + ret = putenv(str); + + free(str); + + return ret ? PFM_ERR_INVAL : PFM_SUCCESS; +} +#else +static inline int +set_env_var(const char *var, const char *value, int ov) +{ + return setenv(var, value, ov); +} +#endif + +static int +event_has_pname(char *s) +{ + char *p; + return (p = strchr(s, ':')) && *(p + 1) == ':'; +} + +static int +print_codes(char *buf, int plm, int max_encoding) +{ + uint64_t *codes = NULL; + int j, ret, count = 0; + + ret = pfm_get_event_encoding(buf, PFM_PLM0 | PFM_PLM3, NULL, NULL, &codes, &count); + if (ret != PFM_SUCCESS) + { + if (ret == PFM_ERR_NOTFOUND) + errx(1, "encoding failed, try setting env variable LIBPFM_ENCODE_INACTIVE=1"); + return -1; + } + for (j = 0; j < max_encoding; j++) + { + if (j < count) + printf("0x%" PRIx64, codes[j]); + printf("%s", options.csv_sep); + } + free(codes); + return 0; +} + +static int +check_valid(char *buf, int plm) +{ + uint64_t *codes = NULL; + int ret, count = 0; + + ret = pfm_get_event_encoding(buf, PFM_PLM0 | PFM_PLM3, NULL, NULL, &codes, &count); + if (ret != PFM_SUCCESS) + return -1; + free(codes); + return 0; +} + +static int +match_ufilters(pfm_event_attr_info_t *info) +{ + uint32_t ufilter1 = 0; + uint32_t ufilter2 = 0; + + if (options.ufilter.is_dfl) + ufilter1 |= 0x1; + + if (info->is_dfl) + ufilter2 |= 0x1; + + if (options.ufilter.is_precise) + ufilter1 |= 0x2; + + if (info->is_precise) + ufilter2 |= 0x2; + + if (!ufilter1) + return 1; + + /* at least one filter matches */ + return ufilter1 & ufilter2; +} + +static int +match_efilters(pfm_event_info_t *info) +{ + pfm_event_attr_info_t ainfo; + int n = 0; + int i, ret; + + if (options.efilter.is_precise && !info->is_precise) + return 0; + + memset(&ainfo, 0, sizeof(ainfo)); + ainfo.size = sizeof(ainfo); + + pfm_for_each_event_attr(i, info) + { + ret = pfm_get_event_attr_info(info->idx, i, options.os, &ainfo); + if (ret != PFM_SUCCESS) + continue; + if (match_ufilters(&ainfo)) + return 1; + if (ainfo.type == PFM_ATTR_UMASK) + n++; + } + return n ? 0 : 1; +} + +static void +show_event_info_combo(pfm_event_info_t *info) +{ + pfm_event_attr_info_t *ainfo; + pfm_pmu_info_t pinfo; + char buf[MAXBUF]; + size_t len; + int numasks = 0; + int i, j, ret; + uint64_t total, m, u; + + memset(&pinfo, 0, sizeof(pinfo)); + + pinfo.size = sizeof(pinfo); + + ret = pfm_get_pmu_info(info->pmu, &pinfo); + if (ret != PFM_SUCCESS) + errx(1, "cannot get PMU info"); + + ainfo = calloc(info->nattrs, sizeof(*ainfo)); + if (!ainfo) + err(1, "event %s : ", info->name); + + /* + * extract attribute information and count number + * of umasks + * + * we cannot just drop non umasks because we need + * to keep attributes in order for the enumeration + * of 2^n + */ + pfm_for_each_event_attr(i, info) + { + ainfo[i].size = sizeof(*ainfo); + + ret = pfm_get_event_attr_info(info->idx, i, options.os, &ainfo[i]); + if (ret != PFM_SUCCESS) + errx(1, "cannot get attribute info: %s", pfm_strerror(ret)); + + if (ainfo[i].type == PFM_ATTR_UMASK) + numasks++; + } + if (numasks > options.combo_lim) + { + warnx("event %s has too many umasks to print all combinations, dropping to simple enumeration", info->name); + free(ainfo); + show_event_info_compact(info); + return; + } + + if (numasks) + { + if (info->nattrs > (int)((sizeof(total) << 3))) + { + warnx("too many umasks, cannot show all combinations for event %s", info->name); + goto end; + } + total = 1ULL << info->nattrs; + + for (u = 1; u < total; u++) + { + len = sizeof(buf); + len -= snprintf(buf, len, "%s::%s", pinfo.name, info->name); + if (len <= 0) + { + warnx("event name too long%s", info->name); + goto end; + } + for (m = u, j = 0; m; m >>= 1, j++) + { + if (m & 0x1ULL) + { + /* we have hit a non umasks attribute, skip */ + if (ainfo[j].type != PFM_ATTR_UMASK) + break; + + if (len < (1 + strlen(ainfo[j].name))) + { + warnx("umasks combination too long for event %s", buf); + break; + } + strncat(buf, ":", len - 1); + buf[len - 1] = '\0'; + len--; + strncat(buf, ainfo[j].name, len - 1); + buf[len - 1] = '\0'; + len -= strlen(ainfo[j].name); + } + } + /* if found a valid umask combination, check encoding */ + if (m == 0) + { + if (options.encode) + ret = print_codes(buf, PFM_PLM0 | PFM_PLM3, pinfo.max_encoding); + else + ret = check_valid(buf, PFM_PLM0 | PFM_PLM3); + if (!ret) + printf("%s\n", buf); + } + } + } + else + { + snprintf(buf, sizeof(buf) - 1, "%s::%s", pinfo.name, info->name); + buf[sizeof(buf) - 1] = '\0'; + + ret = options.encode ? print_codes(buf, PFM_PLM0 | PFM_PLM3, pinfo.max_encoding) : 0; + if (!ret) + printf("%s\n", buf); + } +end: + free(ainfo); +} + +static void +show_event_info_compact(pfm_event_info_t *info) +{ + pfm_event_attr_info_t ainfo; + pfm_pmu_info_t pinfo; + char buf[MAXBUF]; + int i, ret, um = 0; + + memset(&ainfo, 0, sizeof(ainfo)); + memset(&pinfo, 0, sizeof(pinfo)); + + pinfo.size = sizeof(pinfo); + ainfo.size = sizeof(ainfo); + + ret = pfm_get_pmu_info(info->pmu, &pinfo); + if (ret != PFM_SUCCESS) + errx(1, "cannot get pmu info: %s", pfm_strerror(ret)); + + if (options.name_only) + { + if (options.encode) + printf("0x%-10" PRIx64, info->code); + printf("%s\n", info->name); + return; + } + pfm_for_each_event_attr(i, info) + { + ret = pfm_get_event_attr_info(info->idx, i, options.os, &ainfo); + if (ret != PFM_SUCCESS) + errx(1, "cannot get attribute info: %s", pfm_strerror(ret)); + + if (ainfo.type != PFM_ATTR_UMASK) + continue; + + if (!match_ufilters(&ainfo)) + continue; + + snprintf(buf, sizeof(buf) - 1, "%s::%s:%s", pinfo.name, info->name, ainfo.name); + buf[sizeof(buf) - 1] = '\0'; + + ret = 0; + if (options.encode) + { + ret = print_codes(buf, PFM_PLM0 | PFM_PLM3, pinfo.max_encoding); + } + if (!ret) + { + printf("%s", buf); + if (options.desc) + { + printf("%s", options.csv_sep); + printf("\"%s. %s.\"", info->desc, ainfo.desc); + } + putchar('\n'); + } + um++; + } + if (um == 0) + { + if (!match_efilters(info)) + return; + + snprintf(buf, sizeof(buf) - 1, "%s::%s", pinfo.name, info->name); + buf[sizeof(buf) - 1] = '\0'; + if (options.encode) + { + ret = print_codes(buf, PFM_PLM0 | PFM_PLM3, pinfo.max_encoding); + if (ret) + return; + } + printf("%s", buf); + if (options.desc) + { + printf("%s", options.csv_sep); + printf("\"%s.\"", info->desc); + } + putchar('\n'); + } +} + +int compare_codes(const void *a, const void *b) +{ + const code_info_t *aa = a; + const code_info_t *bb = b; + uint64_t m = options.mask; + + if ((aa->code & m) < (bb->code & m)) + return -1; + if ((aa->code & m) == (bb->code & m)) + return 0; + return 1; +} + +static void +print_event_flags(pfm_event_info_t *info) +{ + int n = 0; + int spec = info->is_speculative; + + if (info->is_precise) + { + printf("[precise] "); + n++; + } + + if (info->support_hw_smpl) + { + printf("[hw_smpl] "); + n++; + } + + if (spec > PFM_EVENT_INFO_SPEC_NA) + { + printf("[%s] ", spec == PFM_EVENT_INFO_SPEC_TRUE ? "speculative" : "non-speculative"); + n++; + } + + if (!n) + printf("None"); +} + +static void +print_attr_flags(pfm_event_attr_info_t *info) +{ + int n = 0; + int spec = info->is_speculative; + + if (info->is_dfl) + { + printf("[default] "); + n++; + } + + if (info->is_precise) + { + printf("[precise] "); + n++; + } + + if (info->support_hw_smpl) + { + printf("[hw_smpl] "); + n++; + } + + if (spec > PFM_EVENT_INFO_SPEC_NA) + { + printf("[%s] ", spec == PFM_EVENT_INFO_SPEC_TRUE ? "speculative" : "non-speculative"); + n++; + } + + if (!n) + printf("None "); +} + +static void +show_event_info(pfm_event_info_t *info) +{ + pfm_event_attr_info_t ainfo; + pfm_pmu_info_t pinfo; + int mod = 0, um = 0; + int i, ret; + const char *src; + + if (options.name_only) + { + printf("%s\n", info->name); + return; + } + + memset(&ainfo, 0, sizeof(ainfo)); + memset(&pinfo, 0, sizeof(pinfo)); + + pinfo.size = sizeof(pinfo); + ainfo.size = sizeof(ainfo); + + if (!match_efilters(info)) + return; + ret = pfm_get_pmu_info(info->pmu, &pinfo); + if (ret) + errx(1, "cannot get pmu info: %s", pfm_strerror(ret)); + + printf("#-----------------------------\n" + "IDX : %d\n" + "PMU name : %s (%s)\n" + "Name : %s\n" + "Equiv : %s\n", + info->idx, + pinfo.name, + pinfo.desc, + info->name, + info->equiv ? info->equiv : "None"); + + printf("Flags : "); + print_event_flags(info); + putchar('\n'); + + printf("Desc : %s\n", info->desc ? info->desc : "no description available"); + printf("Code : 0x%" PRIx64 "\n", info->code); + + pfm_for_each_event_attr(i, info) + { + ret = pfm_get_event_attr_info(info->idx, i, options.os, &ainfo); + if (ret != PFM_SUCCESS) + errx(1, "cannot retrieve event %s attribute info: %s", info->name, pfm_strerror(ret)); + + if (ainfo.ctrl >= PFM_ATTR_CTRL_MAX) + { + warnx("event: %s has unsupported attribute source %d", info->name, ainfo.ctrl); + ainfo.ctrl = PFM_ATTR_CTRL_UNKNOWN; + } + src = srcs[ainfo.ctrl]; + switch (ainfo.type) + { + case PFM_ATTR_UMASK: + if (!match_ufilters(&ainfo)) + continue; + + printf("Umask-%02u : 0x%02" PRIx64 " : %s : [%s] : ", + um, + ainfo.code, + src, + ainfo.name); + + print_attr_flags(&ainfo); + + putchar(':'); + + if (ainfo.equiv) + printf(" Alias to %s", ainfo.equiv); + else + printf(" %s", ainfo.desc); + + putchar('\n'); + um++; + break; + case PFM_ATTR_MOD_BOOL: + printf("Modif-%02u : 0x%02" PRIx64 " : %s : [%s] : %s (boolean)\n", mod, ainfo.code, src, ainfo.name, ainfo.desc); + mod++; + break; + case PFM_ATTR_MOD_INTEGER: + printf("Modif-%02u : 0x%02" PRIx64 " : %s : [%s] : %s (integer)\n", mod, ainfo.code, src, ainfo.name, ainfo.desc); + mod++; + break; + default: + printf("Attr-%02u : 0x%02" PRIx64 " : %s : [%s] : %s\n", i, ainfo.code, ainfo.name, src, ainfo.desc); + } + } +} + +static int +show_info(char *event, regex_t *preg) +{ + pfm_pmu_info_t pinfo; + pfm_event_info_t info; + pfm_pmu_t j; + int i, ret, match = 0, pname; + size_t len, l = 0; + char *fullname = NULL; + + memset(&pinfo, 0, sizeof(pinfo)); + memset(&info, 0, sizeof(info)); + + pinfo.size = sizeof(pinfo); + info.size = sizeof(info); + + pname = event_has_pname(event); + + /* + * scan all supported events, incl. those + * from undetected PMU models + */ + pfm_for_all_pmus(j) + { + + ret = pfm_get_pmu_info(j, &pinfo); + if (ret != PFM_SUCCESS) + continue; + + /* no pmu prefix, just look for detected PMU models */ + if (!pname && !pinfo.is_present) + continue; + + for (i = pinfo.first_event; i != -1; i = pfm_get_event_next(i)) + { + ret = pfm_get_event_info(i, options.os, &info); + if (ret != PFM_SUCCESS) + errx(1, "cannot get event info: %s", pfm_strerror(ret)); + + len = strlen(info.name) + strlen(pinfo.name) + 1 + 2; + if (len > l) + { + l = len; + fullname = realloc(fullname, l); + if (!fullname) + err(1, "cannot allocate memory"); + } + sprintf(fullname, "%s::%s", pinfo.name, info.name); + + if (regexec(preg, fullname, 0, NULL, 0) == 0) + { + if (options.compact) + if (options.combo) + show_event_info_combo(&info); + else + show_event_info_compact(&info); + else + show_event_info(&info); + match++; + } + } + } + if (fullname) + free(fullname); + + return match; +} + +static int +show_info_sorted(char *event, regex_t *preg) +{ + pfm_pmu_info_t pinfo; + pfm_event_info_t info; + pfm_pmu_t j; + int i, ret, n, match = 0; + size_t len, l = 0; + char *fullname = NULL; + code_info_t *codes; + + memset(&pinfo, 0, sizeof(pinfo)); + memset(&info, 0, sizeof(info)); + + pinfo.size = sizeof(pinfo); + info.size = sizeof(info); + + pfm_for_all_pmus(j) + { + + ret = pfm_get_pmu_info(j, &pinfo); + if (ret != PFM_SUCCESS) + continue; + + codes = malloc(pinfo.nevents * sizeof(*codes)); + if (!codes) + err(1, "cannot allocate memory\n"); + + /* scans all supported events */ + n = 0; + for (i = pinfo.first_event; i != -1; i = pfm_get_event_next(i)) + { + + ret = pfm_get_event_info(i, options.os, &info); + if (ret != PFM_SUCCESS) + errx(1, "cannot get event info: %s", pfm_strerror(ret)); + + if (info.pmu != j) + continue; + + codes[n].idx = info.idx; + codes[n].code = info.code; + n++; + } + qsort(codes, n, sizeof(*codes), compare_codes); + for (i = 0; i < n; i++) + { + ret = pfm_get_event_info(codes[i].idx, options.os, &info); + if (ret != PFM_SUCCESS) + errx(1, "cannot get event info: %s", pfm_strerror(ret)); + + len = strlen(info.name) + strlen(pinfo.name) + 1 + 2; + if (len > l) + { + l = len; + fullname = realloc(fullname, l); + if (!fullname) + err(1, "cannot allocate memory"); + } + sprintf(fullname, "%s::%s", pinfo.name, info.name); + + if (regexec(preg, fullname, 0, NULL, 0) == 0) + { + if (options.compact) + show_event_info_compact(&info); + else + show_event_info(&info); + match++; + } + } + free(codes); + } + if (fullname) + free(fullname); + + return match; +} + +static void +usage(void) +{ + printf("showevtinfo [-L] [-E] [-h] [-s] [-m mask]\n" + "-L\t\tlist one event per line (compact mode)\n" + "-E\t\tlist one event per line with encoding (compact mode)\n" + "-M\t\tdisplay all valid unit masks combination (use with -L or -E)\n" + "-h\t\tget help\n" + "-s\t\tsort event by PMU and by code based on -m mask\n" + "-l\t\tmaximum number of umasks to list all combinations (default: %d)\n" + "-F\t\tshow only events and attributes with certain flags (precise,...)\n" + "-m mask\t\thexadecimal event code mask, bits to match when sorting\n" + "-x sep\t\tuse sep as field separator in compact mode\n" + "-D\t\t\tprint event description in compact mode\n" + "-O os\t\tshow attributes for the specific operating system\n", + COMBO_MAX); +} + +/* + * keep: [pmu::]event + * drop everything else + */ +static void +drop_event_attributes(char *str) +{ + char *p; + + p = strchr(str, ':'); + if (!p) + return; + + str = p + 1; + /* keep PMU name */ + if (*str == ':') + str++; + + /* stop string at 1st attribute */ + p = strchr(str, ':'); + if (p) + *p = '\0'; +} + +#define EVENT_FLAGS(n, f, l) \ + { \ + .name = n, .ebit = f, .ubit = l \ + } +struct attr_flags +{ + const char *name; + int ebit; /* bit position in pfm_event_info_t.flags, -1 means ignore */ + int ubit; /* bit position in pfm_event_attr_info_t.flags, -1 means ignore */ +}; + +static const struct attr_flags event_flags[] = { + EVENT_FLAGS("precise", 0, 1), + EVENT_FLAGS("pebs", 0, 1), + EVENT_FLAGS("default", -1, 0), + EVENT_FLAGS("dfl", -1, 0), + EVENT_FLAGS(NULL, 0, 0)}; + +static void +parse_filters(char *arg) +{ + const struct attr_flags *attr; + char *p; + + while (arg) + { + p = strchr(arg, ','); + if (p) + *p++ = 0; + + for (attr = event_flags; attr->name; attr++) + { + if (!strcasecmp(attr->name, arg)) + { + switch (attr->ebit) + { + case 0: + options.efilter.is_precise = 1; + break; + case -1: + break; + default: + errx(1, "unknown event flag %d", attr->ebit); + } + switch (attr->ubit) + { + case 0: + options.ufilter.is_dfl = 1; + break; + case 1: + options.ufilter.is_precise = 1; + break; + case -1: + break; + default: + errx(1, "unknown umaks flag %d", attr->ubit); + } + break; + } + } + arg = p; + } +} + +static const struct +{ + char *name; + pfm_os_t os; +} supported_oses[] = { + {.name = "none", .os = PFM_OS_NONE}, + {.name = "raw", .os = PFM_OS_NONE}, + {.name = "pmu", .os = PFM_OS_NONE}, + + {.name = "perf", .os = PFM_OS_PERF_EVENT}, + {.name = "perf_ext", .os = PFM_OS_PERF_EVENT_EXT}, + { + .name = NULL, + }}; + +static const char *pmu_types[] = { + "unknown type", + "core", + "uncore", + "OS generic", +}; + +static void +setup_os(char *ostr) +{ + int i; + + for (i = 0; supported_oses[i].name; i++) + { + if (!strcmp(supported_oses[i].name, ostr)) + { + options.os = supported_oses[i].os; + return; + } + } + fprintf(stderr, "unknown OS layer %s, choose from:", ostr); + for (i = 0; supported_oses[i].name; i++) + { + if (i) + fputc(',', stderr); + fprintf(stderr, " %s", supported_oses[i].name); + } + fputc('\n', stderr); + exit(1); +} + +int main(int argc, char **argv) +{ + static char *argv_all[2] = {".*", NULL}; + pfm_pmu_info_t pinfo; + char *endptr = NULL; + char default_sep[2] = "\t"; + char *ostr = NULL; + char **args; + pfm_pmu_t i; + int match; + regex_t preg; + int ret, c; + + memset(&pinfo, 0, sizeof(pinfo)); + + pinfo.size = sizeof(pinfo); + + while ((c = getopt(argc, argv, "hELsm:MNl:F:x:DO:")) != -1) + { + switch (c) + { + case 'L': + options.compact = 1; + break; + case 'F': + parse_filters(optarg); + break; + case 'E': + options.compact = 1; + options.encode = 1; + break; + case 'M': + options.combo = 1; + break; + case 'N': + options.name_only = 1; + break; + case 's': + options.sort = 1; + break; + case 'D': + options.desc = 1; + break; + case 'l': + options.combo_lim = atoi(optarg); + break; + case 'x': + options.csv_sep = optarg; + break; + case 'O': + ostr = optarg; + break; + case 'm': + options.mask = strtoull(optarg, &endptr, 16); + if (*endptr) + errx(1, "mask must be in hexadecimal\n"); + break; + case 'h': + usage(); + exit(0); + default: + errx(1, "unknown option error"); + } + } + /* to allow encoding of events from non detected PMU models */ + ret = set_env_var("LIBPFM_ENCODE_INACTIVE", "1", 1); + if (ret != PFM_SUCCESS) + errx(1, "cannot force inactive encoding"); + + ret = pfm_initialize(); + if (ret != PFM_SUCCESS) + errx(1, "cannot initialize libpfm: %s", pfm_strerror(ret)); + + if (options.mask == 0) + options.mask = ~0; + + if (optind == argc) + { + args = argv_all; + } + else + { + args = argv + optind; + } + if (!options.csv_sep) + options.csv_sep = default_sep; + + /* avoid combinatorial explosion */ + if (options.combo_lim == 0) + options.combo_lim = COMBO_MAX; + + if (ostr) + setup_os(ostr); + else + options.os = PFM_OS_NONE; + + if (!options.compact) + { + int total_supported_events = 0; + int total_available_events = 0; + + printf("Supported PMU models:\n"); + pfm_for_all_pmus(i) + { + ret = pfm_get_pmu_info(i, &pinfo); + if (ret != PFM_SUCCESS) + continue; + + printf("\t[%d, %s, \"%s\"]\n", i, pinfo.name, pinfo.desc); + } + + printf("Detected PMU models:\n"); + pfm_for_all_pmus(i) + { + ret = pfm_get_pmu_info(i, &pinfo); + if (ret != PFM_SUCCESS) + continue; + + if (pinfo.is_present) + { + if (pinfo.type >= PFM_PMU_TYPE_MAX) + pinfo.type = PFM_PMU_TYPE_UNKNOWN; + + printf("\t[%d, %s, \"%s\", %d events, %d max encoding, %d counters, %s PMU]\n", + i, + pinfo.name, + pinfo.desc, + pinfo.nevents, + pinfo.max_encoding, + pinfo.num_cntrs + pinfo.num_fixed_cntrs, + pmu_types[pinfo.type]); + + total_supported_events += pinfo.nevents; + } + total_available_events += pinfo.nevents; + } + printf("Total events: %d available, %d supported\n", total_available_events, total_supported_events); + } + + while (*args) + { + /* drop umasks and modifiers */ + drop_event_attributes(*args); + if (regcomp(&preg, *args, REG_ICASE)) + errx(1, "error in regular expression for event \"%s\"", *argv); + + if (options.sort) + match = show_info_sorted(*args, &preg); + else + match = show_info(*args, &preg); + + if (match == 0) + errx(1, "event %s not found", *args); + + args++; + } + + regfree(&preg); + + pfm_terminate(); + + return 0; +} diff --git a/repos/mml/src/app/libpfm_test/target.mk b/repos/mml/src/app/libpfm_test/target.mk new file mode 100644 index 0000000000..5134b51d97 --- /dev/null +++ b/repos/mml/src/app/libpfm_test/target.mk @@ -0,0 +1,5 @@ +TARGET = libpfm_test +SRC_CC = check_events.c +LIBS += base posix libm libc stdcxx libpfm4 +CC_OPT += -Wno-error -Wno-permissive -fpermissive + diff --git a/repos/mml/src/app/thread_test/target.mk b/repos/mml/src/app/thread_test/target.mk index 79ffb18ea9..55f1259a48 100644 --- a/repos/mml/src/app/thread_test/target.mk +++ b/repos/mml/src/app/thread_test/target.mk @@ -1,4 +1,4 @@ TARGET = thread_test SRC_CC = thread_test.cc -LIBS += base stdcxx +LIBS += base libc stdcxx CXXFLAGS += -Wno-error