Add PMU support for the CPU-measurement counter facility available for Linux on System z instances. The CPU-measurement counter facility provides multiple counter sets for measuring generic, problem-state, and crypto activaties. Also an extended counter set for the IBM System z10 and IBM z196 mainframes is available.
Signed-off-by: Hendrik Brueckner <brueck...@linux.vnet.ibm.com> --- config.mk | 4 + include/perfmon/pfmlib.h | 2 + lib/Makefile | 14 + lib/events/s390x_cpumf_events.h | 562 +++++++++++++++++++++++++++++++++++++++ lib/pfmlib_common.c | 3 + lib/pfmlib_priv.h | 1 + lib/pfmlib_s390x_cpumf.c | 265 ++++++++++++++++++ lib/pfmlib_s390x_perf_event.c | 52 ++++ lib/pfmlib_s390x_priv.h | 15 + 9 files changed, 918 insertions(+), 0 deletions(-) create mode 100644 lib/events/s390x_cpumf_events.h create mode 100644 lib/pfmlib_s390x_cpumf.c create mode 100644 lib/pfmlib_s390x_perf_event.c create mode 100644 lib/pfmlib_s390x_priv.h diff --git a/config.mk b/config.mk index 29d848f..9e5504c 100644 --- a/config.mk +++ b/config.mk @@ -146,6 +146,10 @@ ifeq ($(ARCH),arm) CONFIG_PFMLIB_ARCH_ARM=y endif +ifeq ($(ARCH),s390x) +CONFIG_PFMLIB_ARCH_S390X=y +endif + ifeq ($(XTPE_COMPILE_TARGET),linux) CONFIG_PFMLIB_ARCH_CRAYXT=y endif diff --git a/include/perfmon/pfmlib.h b/include/perfmon/pfmlib.h index 6af4328..b122ca5 100644 --- a/include/perfmon/pfmlib.h +++ b/include/perfmon/pfmlib.h @@ -178,6 +178,8 @@ typedef enum { PFM_PMU_INTEL_SNBEP_UNC_R3QPI1, /* Intel SandyBridge-EP R3QPI 1 uncore */ PFM_PMU_INTEL_KNC, /* Intel Knights Corner (Xeon Phi) */ + PFM_PMU_S390X_CPUM_CF, /* s390x: CPU-M counter facility */ + /* MUST ADD NEW PMU MODELS HERE */ PFM_PMU_MAX /* end marker */ diff --git a/lib/Makefile b/lib/Makefile index 3d36063..d2f00a9 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -98,6 +98,17 @@ SRCS += pfmlib_powerpc.c pfmlib_power4.c pfmlib_ppc970.c pfmlib_power5.c pfmli 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) @@ -216,6 +227,9 @@ INC_POWERPC=events/ppc970_events.h \ events/power7_events.h \ events/torrent_events.h +INC_S390X=pfmlib_s390x_priv.h \ + events/s390x_cpumf_events.h + INC_SPARC=events/sparc_ultra12_events.h \ events/sparc_ultra3_events.h \ events/sparc_ultra3plus_events.h \ diff --git a/lib/events/s390x_cpumf_events.h b/lib/events/s390x_cpumf_events.h new file mode 100644 index 0000000..9628cee --- /dev/null +++ b/lib/events/s390x_cpumf_events.h @@ -0,0 +1,562 @@ +#ifndef __S390X_CPUMF_EVENTS_H__ +#define __S390X_CPUMF_EVENTS_H__ + + +#define __stringify(x) #x +#define STRINGIFY(x) __stringify(x) + +/* CPUMF counter sets */ +#define CPUMF_CTRSET_BASIC 0 +#define CPUMF_CTRSET_PROBLEM_STATE 1 +#define CPUMF_CTRSET_CRYPTO 2 +#define CPUMF_CTRSET_EXTENDED 3 + + +static const pme_cpumf_ctr_t cpumf_generic_ctr[] = { + /* Basic counter set */ + { + .ctrnum = 0, + .ctrset = CPUMF_CTRSET_BASIC, + .name = "CPU_CYCLES", + .desc = "Cycle Count", + }, + { + .ctrnum = 1, + .ctrset = CPUMF_CTRSET_BASIC, + .name = "INSTRUCTIONS", + .desc = "Instruction Count", + }, + { + .ctrnum = 2, + .ctrset = CPUMF_CTRSET_BASIC, + .name = "L1I_DRCT_WRITES", + .desc = "Level-1 I-Cache Directory Write Count", + }, + { + .ctrnum = 3, + .ctrset = CPUMF_CTRSET_BASIC, + .name = "L1I_PENALTY_CYCLES", + .desc = "Level-1 I-Cache Penalty Cycle Count", + }, + { + .ctrnum = 4, + .ctrset = CPUMF_CTRSET_BASIC, + .name = "L1D_DRCT_WRITES", + .desc = "Level-1 D-Cache Directory Write Count", + }, + { + .ctrnum = 5, + .ctrset = CPUMF_CTRSET_BASIC, + .name = "L1D_PENALTY_CYCLES", + .desc = "Level-1 D-Cache Penalty Cycle Count", + }, + /* Problem-state counter set */ + { + .ctrnum = 32, + .ctrset = CPUMF_CTRSET_PROBLEM_STATE, + .name = "PROBLEM_STATE_CPU_CYCLES", + .desc = "Problem-State Cycle Count", + }, + { + .ctrnum = 33, + .ctrset = CPUMF_CTRSET_PROBLEM_STATE, + .name = "PROBLEM_STATE_INSTRUCTIONS", + .desc = "Problem-State Instruction Count", + }, + { + .ctrnum = 34, + .ctrset = CPUMF_CTRSET_PROBLEM_STATE, + .name = "PROBLEM_STATE_L1I_DRCT_WRITES", + .desc = "Problem-State Level-1 I-Cache Directory Write Count", + }, + { + .ctrnum = 35, + .ctrset = CPUMF_CTRSET_PROBLEM_STATE, + .name = "PROBLEM_STATE_L1I_PENALTY_CYCLES", + .desc = "Problem-State Level-1 I-Cache Penalty Cycle Count", + }, + { + .ctrnum = 36, + .ctrset = CPUMF_CTRSET_PROBLEM_STATE, + .name = "PROBLEM_STATE_L1D_DRCT_WRITES", + .desc = "Problem-State Level-1 D-Cache Directory Write Count", + }, + { + .ctrnum = 37, + .ctrset = CPUMF_CTRSET_PROBLEM_STATE, + .name = "PROBLEM_STATE_L1D_PENALTY_CYCLES", + .desc = "Problem-State Level-1 D-Cache Penalty Cycle Count", + }, + /* Crypto-activity counter set */ + { + .ctrnum = 64, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "PRNG_FUNCTIONS", + .desc = "Total number of the PRNG functions issued by the CPU", + }, + { + .ctrnum = 65, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "PRNG_CYCLES", + .desc = "Total number of CPU cycles when the DEA/AES " + "coprocessor is busy performing PRNG functions " + "issued by the CPU", + }, + { + .ctrnum = 66, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "PRNG_BLOCKED_FUNCTIONS", + .desc = "Total number of the PRNG functions that are issued " + "by the CPU and are blocked because the DEA/AES " + "coprocessor is busy performing a function issued " + "by another CPU", + }, + { + .ctrnum = 67, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "PRNG_BLOCKED_CYCLES", + .desc = "Total number of CPU cycles blocked for the PRNG " + "functions issued by the CPU because the DEA/AES " + "coprocessor is busy performing a function issued " + "by another CPU", + }, + { + .ctrnum = 68, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "SHA_FUNCTIONS", + .desc = "Total number of SHA functions issued by the CPU", + }, + { + .ctrnum = 69, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "SHA_CYCLES", + .desc = "Total number of CPU cycles when the SHA coprocessor " + "is busy performing the SHA functions issued by the " + "CPU", + }, + { + .ctrnum = 70, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "SHA_BLOCKED_FUNCTIONS", + .desc = "Total number of the SHA functions that are issued by " + "the CPU and are blocked because the SHA coprocessor " + "is busy performing a function issued by another CPU", + }, + { + .ctrnum = 71, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "SHA_BLOCKED_CYCLES", + .desc = "Total number of CPU cycles blocked for the SHA " + "functions issued by the CPU because the SHA " + "coprocessor is busy performing a function issued by " + "another CPU", + }, + { + .ctrnum = 72, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "DEA_FUNCTIONS", + .desc = "Total number of the DEA functions issued by the CPU", + }, + { + .ctrnum = 73, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "DEA_CYCLES", + .desc = "Total number of CPU cycles when the DEA/AES coprocessor" + " is busy performing the DEA functions issued by the CPU", + }, + { + .ctrnum = 74, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "DEA_BLOCKED_FUNCTIONS", + .desc = "Total number of the DEA functions that are issued by " + "the CPU and are blocked because the DEA/AES coprocessor" + " is busy performing a function issued by another CPU", + }, + { + .ctrnum = 75, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "DEA_BLOCKED_CYCLES", + .desc = "Total number of CPU cycles blocked for the DEA functions" + " issued by the CPU because the DEA/AES coprocessor is " + "busy performing a function issued by another CPU", + }, + { + .ctrnum = 76, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "AES_FUNCTIONS", + .desc = "Total number of AES functions issued by the CPU", + }, + { + .ctrnum = 77, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "AES_CYCLES", + .desc = "Total number of CPU cycles when the DEA/AES coprocessor" + " is busy performing the AES functions issued by the CPU", + }, + { + .ctrnum = 78, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "AES_BLOCKED_FUNCTIONS", + .desc = "Total number of AES functions that are issued by the CPU" + " and are blocked because the DEA/AES coprocessor is" + " busy performing a function issued by another CPU", + }, + { + .ctrnum = 79, + .ctrset = CPUMF_CTRSET_CRYPTO, + .name = "AES_BLOCKED_CYCLES", + .desc = "Total number of CPU cycles blocked for the AES functions" + " issued by the CPU because the DEA/AES coprocessor is" + " busy performing a function issued by another CPU", + }, +}; + +/* Extended counter set for IBM System z10 */ +static const pme_cpumf_ctr_t cpumf_ctr_set_ext_z10[] = { + { + .ctrnum = 128, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_L2_SOURCED_WRITES", + .desc = "A directory write to the Level-1 I-Cache directory" + " where the returned cache line was sourced from the" + " Level-2 (L1.5) cache", + }, + { + .ctrnum = 129, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_L2_SOURCED_WRITES", + .desc = "A directory write to the Level-1 D-Cache directory" + " where the installed cache line was sourced from the" + " Level-2 (L1.5) cache", + }, + { + .ctrnum = 130, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_L3_LOCAL_WRITES", + .desc = "A directory write to the Level-1 I-Cache directory" + " where the installed cache line was sourced from the" + " Level-3 cache that is on the same book as the" + " Instruction cache (Local L2 cache)", + }, + { + .ctrnum = 131, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_L3_LOCAL_WRITES", + .desc = "A directory write to the Level-1 D-Cache directory" + " where the installtion cache line was source from the" + " Level-3 cache that is on the same book as the Data" + " cache (Local L2 cache)", + }, + { + .ctrnum = 132, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_L3_REMOTE_WRITES", + .desc = "A directory write to the Level-1 I-Cache directory" + " where the installed cache line was sourced from a" + " Level-3 cache that is not on the same book as the" + " Instruction cache (Remote L2 cache)", + }, + { + .ctrnum = 133, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_L3_REMOTE_WRITES", + .desc = "A directory write to the Level-1 D-Cache directory" + " where the installed cache line was sourced from a" + " Level-3 cache that is not on the same book as the" + " Data cache (Remote L2 cache)", + }, + { + .ctrnum = 134, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_LMEM_SOURCED_WRITES", + .desc = "A directory write to the Level-1 D-Cache directory" + " where the installed cache line was sourced from" + " memory that is attached to the same book as the" + " Data cache (Local Memory)", + }, + { + .ctrnum = 135, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_LMEM_SOURCED_WRITES", + .desc = "A directory write to the Level-1 I-Cache where the" + " installed cache line was sourced from memory that" + " is attached to the s ame book as the Instruction" + " cahe (local Memory)", + }, + { + .ctrnum = 136, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_RO_EXCL_WRITES", + .desc = "A directory write to the Level-1 D-Cache where the" + " line was originally in a Read-Only state in the" + " cache but has been updated to be in the Exclusive" + " state that allows stores to the cache line", + }, + { + .ctrnum = 137, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_CACHELINE_INVALIDATES", + .desc = "A cache line in the Level-1 I-Cache has been" + " invalidated by a store on the same CPU as the Level-1" + " I-Cache", + }, + { + .ctrnum = 138, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "ITLB1_WRITES", + .desc = "A translation entry has been written into the Level-1" + " Instruction Translation Lookaside Buffer", + }, + { + .ctrnum = 139, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "DTLB1_WRITES", + .desc = "A translation entry has been written to the Level-1" + " Data Translation Lookaside Buffer", + }, + { + .ctrnum = 140, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "TLB2_PTE_WRITES", + .desc = "A translation entry has been written to the Level-2" + " TLB Page Table Entry arrays", + }, + { + .ctrnum = 141, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "TLB2_CRSTE_WRITES", + .desc = "A translation entry has been written to the Level-2" + " TLB Common Region Segment Table Entry arrays", + }, + { + .ctrnum = 142, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "TLB2_CRSTE_HPAGE_WRITES", + .desc = "A translation entry has been written to the Level-2" + " TLB Common Region Segment Table Entry arrays for a" + " one-megabyte large page translation", + }, + { + .ctrnum = 145, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "ITLB1_MISSES", + .desc = "Level-1 Instruction TLB miss in progress. Incremented" + " by one for every cycle an ITLB1 miss is in progress", + }, + { + .ctrnum = 146, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "DTLB1_MISSES", + .desc = "Level-1 Data TLB miss in progress. Incremented by one" + " for every cycle an DTLB1 miss is in progress", + }, + { + .ctrnum = 147, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L2C_STORES_SENT", + .desc = "Incremented by one for every store sent to" + " Level-2 (L1.5) cache", + }, +}; + +/* Extended counter set for IBM zEnterprise 196 */ +static const pme_cpumf_ctr_t cpumf_ctr_set_ext_z196[] = { + { + .ctrnum = 128, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_L2_SOURCED_WRITES", + .desc = "A directory write to the Level-1 D-Cache directory" + " where the returned cache line was sourced from the" + " Level-2 cache", + }, + { + .ctrnum = 129, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_L2_SOURCED_WRITES", + .desc = "A directory write to the Level-1 I-Cache directory" + " where the returned cache line was sourced from" + " the Level-2 cache", + }, + { + .ctrnum = 130, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "DTLB1_MISSES", + .desc = "Level-1 Data TLB miss in progress. Incremented by one" + " for every cycle a DTLB1 miss is in progress.", + }, + { + .ctrnum = 131, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "ITLB1_MISSES", + .desc = "Level-1 Instruction TLB miss in progress. Incremented" + " by one for every cycle a ITLB1 miss is in progress.", + }, + { + .ctrnum = 133, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L2C_STORES_SENT", + .desc = "Incremented by one for every store sent to" + " Level-2 cache", + }, + { + .ctrnum = 134, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_OFFBOOK_L3_SOURCED_WRITES", + .desc = "A directory write to the Level-1 D-Cache directory" + " where the returned cache line was sourced from an" + " Off Book Level-3 cache", + }, + { + .ctrnum = 135, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_ONBOOK_L4_SOURCED_WRITES", + .desc = "A directory write to the Level-1 D-Cache directory" + " where the returned cache line was sourced from an" + " On Book Level-4 cache", + }, + { + .ctrnum = 136, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_ONBOOK_L4_SOURCED_WRITES", + .desc = "A directory write to the Level-1 I-Cache directory" + " where the returned cache line was sourced from an" + " On Book Level-4 cache", + }, + { + .ctrnum = 137, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_RO_EXCL_WRITES", + .desc = "A directory write to the Level-1 D-Cache where the" + " line was originally in a Read-Only state in the" + " cache but has been updated to be in the Exclusive" + " state that allows stores to the cache line", + }, + { + .ctrnum = 138, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_OFFBOOK_L4_SOURCED_WRITES", + .desc = "A directory write to the Level-1 D-Cache directory" + " where the returned cache line was sourced from an" + " Off Book Level-4 cache", + }, + { + .ctrnum = 139, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_OFFBOOK_L4_SOURCED_WRITES", + .desc = "A directory write to the Level-1 I-Cache directory" + " where the returned cache line was sourced from an" + " Off Book Level-4 cache", + }, + { + .ctrnum = 140, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "DTLB1_HPAGE_WRITES", + .desc = "A translation entry has been written to the Level-1" + " Data Translation Lookaside Buffer for a one-megabyte" + " page", + }, + { + .ctrnum = 141, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_LMEM_SOURCED_WRITES", + .desc = "A directory write to the Level-1 D-Cache where the" + " installed cache line was sourced from memory that" + " is attached to the same book as the Data cache" + " (Local Memory)", + }, + { + .ctrnum = 142, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_LMEM_SOURCED_WRITES", + .desc = "A directory write to the Level-1 I-Cache where the" + " installed cache line was sourced from memory that" + " is attached to the same book as the Instruction" + " cache (Local Memory)", + }, + { + .ctrnum = 143, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_OFFBOOK_L3_SOURCED_WRITES", + .desc = "A directory write to the Level-1 I-Cache directory" + " where the returned cache line was sourced from an" + " Off Book Level-3 cache", + }, + { + .ctrnum = 144, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "DTLB1_WRITES", + .desc = "A translation entry has been written to the Level-1" + " Data Translation Lookaside Buffer", + }, + { + .ctrnum = 145, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "ITLB1_WRITES", + .desc = "A translation entry has been written to the Level-1" + " Instruction Translation Lookaside Buffer", + }, + { + .ctrnum = 146, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "TLB2_PTE_WRITES", + .desc = "A translation entry has been written to the Level-2" + " TLB Page Table Entry arrays", + }, + { + .ctrnum = 147, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "TLB2_CRSTE_HPAGE_WRITES", + .desc = "A translation entry has been written to the Level-2" + " TLB Common Region Segment Table Entry arrays for a" + " one-megabyte large page translation", + }, + { + .ctrnum = 148, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "TLB2_CRSTE_WRITES", + .desc = "A translation entry has been written to the Level-2" + " TLB Common Region Segment Table Entry arrays", + }, + { + .ctrnum = 150, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_ONCHIP_L3_WRITES", + .desc = "A directory write to the Level-1 D-Cache directory" + " where the returned cache line was sourced from an" + " On Chip Level-3 cache", + }, + { + .ctrnum = 152, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1D_OFFCHIP_L3_WRITES", + .desc = "A directory write to the Level-1 D-Cache directory" + " where the returned cache line was sourced from an" + " Off Chip/On Book Level-3 cache", + }, + { + .ctrnum = 153, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_ONCHIP_L3_WRITES", + .desc = "A directory write to the Level-1 I-Cache directory" + " where the returned cache line was sourced from an" + " On Chip Level-3 cache", + }, + { + .ctrnum = 155, + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "L1I_OFFCHIP_L3_WRITES", + .desc = "A directory write to the Level-1 I-Cache directory" + " where the returned cache line was sourced from an" + " Off Chip/On Book Level-3 cache", + }, +}; + +#if 0 + { + .ctrnum = , + .ctrset = CPUMF_CTRSET_EXTENDED, + .name = "", + .desc = "", + }, +#endif +#endif /* __S390X_CPUMF_EVENTS_H__ */ diff --git a/lib/pfmlib_common.c b/lib/pfmlib_common.c index 765f45b..dcaa0ce 100644 --- a/lib/pfmlib_common.c +++ b/lib/pfmlib_common.c @@ -153,6 +153,9 @@ static pfmlib_pmu_t *pfmlib_pmus[]= &arm_cortex_a9_support, &arm_cortex_a15_support, #endif +#ifdef CONFIG_PFMLIB_ARCH_S390X + &s390x_cpum_cf_support, +#endif #ifdef __linux__ &perf_event_support, #endif diff --git a/lib/pfmlib_priv.h b/lib/pfmlib_priv.h index 7fb550a..8d3353d 100644 --- a/lib/pfmlib_priv.h +++ b/lib/pfmlib_priv.h @@ -275,6 +275,7 @@ extern pfmlib_pmu_t arm_cortex_a8_support; extern pfmlib_pmu_t arm_cortex_a9_support; extern pfmlib_pmu_t arm_cortex_a15_support; extern pfmlib_pmu_t mips_74k_support; +extern pfmlib_pmu_t s390x_cpum_cf_support; extern pfmlib_os_t pfmlib_os_perf; extern pfmlib_os_t pfmlib_os_perf_ext; diff --git a/lib/pfmlib_s390x_cpumf.c b/lib/pfmlib_s390x_cpumf.c new file mode 100644 index 0000000..025c9d2 --- /dev/null +++ b/lib/pfmlib_s390x_cpumf.c @@ -0,0 +1,265 @@ +/* + * PMU support for the CPU-measurement counter facility + * + * Copyright IBM Corp. 2012 + * Contributed by Hendrik Brueckner <brueck...@linux.vnet.ibm.com> + * + * 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. + */ +#include <ctype.h> +#include <sys/types.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +/* private library and arch headers */ +#include "pfmlib_priv.h" +#include "pfmlib_s390x_priv.h" +#include "pfmlib_perf_event_priv.h" +#include "events/s390x_cpumf_events.h" + + +#define CPUMF_DEVICE_DIR "/sys/bus/event_source/devices/cpum_cf" +#define SYS_INFO "/proc/sysinfo" + + +/* CPU-measurement counter list (pmu events) */ +static pme_cpumf_ctr_t *cpumcf_pe = NULL; + +/* Detect the CPU-measurement facility */ +static int pfm_cpumcf_detect(void *this) +{ + if (access(CPUMF_DEVICE_DIR, R_OK)) + return PFM_ERR_NOTSUPP; + return PFM_SUCCESS; +} + +/* Parses the machine type that identifies an IBM mainframe. + * These kind of information are from /proc/sysinfo. + */ +static long get_machine_type(void) +{ + long machine_type; + size_t buflen, len; + char *buffer, *tmp; + FILE *fp; + + machine_type = 0; + fp = fopen(SYS_INFO, "r"); + if (fp == NULL) + goto out; + + buffer = NULL; + while (pfmlib_getl(&buffer, &buflen, fp) != -1) { + /* skip empty lines */ + if (*buffer == '\n') + continue; + + /* look for 'Type:' entry */ + if (!strncmp("Type:", buffer, 5)) { + tmp = buffer + 5; /* set ptr after ':' */ + /* skip leading blanks */ + while (isspace(*tmp)) + tmp++; + /* skip trailing blanks */ + len = strlen(tmp); + while (len > 0 && isspace(tmp[len])) + len--; + tmp[len+1] = '\0'; + machine_type = strtol(tmp, NULL, 10); + break; + } + } + fclose(fp); + free(buffer); +out: + return machine_type; +} + +/* Initialize the PMU representation for CPUMF. + * + * Set up the PMU events array based on + * - generic (basic, problem-state, and crypto-activaty) counter sets + * - the extended counter depending on the machine type + */ +static int pfm_cpumcf_init(void *this) +{ + pfmlib_pmu_t *pmu = this; + const pme_cpumf_ctr_t *ext_set; + size_t generic_count, ext_set_count; + + /* check and assign a machine-specific extended counter set */ + switch (get_machine_type()) { + case 2097: /* IBM System z10 EC */ + case 2098: /* IBM System z10 BC */ + ext_set = cpumf_ctr_set_ext_z10; + ext_set_count = LIBPFM_ARRAY_SIZE(cpumf_ctr_set_ext_z10); + break; + case 2817: /* IBM zEnterprise 196 */ + case 2818: /* IBM zEnterprise 114 */ + ext_set = cpumf_ctr_set_ext_z196; + ext_set_count = LIBPFM_ARRAY_SIZE(cpumf_ctr_set_ext_z196); + break; + default: + /* No extended counter set for this machine type or there + * was an error retrieving the machine type */ + ext_set = NULL; + ext_set_count = 0; + break; + } + + generic_count = LIBPFM_ARRAY_SIZE(cpumf_generic_ctr); + + cpumcf_pe = calloc(sizeof(*cpumcf_pe), generic_count + ext_set_count); + if (cpumcf_pe == NULL) + return PFM_ERR_NOMEM; + + memcpy(cpumcf_pe, cpumf_generic_ctr, sizeof(*cpumcf_pe) * generic_count); + if (ext_set_count) + memcpy((void *) (cpumcf_pe + generic_count), + ext_set, sizeof(*cpumcf_pe) * ext_set_count); + + pmu->pe = cpumcf_pe; + pmu->pme_count = generic_count + ext_set_count; + + return PFM_SUCCESS; +} + +static void pfm_cpumcf_exit(void *this) +{ + pfmlib_pmu_t *pmu = this; + + pmu->pme_count = 0; + pmu->pe = NULL; + + free(cpumcf_pe); +} + +static int pfm_cpumcf_get_encoding(void *this, pfmlib_event_desc_t *e) +{ + const pme_cpumf_ctr_t *pe = this_pe(this); + + e->count = 1; /* number of encoded entries in e->codes */ + e->codes[0] = pe[e->event].ctrnum; + evt_strcat(e->fstr, "%s", pe[e->event].name); + + return PFM_SUCCESS; +} + +static int pfm_cpumcf_get_event_first(void *this) +{ + return 0; +} + +static int pfm_cpumcf_get_event_next(void *this, int idx) +{ + pfmlib_pmu_t *pmu = this; + + if (idx >= (pmu->pme_count - 1)) + return -1; + return idx + 1; +} + +static int pfm_cpumcf_event_is_valid(void *this, int idx) +{ + pfmlib_pmu_t *pmu = this; + + return (idx >= 0 && idx < pmu->pme_count); +} + +static int pfm_cpumcf_validate_table(void *this, FILE *fp) +{ + pfmlib_pmu_t *pmu = this; + const pme_cpumf_ctr_t *pe = this_pe(this); + int i, rc; + + rc = PFM_ERR_INVAL; + if (pmu->pme_count > CPUMF_COUNTER_MAX) { + fprintf(fp, "pmu: %s: pme number exceeded maximum\n", + pmu->name); + goto failed; + } + + for (i = 0; i < pmu->pme_count; i++) { + if (!pe[i].name) { + fprintf(fp, "pmu: %s event: %i: No name\n", + pmu->name, i); + goto failed; + } + if (!pe[i].desc) { + fprintf(fp, "pmu: %s event: %i: No description\n", + pmu->name, i); + goto failed; + } + } + + rc = PFM_SUCCESS; +failed: + return rc; +} + +static int pfm_cpumcf_get_event_info(void *this, int idx, + pfm_event_info_t *info) +{ + pfmlib_pmu_t *pmu = this; + const pme_cpumf_ctr_t *pe = this_pe(this); + + info->name = pe[idx].name; + info->desc = pe[idx].desc; + info->code = pe[idx].ctrnum; + info->equiv = NULL; + info->idx = idx; + info->pmu = pmu->pmu; + info->is_precise = 0; + + info->nattrs = 0; /* attributes are not supported */ + + return PFM_SUCCESS; +} + +static int pfm_cpumcf_get_event_attr_info(void *this, int idx, int umask_idx, + pfm_event_attr_info_t *info) +{ + /* Attributes are not supported */ + return PFM_ERR_ATTR; +} + +pfmlib_pmu_t s390x_cpum_cf_support = { + .desc = "CPU-measurement counter facility", + .name = "cpum_cf", + .pmu = PFM_PMU_S390X_CPUM_CF, + .type = PFM_PMU_TYPE_CORE, + .flags = PFMLIB_PMU_FL_ARCH_DFL, + + .num_cntrs = 0, /* no general-purpose counters */ + .num_fixed_cntrs = CPUMF_COUNTER_MAX, /* fixed counters only */ + .max_encoding = 1, + + .pmu_detect = pfm_cpumcf_detect, + .pmu_init = pfm_cpumcf_init, + .pmu_terminate = pfm_cpumcf_exit, + + .get_event_encoding[PFM_OS_NONE] = pfm_cpumcf_get_encoding, + PFMLIB_ENCODE_PERF(pfm_s390x_get_perf_encoding), + .get_event_first = pfm_cpumcf_get_event_first, + .get_event_next = pfm_cpumcf_get_event_next, + .event_is_valid = pfm_cpumcf_event_is_valid, + .validate_table = pfm_cpumcf_validate_table, + .get_event_info = pfm_cpumcf_get_event_info, + .get_event_attr_info = pfm_cpumcf_get_event_attr_info, +}; diff --git a/lib/pfmlib_s390x_perf_event.c b/lib/pfmlib_s390x_perf_event.c new file mode 100644 index 0000000..fb75892 --- /dev/null +++ b/lib/pfmlib_s390x_perf_event.c @@ -0,0 +1,52 @@ +/* + * perf_event for Linux on IBM System z + * + * Copyright IBM Corp. 2012 + * Contributed by Hendrik Brueckner <brueck...@linux.vnet.ibm.com> + * + * 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. + */ +#include <sys/types.h> +#include <string.h> +#include <stdlib.h> + +/* private library and arch headers */ +#include "pfmlib_priv.h" +#include "pfmlib_s390x_priv.h" +#include "pfmlib_perf_event_priv.h" + + +int pfm_s390x_get_perf_encoding(void *this, pfmlib_event_desc_t *e) +{ + pfmlib_pmu_t *pmu = this; + struct perf_event_attr *attr = e->os_data; + int rc; + + if (!pmu->get_event_encoding[PFM_OS_NONE]) + return PFM_ERR_NOTSUPP; + + /* set up raw pmu event encoding */ + rc = pmu->get_event_encoding[PFM_OS_NONE](this, e); + if (rc == PFM_SUCCESS) { + /* currently use raw events only */ + attr->type = PERF_TYPE_RAW; + attr->config = e->codes[0]; + } + + return rc; +} diff --git a/lib/pfmlib_s390x_priv.h b/lib/pfmlib_s390x_priv.h new file mode 100644 index 0000000..45259f2 --- /dev/null +++ b/lib/pfmlib_s390x_priv.h @@ -0,0 +1,15 @@ +#ifndef __PFMLIB_S390X_PRIV_H__ +#define __PFMLIB_S390X_PRIV_H__ + +#define CPUMF_COUNTER_MAX 160 +typedef struct { + uint64_t ctrnum; /* counter number */ + unsigned int ctrset; /* counter set */ + char *name; /* counter ID */ + char *desc; /* short description */ +} pme_cpumf_ctr_t; + +#define min(a, b) ((a) < (b) ? (a) : (b)) +extern int pfm_s390x_get_perf_encoding(void *this, pfmlib_event_desc_t *e); + +#endif /* __PFMLIB_S390X_PRIV_H__ */ -- 1.7.5.4 ------------------------------------------------------------------------------ Keep yourself connected to Go Parallel: INSIGHTS What's next for parallel hardware, programming and related areas? Interviews and blogs by thought leaders keep you ahead of the curve. http://goparallel.sourceforge.net _______________________________________________ perfmon2-devel mailing list perfmon2-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/perfmon2-devel