From: Andreas K. <kr...@li...> - 2011-10-12 16:57:56
|
Since kernel version 2.6.39 the hardware sampling facility of IBM System z is supported as part of the OProfile kernel module. http://marc.info/?l=oprofile-list&m=129785521106543&w=2 The user space interface stayed compatible to the timer mode sampling and therefore the kernel part keeps working with an unmodified user space. However there are some disadvantages due to that: - The configuration of the hardware sampling must be done by echoing values into virtual files provided by the hardware sampling kernel part. - The user can not easily see whether hardware sampling or timer based sampling is being used. The user space tools will always tell you that you are in timer mode. This patch enhances the user space part of OProfile in order to make hardware sampling easier to use. - New options are provided which allow to set the hardware sampling parameters on opcontrol command line. - A new option allows to fallback to timer based sampling without reloading the kernel module. - A new cpu type for System z machines with hardware sampling is added. In order to enable the features of this patch a one line kernel patch is needed as well. The kernel patch will be submitted after the user space support has been integrated since it would otherwise break the existing OProfile user space by introducing an unknown cpu type. Signed-off-by: Andreas Krebbel <kr...@li...> --- daemon/opd_events.c | 2 doc/internals.xml | 20 ++ doc/oprofile.xml | 44 ++++++ gui/oprof_start.cpp | 4 libop/op_cpu_type.c | 185 +++++++++++++++++---------- libop/op_cpu_type.h | 30 ++++ libop/op_events.c | 4 libop/tests/load_events_files_tests.c | 2 libpp/op_header.cpp | 26 ++- utils/opcontrol | 227 ++++++++++++++++++++++++++++------ utils/ophelp.c | 34 ++++- 11 files changed, 456 insertions(+), 122 deletions(-) diff --git a/daemon/opd_events.c b/daemon/opd_events.c index b544fb3..885e6a6 100644 --- a/daemon/opd_events.c +++ b/daemon/opd_events.c @@ -82,7 +82,7 @@ void opd_parse_events(char const * events) char * c; size_t cur = 0; - if (cpu_type == CPU_TIMER_INT) { + if (!op_has_hardware_counters(cpu_type)) { struct opd_event * event = &opd_events[0]; event->name = xstrdup("TIMER"); event->value = event->counter diff --git a/doc/internals.xml b/doc/internals.xml index a7feac7..fa70f5e 100644 --- a/doc/internals.xml +++ b/doc/internals.xml @@ -309,6 +309,26 @@ samples are registered with the OProfile core itself as usual (with </chapter> +<chapter id="hardware-sampling"> +<title>Hardware Sampling Support</title> +<para> +Some hardware (e.g. IBM System z) provides facilities which do +instruction sampling as part of the CPU. This usually has great +advantages over the timer based sampling approach like e.g. better +sampling resolution with less overhead and the possibility to get +samples within code sections where interrupts are disabled. +</para> +<para> +Since the hardware sampling facilites basically cover the same task as +timer based sampling the interface between the Linux kernel and the +OProfile user space part stays the same. However, a few extensions to +the user space tools have been added in order to provide the user with +a way to change the configuration and disable the hardware sampling +temporarily. Please see the OProfile user manual for details about +how to configure hardware sampling for your hardware. +</para> +</chapter> + <chapter id="collecting-samples"> <title>Collecting and processing samples</title> diff --git a/doc/oprofile.xml b/doc/oprofile.xml index 6a17c6d..07d02d0 100644 --- a/doc/oprofile.xml +++ b/doc/oprofile.xml @@ -1328,6 +1328,50 @@ Note: * All IBS fetch event must have the same event count and unitmask, </sect2> +<sect2 id="systemz"> +<title>IBM System z hardware sampling support</title> +<para> +IBM System z provides a facility which does instruction sampling as +part of the CPU. This has great advantages over the timer based +sampling approach like better sampling resolution with less overhead +and the possibility to get samples within code sections where +interrupts are disabled (useful especially for Linux kernel code). +</para> +<para> +System z hardware sampling can be used for Linux instances in LPAR +mode. The hardware sampling support used by OProfile was introduced +for System z10 in October 2008. +</para> +<para> +To enable hardware sampling for an LPAR you must activate the LPAR +with authorization for basic sampling control. See the "Support +Element Operations Guide" for your mainframe system for more +information. +</para> +<para> +The opcontrol tool provides a few options specific to System z +hardware sampling. These options get in effect immediately. They do +not require to restart the OProfile daemon. The hardware sampling +rate and the sampling buffer size is stored into the OProfile +configuration file. +</para> + +<variablelist> +<varlistentry><term><option>--disable-hardwaresampling</option></term><listitem><para> +On platforms providing hardware sampling capabilities this can be used +to force a fallback to timer based sampling. This option is not +stored in the OProfile configuration file.</para></listitem></varlistentry> +<varlistentry><term><option>--s390hwsamprate=</option>cycles</term><listitem><para> +Number of machine cycles between taking samples. This number must be within a hardware specific range. The range with z10 (October 2008) is [2202, 144305868].</para></listitem></varlistentry> +<varlistentry><term><option>--s390hwsampbufsize=</option>buffers</term><listitem><para> +Number of 2MB areas used per CPU for storing sample data. The best +size for the sample memory depends on the particular system and the +workload to be measured. Providing the sampler with too little memory +results in lost samples. Reserving too much system memory for the +sampler impacts the overall performance and, hence, also the workload +to be measures</para></listitem></varlistentry> +</variablelist> +</sect2> <sect2 id="misuse"> <title>Dangerous counter settings</title> diff --git a/gui/oprof_start.cpp b/gui/oprof_start.cpp index 725b215..5753e0f 100644 --- a/gui/oprof_start.cpp +++ b/gui/oprof_start.cpp @@ -139,7 +139,7 @@ oprof_start::oprof_start() cpu_type = op_get_cpu_type(); op_nr_counters = op_get_nr_counters(cpu_type); - if (cpu_type == CPU_TIMER_INT) { + if (!op_has_hardware_counters(cpu_type) { setup_config_tab->removePage(counter_setup_page); } else { fill_events(); @@ -907,7 +907,7 @@ void oprof_start::on_start_profiler() } } - if (one_enable == false && cpu_type != CPU_TIMER_INT) { + if (one_enable == false && op_has_hardware_counters(cpu_type)) { QMessageBox::warning(this, 0, "No counters enabled.\n"); return; } diff --git a/libop/op_cpu_type.c b/libop/op_cpu_type.c index 14e26bf..01054a5 100644 --- a/libop/op_cpu_type.c +++ b/libop/op_cpu_type.c @@ -21,79 +21,82 @@ struct cpu_descr { char const * name; op_cpu cpu; unsigned int nr_counters; + int hardware_counters_p; + int hardware_sampling_p; }; static struct cpu_descr const cpu_descrs[MAX_CPU_TYPE] = { - { "Pentium Pro", "i386/ppro", CPU_PPRO, 2 }, - { "PII", "i386/pii", CPU_PII, 2 }, - { "PIII", "i386/piii", CPU_PIII, 2 }, - { "Athlon", "i386/athlon", CPU_ATHLON, 4 }, - { "CPU with timer interrupt", "timer", CPU_TIMER_INT, 1 }, - { "CPU with RTC device", "rtc", CPU_RTC, 1 }, - { "P4 / Xeon", "i386/p4", CPU_P4, 8 }, - { "IA64", "ia64/ia64", CPU_IA64, 4 }, - { "Itanium", "ia64/itanium", CPU_IA64_1, 4 }, - { "Itanium 2", "ia64/itanium2", CPU_IA64_2, 4 }, - { "AMD64 processors", "x86-64/hammer", CPU_HAMMER, 4 }, - { "P4 / Xeon with 2 hyper-threads", "i386/p4-ht", CPU_P4_HT2, 4 }, - { "Alpha EV4", "alpha/ev4", CPU_AXP_EV4, 2 }, - { "Alpha EV5", "alpha/ev5", CPU_AXP_EV5, 3 }, - { "Alpha PCA56", "alpha/pca56", CPU_AXP_PCA56, 3 }, - { "Alpha EV6", "alpha/ev6", CPU_AXP_EV6, 2 }, - { "Alpha EV67", "alpha/ev67", CPU_AXP_EV67, 20 }, - { "Pentium M (P6 core)", "i386/p6_mobile", CPU_P6_MOBILE, 2 }, - { "ARM/XScale PMU1", "arm/xscale1", CPU_ARM_XSCALE1, 3 }, - { "ARM/XScale PMU2", "arm/xscale2", CPU_ARM_XSCALE2, 5 }, - { "ppc64 POWER4", "ppc64/power4", CPU_PPC64_POWER4, 8 }, - { "ppc64 POWER5", "ppc64/power5", CPU_PPC64_POWER5, 6 }, - { "ppc64 POWER5+", "ppc64/power5+", CPU_PPC64_POWER5p, 6 }, - { "ppc64 970", "ppc64/970", CPU_PPC64_970, 8 }, - { "MIPS 20K", "mips/20K", CPU_MIPS_20K, 1}, - { "MIPS 24K", "mips/24K", CPU_MIPS_24K, 2}, - { "MIPS 25K", "mips/25K", CPU_MIPS_25K, 2}, - { "MIPS 34K", "mips/34K", CPU_MIPS_34K, 2}, - { "MIPS 5K", "mips/5K", CPU_MIPS_5K, 2}, - { "MIPS R10000", "mips/r10000", CPU_MIPS_R10000, 2 }, - { "MIPS R12000", "mips/r12000", CPU_MIPS_R12000, 4 }, - { "QED RM7000", "mips/rm7000", CPU_MIPS_RM7000, 1 }, - { "PMC-Sierra RM9000", "mips/rm9000", CPU_MIPS_RM9000, 2 }, - { "Sibyte SB1", "mips/sb1", CPU_MIPS_SB1, 4 }, - { "NEC VR5432", "mips/vr5432", CPU_MIPS_VR5432, 2 }, - { "NEC VR5500", "mips/vr5500", CPU_MIPS_VR5500, 2 }, - { "e500", "ppc/e500", CPU_PPC_E500, 4 }, - { "e500v2", "ppc/e500v2", CPU_PPC_E500_2, 4 }, - { "Core Solo / Duo", "i386/core", CPU_CORE, 2 }, - { "PowerPC G4", "ppc/7450", CPU_PPC_7450, 6 }, - { "Core 2", "i386/core_2", CPU_CORE_2, 2 }, - { "ppc64 POWER6", "ppc64/power6", CPU_PPC64_POWER6, 4 }, - { "ppc64 970MP", "ppc64/970MP", CPU_PPC64_970MP, 8 }, - { "ppc64 Cell Broadband Engine", "ppc64/cell-be", CPU_PPC64_CELL, 8 }, - { "AMD64 family10", "x86-64/family10", CPU_FAMILY10, 4 }, - { "ppc64 PA6T", "ppc64/pa6t", CPU_PPC64_PA6T, 6 }, - { "ARM 11MPCore", "arm/mpcore", CPU_ARM_MPCORE, 2 }, - { "ARM V6 PMU", "arm/armv6", CPU_ARM_V6, 3 }, - { "ppc64 POWER5++", "ppc64/power5++", CPU_PPC64_POWER5pp, 6 }, - { "e300", "ppc/e300", CPU_PPC_E300, 4 }, - { "AVR32", "avr32", CPU_AVR32, 3 }, - { "ARM Cortex-A8", "arm/armv7", CPU_ARM_V7, 5 }, - { "Intel Architectural Perfmon", "i386/arch_perfmon", CPU_ARCH_PERFMON, 0}, - { "AMD64 family11h", "x86-64/family11h", CPU_FAMILY11H, 4 }, - { "ppc64 POWER7", "ppc64/power7", CPU_PPC64_POWER7, 6 }, - { "ppc64 compat version 1", "ppc64/ibm-compat-v1", CPU_PPC64_IBM_COMPAT_V1, 4 }, - { "Intel Core/i7", "i386/core_i7", CPU_CORE_I7, 4 }, - { "Intel Atom", "i386/atom", CPU_ATOM, 2 }, - { "Loongson2", "mips/loongson2", CPU_MIPS_LOONGSON2, 2 }, - { "Intel Nehalem microarchitecture", "i386/nehalem", CPU_NEHALEM, 4 }, - { "ARM Cortex-A9", "arm/armv7-ca9", CPU_ARM_V7_CA9, 7 }, - { "MIPS 74K", "mips/74K", CPU_MIPS_74K, 4}, - { "MIPS 1004K", "mips/1004K", CPU_MIPS_1004K, 2}, - { "AMD64 family12h", "x86-64/family12h", CPU_FAMILY12H, 4 }, - { "AMD64 family14h", "x86-64/family14h", CPU_FAMILY14H, 4 }, - { "AMD64 family15h", "x86-64/family15h", CPU_FAMILY15H, 6 }, - { "Intel Westmere microarchitecture", "i386/westmere", CPU_WESTMERE, 4 }, - { "ARMv7 Scorpion", "arm/armv7-scorpion", CPU_ARM_SCORPION, 5 }, - { "ARMv7 ScorpionMP", "arm/armv7-scorpionmp", CPU_ARM_SCORPIONMP, 5 }, - { "Intel Sandy Bridge microarchitecture", "i386/sandybridge", CPU_SANDYBRIDGE, 8 }, + { "Pentium Pro", "i386/ppro", CPU_PPRO, 2, 1, 0 }, + { "PII", "i386/pii", CPU_PII, 2, 1, 0 }, + { "PIII", "i386/piii", CPU_PIII, 2, 1, 0 }, + { "Athlon", "i386/athlon", CPU_ATHLON, 4, 1, 0 }, + { "CPU with timer interrupt", "timer", CPU_TIMER_INT, 1, 0, 0 }, + { "CPU with RTC device", "rtc", CPU_RTC, 1, 1, 0 }, + { "P4 / Xeon", "i386/p4", CPU_P4, 8, 1, 0 }, + { "IA64", "ia64/ia64", CPU_IA64, 4, 1, 0 }, + { "Itanium", "ia64/itanium", CPU_IA64_1, 4, 1, 0 }, + { "Itanium 2", "ia64/itanium2", CPU_IA64_2, 4, 1, 0 }, + { "AMD64 processors", "x86-64/hammer", CPU_HAMMER, 4, 1, 0 }, + { "P4 / Xeon with 2 hyper-threads", "i386/p4-ht", CPU_P4_HT2, 4, 1, 0 }, + { "Alpha EV4", "alpha/ev4", CPU_AXP_EV4, 2, 1, 0 }, + { "Alpha EV5", "alpha/ev5", CPU_AXP_EV5, 3, 1, 0 }, + { "Alpha PCA56", "alpha/pca56", CPU_AXP_PCA56, 3, 1, 0 }, + { "Alpha EV6", "alpha/ev6", CPU_AXP_EV6, 2, 1, 0 }, + { "Alpha EV67", "alpha/ev67", CPU_AXP_EV67, 21, 1, 0 }, + { "Pentium M (P6 core)", "i386/p6_mobile", CPU_P6_MOBILE, 2, 1, 0 }, + { "ARM/XScale PMU1", "arm/xscale1", CPU_ARM_XSCALE1, 3, 1, 0 }, + { "ARM/XScale PMU2", "arm/xscale2", CPU_ARM_XSCALE2, 5, 1, 0 }, + { "ppc64 POWER4", "ppc64/power4", CPU_PPC64_POWER4, 8, 1, 0 }, + { "ppc64 POWER5", "ppc64/power5", CPU_PPC64_POWER5, 6, 1, 0 }, + { "ppc64 POWER5+", "ppc64/power5+", CPU_PPC64_POWER5p, 6, 1, 0 }, + { "ppc64 970", "ppc64/970", CPU_PPC64_970, 8, 1, 0 }, + { "MIPS 20K", "mips/20K", CPU_MIPS_20K, 1, 1, 0 }, + { "MIPS 24K", "mips/24K", CPU_MIPS_24K, 2, 1, 0 }, + { "MIPS 25K", "mips/25K", CPU_MIPS_25K, 2, 1, 0 }, + { "MIPS 34K", "mips/34K", CPU_MIPS_34K, 2, 1, 0 }, + { "MIPS 5K", "mips/5K", CPU_MIPS_5K, 2, 1, 0 }, + { "MIPS R10000", "mips/r10000", CPU_MIPS_R10000, 2, 1, 0 }, + { "MIPS R12000", "mips/r12000", CPU_MIPS_R12000, 4, 1, 0 }, + { "QED RM7000", "mips/rm7000", CPU_MIPS_RM7000, 1, 1, 0 }, + { "PMC-Sierra RM9000", "mips/rm9000", CPU_MIPS_RM9000, 2, 1, 0 }, + { "Sibyte SB1", "mips/sb1", CPU_MIPS_SB1, 4, 1, 0 }, + { "NEC VR5432", "mips/vr5432", CPU_MIPS_VR5432, 2, 1, 0 }, + { "NEC VR5500", "mips/vr5500", CPU_MIPS_VR5500, 2, 1, 0 }, + { "e500", "ppc/e500", CPU_PPC_E500, 4, 1, 0 }, + { "e500v2", "ppc/e500v2", CPU_PPC_E500_2, 4, 1, 0 }, + { "Core Solo / Duo", "i386/core", CPU_CORE, 2, 1, 0 }, + { "PowerPC G4", "ppc/7450", CPU_PPC_7450, 6, 1, 0 }, + { "Core 2", "i386/core_2", CPU_CORE_2, 2, 1, 0 }, + { "ppc64 POWER6", "ppc64/power6", CPU_PPC64_POWER6, 4, 1, 0 }, + { "ppc64 970MP", "ppc64/970MP", CPU_PPC64_970MP, 8, 1, 0 }, + { "ppc64 Cell Broadband Engine", "ppc64/cell-be", CPU_PPC64_CELL, 8, 1, 0 }, + { "AMD64 family10", "x86-64/family10", CPU_FAMILY10, 4, 1, 0 }, + { "ppc64 PA6T", "ppc64/pa6t", CPU_PPC64_PA6T, 6, 1, 0 }, + { "ARM 11MPCore", "arm/mpcore", CPU_ARM_MPCORE, 2, 1, 0 }, + { "ARM V6 PMU", "arm/armv6", CPU_ARM_V6, 3, 1, 0 }, + { "ppc64 POWER5++", "ppc64/power5++", CPU_PPC64_POWER5pp, 6, 1, 0 }, + { "e300", "ppc/e300", CPU_PPC_E300, 4, 1, 0 }, + { "AVR32", "avr32", CPU_AVR32, 3, 1, 0 }, + { "ARM Cortex-A8", "arm/armv7", CPU_ARM_V7, 5, 1, 0 }, + { "Intel Architectural Perfmon", "i386/arch_perfmon", CPU_ARCH_PERFMON, 0, 1, 0 }, + { "AMD64 family11h", "x86-64/family11h", CPU_FAMILY11H, 4, 1, 0 }, + { "ppc64 POWER7", "ppc64/power7", CPU_PPC64_POWER7, 6, 1, 0 }, + { "ppc64 compat version 1", "ppc64/ibm-compat-v1", CPU_PPC64_IBM_COMPAT_V1, 4, 1, 0 }, + { "Intel Core/i7", "i386/core_i7", CPU_CORE_I7, 4, 1, 0 }, + { "Intel Atom", "i386/atom", CPU_ATOM, 2, 1, 0 }, + { "Loongson2", "mips/loongson2", CPU_MIPS_LOONGSON2, 2, 1, 0 }, + { "Intel Nehalem microarchitecture", "i386/nehalem", CPU_NEHALEM, 4, 1, 0 }, + { "ARM Cortex-A9", "arm/armv7-ca9", CPU_ARM_V7_CA9, 7, 1, 0 }, + { "MIPS 74K", "mips/74K", CPU_MIPS_74K, 4, 1, 0 }, + { "MIPS 1004K", "mips/1004K", CPU_MIPS_1004K, 2, 1, 0 }, + { "AMD64 family12h", "x86-64/family12h", CPU_FAMILY12H, 4, 1, 0 }, + { "AMD64 family14h", "x86-64/family14h", CPU_FAMILY14H, 4, 1, 0 }, + { "AMD64 family15h", "x86-64/family15h", CPU_FAMILY15H, 6, 1, 0 }, + { "Intel Westmere microarchitecture", "i386/westmere", CPU_WESTMERE, 4, 1, 0 }, + { "ARMv7 Scorpion", "arm/armv7-scorpion", CPU_ARM_SCORPION, 5, 1, 0 }, + { "ARMv7 ScorpionMP", "arm/armv7-scorpionmp", CPU_ARM_SCORPIONMP, 5, 1, 0 }, + { "Intel Sandy Bridge microarchitecture", "i386/sandybridge", CPU_SANDYBRIDGE, 8, 1, 0 }, + { "System Z with basic mode sampling support", "systemz/hwsampling_v1", CPU_SYSTEMZ_HWSAMPV1, 1, 0, 1 }, }; static size_t const nr_cpu_descrs = sizeof(cpu_descrs) / sizeof(struct cpu_descr); @@ -214,3 +217,45 @@ int op_get_nr_counters(op_cpu cpu_type) return cpu_descrs[cpu_type].nr_counters; } + +int op_has_hardware_counters(op_cpu cpu_type) +{ + return cpu_descrs[cpu_type].hardware_counters_p; +} + +int op_has_hardware_sampling(op_cpu cpu_type) +{ + return cpu_descrs[cpu_type].hardware_sampling_p; +} + +int op_hardware_sampling_enabled(op_cpu cpu_type) +{ + int result = 0; + + if (!op_has_hardware_sampling(cpu_type)) + return 0; + + switch (cpu_type) { + case CPU_SYSTEMZ_HWSAMPV1: + { + FILE * fp; + int enabled; + + fp = fopen("/dev/oprofile/hwsampling/hwsampler", "r"); + if (!fp) { + fprintf(stderr, "Unable to open cpu_type file for reading\n"); + fprintf(stderr, "Make sure you have done opcontrol --init\n"); + return 0; + } + if ((enabled = fgetc(fp)) == EOF) + break; + result = (char)enabled == '1' ? 1 : 0; + fclose(fp); + } + + break; + default: + return 0; + } + return result; +} diff --git a/libop/op_cpu_type.h b/libop/op_cpu_type.h index d6cae3a..becf31a 100644 --- a/libop/op_cpu_type.h +++ b/libop/op_cpu_type.h @@ -91,6 +91,7 @@ typedef enum { CPU_ARM_SCORPION, /**< ARM SCORPION */ CPU_ARM_SCORPIONMP, /**< ARM SCORPIONMP */ CPU_SANDYBRIDGE, /* Intel Sandy-Bridge microarchitecture */ + CPU_SYSTEMZ_HWSAMPV1, /**< System z with hardware sampling support */ MAX_CPU_TYPE } op_cpu; @@ -150,12 +151,41 @@ char const * op_get_cpu_name(op_cpu cpu_type); */ int op_get_nr_counters(op_cpu cpu_type); +/** + * return true if the CPU type supports hardware counters + * @param cpu_type numeric processor type + * + * returns 1 if the CPU supports hardware counters + */ +int op_has_hardware_counters(op_cpu cpu_type); + +/** + * return true if the CPU type supports hardware sampling + * @param cpu_type numeric processor type + * + * returns 1 if the CPU supports hardware sampling + */ +int op_has_hardware_sampling(op_cpu cpu_type); + +/** + * return true if the CPU type supports hardware sampling + * and it is currently enabled in the kernel + * @param cpu_type numeric processor type + * + * returns 1 if the CPU supports hardware sampling and + * it is currently enabled + */ +int op_hardware_sampling_enabled(op_cpu cpu_type); + + typedef enum { OP_INTERFACE_NO_GOOD = -1, OP_INTERFACE_24, OP_INTERFACE_26 } op_interface; + + /** * get the INTERFACE used to communicate between daemon and the kernel * diff --git a/libop/op_events.c b/libop/op_events.c index f4d54f9..42e3751 100644 --- a/libop/op_events.c +++ b/libop/op_events.c @@ -1126,6 +1126,10 @@ void op_default_event(op_cpu cpu_type, struct op_default_event_descr * descr) descr->name = "CPU_CLK"; break; + case CPU_SYSTEMZ_HWSAMPV1: + descr->name = "HWSAMPLING"; + break; + // don't use default, if someone add a cpu he wants a compiler // warning if he forgets to handle it here. case CPU_TIMER_INT: diff --git a/libop/tests/load_events_files_tests.c b/libop/tests/load_events_files_tests.c index de548e5..66ab714 100644 --- a/libop/tests/load_events_files_tests.c +++ b/libop/tests/load_events_files_tests.c @@ -21,7 +21,7 @@ int main(void) setenv("OPROFILE_EVENTS_DIR", OPROFILE_SRCDIR "/events", 1); for (cpu_type = CPU_NO_GOOD + 1; cpu_type < MAX_CPU_TYPE; ++cpu_type) { - if (cpu_type != CPU_TIMER_INT) { + if (op_has_hardware_counters(cpu_type)) { op_events(cpu_type); op_free_events(); } diff --git a/libpp/op_header.cpp b/libpp/op_header.cpp index 754015a..bb7973e 100644 --- a/libpp/op_header.cpp +++ b/libpp/op_header.cpp @@ -160,11 +160,6 @@ string const op_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count) { string str; - if (cpu_type == CPU_TIMER_INT) { - str += "Profiling through timer interrupt"; - return str; - } - struct op_event * event = op_find_event(cpu_type, type, um); if (!event) { @@ -234,6 +229,10 @@ string const describe_header(opd_header const & header) { op_cpu cpu = static_cast<op_cpu>(header.cpu_type); + if (!op_has_hardware_counters(cpu)) { + return ""; + } + if (want_xml) return op_xml_print_event(cpu, header.ctr_event, header.ctr_um, header.ctr_count); @@ -254,11 +253,20 @@ string const describe_cpu(opd_header const & header) str = xml_utils::get_profile_header(cpu_name, header.cpu_speed); } else { str += string("CPU: ") + op_get_cpu_type_str(cpu); - str += ", speed "; - ostringstream ss; - ss << header.cpu_speed; - str += ss.str() + " MHz (estimated)"; + if (header.cpu_speed > 0) { + str += ", speed "; + + ostringstream ss; + ss << header.cpu_speed; + str += ss.str() + " MHz (estimated)"; + } + if (op_has_hardware_sampling(cpu)) { + if (op_hardware_sampling_enabled(cpu)) + str += " (hardware sampling enabled)"; + else + str += " (hardware sampling disabled)"; + } } return str; } diff --git a/utils/opcontrol b/utils/opcontrol index 0951574..bc69b1e 100644 --- a/utils/opcontrol +++ b/utils/opcontrol @@ -239,6 +239,14 @@ opcontrol: usage: --xen Xen image (for Xen only) --active-domains=<list> List of domains in profiling session (for Xen) (list contains domain ids separated by commas) + + --disable-hardwaresampling Force to use timer based sampling. + By default hardware sampling is used if possible. + + System z specific options + + --s390hwsamprate=cycles Number of machine cycles between taking samples. + --s390hwsampbufsize=buffers Number of 2MB areas used per CPU for storing sample data. EOF } @@ -381,6 +389,10 @@ do_init() IBS_OP_COUNT=0 IBS_OP_UNITMASK=0 + # System z specific values + S390_HW_SAMPLER_INTERVAL=0 + S390_HW_SAMPLER_BUFSIZE=0 + OPROFILED="$OPDIR/oprofiled" # location for daemon setup information @@ -398,18 +410,13 @@ do_init() decide_oprofile_device DEFAULT_EVENT=`$OPHELP --get-default-event` - - IS_TIMER=0 - IS_PERFMON=0 - if test "$CPUTYPE" = "timer"; then - IS_TIMER=1 - else - case "$CPUTYPE" in - ia64/*) - IS_PERFMON=$KERNEL_SUPPORT - ;; - esac - fi + HAVE_HWSAMPLING=`$OPHELP --have-hwsampling` + HAVE_HWCOUNTERS=`$OPHELP --have-hwcounters` + case "$CPUTYPE" in + ia64/*) + IS_PERFMON=$KERNEL_SUPPORT + ;; + esac } @@ -435,6 +442,23 @@ set_event() eval "CHOSEN_EVENTS_$1=$2" } +do_platform_save_setup() +{ + case "$PLATFORM" in + s390*) + if test "$HAVE_HWSAMPLING" = "1"; then + if test "$S390_HW_SAMPLER_INTERVAL" != "0"; then + echo "S390_HW_SAMPLER_INTERVAL=$S390_HW_SAMPLER_INTERVAL" >> $SETUP_FILE + fi + if test "$S390_HW_SAMPLER_BUFSIZE" != "0"; then + echo "S390_HW_SAMPLER_BUFSIZE=$S390_HW_SAMPLER_BUFSIZE" >> $SETUP_FILE + fi + fi + ;; + *) + ;; + esac +} # save all the setup related information do_save_setup() @@ -448,10 +472,12 @@ do_save_setup() # daemon is restarted, we'll reload the config data from this secondary # cache file. - if is_oprofiled_active "$LOCK_FILE"; then - SETUP_FILE="$SEC_SETUP_FILE" - echo "The profiling daemon is currently active, so changes to the configuration" - echo "will be used the next time you restart oprofile after a --shutdown or --deinit." + if test "$DO_SETUP" = "yes"; then + if is_oprofiled_active "$LOCK_FILE"; then + SETUP_FILE="$SEC_SETUP_FILE" + echo "The profiling daemon is currently active, so changes to the configuration of the daemon" + echo "will be used the next time you restart oprofile after a --shutdown or --deinit." + fi fi touch $SETUP_FILE @@ -496,6 +522,9 @@ do_save_setup() if test "$XEN_RANGE"; then echo "XEN_RANGE=$XEN_RANGE" >> $SETUP_FILE fi + + do_platform_save_setup + SETUP_FILE="$SAVE_SETUP_FILE" } @@ -539,6 +568,53 @@ do_load_setup() } +# Various checks related to Hardware sampler option +check_platform_args() +{ + case "$PLATFORM" in + s390*) + if test "$HAVE_HWSAMPLING" == "0"; then + return + fi + if test -r $MOUNT/hwsampling/hw_min_interval; then + min_interval=`cat $MOUNT/hwsampling/hw_min_interval` + fi + if test -r $MOUNT/hwsampling/hw_max_interval; then + max_interval=`cat $MOUNT/hwsampling/hw_max_interval` + fi + + # Bounds check for Hardware Sampler rate. + if test "$S390_HW_SAMPLER_INTERVAL" != "0"; then + case "$S390_HW_SAMPLER_INTERVAL" in + *[^0-9]*) + echo "Invalid value for hardware sampling rate." >&2 + echo "Numeric value expected." >&2 + exit 1 + ;; + esac + if test "$S390_HW_SAMPLER_INTERVAL" -lt "$min_interval" || test "$S390_HW_SAMPLER_INTERVAL" -gt "$max_interval"; then + echo "Invalid value for hardware sampling rate" >&2 + echo "should be between $min_interval and $max_interval" >&2 + exit 1 + fi + fi + + # Format check for hardware sampler buffer size. + if test "$S390_HW_SAMPLER_BUFSIZE" != "0"; then + case "$S390_HW_SAMPLER_BUFSIZE" in + *[^0-9]*) + echo "Invalid value for hardware sampling buffer size." >&2 + echo "Numeric value expected." >&2 + exit 1 + ;; + esac + fi + ;; + *) + ;; + esac +} + check_valid_args() { if test -z "$VMLINUX"; then @@ -672,10 +748,11 @@ validate_separate_args() # check the counters make sense, and resolve the hardware allocation verify_counters() { - if test "$IS_TIMER" = 1; then + if test "$HAVE_HWCOUNTERS" = "0"; then if test "$NR_CHOSEN" != 0; then - echo "You cannot specify any performance counter events" >&2 - echo "because OProfile is in timer mode." >&2 + echo "Counter events are not supported." >&2 + echo "Either no counter events are supported for this platform " >&2 + echo "or the OProfile module has been forced to use timer based sampling." >&2 exit 1 fi return @@ -705,7 +782,7 @@ verify_counters() # setup any needed default value in chosen events normalise_events() { - if test "$NR_CHOSEN" -le 0 || test "$IS_TIMER" = 1; then + if test "$NR_CHOSEN" -le 0 || test "$HAVE_HWCOUNTERS" = "0"; then return fi @@ -745,6 +822,7 @@ do_options() { EXCLUSIVE_ARGC=0 SETUP=no + DO_HWSAMP_SETUP=no NEED_SETUP=no SEEN_EVENT=0 @@ -971,10 +1049,26 @@ do_options() exec $OPHELP ;; - *) - echo "Unknown option \"$arg\". See opcontrol --help" >&2 - exit 1 + --disable-hardwaresampling) + HAVE_HWSAMPLING=0 + ;; + + --s390hwsamprate) + error_if_empty $arg $val + S390_HW_SAMPLER_INTERVAL=$val + DO_HWSAMP_SETUP=yes + ;; + + --s390hwsampbufsize) + error_if_empty $arg $val + S390_HW_SAMPLER_BUFSIZE=$val + DO_HWSAMP_SETUP=yes ;; + + *) + echo "Unknown option \"$arg\". See opcontrol --help" >&2 + exit 1 + ;; esac done @@ -987,7 +1081,7 @@ do_options() exit 1 fi - if test "$SETUP" = "yes" -a "$DO_SETUP" != "yes"; then + if test "$SETUP" = "yes" -a "$DO_SETUP" != "yes" -a "$DO_HWSAMP_SETUP" != "yes"; then echo "No options specified for --setup." >&2 exit 1 fi @@ -999,8 +1093,8 @@ do_options() fi fi - if test "$DO_SETUP" = "yes"; then - SETUP="$DO_SETUP" + if test "$DO_SETUP" = "yes" -o "$DO_HWSAMP_SETUP" = "yes"; then + SETUP="yes" fi if test "$EXCLUSIVE_ARGC" -eq 1 -a "$SETUP" = "yes"; then @@ -1033,6 +1127,10 @@ do_options() vecho "CPU_BUF_SIZE default value" fi fi + if test "$HAVE_HWSAMPLING" = "1"; then + vecho "S390_HW_SAMPLER_INTERVAL $S390_HW_SAMPLER_INTERVAL" + vecho "S390_HW_SAMPLER_BUFSIZE $S390_HW_SAMPLER_BUFSIZE" + fi vecho "SEPARATE_LIB $SEPARATE_LIB" vecho "SEPARATE_KERNEL $SEPARATE_KERNEL" @@ -1228,15 +1326,15 @@ set_ctr_param() is_non_cell_ppc64_variant() { case "$1" in - ppc64/*cell*) - return 0 - ;; - ppc64/*) - return 1 - ;; - *) - return 0 - ;; + ppc64/*cell*) + return 0 + ;; + ppc64/*) + return 1 + ;; + *) + return 0 + ;; esac } @@ -1414,7 +1512,7 @@ do_param_setup() echo "Call-graph profiling not supported - ignored" >&2 fi - if test "$IS_TIMER" = 1; then + if test "$HAVE_HWCOUNTERS" = "0"; then return fi @@ -1578,7 +1676,7 @@ do_start_daemon() --separate-thread=$SEPARATE_THREAD \ --separate-cpu=$SEPARATE_CPU" - if test "$IS_TIMER" = 1; then + if test "$HAVE_HWCOUNTERS" = "0"; then OPD_ARGS="$OPD_ARGS --events=" else if ! test -z "$OPROFILED_EVENTS"; then @@ -1625,9 +1723,35 @@ do_start_daemon() echo "Daemon started." } +do_platform_start() +{ + case "$PLATFORM" in + s390*) + if test "$HAVE_HWSAMPLING" = "0"; then + if test -f $MOUNT/hwsampling/hwsampler; then + echo "Disabling Hardware sampling" + echo 0 > $MOUNT/hwsampling/hwsampler + fi + return + fi + echo "Enabling Hardware sampling" + echo 1 > $MOUNT/hwsampling/hwsampler + if test "$S390_HW_SAMPLER_INTERVAL" != 0; then + echo $S390_HW_SAMPLER_INTERVAL >$MOUNT/hwsampling/hw_interval + fi + if test "$S390_HW_SAMPLER_BUFSIZE" != 0; then + echo $S390_HW_SAMPLER_BUFSIZE >$MOUNT/hwsampling/hw_sdbt_blocks + fi + ;; + *) + ;; + esac +} + do_start() { prep_jitdump; + do_platform_start if test "$KERNEL_SUPPORT" = "yes"; then echo 1 >$MOUNT/enable fi @@ -1636,6 +1760,27 @@ do_start() } +do_platform_status() +{ + case "$PLATFORM" in + s390*) + if test "$HAVE_HWSAMPLING" = "0"; then + return + fi + echo -n "Hardware sampling interval: " + echo -n $S390_HW_SAMPLER_INTERVAL + echo -n " - current hardware setting: " + cat $MOUNT/hwsampling/hw_interval + echo -n "Hardware sampling buffer size: " + echo -n $S390_HW_SAMPLER_BUFSIZE + echo -n " - current hardware setting: " + cat $MOUNT/hwsampling/hw_sdbt_blocks + ;; + *) + ;; + esac +} + # print status do_status() { @@ -1702,6 +1847,10 @@ do_status() fi fi + if test "$HAVE_HWSAMPLING" = "1"; then + do_platform_status + fi + exit 0 } @@ -1855,6 +2004,9 @@ do_operations() fi if test "$SETUP" = "yes"; then + if test "$DO_HWSAMP_SETUP" = "yes"; then + check_platform_args + fi check_valid_args do_save_setup fi @@ -2161,6 +2313,7 @@ if test -z "$OPDIR"; then fi PATH=$OPDIR:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin +PLATFORM=`uname -i` check_options_early $@ diff --git a/utils/ophelp.c b/utils/ophelp.c index 5dcb217..a51be63 100644 --- a/utils/ophelp.c +++ b/utils/ophelp.c @@ -33,6 +33,8 @@ static op_cpu cpu_type = CPU_NO_GOOD; static char * cpu_string; static int callgraph_depth; static int want_xml; +static int have_hwsamp; +static int have_hwcounters; static poptContext optcon; @@ -339,9 +341,13 @@ static struct poptOption options[] = { { "callgraph", '\0', POPT_ARG_INT, &callgraph_depth, 0, "use this callgraph depth", "callgraph depth", }, { "version", 'v', POPT_ARG_NONE, &show_vers, 0, - "show version", NULL, }, + "show version", NULL, }, { "xml", 'X', POPT_ARG_NONE, &want_xml, 0, - "list events as XML", NULL, }, + "list events as XML", NULL, }, + { "have-hwsampling", 's', POPT_ARG_NONE, &have_hwsamp, 0, + "print 1 if the CPU supports hardware sampling", NULL, }, + { "have-hwcounters", 'k', POPT_ARG_NONE, &have_hwcounters, 0, + "print 1 if the CPU supports hardware counters", NULL, }, { "extra-mask", 'E', POPT_ARG_NONE, &extra_mask, 0, "print extra mask for event", NULL, }, POPT_AUTOHELP @@ -422,6 +428,20 @@ int main(int argc, char const * argv[]) exit(EXIT_FAILURE); } + if (have_hwsamp) { + if (have_hwcounters) { + fprintf(stderr, "-s and -k cannot be used in combination.\n"); + exit(EXIT_FAILURE); + } + printf("%d", op_has_hardware_sampling(cpu_type)); + exit(EXIT_SUCCESS); + } + + if (have_hwcounters) { + printf("%d", op_has_hardware_counters(cpu_type)); + exit(EXIT_SUCCESS); + } + parsed_events = (struct parsed_event *)xcalloc(num_chosen_events, sizeof(struct parsed_event)); @@ -443,6 +463,12 @@ int main(int argc, char const * argv[]) exit(EXIT_SUCCESS); } + if (op_has_hardware_sampling(cpu_type)) + printf("Using CPU hardware sampling support.\n"); + + if (!op_has_hardware_counters(cpu_type)) + exit(EXIT_SUCCESS); + events = op_events(cpu_type); if (!chosen_events && (unit_mask || check_events || extra_mask)) { @@ -731,6 +757,10 @@ int main(int argc, char const * argv[]) "Chapter 6: Performance Counters\n" "http://www.atmel.com/dyn/resources/prod_documents/doc32000.pdf\n"; + case CPU_SYSTEMZ_HWSAMPV1: + event_doc = "Hardware Basic Mode Sampling\n"; + break; + case CPU_RTC: break; |
From: Maynard J. <may...@us...> - 2011-10-17 16:29:36
|
On 10/12/2011 10:20 AM, Andreas Krebbel wrote: > Since kernel version 2.6.39 the hardware sampling facility of IBM > System z is supported as part of the OProfile kernel module. > > http://marc.info/?l=oprofile-list&m=129785521106543&w=2 > > The user space interface stayed compatible to the timer mode sampling > and therefore the kernel part keeps working with an unmodified user > space. However there are some disadvantages due to that: > > - The configuration of the hardware sampling must be done by echoing > values into virtual files provided by the hardware sampling kernel > part. > - The user can not easily see whether hardware sampling or timer based > sampling is being used. The user space tools will always tell you > that you are in timer mode. > > This patch enhances the user space part of OProfile in order to make > hardware sampling easier to use. Andreas, I was out for the past few days . . . I'll review your patch soon. Thanks. -Maynard > > - New options are provided which allow to set the hardware sampling > parameters on opcontrol command line. > - A new option allows to fallback to timer based sampling without > reloading the kernel module. > - A new cpu type for System z machines with hardware sampling is > added. > > In order to enable the features of this patch a one line kernel patch > is needed as well. The kernel patch will be submitted after the user > space support has been integrated since it would otherwise break the > existing OProfile user space by introducing an unknown cpu type. > > Signed-off-by: Andreas Krebbel<kr...@li...> > --- > > daemon/opd_events.c | 2 > doc/internals.xml | 20 ++ > doc/oprofile.xml | 44 ++++++ > gui/oprof_start.cpp | 4 > libop/op_cpu_type.c | 185 +++++++++++++++++---------- > libop/op_cpu_type.h | 30 ++++ > libop/op_events.c | 4 > libop/tests/load_events_files_tests.c | 2 > libpp/op_header.cpp | 26 ++- > utils/opcontrol | 227 ++++++++++++++++++++++++++++------ > utils/ophelp.c | 34 ++++- > 11 files changed, 456 insertions(+), 122 deletions(-) > > diff --git a/daemon/opd_events.c b/daemon/opd_events.c > index b544fb3..885e6a6 100644 > --- a/daemon/opd_events.c > +++ b/daemon/opd_events.c > @@ -82,7 +82,7 @@ void opd_parse_events(char const * events) > char * c; > size_t cur = 0; > > - if (cpu_type == CPU_TIMER_INT) { > + if (!op_has_hardware_counters(cpu_type)) { > struct opd_event * event =&opd_events[0]; > event->name = xstrdup("TIMER"); > event->value = event->counter > diff --git a/doc/internals.xml b/doc/internals.xml > index a7feac7..fa70f5e 100644 > --- a/doc/internals.xml > +++ b/doc/internals.xml > @@ -309,6 +309,26 @@ samples are registered with the OProfile core itself as usual (with > > </chapter> > > +<chapter id="hardware-sampling"> > +<title>Hardware Sampling Support</title> > +<para> > +Some hardware (e.g. IBM System z) provides facilities which do > +instruction sampling as part of the CPU. This usually has great > +advantages over the timer based sampling approach like e.g. better > +sampling resolution with less overhead and the possibility to get > +samples within code sections where interrupts are disabled. > +</para> > +<para> > +Since the hardware sampling facilites basically cover the same task as > +timer based sampling the interface between the Linux kernel and the > +OProfile user space part stays the same. However, a few extensions to > +the user space tools have been added in order to provide the user with > +a way to change the configuration and disable the hardware sampling > +temporarily. Please see the OProfile user manual for details about > +how to configure hardware sampling for your hardware. > +</para> > +</chapter> > + > <chapter id="collecting-samples"> > <title>Collecting and processing samples</title> > > diff --git a/doc/oprofile.xml b/doc/oprofile.xml > index 6a17c6d..07d02d0 100644 > --- a/doc/oprofile.xml > +++ b/doc/oprofile.xml > @@ -1328,6 +1328,50 @@ Note: * All IBS fetch event must have the same event count and unitmask, > > </sect2> > > +<sect2 id="systemz"> > +<title>IBM System z hardware sampling support</title> > +<para> > +IBM System z provides a facility which does instruction sampling as > +part of the CPU. This has great advantages over the timer based > +sampling approach like better sampling resolution with less overhead > +and the possibility to get samples within code sections where > +interrupts are disabled (useful especially for Linux kernel code). > +</para> > +<para> > +System z hardware sampling can be used for Linux instances in LPAR > +mode. The hardware sampling support used by OProfile was introduced > +for System z10 in October 2008. > +</para> > +<para> > +To enable hardware sampling for an LPAR you must activate the LPAR > +with authorization for basic sampling control. See the "Support > +Element Operations Guide" for your mainframe system for more > +information. > +</para> > +<para> > +The opcontrol tool provides a few options specific to System z > +hardware sampling. These options get in effect immediately. They do > +not require to restart the OProfile daemon. The hardware sampling > +rate and the sampling buffer size is stored into the OProfile > +configuration file. > +</para> > + > +<variablelist> > +<varlistentry><term><option>--disable-hardwaresampling</option></term><listitem><para> > +On platforms providing hardware sampling capabilities this can be used > +to force a fallback to timer based sampling. This option is not > +stored in the OProfile configuration file.</para></listitem></varlistentry> > +<varlistentry><term><option>--s390hwsamprate=</option>cycles</term><listitem><para> > +Number of machine cycles between taking samples. This number must be within a hardware specific range. The range with z10 (October 2008) is [2202, 144305868].</para></listitem></varlistentry> > +<varlistentry><term><option>--s390hwsampbufsize=</option>buffers</term><listitem><para> > +Number of 2MB areas used per CPU for storing sample data. The best > +size for the sample memory depends on the particular system and the > +workload to be measured. Providing the sampler with too little memory > +results in lost samples. Reserving too much system memory for the > +sampler impacts the overall performance and, hence, also the workload > +to be measures</para></listitem></varlistentry> > +</variablelist> > +</sect2> > > <sect2 id="misuse"> > <title>Dangerous counter settings</title> > diff --git a/gui/oprof_start.cpp b/gui/oprof_start.cpp > index 725b215..5753e0f 100644 > --- a/gui/oprof_start.cpp > +++ b/gui/oprof_start.cpp > @@ -139,7 +139,7 @@ oprof_start::oprof_start() > cpu_type = op_get_cpu_type(); > op_nr_counters = op_get_nr_counters(cpu_type); > > - if (cpu_type == CPU_TIMER_INT) { > + if (!op_has_hardware_counters(cpu_type) { > setup_config_tab->removePage(counter_setup_page); > } else { > fill_events(); > @@ -907,7 +907,7 @@ void oprof_start::on_start_profiler() > } > } > > - if (one_enable == false&& cpu_type != CPU_TIMER_INT) { > + if (one_enable == false&& op_has_hardware_counters(cpu_type)) { > QMessageBox::warning(this, 0, "No counters enabled.\n"); > return; > } > diff --git a/libop/op_cpu_type.c b/libop/op_cpu_type.c > index 14e26bf..01054a5 100644 > --- a/libop/op_cpu_type.c > +++ b/libop/op_cpu_type.c > @@ -21,79 +21,82 @@ struct cpu_descr { > char const * name; > op_cpu cpu; > unsigned int nr_counters; > + int hardware_counters_p; > + int hardware_sampling_p; > }; > > static struct cpu_descr const cpu_descrs[MAX_CPU_TYPE] = { > - { "Pentium Pro", "i386/ppro", CPU_PPRO, 2 }, > - { "PII", "i386/pii", CPU_PII, 2 }, > - { "PIII", "i386/piii", CPU_PIII, 2 }, > - { "Athlon", "i386/athlon", CPU_ATHLON, 4 }, > - { "CPU with timer interrupt", "timer", CPU_TIMER_INT, 1 }, > - { "CPU with RTC device", "rtc", CPU_RTC, 1 }, > - { "P4 / Xeon", "i386/p4", CPU_P4, 8 }, > - { "IA64", "ia64/ia64", CPU_IA64, 4 }, > - { "Itanium", "ia64/itanium", CPU_IA64_1, 4 }, > - { "Itanium 2", "ia64/itanium2", CPU_IA64_2, 4 }, > - { "AMD64 processors", "x86-64/hammer", CPU_HAMMER, 4 }, > - { "P4 / Xeon with 2 hyper-threads", "i386/p4-ht", CPU_P4_HT2, 4 }, > - { "Alpha EV4", "alpha/ev4", CPU_AXP_EV4, 2 }, > - { "Alpha EV5", "alpha/ev5", CPU_AXP_EV5, 3 }, > - { "Alpha PCA56", "alpha/pca56", CPU_AXP_PCA56, 3 }, > - { "Alpha EV6", "alpha/ev6", CPU_AXP_EV6, 2 }, > - { "Alpha EV67", "alpha/ev67", CPU_AXP_EV67, 20 }, > - { "Pentium M (P6 core)", "i386/p6_mobile", CPU_P6_MOBILE, 2 }, > - { "ARM/XScale PMU1", "arm/xscale1", CPU_ARM_XSCALE1, 3 }, > - { "ARM/XScale PMU2", "arm/xscale2", CPU_ARM_XSCALE2, 5 }, > - { "ppc64 POWER4", "ppc64/power4", CPU_PPC64_POWER4, 8 }, > - { "ppc64 POWER5", "ppc64/power5", CPU_PPC64_POWER5, 6 }, > - { "ppc64 POWER5+", "ppc64/power5+", CPU_PPC64_POWER5p, 6 }, > - { "ppc64 970", "ppc64/970", CPU_PPC64_970, 8 }, > - { "MIPS 20K", "mips/20K", CPU_MIPS_20K, 1}, > - { "MIPS 24K", "mips/24K", CPU_MIPS_24K, 2}, > - { "MIPS 25K", "mips/25K", CPU_MIPS_25K, 2}, > - { "MIPS 34K", "mips/34K", CPU_MIPS_34K, 2}, > - { "MIPS 5K", "mips/5K", CPU_MIPS_5K, 2}, > - { "MIPS R10000", "mips/r10000", CPU_MIPS_R10000, 2 }, > - { "MIPS R12000", "mips/r12000", CPU_MIPS_R12000, 4 }, > - { "QED RM7000", "mips/rm7000", CPU_MIPS_RM7000, 1 }, > - { "PMC-Sierra RM9000", "mips/rm9000", CPU_MIPS_RM9000, 2 }, > - { "Sibyte SB1", "mips/sb1", CPU_MIPS_SB1, 4 }, > - { "NEC VR5432", "mips/vr5432", CPU_MIPS_VR5432, 2 }, > - { "NEC VR5500", "mips/vr5500", CPU_MIPS_VR5500, 2 }, > - { "e500", "ppc/e500", CPU_PPC_E500, 4 }, > - { "e500v2", "ppc/e500v2", CPU_PPC_E500_2, 4 }, > - { "Core Solo / Duo", "i386/core", CPU_CORE, 2 }, > - { "PowerPC G4", "ppc/7450", CPU_PPC_7450, 6 }, > - { "Core 2", "i386/core_2", CPU_CORE_2, 2 }, > - { "ppc64 POWER6", "ppc64/power6", CPU_PPC64_POWER6, 4 }, > - { "ppc64 970MP", "ppc64/970MP", CPU_PPC64_970MP, 8 }, > - { "ppc64 Cell Broadband Engine", "ppc64/cell-be", CPU_PPC64_CELL, 8 }, > - { "AMD64 family10", "x86-64/family10", CPU_FAMILY10, 4 }, > - { "ppc64 PA6T", "ppc64/pa6t", CPU_PPC64_PA6T, 6 }, > - { "ARM 11MPCore", "arm/mpcore", CPU_ARM_MPCORE, 2 }, > - { "ARM V6 PMU", "arm/armv6", CPU_ARM_V6, 3 }, > - { "ppc64 POWER5++", "ppc64/power5++", CPU_PPC64_POWER5pp, 6 }, > - { "e300", "ppc/e300", CPU_PPC_E300, 4 }, > - { "AVR32", "avr32", CPU_AVR32, 3 }, > - { "ARM Cortex-A8", "arm/armv7", CPU_ARM_V7, 5 }, > - { "Intel Architectural Perfmon", "i386/arch_perfmon", CPU_ARCH_PERFMON, 0}, > - { "AMD64 family11h", "x86-64/family11h", CPU_FAMILY11H, 4 }, > - { "ppc64 POWER7", "ppc64/power7", CPU_PPC64_POWER7, 6 }, > - { "ppc64 compat version 1", "ppc64/ibm-compat-v1", CPU_PPC64_IBM_COMPAT_V1, 4 }, > - { "Intel Core/i7", "i386/core_i7", CPU_CORE_I7, 4 }, > - { "Intel Atom", "i386/atom", CPU_ATOM, 2 }, > - { "Loongson2", "mips/loongson2", CPU_MIPS_LOONGSON2, 2 }, > - { "Intel Nehalem microarchitecture", "i386/nehalem", CPU_NEHALEM, 4 }, > - { "ARM Cortex-A9", "arm/armv7-ca9", CPU_ARM_V7_CA9, 7 }, > - { "MIPS 74K", "mips/74K", CPU_MIPS_74K, 4}, > - { "MIPS 1004K", "mips/1004K", CPU_MIPS_1004K, 2}, > - { "AMD64 family12h", "x86-64/family12h", CPU_FAMILY12H, 4 }, > - { "AMD64 family14h", "x86-64/family14h", CPU_FAMILY14H, 4 }, > - { "AMD64 family15h", "x86-64/family15h", CPU_FAMILY15H, 6 }, > - { "Intel Westmere microarchitecture", "i386/westmere", CPU_WESTMERE, 4 }, > - { "ARMv7 Scorpion", "arm/armv7-scorpion", CPU_ARM_SCORPION, 5 }, > - { "ARMv7 ScorpionMP", "arm/armv7-scorpionmp", CPU_ARM_SCORPIONMP, 5 }, > - { "Intel Sandy Bridge microarchitecture", "i386/sandybridge", CPU_SANDYBRIDGE, 8 }, > + { "Pentium Pro", "i386/ppro", CPU_PPRO, 2, 1, 0 }, > + { "PII", "i386/pii", CPU_PII, 2, 1, 0 }, > + { "PIII", "i386/piii", CPU_PIII, 2, 1, 0 }, > + { "Athlon", "i386/athlon", CPU_ATHLON, 4, 1, 0 }, > + { "CPU with timer interrupt", "timer", CPU_TIMER_INT, 1, 0, 0 }, > + { "CPU with RTC device", "rtc", CPU_RTC, 1, 1, 0 }, > + { "P4 / Xeon", "i386/p4", CPU_P4, 8, 1, 0 }, > + { "IA64", "ia64/ia64", CPU_IA64, 4, 1, 0 }, > + { "Itanium", "ia64/itanium", CPU_IA64_1, 4, 1, 0 }, > + { "Itanium 2", "ia64/itanium2", CPU_IA64_2, 4, 1, 0 }, > + { "AMD64 processors", "x86-64/hammer", CPU_HAMMER, 4, 1, 0 }, > + { "P4 / Xeon with 2 hyper-threads", "i386/p4-ht", CPU_P4_HT2, 4, 1, 0 }, > + { "Alpha EV4", "alpha/ev4", CPU_AXP_EV4, 2, 1, 0 }, > + { "Alpha EV5", "alpha/ev5", CPU_AXP_EV5, 3, 1, 0 }, > + { "Alpha PCA56", "alpha/pca56", CPU_AXP_PCA56, 3, 1, 0 }, > + { "Alpha EV6", "alpha/ev6", CPU_AXP_EV6, 2, 1, 0 }, > + { "Alpha EV67", "alpha/ev67", CPU_AXP_EV67, 21, 1, 0 }, > + { "Pentium M (P6 core)", "i386/p6_mobile", CPU_P6_MOBILE, 2, 1, 0 }, > + { "ARM/XScale PMU1", "arm/xscale1", CPU_ARM_XSCALE1, 3, 1, 0 }, > + { "ARM/XScale PMU2", "arm/xscale2", CPU_ARM_XSCALE2, 5, 1, 0 }, > + { "ppc64 POWER4", "ppc64/power4", CPU_PPC64_POWER4, 8, 1, 0 }, > + { "ppc64 POWER5", "ppc64/power5", CPU_PPC64_POWER5, 6, 1, 0 }, > + { "ppc64 POWER5+", "ppc64/power5+", CPU_PPC64_POWER5p, 6, 1, 0 }, > + { "ppc64 970", "ppc64/970", CPU_PPC64_970, 8, 1, 0 }, > + { "MIPS 20K", "mips/20K", CPU_MIPS_20K, 1, 1, 0 }, > + { "MIPS 24K", "mips/24K", CPU_MIPS_24K, 2, 1, 0 }, > + { "MIPS 25K", "mips/25K", CPU_MIPS_25K, 2, 1, 0 }, > + { "MIPS 34K", "mips/34K", CPU_MIPS_34K, 2, 1, 0 }, > + { "MIPS 5K", "mips/5K", CPU_MIPS_5K, 2, 1, 0 }, > + { "MIPS R10000", "mips/r10000", CPU_MIPS_R10000, 2, 1, 0 }, > + { "MIPS R12000", "mips/r12000", CPU_MIPS_R12000, 4, 1, 0 }, > + { "QED RM7000", "mips/rm7000", CPU_MIPS_RM7000, 1, 1, 0 }, > + { "PMC-Sierra RM9000", "mips/rm9000", CPU_MIPS_RM9000, 2, 1, 0 }, > + { "Sibyte SB1", "mips/sb1", CPU_MIPS_SB1, 4, 1, 0 }, > + { "NEC VR5432", "mips/vr5432", CPU_MIPS_VR5432, 2, 1, 0 }, > + { "NEC VR5500", "mips/vr5500", CPU_MIPS_VR5500, 2, 1, 0 }, > + { "e500", "ppc/e500", CPU_PPC_E500, 4, 1, 0 }, > + { "e500v2", "ppc/e500v2", CPU_PPC_E500_2, 4, 1, 0 }, > + { "Core Solo / Duo", "i386/core", CPU_CORE, 2, 1, 0 }, > + { "PowerPC G4", "ppc/7450", CPU_PPC_7450, 6, 1, 0 }, > + { "Core 2", "i386/core_2", CPU_CORE_2, 2, 1, 0 }, > + { "ppc64 POWER6", "ppc64/power6", CPU_PPC64_POWER6, 4, 1, 0 }, > + { "ppc64 970MP", "ppc64/970MP", CPU_PPC64_970MP, 8, 1, 0 }, > + { "ppc64 Cell Broadband Engine", "ppc64/cell-be", CPU_PPC64_CELL, 8, 1, 0 }, > + { "AMD64 family10", "x86-64/family10", CPU_FAMILY10, 4, 1, 0 }, > + { "ppc64 PA6T", "ppc64/pa6t", CPU_PPC64_PA6T, 6, 1, 0 }, > + { "ARM 11MPCore", "arm/mpcore", CPU_ARM_MPCORE, 2, 1, 0 }, > + { "ARM V6 PMU", "arm/armv6", CPU_ARM_V6, 3, 1, 0 }, > + { "ppc64 POWER5++", "ppc64/power5++", CPU_PPC64_POWER5pp, 6, 1, 0 }, > + { "e300", "ppc/e300", CPU_PPC_E300, 4, 1, 0 }, > + { "AVR32", "avr32", CPU_AVR32, 3, 1, 0 }, > + { "ARM Cortex-A8", "arm/armv7", CPU_ARM_V7, 5, 1, 0 }, > + { "Intel Architectural Perfmon", "i386/arch_perfmon", CPU_ARCH_PERFMON, 0, 1, 0 }, > + { "AMD64 family11h", "x86-64/family11h", CPU_FAMILY11H, 4, 1, 0 }, > + { "ppc64 POWER7", "ppc64/power7", CPU_PPC64_POWER7, 6, 1, 0 }, > + { "ppc64 compat version 1", "ppc64/ibm-compat-v1", CPU_PPC64_IBM_COMPAT_V1, 4, 1, 0 }, > + { "Intel Core/i7", "i386/core_i7", CPU_CORE_I7, 4, 1, 0 }, > + { "Intel Atom", "i386/atom", CPU_ATOM, 2, 1, 0 }, > + { "Loongson2", "mips/loongson2", CPU_MIPS_LOONGSON2, 2, 1, 0 }, > + { "Intel Nehalem microarchitecture", "i386/nehalem", CPU_NEHALEM, 4, 1, 0 }, > + { "ARM Cortex-A9", "arm/armv7-ca9", CPU_ARM_V7_CA9, 7, 1, 0 }, > + { "MIPS 74K", "mips/74K", CPU_MIPS_74K, 4, 1, 0 }, > + { "MIPS 1004K", "mips/1004K", CPU_MIPS_1004K, 2, 1, 0 }, > + { "AMD64 family12h", "x86-64/family12h", CPU_FAMILY12H, 4, 1, 0 }, > + { "AMD64 family14h", "x86-64/family14h", CPU_FAMILY14H, 4, 1, 0 }, > + { "AMD64 family15h", "x86-64/family15h", CPU_FAMILY15H, 6, 1, 0 }, > + { "Intel Westmere microarchitecture", "i386/westmere", CPU_WESTMERE, 4, 1, 0 }, > + { "ARMv7 Scorpion", "arm/armv7-scorpion", CPU_ARM_SCORPION, 5, 1, 0 }, > + { "ARMv7 ScorpionMP", "arm/armv7-scorpionmp", CPU_ARM_SCORPIONMP, 5, 1, 0 }, > + { "Intel Sandy Bridge microarchitecture", "i386/sandybridge", CPU_SANDYBRIDGE, 8, 1, 0 }, > + { "System Z with basic mode sampling support", "systemz/hwsampling_v1", CPU_SYSTEMZ_HWSAMPV1, 1, 0, 1 }, > }; > > static size_t const nr_cpu_descrs = sizeof(cpu_descrs) / sizeof(struct cpu_descr); > @@ -214,3 +217,45 @@ int op_get_nr_counters(op_cpu cpu_type) > > return cpu_descrs[cpu_type].nr_counters; > } > + > +int op_has_hardware_counters(op_cpu cpu_type) > +{ > + return cpu_descrs[cpu_type].hardware_counters_p; > +} > + > +int op_has_hardware_sampling(op_cpu cpu_type) > +{ > + return cpu_descrs[cpu_type].hardware_sampling_p; > +} > + > +int op_hardware_sampling_enabled(op_cpu cpu_type) > +{ > + int result = 0; > + > + if (!op_has_hardware_sampling(cpu_type)) > + return 0; > + > + switch (cpu_type) { > + case CPU_SYSTEMZ_HWSAMPV1: > + { > + FILE * fp; > + int enabled; > + > + fp = fopen("/dev/oprofile/hwsampling/hwsampler", "r"); > + if (!fp) { > + fprintf(stderr, "Unable to open cpu_type file for reading\n"); > + fprintf(stderr, "Make sure you have done opcontrol --init\n"); > + return 0; > + } > + if ((enabled = fgetc(fp)) == EOF) > + break; > + result = (char)enabled == '1' ? 1 : 0; > + fclose(fp); > + } > + > + break; > + default: > + return 0; > + } > + return result; > +} > diff --git a/libop/op_cpu_type.h b/libop/op_cpu_type.h > index d6cae3a..becf31a 100644 > --- a/libop/op_cpu_type.h > +++ b/libop/op_cpu_type.h > @@ -91,6 +91,7 @@ typedef enum { > CPU_ARM_SCORPION, /**< ARM SCORPION */ > CPU_ARM_SCORPIONMP, /**< ARM SCORPIONMP */ > CPU_SANDYBRIDGE, /* Intel Sandy-Bridge microarchitecture */ > + CPU_SYSTEMZ_HWSAMPV1, /**< System z with hardware sampling support */ > MAX_CPU_TYPE > } op_cpu; > > @@ -150,12 +151,41 @@ char const * op_get_cpu_name(op_cpu cpu_type); > */ > int op_get_nr_counters(op_cpu cpu_type); > > +/** > + * return true if the CPU type supports hardware counters > + * @param cpu_type numeric processor type > + * > + * returns 1 if the CPU supports hardware counters > + */ > +int op_has_hardware_counters(op_cpu cpu_type); > + > +/** > + * return true if the CPU type supports hardware sampling > + * @param cpu_type numeric processor type > + * > + * returns 1 if the CPU supports hardware sampling > + */ > +int op_has_hardware_sampling(op_cpu cpu_type); > + > +/** > + * return true if the CPU type supports hardware sampling > + * and it is currently enabled in the kernel > + * @param cpu_type numeric processor type > + * > + * returns 1 if the CPU supports hardware sampling and > + * it is currently enabled > + */ > +int op_hardware_sampling_enabled(op_cpu cpu_type); > + > + > typedef enum { > OP_INTERFACE_NO_GOOD = -1, > OP_INTERFACE_24, > OP_INTERFACE_26 > } op_interface; > > + > + > /** > * get the INTERFACE used to communicate between daemon and the kernel > * > diff --git a/libop/op_events.c b/libop/op_events.c > index f4d54f9..42e3751 100644 > --- a/libop/op_events.c > +++ b/libop/op_events.c > @@ -1126,6 +1126,10 @@ void op_default_event(op_cpu cpu_type, struct op_default_event_descr * descr) > descr->name = "CPU_CLK"; > break; > > + case CPU_SYSTEMZ_HWSAMPV1: > + descr->name = "HWSAMPLING"; > + break; > + > // don't use default, if someone add a cpu he wants a compiler > // warning if he forgets to handle it here. > case CPU_TIMER_INT: > diff --git a/libop/tests/load_events_files_tests.c b/libop/tests/load_events_files_tests.c > index de548e5..66ab714 100644 > --- a/libop/tests/load_events_files_tests.c > +++ b/libop/tests/load_events_files_tests.c > @@ -21,7 +21,7 @@ int main(void) > setenv("OPROFILE_EVENTS_DIR", OPROFILE_SRCDIR "/events", 1); > > for (cpu_type = CPU_NO_GOOD + 1; cpu_type< MAX_CPU_TYPE; ++cpu_type) { > - if (cpu_type != CPU_TIMER_INT) { > + if (op_has_hardware_counters(cpu_type)) { > op_events(cpu_type); > op_free_events(); > } > diff --git a/libpp/op_header.cpp b/libpp/op_header.cpp > index 754015a..bb7973e 100644 > --- a/libpp/op_header.cpp > +++ b/libpp/op_header.cpp > @@ -160,11 +160,6 @@ string const op_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count) > { > string str; > > - if (cpu_type == CPU_TIMER_INT) { > - str += "Profiling through timer interrupt"; > - return str; > - } > - > struct op_event * event = op_find_event(cpu_type, type, um); > > if (!event) { > @@ -234,6 +229,10 @@ string const describe_header(opd_header const& header) > { > op_cpu cpu = static_cast<op_cpu>(header.cpu_type); > > + if (!op_has_hardware_counters(cpu)) { > + return ""; > + } > + > if (want_xml) > return op_xml_print_event(cpu, header.ctr_event, > header.ctr_um, header.ctr_count); > @@ -254,11 +253,20 @@ string const describe_cpu(opd_header const& header) > str = xml_utils::get_profile_header(cpu_name, header.cpu_speed); > } else { > str += string("CPU: ") + op_get_cpu_type_str(cpu); > - str += ", speed "; > > - ostringstream ss; > - ss<< header.cpu_speed; > - str += ss.str() + " MHz (estimated)"; > + if (header.cpu_speed> 0) { > + str += ", speed "; > + > + ostringstream ss; > + ss<< header.cpu_speed; > + str += ss.str() + " MHz (estimated)"; > + } > + if (op_has_hardware_sampling(cpu)) { > + if (op_hardware_sampling_enabled(cpu)) > + str += " (hardware sampling enabled)"; > + else > + str += " (hardware sampling disabled)"; > + } > } > return str; > } > diff --git a/utils/opcontrol b/utils/opcontrol > index 0951574..bc69b1e 100644 > --- a/utils/opcontrol > +++ b/utils/opcontrol > @@ -239,6 +239,14 @@ opcontrol: usage: > --xen Xen image (for Xen only) > --active-domains=<list> List of domains in profiling session (for Xen) > (list contains domain ids separated by commas) > + > + --disable-hardwaresampling Force to use timer based sampling. > + By default hardware sampling is used if possible. > + > + System z specific options > + > + --s390hwsamprate=cycles Number of machine cycles between taking samples. > + --s390hwsampbufsize=buffers Number of 2MB areas used per CPU for storing sample data. > EOF > } > > @@ -381,6 +389,10 @@ do_init() > IBS_OP_COUNT=0 > IBS_OP_UNITMASK=0 > > + # System z specific values > + S390_HW_SAMPLER_INTERVAL=0 > + S390_HW_SAMPLER_BUFSIZE=0 > + > OPROFILED="$OPDIR/oprofiled" > > # location for daemon setup information > @@ -398,18 +410,13 @@ do_init() > decide_oprofile_device > > DEFAULT_EVENT=`$OPHELP --get-default-event` > - > - IS_TIMER=0 > - IS_PERFMON=0 > - if test "$CPUTYPE" = "timer"; then > - IS_TIMER=1 > - else > - case "$CPUTYPE" in > - ia64/*) > - IS_PERFMON=$KERNEL_SUPPORT > - ;; > - esac > - fi > + HAVE_HWSAMPLING=`$OPHELP --have-hwsampling` > + HAVE_HWCOUNTERS=`$OPHELP --have-hwcounters` > + case "$CPUTYPE" in > + ia64/*) > + IS_PERFMON=$KERNEL_SUPPORT > + ;; > + esac > } > > > @@ -435,6 +442,23 @@ set_event() > eval "CHOSEN_EVENTS_$1=$2" > } > > +do_platform_save_setup() > +{ > + case "$PLATFORM" in > + s390*) > + if test "$HAVE_HWSAMPLING" = "1"; then > + if test "$S390_HW_SAMPLER_INTERVAL" != "0"; then > + echo "S390_HW_SAMPLER_INTERVAL=$S390_HW_SAMPLER_INTERVAL">> $SETUP_FILE > + fi > + if test "$S390_HW_SAMPLER_BUFSIZE" != "0"; then > + echo "S390_HW_SAMPLER_BUFSIZE=$S390_HW_SAMPLER_BUFSIZE">> $SETUP_FILE > + fi > + fi > + ;; > + *) > + ;; > + esac > +} > > # save all the setup related information > do_save_setup() > @@ -448,10 +472,12 @@ do_save_setup() > # daemon is restarted, we'll reload the config data from this secondary > # cache file. > > - if is_oprofiled_active "$LOCK_FILE"; then > - SETUP_FILE="$SEC_SETUP_FILE" > - echo "The profiling daemon is currently active, so changes to the configuration" > - echo "will be used the next time you restart oprofile after a --shutdown or --deinit." > + if test "$DO_SETUP" = "yes"; then > + if is_oprofiled_active "$LOCK_FILE"; then > + SETUP_FILE="$SEC_SETUP_FILE" > + echo "The profiling daemon is currently active, so changes to the configuration of the daemon" > + echo "will be used the next time you restart oprofile after a --shutdown or --deinit." > + fi > fi > > touch $SETUP_FILE > @@ -496,6 +522,9 @@ do_save_setup() > if test "$XEN_RANGE"; then > echo "XEN_RANGE=$XEN_RANGE">> $SETUP_FILE > fi > + > + do_platform_save_setup > + > SETUP_FILE="$SAVE_SETUP_FILE" > } > > @@ -539,6 +568,53 @@ do_load_setup() > } > > > +# Various checks related to Hardware sampler option > +check_platform_args() > +{ > + case "$PLATFORM" in > + s390*) > + if test "$HAVE_HWSAMPLING" == "0"; then > + return > + fi > + if test -r $MOUNT/hwsampling/hw_min_interval; then > + min_interval=`cat $MOUNT/hwsampling/hw_min_interval` > + fi > + if test -r $MOUNT/hwsampling/hw_max_interval; then > + max_interval=`cat $MOUNT/hwsampling/hw_max_interval` > + fi > + > + # Bounds check for Hardware Sampler rate. > + if test "$S390_HW_SAMPLER_INTERVAL" != "0"; then > + case "$S390_HW_SAMPLER_INTERVAL" in > + *[^0-9]*) > + echo "Invalid value for hardware sampling rate.">&2 > + echo "Numeric value expected.">&2 > + exit 1 > + ;; > + esac > + if test "$S390_HW_SAMPLER_INTERVAL" -lt "$min_interval" || test "$S390_HW_SAMPLER_INTERVAL" -gt "$max_interval"; then > + echo "Invalid value for hardware sampling rate">&2 > + echo "should be between $min_interval and $max_interval">&2 > + exit 1 > + fi > + fi > + > + # Format check for hardware sampler buffer size. > + if test "$S390_HW_SAMPLER_BUFSIZE" != "0"; then > + case "$S390_HW_SAMPLER_BUFSIZE" in > + *[^0-9]*) > + echo "Invalid value for hardware sampling buffer size.">&2 > + echo "Numeric value expected.">&2 > + exit 1 > + ;; > + esac > + fi > + ;; > + *) > + ;; > + esac > +} > + > check_valid_args() > { > if test -z "$VMLINUX"; then > @@ -672,10 +748,11 @@ validate_separate_args() > # check the counters make sense, and resolve the hardware allocation > verify_counters() > { > - if test "$IS_TIMER" = 1; then > + if test "$HAVE_HWCOUNTERS" = "0"; then > if test "$NR_CHOSEN" != 0; then > - echo "You cannot specify any performance counter events">&2 > - echo "because OProfile is in timer mode.">&2 > + echo "Counter events are not supported.">&2 > + echo "Either no counter events are supported for this platform ">&2 > + echo "or the OProfile module has been forced to use timer based sampling.">&2 > exit 1 > fi > return > @@ -705,7 +782,7 @@ verify_counters() > # setup any needed default value in chosen events > normalise_events() > { > - if test "$NR_CHOSEN" -le 0 || test "$IS_TIMER" = 1; then > + if test "$NR_CHOSEN" -le 0 || test "$HAVE_HWCOUNTERS" = "0"; then > return > fi > > @@ -745,6 +822,7 @@ do_options() > { > EXCLUSIVE_ARGC=0 > SETUP=no > + DO_HWSAMP_SETUP=no > NEED_SETUP=no > SEEN_EVENT=0 > > @@ -971,10 +1049,26 @@ do_options() > exec $OPHELP > ;; > > - *) > - echo "Unknown option \"$arg\". See opcontrol --help">&2 > - exit 1 > + --disable-hardwaresampling) > + HAVE_HWSAMPLING=0 > + ;; > + > + --s390hwsamprate) > + error_if_empty $arg $val > + S390_HW_SAMPLER_INTERVAL=$val > + DO_HWSAMP_SETUP=yes > + ;; > + > + --s390hwsampbufsize) > + error_if_empty $arg $val > + S390_HW_SAMPLER_BUFSIZE=$val > + DO_HWSAMP_SETUP=yes > ;; > + > + *) > + echo "Unknown option \"$arg\". See opcontrol --help">&2 > + exit 1 > + ;; > esac > done > > @@ -987,7 +1081,7 @@ do_options() > exit 1 > fi > > - if test "$SETUP" = "yes" -a "$DO_SETUP" != "yes"; then > + if test "$SETUP" = "yes" -a "$DO_SETUP" != "yes" -a "$DO_HWSAMP_SETUP" != "yes"; then > echo "No options specified for --setup.">&2 > exit 1 > fi > @@ -999,8 +1093,8 @@ do_options() > fi > fi > > - if test "$DO_SETUP" = "yes"; then > - SETUP="$DO_SETUP" > + if test "$DO_SETUP" = "yes" -o "$DO_HWSAMP_SETUP" = "yes"; then > + SETUP="yes" > fi > > if test "$EXCLUSIVE_ARGC" -eq 1 -a "$SETUP" = "yes"; then > @@ -1033,6 +1127,10 @@ do_options() > vecho "CPU_BUF_SIZE default value" > fi > fi > + if test "$HAVE_HWSAMPLING" = "1"; then > + vecho "S390_HW_SAMPLER_INTERVAL $S390_HW_SAMPLER_INTERVAL" > + vecho "S390_HW_SAMPLER_BUFSIZE $S390_HW_SAMPLER_BUFSIZE" > + fi > > vecho "SEPARATE_LIB $SEPARATE_LIB" > vecho "SEPARATE_KERNEL $SEPARATE_KERNEL" > @@ -1228,15 +1326,15 @@ set_ctr_param() > is_non_cell_ppc64_variant() > { > case "$1" in > - ppc64/*cell*) > - return 0 > - ;; > - ppc64/*) > - return 1 > - ;; > - *) > - return 0 > - ;; > + ppc64/*cell*) > + return 0 > + ;; > + ppc64/*) > + return 1 > + ;; > + *) > + return 0 > + ;; > esac > } > > @@ -1414,7 +1512,7 @@ do_param_setup() > echo "Call-graph profiling not supported - ignored">&2 > fi > > - if test "$IS_TIMER" = 1; then > + if test "$HAVE_HWCOUNTERS" = "0"; then > return > fi > > @@ -1578,7 +1676,7 @@ do_start_daemon() > --separate-thread=$SEPARATE_THREAD \ > --separate-cpu=$SEPARATE_CPU" > > - if test "$IS_TIMER" = 1; then > + if test "$HAVE_HWCOUNTERS" = "0"; then > OPD_ARGS="$OPD_ARGS --events=" > else > if ! test -z "$OPROFILED_EVENTS"; then > @@ -1625,9 +1723,35 @@ do_start_daemon() > echo "Daemon started." > } > > +do_platform_start() > +{ > + case "$PLATFORM" in > + s390*) > + if test "$HAVE_HWSAMPLING" = "0"; then > + if test -f $MOUNT/hwsampling/hwsampler; then > + echo "Disabling Hardware sampling" > + echo 0> $MOUNT/hwsampling/hwsampler > + fi > + return > + fi > + echo "Enabling Hardware sampling" > + echo 1> $MOUNT/hwsampling/hwsampler > + if test "$S390_HW_SAMPLER_INTERVAL" != 0; then > + echo $S390_HW_SAMPLER_INTERVAL>$MOUNT/hwsampling/hw_interval > + fi > + if test "$S390_HW_SAMPLER_BUFSIZE" != 0; then > + echo $S390_HW_SAMPLER_BUFSIZE>$MOUNT/hwsampling/hw_sdbt_blocks > + fi > + ;; > + *) > + ;; > + esac > +} > + > do_start() > { > prep_jitdump; > + do_platform_start > if test "$KERNEL_SUPPORT" = "yes"; then > echo 1>$MOUNT/enable > fi > @@ -1636,6 +1760,27 @@ do_start() > } > > > +do_platform_status() > +{ > + case "$PLATFORM" in > + s390*) > + if test "$HAVE_HWSAMPLING" = "0"; then > + return > + fi > + echo -n "Hardware sampling interval: " > + echo -n $S390_HW_SAMPLER_INTERVAL > + echo -n " - current hardware setting: " > + cat $MOUNT/hwsampling/hw_interval > + echo -n "Hardware sampling buffer size: " > + echo -n $S390_HW_SAMPLER_BUFSIZE > + echo -n " - current hardware setting: " > + cat $MOUNT/hwsampling/hw_sdbt_blocks > + ;; > + *) > + ;; > + esac > +} > + > # print status > do_status() > { > @@ -1702,6 +1847,10 @@ do_status() > fi > fi > > + if test "$HAVE_HWSAMPLING" = "1"; then > + do_platform_status > + fi > + > exit 0 > } > > @@ -1855,6 +2004,9 @@ do_operations() > fi > > if test "$SETUP" = "yes"; then > + if test "$DO_HWSAMP_SETUP" = "yes"; then > + check_platform_args > + fi > check_valid_args > do_save_setup > fi > @@ -2161,6 +2313,7 @@ if test -z "$OPDIR"; then > fi > > PATH=$OPDIR:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin > +PLATFORM=`uname -i` > > check_options_early $@ > > diff --git a/utils/ophelp.c b/utils/ophelp.c > index 5dcb217..a51be63 100644 > --- a/utils/ophelp.c > +++ b/utils/ophelp.c > @@ -33,6 +33,8 @@ static op_cpu cpu_type = CPU_NO_GOOD; > static char * cpu_string; > static int callgraph_depth; > static int want_xml; > +static int have_hwsamp; > +static int have_hwcounters; > > static poptContext optcon; > > @@ -339,9 +341,13 @@ static struct poptOption options[] = { > { "callgraph", '\0', POPT_ARG_INT,&callgraph_depth, 0, > "use this callgraph depth", "callgraph depth", }, > { "version", 'v', POPT_ARG_NONE,&show_vers, 0, > - "show version", NULL, }, > + "show version", NULL, }, > { "xml", 'X', POPT_ARG_NONE,&want_xml, 0, > - "list events as XML", NULL, }, > + "list events as XML", NULL, }, > + { "have-hwsampling", 's', POPT_ARG_NONE,&have_hwsamp, 0, > + "print 1 if the CPU supports hardware sampling", NULL, }, > + { "have-hwcounters", 'k', POPT_ARG_NONE,&have_hwcounters, 0, > + "print 1 if the CPU supports hardware counters", NULL, }, > { "extra-mask", 'E', POPT_ARG_NONE,&extra_mask, 0, > "print extra mask for event", NULL, }, > POPT_AUTOHELP > @@ -422,6 +428,20 @@ int main(int argc, char const * argv[]) > exit(EXIT_FAILURE); > } > > + if (have_hwsamp) { > + if (have_hwcounters) { > + fprintf(stderr, "-s and -k cannot be used in combination.\n"); > + exit(EXIT_FAILURE); > + } > + printf("%d", op_has_hardware_sampling(cpu_type)); > + exit(EXIT_SUCCESS); > + } > + > + if (have_hwcounters) { > + printf("%d", op_has_hardware_counters(cpu_type)); > + exit(EXIT_SUCCESS); > + } > + > parsed_events = (struct parsed_event *)xcalloc(num_chosen_events, > sizeof(struct parsed_event)); > > @@ -443,6 +463,12 @@ int main(int argc, char const * argv[]) > exit(EXIT_SUCCESS); > } > > + if (op_has_hardware_sampling(cpu_type)) > + printf("Using CPU hardware sampling support.\n"); > + > + if (!op_has_hardware_counters(cpu_type)) > + exit(EXIT_SUCCESS); > + > events = op_events(cpu_type); > > if (!chosen_events&& (unit_mask || check_events || extra_mask)) { > @@ -731,6 +757,10 @@ int main(int argc, char const * argv[]) > "Chapter 6: Performance Counters\n" > "http://www.atmel.com/dyn/resources/prod_documents/doc32000.pdf\n"; > > + case CPU_SYSTEMZ_HWSAMPV1: > + event_doc = "Hardware Basic Mode Sampling\n"; > + break; > + > case CPU_RTC: > break; > > > ------------------------------------------------------------------------------ > All the data continuously generated in your IT infrastructure contains a > definitive record of customers, application performance, security > threats, fraudulent activity and more. Splunk takes this data and makes > sense of it. Business sense. IT sense. Common sense. > http://p.sf.net/sfu/splunk-d2d-oct > _______________________________________________ > oprofile-list mailing list > opr...@li... > https://lists.sourceforge.net/lists/listinfo/oprofile-list > |
From: Maynard J. <may...@us...> - 2011-10-19 20:02:00
|
On 10/12/2011 10:20 AM, Andreas Krebbel wrote: > Since kernel version 2.6.39 the hardware sampling facility of IBM > System z is supported as part of the OProfile kernel module. Andreas, This patch seems way more intrusive than it needs to be. Please look at how support for other new processor types have been added to oprofile -- for example, the recently contributed tile<x> support. When contributing new processor support for oprofile, we expect corresponding oprofile kernel code to fit the model that oprofile userspace needs. A lot of the changes I see below are the result of your oprofile kernel module not communicating with oprofile userspace in the standard form. I don't think the new 'disable-hardwaresampling' and 's390hwsamprate' options to opcontrol are really needed. What you should do is create a new events/s390/events file and add two pseudo events (say, "HW_SAMPLING" and "TIME_BASED_SAMPLING"). (You'd also need to add a unit_masks file. Look at events/arm/* for example of adding a non-functional unit_mask file.) Then users can use the same event specification on the opcontrol command line that's used for every other processor type -- for example: opcontrol --event=HW_SAMPLING:100000 where the '100000' is the sample rate. This, of course, implies that your oprofile kernel driver should do what every other arch's oprofile kernel driver does (AFAIK) and read the /dev/oprofile/<counter_num>/[count,event] pseudo files to get the event ID and sample rate. Yes, I know, there aren't *really* any h/w counters on s390, but in the interest of reusing a standard userspace-to-kernel communication protocol, you can fake it and just pretend the s390 has 1 counter. Also, is there a reason why the existing 'buffer-size' option cannot be used instead of the new 's390hwsampbufsize' option? I suspect you can do away with the new fields to the 'struct cpu_descr' and the new "do_platform_start" function (and related functions) in opcontrol if you follow the standards mentioned above. One final comment . . . There are a number of superflous changed lines that are only whitespace changes. Please avoid that. Regards, -Maynard > > http://marc.info/?l=oprofile-list&m=129785521106543&w=2 > > The user space interface stayed compatible to the timer mode sampling > and therefore the kernel part keeps working with an unmodified user > space. However there are some disadvantages due to that: > > - The configuration of the hardware sampling must be done by echoing > values into virtual files provided by the hardware sampling kernel > part. > - The user can not easily see whether hardware sampling or timer based > sampling is being used. The user space tools will always tell you > that you are in timer mode. > > This patch enhances the user space part of OProfile in order to make > hardware sampling easier to use. > > - New options are provided which allow to set the hardware sampling > parameters on opcontrol command line. > - A new option allows to fallback to timer based sampling without > reloading the kernel module. > - A new cpu type for System z machines with hardware sampling is > added. > > In order to enable the features of this patch a one line kernel patch > is needed as well. The kernel patch will be submitted after the user > space support has been integrated since it would otherwise break the > existing OProfile user space by introducing an unknown cpu type. > > Signed-off-by: Andreas Krebbel<kr...@li...> > --- > > daemon/opd_events.c | 2 > doc/internals.xml | 20 ++ > doc/oprofile.xml | 44 ++++++ > gui/oprof_start.cpp | 4 > libop/op_cpu_type.c | 185 +++++++++++++++++---------- > libop/op_cpu_type.h | 30 ++++ > libop/op_events.c | 4 > libop/tests/load_events_files_tests.c | 2 > libpp/op_header.cpp | 26 ++- > utils/opcontrol | 227 ++++++++++++++++++++++++++++------ > utils/ophelp.c | 34 ++++- > 11 files changed, 456 insertions(+), 122 deletions(-) > > diff --git a/daemon/opd_events.c b/daemon/opd_events.c > index b544fb3..885e6a6 100644 > --- a/daemon/opd_events.c > +++ b/daemon/opd_events.c > @@ -82,7 +82,7 @@ void opd_parse_events(char const * events) > char * c; > size_t cur = 0; > > - if (cpu_type == CPU_TIMER_INT) { > + if (!op_has_hardware_counters(cpu_type)) { > struct opd_event * event =&opd_events[0]; > event->name = xstrdup("TIMER"); > event->value = event->counter > diff --git a/doc/internals.xml b/doc/internals.xml > index a7feac7..fa70f5e 100644 > --- a/doc/internals.xml > +++ b/doc/internals.xml > @@ -309,6 +309,26 @@ samples are registered with the OProfile core itself as usual (with > > </chapter> > > +<chapter id="hardware-sampling"> > +<title>Hardware Sampling Support</title> > +<para> > +Some hardware (e.g. IBM System z) provides facilities which do > +instruction sampling as part of the CPU. This usually has great > +advantages over the timer based sampling approach like e.g. better > +sampling resolution with less overhead and the possibility to get > +samples within code sections where interrupts are disabled. > +</para> > +<para> > +Since the hardware sampling facilites basically cover the same task as > +timer based sampling the interface between the Linux kernel and the > +OProfile user space part stays the same. However, a few extensions to > +the user space tools have been added in order to provide the user with > +a way to change the configuration and disable the hardware sampling > +temporarily. Please see the OProfile user manual for details about > +how to configure hardware sampling for your hardware. > +</para> > +</chapter> > + > <chapter id="collecting-samples"> > <title>Collecting and processing samples</title> > > diff --git a/doc/oprofile.xml b/doc/oprofile.xml > index 6a17c6d..07d02d0 100644 > --- a/doc/oprofile.xml > +++ b/doc/oprofile.xml > @@ -1328,6 +1328,50 @@ Note: * All IBS fetch event must have the same event count and unitmask, > > </sect2> > > +<sect2 id="systemz"> > +<title>IBM System z hardware sampling support</title> > +<para> > +IBM System z provides a facility which does instruction sampling as > +part of the CPU. This has great advantages over the timer based > +sampling approach like better sampling resolution with less overhead > +and the possibility to get samples within code sections where > +interrupts are disabled (useful especially for Linux kernel code). > +</para> > +<para> > +System z hardware sampling can be used for Linux instances in LPAR > +mode. The hardware sampling support used by OProfile was introduced > +for System z10 in October 2008. > +</para> > +<para> > +To enable hardware sampling for an LPAR you must activate the LPAR > +with authorization for basic sampling control. See the "Support > +Element Operations Guide" for your mainframe system for more > +information. > +</para> > +<para> > +The opcontrol tool provides a few options specific to System z > +hardware sampling. These options get in effect immediately. They do > +not require to restart the OProfile daemon. The hardware sampling > +rate and the sampling buffer size is stored into the OProfile > +configuration file. > +</para> > + > +<variablelist> > +<varlistentry><term><option>--disable-hardwaresampling</option></term><listitem><para> > +On platforms providing hardware sampling capabilities this can be used > +to force a fallback to timer based sampling. This option is not > +stored in the OProfile configuration file.</para></listitem></varlistentry> > +<varlistentry><term><option>--s390hwsamprate=</option>cycles</term><listitem><para> > +Number of machine cycles between taking samples. This number must be within a hardware specific range. The range with z10 (October 2008) is [2202, 144305868].</para></listitem></varlistentry> > +<varlistentry><term><option>--s390hwsampbufsize=</option>buffers</term><listitem><para> > +Number of 2MB areas used per CPU for storing sample data. The best > +size for the sample memory depends on the particular system and the > +workload to be measured. Providing the sampler with too little memory > +results in lost samples. Reserving too much system memory for the > +sampler impacts the overall performance and, hence, also the workload > +to be measures</para></listitem></varlistentry> > +</variablelist> > +</sect2> > > <sect2 id="misuse"> > <title>Dangerous counter settings</title> > diff --git a/gui/oprof_start.cpp b/gui/oprof_start.cpp > index 725b215..5753e0f 100644 > --- a/gui/oprof_start.cpp > +++ b/gui/oprof_start.cpp > @@ -139,7 +139,7 @@ oprof_start::oprof_start() > cpu_type = op_get_cpu_type(); > op_nr_counters = op_get_nr_counters(cpu_type); > > - if (cpu_type == CPU_TIMER_INT) { > + if (!op_has_hardware_counters(cpu_type) { > setup_config_tab->removePage(counter_setup_page); > } else { > fill_events(); > @@ -907,7 +907,7 @@ void oprof_start::on_start_profiler() > } > } > > - if (one_enable == false&& cpu_type != CPU_TIMER_INT) { > + if (one_enable == false&& op_has_hardware_counters(cpu_type)) { > QMessageBox::warning(this, 0, "No counters enabled.\n"); > return; > } > diff --git a/libop/op_cpu_type.c b/libop/op_cpu_type.c > index 14e26bf..01054a5 100644 > --- a/libop/op_cpu_type.c > +++ b/libop/op_cpu_type.c > @@ -21,79 +21,82 @@ struct cpu_descr { > char const * name; > op_cpu cpu; > unsigned int nr_counters; > + int hardware_counters_p; > + int hardware_sampling_p; > }; > > static struct cpu_descr const cpu_descrs[MAX_CPU_TYPE] = { > - { "Pentium Pro", "i386/ppro", CPU_PPRO, 2 }, > - { "PII", "i386/pii", CPU_PII, 2 }, > - { "PIII", "i386/piii", CPU_PIII, 2 }, > - { "Athlon", "i386/athlon", CPU_ATHLON, 4 }, > - { "CPU with timer interrupt", "timer", CPU_TIMER_INT, 1 }, > - { "CPU with RTC device", "rtc", CPU_RTC, 1 }, > - { "P4 / Xeon", "i386/p4", CPU_P4, 8 }, > - { "IA64", "ia64/ia64", CPU_IA64, 4 }, > - { "Itanium", "ia64/itanium", CPU_IA64_1, 4 }, > - { "Itanium 2", "ia64/itanium2", CPU_IA64_2, 4 }, > - { "AMD64 processors", "x86-64/hammer", CPU_HAMMER, 4 }, > - { "P4 / Xeon with 2 hyper-threads", "i386/p4-ht", CPU_P4_HT2, 4 }, > - { "Alpha EV4", "alpha/ev4", CPU_AXP_EV4, 2 }, > - { "Alpha EV5", "alpha/ev5", CPU_AXP_EV5, 3 }, > - { "Alpha PCA56", "alpha/pca56", CPU_AXP_PCA56, 3 }, > - { "Alpha EV6", "alpha/ev6", CPU_AXP_EV6, 2 }, > - { "Alpha EV67", "alpha/ev67", CPU_AXP_EV67, 20 }, > - { "Pentium M (P6 core)", "i386/p6_mobile", CPU_P6_MOBILE, 2 }, > - { "ARM/XScale PMU1", "arm/xscale1", CPU_ARM_XSCALE1, 3 }, > - { "ARM/XScale PMU2", "arm/xscale2", CPU_ARM_XSCALE2, 5 }, > - { "ppc64 POWER4", "ppc64/power4", CPU_PPC64_POWER4, 8 }, > - { "ppc64 POWER5", "ppc64/power5", CPU_PPC64_POWER5, 6 }, > - { "ppc64 POWER5+", "ppc64/power5+", CPU_PPC64_POWER5p, 6 }, > - { "ppc64 970", "ppc64/970", CPU_PPC64_970, 8 }, > - { "MIPS 20K", "mips/20K", CPU_MIPS_20K, 1}, > - { "MIPS 24K", "mips/24K", CPU_MIPS_24K, 2}, > - { "MIPS 25K", "mips/25K", CPU_MIPS_25K, 2}, > - { "MIPS 34K", "mips/34K", CPU_MIPS_34K, 2}, > - { "MIPS 5K", "mips/5K", CPU_MIPS_5K, 2}, > - { "MIPS R10000", "mips/r10000", CPU_MIPS_R10000, 2 }, > - { "MIPS R12000", "mips/r12000", CPU_MIPS_R12000, 4 }, > - { "QED RM7000", "mips/rm7000", CPU_MIPS_RM7000, 1 }, > - { "PMC-Sierra RM9000", "mips/rm9000", CPU_MIPS_RM9000, 2 }, > - { "Sibyte SB1", "mips/sb1", CPU_MIPS_SB1, 4 }, > - { "NEC VR5432", "mips/vr5432", CPU_MIPS_VR5432, 2 }, > - { "NEC VR5500", "mips/vr5500", CPU_MIPS_VR5500, 2 }, > - { "e500", "ppc/e500", CPU_PPC_E500, 4 }, > - { "e500v2", "ppc/e500v2", CPU_PPC_E500_2, 4 }, > - { "Core Solo / Duo", "i386/core", CPU_CORE, 2 }, > - { "PowerPC G4", "ppc/7450", CPU_PPC_7450, 6 }, > - { "Core 2", "i386/core_2", CPU_CORE_2, 2 }, > - { "ppc64 POWER6", "ppc64/power6", CPU_PPC64_POWER6, 4 }, > - { "ppc64 970MP", "ppc64/970MP", CPU_PPC64_970MP, 8 }, > - { "ppc64 Cell Broadband Engine", "ppc64/cell-be", CPU_PPC64_CELL, 8 }, > - { "AMD64 family10", "x86-64/family10", CPU_FAMILY10, 4 }, > - { "ppc64 PA6T", "ppc64/pa6t", CPU_PPC64_PA6T, 6 }, > - { "ARM 11MPCore", "arm/mpcore", CPU_ARM_MPCORE, 2 }, > - { "ARM V6 PMU", "arm/armv6", CPU_ARM_V6, 3 }, > - { "ppc64 POWER5++", "ppc64/power5++", CPU_PPC64_POWER5pp, 6 }, > - { "e300", "ppc/e300", CPU_PPC_E300, 4 }, > - { "AVR32", "avr32", CPU_AVR32, 3 }, > - { "ARM Cortex-A8", "arm/armv7", CPU_ARM_V7, 5 }, > - { "Intel Architectural Perfmon", "i386/arch_perfmon", CPU_ARCH_PERFMON, 0}, > - { "AMD64 family11h", "x86-64/family11h", CPU_FAMILY11H, 4 }, > - { "ppc64 POWER7", "ppc64/power7", CPU_PPC64_POWER7, 6 }, > - { "ppc64 compat version 1", "ppc64/ibm-compat-v1", CPU_PPC64_IBM_COMPAT_V1, 4 }, > - { "Intel Core/i7", "i386/core_i7", CPU_CORE_I7, 4 }, > - { "Intel Atom", "i386/atom", CPU_ATOM, 2 }, > - { "Loongson2", "mips/loongson2", CPU_MIPS_LOONGSON2, 2 }, > - { "Intel Nehalem microarchitecture", "i386/nehalem", CPU_NEHALEM, 4 }, > - { "ARM Cortex-A9", "arm/armv7-ca9", CPU_ARM_V7_CA9, 7 }, > - { "MIPS 74K", "mips/74K", CPU_MIPS_74K, 4}, > - { "MIPS 1004K", "mips/1004K", CPU_MIPS_1004K, 2}, > - { "AMD64 family12h", "x86-64/family12h", CPU_FAMILY12H, 4 }, > - { "AMD64 family14h", "x86-64/family14h", CPU_FAMILY14H, 4 }, > - { "AMD64 family15h", "x86-64/family15h", CPU_FAMILY15H, 6 }, > - { "Intel Westmere microarchitecture", "i386/westmere", CPU_WESTMERE, 4 }, > - { "ARMv7 Scorpion", "arm/armv7-scorpion", CPU_ARM_SCORPION, 5 }, > - { "ARMv7 ScorpionMP", "arm/armv7-scorpionmp", CPU_ARM_SCORPIONMP, 5 }, > - { "Intel Sandy Bridge microarchitecture", "i386/sandybridge", CPU_SANDYBRIDGE, 8 }, > + { "Pentium Pro", "i386/ppro", CPU_PPRO, 2, 1, 0 }, > + { "PII", "i386/pii", CPU_PII, 2, 1, 0 }, > + { "PIII", "i386/piii", CPU_PIII, 2, 1, 0 }, > + { "Athlon", "i386/athlon", CPU_ATHLON, 4, 1, 0 }, > + { "CPU with timer interrupt", "timer", CPU_TIMER_INT, 1, 0, 0 }, > + { "CPU with RTC device", "rtc", CPU_RTC, 1, 1, 0 }, > + { "P4 / Xeon", "i386/p4", CPU_P4, 8, 1, 0 }, > + { "IA64", "ia64/ia64", CPU_IA64, 4, 1, 0 }, > + { "Itanium", "ia64/itanium", CPU_IA64_1, 4, 1, 0 }, > + { "Itanium 2", "ia64/itanium2", CPU_IA64_2, 4, 1, 0 }, > + { "AMD64 processors", "x86-64/hammer", CPU_HAMMER, 4, 1, 0 }, > + { "P4 / Xeon with 2 hyper-threads", "i386/p4-ht", CPU_P4_HT2, 4, 1, 0 }, > + { "Alpha EV4", "alpha/ev4", CPU_AXP_EV4, 2, 1, 0 }, > + { "Alpha EV5", "alpha/ev5", CPU_AXP_EV5, 3, 1, 0 }, > + { "Alpha PCA56", "alpha/pca56", CPU_AXP_PCA56, 3, 1, 0 }, > + { "Alpha EV6", "alpha/ev6", CPU_AXP_EV6, 2, 1, 0 }, > + { "Alpha EV67", "alpha/ev67", CPU_AXP_EV67, 21, 1, 0 }, > + { "Pentium M (P6 core)", "i386/p6_mobile", CPU_P6_MOBILE, 2, 1, 0 }, > + { "ARM/XScale PMU1", "arm/xscale1", CPU_ARM_XSCALE1, 3, 1, 0 }, > + { "ARM/XScale PMU2", "arm/xscale2", CPU_ARM_XSCALE2, 5, 1, 0 }, > + { "ppc64 POWER4", "ppc64/power4", CPU_PPC64_POWER4, 8, 1, 0 }, > + { "ppc64 POWER5", "ppc64/power5", CPU_PPC64_POWER5, 6, 1, 0 }, > + { "ppc64 POWER5+", "ppc64/power5+", CPU_PPC64_POWER5p, 6, 1, 0 }, > + { "ppc64 970", "ppc64/970", CPU_PPC64_970, 8, 1, 0 }, > + { "MIPS 20K", "mips/20K", CPU_MIPS_20K, 1, 1, 0 }, > + { "MIPS 24K", "mips/24K", CPU_MIPS_24K, 2, 1, 0 }, > + { "MIPS 25K", "mips/25K", CPU_MIPS_25K, 2, 1, 0 }, > + { "MIPS 34K", "mips/34K", CPU_MIPS_34K, 2, 1, 0 }, > + { "MIPS 5K", "mips/5K", CPU_MIPS_5K, 2, 1, 0 }, > + { "MIPS R10000", "mips/r10000", CPU_MIPS_R10000, 2, 1, 0 }, > + { "MIPS R12000", "mips/r12000", CPU_MIPS_R12000, 4, 1, 0 }, > + { "QED RM7000", "mips/rm7000", CPU_MIPS_RM7000, 1, 1, 0 }, > + { "PMC-Sierra RM9000", "mips/rm9000", CPU_MIPS_RM9000, 2, 1, 0 }, > + { "Sibyte SB1", "mips/sb1", CPU_MIPS_SB1, 4, 1, 0 }, > + { "NEC VR5432", "mips/vr5432", CPU_MIPS_VR5432, 2, 1, 0 }, > + { "NEC VR5500", "mips/vr5500", CPU_MIPS_VR5500, 2, 1, 0 }, > + { "e500", "ppc/e500", CPU_PPC_E500, 4, 1, 0 }, > + { "e500v2", "ppc/e500v2", CPU_PPC_E500_2, 4, 1, 0 }, > + { "Core Solo / Duo", "i386/core", CPU_CORE, 2, 1, 0 }, > + { "PowerPC G4", "ppc/7450", CPU_PPC_7450, 6, 1, 0 }, > + { "Core 2", "i386/core_2", CPU_CORE_2, 2, 1, 0 }, > + { "ppc64 POWER6", "ppc64/power6", CPU_PPC64_POWER6, 4, 1, 0 }, > + { "ppc64 970MP", "ppc64/970MP", CPU_PPC64_970MP, 8, 1, 0 }, > + { "ppc64 Cell Broadband Engine", "ppc64/cell-be", CPU_PPC64_CELL, 8, 1, 0 }, > + { "AMD64 family10", "x86-64/family10", CPU_FAMILY10, 4, 1, 0 }, > + { "ppc64 PA6T", "ppc64/pa6t", CPU_PPC64_PA6T, 6, 1, 0 }, > + { "ARM 11MPCore", "arm/mpcore", CPU_ARM_MPCORE, 2, 1, 0 }, > + { "ARM V6 PMU", "arm/armv6", CPU_ARM_V6, 3, 1, 0 }, > + { "ppc64 POWER5++", "ppc64/power5++", CPU_PPC64_POWER5pp, 6, 1, 0 }, > + { "e300", "ppc/e300", CPU_PPC_E300, 4, 1, 0 }, > + { "AVR32", "avr32", CPU_AVR32, 3, 1, 0 }, > + { "ARM Cortex-A8", "arm/armv7", CPU_ARM_V7, 5, 1, 0 }, > + { "Intel Architectural Perfmon", "i386/arch_perfmon", CPU_ARCH_PERFMON, 0, 1, 0 }, > + { "AMD64 family11h", "x86-64/family11h", CPU_FAMILY11H, 4, 1, 0 }, > + { "ppc64 POWER7", "ppc64/power7", CPU_PPC64_POWER7, 6, 1, 0 }, > + { "ppc64 compat version 1", "ppc64/ibm-compat-v1", CPU_PPC64_IBM_COMPAT_V1, 4, 1, 0 }, > + { "Intel Core/i7", "i386/core_i7", CPU_CORE_I7, 4, 1, 0 }, > + { "Intel Atom", "i386/atom", CPU_ATOM, 2, 1, 0 }, > + { "Loongson2", "mips/loongson2", CPU_MIPS_LOONGSON2, 2, 1, 0 }, > + { "Intel Nehalem microarchitecture", "i386/nehalem", CPU_NEHALEM, 4, 1, 0 }, > + { "ARM Cortex-A9", "arm/armv7-ca9", CPU_ARM_V7_CA9, 7, 1, 0 }, > + { "MIPS 74K", "mips/74K", CPU_MIPS_74K, 4, 1, 0 }, > + { "MIPS 1004K", "mips/1004K", CPU_MIPS_1004K, 2, 1, 0 }, > + { "AMD64 family12h", "x86-64/family12h", CPU_FAMILY12H, 4, 1, 0 }, > + { "AMD64 family14h", "x86-64/family14h", CPU_FAMILY14H, 4, 1, 0 }, > + { "AMD64 family15h", "x86-64/family15h", CPU_FAMILY15H, 6, 1, 0 }, > + { "Intel Westmere microarchitecture", "i386/westmere", CPU_WESTMERE, 4, 1, 0 }, > + { "ARMv7 Scorpion", "arm/armv7-scorpion", CPU_ARM_SCORPION, 5, 1, 0 }, > + { "ARMv7 ScorpionMP", "arm/armv7-scorpionmp", CPU_ARM_SCORPIONMP, 5, 1, 0 }, > + { "Intel Sandy Bridge microarchitecture", "i386/sandybridge", CPU_SANDYBRIDGE, 8, 1, 0 }, > + { "System Z with basic mode sampling support", "systemz/hwsampling_v1", CPU_SYSTEMZ_HWSAMPV1, 1, 0, 1 }, > }; > > static size_t const nr_cpu_descrs = sizeof(cpu_descrs) / sizeof(struct cpu_descr); > @@ -214,3 +217,45 @@ int op_get_nr_counters(op_cpu cpu_type) > > return cpu_descrs[cpu_type].nr_counters; > } > + > +int op_has_hardware_counters(op_cpu cpu_type) > +{ > + return cpu_descrs[cpu_type].hardware_counters_p; > +} > + > +int op_has_hardware_sampling(op_cpu cpu_type) > +{ > + return cpu_descrs[cpu_type].hardware_sampling_p; > +} > + > +int op_hardware_sampling_enabled(op_cpu cpu_type) > +{ > + int result = 0; > + > + if (!op_has_hardware_sampling(cpu_type)) > + return 0; > + > + switch (cpu_type) { > + case CPU_SYSTEMZ_HWSAMPV1: > + { > + FILE * fp; > + int enabled; > + > + fp = fopen("/dev/oprofile/hwsampling/hwsampler", "r"); > + if (!fp) { > + fprintf(stderr, "Unable to open cpu_type file for reading\n"); > + fprintf(stderr, "Make sure you have done opcontrol --init\n"); > + return 0; > + } > + if ((enabled = fgetc(fp)) == EOF) > + break; > + result = (char)enabled == '1' ? 1 : 0; > + fclose(fp); > + } > + > + break; > + default: > + return 0; > + } > + return result; > +} > diff --git a/libop/op_cpu_type.h b/libop/op_cpu_type.h > index d6cae3a..becf31a 100644 > --- a/libop/op_cpu_type.h > +++ b/libop/op_cpu_type.h > @@ -91,6 +91,7 @@ typedef enum { > CPU_ARM_SCORPION, /**< ARM SCORPION */ > CPU_ARM_SCORPIONMP, /**< ARM SCORPIONMP */ > CPU_SANDYBRIDGE, /* Intel Sandy-Bridge microarchitecture */ > + CPU_SYSTEMZ_HWSAMPV1, /**< System z with hardware sampling support */ > MAX_CPU_TYPE > } op_cpu; > > @@ -150,12 +151,41 @@ char const * op_get_cpu_name(op_cpu cpu_type); > */ > int op_get_nr_counters(op_cpu cpu_type); > > +/** > + * return true if the CPU type supports hardware counters > + * @param cpu_type numeric processor type > + * > + * returns 1 if the CPU supports hardware counters > + */ > +int op_has_hardware_counters(op_cpu cpu_type); > + > +/** > + * return true if the CPU type supports hardware sampling > + * @param cpu_type numeric processor type > + * > + * returns 1 if the CPU supports hardware sampling > + */ > +int op_has_hardware_sampling(op_cpu cpu_type); > + > +/** > + * return true if the CPU type supports hardware sampling > + * and it is currently enabled in the kernel > + * @param cpu_type numeric processor type > + * > + * returns 1 if the CPU supports hardware sampling and > + * it is currently enabled > + */ > +int op_hardware_sampling_enabled(op_cpu cpu_type); > + > + > typedef enum { > OP_INTERFACE_NO_GOOD = -1, > OP_INTERFACE_24, > OP_INTERFACE_26 > } op_interface; > > + > + > /** > * get the INTERFACE used to communicate between daemon and the kernel > * > diff --git a/libop/op_events.c b/libop/op_events.c > index f4d54f9..42e3751 100644 > --- a/libop/op_events.c > +++ b/libop/op_events.c > @@ -1126,6 +1126,10 @@ void op_default_event(op_cpu cpu_type, struct op_default_event_descr * descr) > descr->name = "CPU_CLK"; > break; > > + case CPU_SYSTEMZ_HWSAMPV1: > + descr->name = "HWSAMPLING"; > + break; > + > // don't use default, if someone add a cpu he wants a compiler > // warning if he forgets to handle it here. > case CPU_TIMER_INT: > diff --git a/libop/tests/load_events_files_tests.c b/libop/tests/load_events_files_tests.c > index de548e5..66ab714 100644 > --- a/libop/tests/load_events_files_tests.c > +++ b/libop/tests/load_events_files_tests.c > @@ -21,7 +21,7 @@ int main(void) > setenv("OPROFILE_EVENTS_DIR", OPROFILE_SRCDIR "/events", 1); > > for (cpu_type = CPU_NO_GOOD + 1; cpu_type< MAX_CPU_TYPE; ++cpu_type) { > - if (cpu_type != CPU_TIMER_INT) { > + if (op_has_hardware_counters(cpu_type)) { > op_events(cpu_type); > op_free_events(); > } > diff --git a/libpp/op_header.cpp b/libpp/op_header.cpp > index 754015a..bb7973e 100644 > --- a/libpp/op_header.cpp > +++ b/libpp/op_header.cpp > @@ -160,11 +160,6 @@ string const op_print_event(op_cpu cpu_type, u32 type, u32 um, u32 count) > { > string str; > > - if (cpu_type == CPU_TIMER_INT) { > - str += "Profiling through timer interrupt"; > - return str; > - } > - > struct op_event * event = op_find_event(cpu_type, type, um); > > if (!event) { > @@ -234,6 +229,10 @@ string const describe_header(opd_header const& header) > { > op_cpu cpu = static_cast<op_cpu>(header.cpu_type); > > + if (!op_has_hardware_counters(cpu)) { > + return ""; > + } > + > if (want_xml) > return op_xml_print_event(cpu, header.ctr_event, > header.ctr_um, header.ctr_count); > @@ -254,11 +253,20 @@ string const describe_cpu(opd_header const& header) > str = xml_utils::get_profile_header(cpu_name, header.cpu_speed); > } else { > str += string("CPU: ") + op_get_cpu_type_str(cpu); > - str += ", speed "; > > - ostringstream ss; > - ss<< header.cpu_speed; > - str += ss.str() + " MHz (estimated)"; > + if (header.cpu_speed> 0) { > + str += ", speed "; > + > + ostringstream ss; > + ss<< header.cpu_speed; > + str += ss.str() + " MHz (estimated)"; > + } > + if (op_has_hardware_sampling(cpu)) { > + if (op_hardware_sampling_enabled(cpu)) > + str += " (hardware sampling enabled)"; > + else > + str += " (hardware sampling disabled)"; > + } > } > return str; > } > diff --git a/utils/opcontrol b/utils/opcontrol > index 0951574..bc69b1e 100644 > --- a/utils/opcontrol > +++ b/utils/opcontrol > @@ -239,6 +239,14 @@ opcontrol: usage: > --xen Xen image (for Xen only) > --active-domains=<list> List of domains in profiling session (for Xen) > (list contains domain ids separated by commas) > + > + --disable-hardwaresampling Force to use timer based sampling. > + By default hardware sampling is used if possible. > + > + System z specific options > + > + --s390hwsamprate=cycles Number of machine cycles between taking samples. > + --s390hwsampbufsize=buffers Number of 2MB areas used per CPU for storing sample data. > EOF > } > > @@ -381,6 +389,10 @@ do_init() > IBS_OP_COUNT=0 > IBS_OP_UNITMASK=0 > > + # System z specific values > + S390_HW_SAMPLER_INTERVAL=0 > + S390_HW_SAMPLER_BUFSIZE=0 > + > OPROFILED="$OPDIR/oprofiled" > > # location for daemon setup information > @@ -398,18 +410,13 @@ do_init() > decide_oprofile_device > > DEFAULT_EVENT=`$OPHELP --get-default-event` > - > - IS_TIMER=0 > - IS_PERFMON=0 > - if test "$CPUTYPE" = "timer"; then > - IS_TIMER=1 > - else > - case "$CPUTYPE" in > - ia64/*) > - IS_PERFMON=$KERNEL_SUPPORT > - ;; > - esac > - fi > + HAVE_HWSAMPLING=`$OPHELP --have-hwsampling` > + HAVE_HWCOUNTERS=`$OPHELP --have-hwcounters` > + case "$CPUTYPE" in > + ia64/*) > + IS_PERFMON=$KERNEL_SUPPORT > + ;; > + esac > } > > > @@ -435,6 +442,23 @@ set_event() > eval "CHOSEN_EVENTS_$1=$2" > } > > +do_platform_save_setup() > +{ > + case "$PLATFORM" in > + s390*) > + if test "$HAVE_HWSAMPLING" = "1"; then > + if test "$S390_HW_SAMPLER_INTERVAL" != "0"; then > + echo "S390_HW_SAMPLER_INTERVAL=$S390_HW_SAMPLER_INTERVAL">> $SETUP_FILE > + fi > + if test "$S390_HW_SAMPLER_BUFSIZE" != "0"; then > + echo "S390_HW_SAMPLER_BUFSIZE=$S390_HW_SAMPLER_BUFSIZE">> $SETUP_FILE > + fi > + fi > + ;; > + *) > + ;; > + esac > +} > > # save all the setup related information > do_save_setup() > @@ -448,10 +472,12 @@ do_save_setup() > # daemon is restarted, we'll reload the config data from this secondary > # cache file. > > - if is_oprofiled_active "$LOCK_FILE"; then > - SETUP_FILE="$SEC_SETUP_FILE" > - echo "The profiling daemon is currently active, so changes to the configuration" > - echo "will be used the next time you restart oprofile after a --shutdown or --deinit." > + if test "$DO_SETUP" = "yes"; then > + if is_oprofiled_active "$LOCK_FILE"; then > + SETUP_FILE="$SEC_SETUP_FILE" > + echo "The profiling daemon is currently active, so changes to the configuration of the daemon" > + echo "will be used the next time you restart oprofile after a --shutdown or --deinit." > + fi > fi > > touch $SETUP_FILE > @@ -496,6 +522,9 @@ do_save_setup() > if test "$XEN_RANGE"; then > echo "XEN_RANGE=$XEN_RANGE">> $SETUP_FILE > fi > + > + do_platform_save_setup > + > SETUP_FILE="$SAVE_SETUP_FILE" > } > > @@ -539,6 +568,53 @@ do_load_setup() > } > > > +# Various checks related to Hardware sampler option > +check_platform_args() > +{ > + case "$PLATFORM" in > + s390*) > + if test "$HAVE_HWSAMPLING" == "0"; then > + return > + fi > + if test -r $MOUNT/hwsampling/hw_min_interval; then > + min_interval=`cat $MOUNT/hwsampling/hw_min_interval` > + fi > + if test -r $MOUNT/hwsampling/hw_max_interval; then > + max_interval=`cat $MOUNT/hwsampling/hw_max_interval` > + fi > + > + # Bounds check for Hardware Sampler rate. > + if test "$S390_HW_SAMPLER_INTERVAL" != "0"; then > + case "$S390_HW_SAMPLER_INTERVAL" in > + *[^0-9]*) > + echo "Invalid value for hardware sampling rate.">&2 > + echo "Numeric value expected.">&2 > + exit 1 > + ;; > + esac > + if test "$S390_HW_SAMPLER_INTERVAL" -lt "$min_interval" || test "$S390_HW_SAMPLER_INTERVAL" -gt "$max_interval"; then > + echo "Invalid value for hardware sampling rate">&2 > + echo "should be between $min_interval and $max_interval">&2 > + exit 1 > + fi > + fi > + > + # Format check for hardware sampler buffer size. > + if test "$S390_HW_SAMPLER_BUFSIZE" != "0"; then > + case "$S390_HW_SAMPLER_BUFSIZE" in > + *[^0-9]*) > + echo "Invalid value for hardware sampling buffer size.">&2 > + echo "Numeric value expected.">&2 > + exit 1 > + ;; > + esac > + fi > + ;; > + *) > + ;; > + esac > +} > + > check_valid_args() > { > if test -z "$VMLINUX"; then > @@ -672,10 +748,11 @@ validate_separate_args() > # check the counters make sense, and resolve the hardware allocation > verify_counters() > { > - if test "$IS_TIMER" = 1; then > + if test "$HAVE_HWCOUNTERS" = "0"; then > if test "$NR_CHOSEN" != 0; then > - echo "You cannot specify any performance counter events">&2 > - echo "because OProfile is in timer mode.">&2 > + echo "Counter events are not supported.">&2 > + echo "Either no counter events are supported for this platform ">&2 > + echo "or the OProfile module has been forced to use timer based sampling.">&2 > exit 1 > fi > return > @@ -705,7 +782,7 @@ verify_counters() > # setup any needed default value in chosen events > normalise_events() > { > - if test "$NR_CHOSEN" -le 0 || test "$IS_TIMER" = 1; then > + if test "$NR_CHOSEN" -le 0 || test "$HAVE_HWCOUNTERS" = "0"; then > return > fi > > @@ -745,6 +822,7 @@ do_options() > { > EXCLUSIVE_ARGC=0 > SETUP=no > + DO_HWSAMP_SETUP=no > NEED_SETUP=no > SEEN_EVENT=0 > > @@ -971,10 +1049,26 @@ do_options() > exec $OPHELP > ;; > > - *) > - echo "Unknown option \"$arg\". See opcontrol --help">&2 > - exit 1 > + --disable-hardwaresampling) > + HAVE_HWSAMPLING=0 > + ;; > + > + --s390hwsamprate) > + error_if_empty $arg $val > + S390_HW_SAMPLER_INTERVAL=$val > + DO_HWSAMP_SETUP=yes > + ;; > + > + --s390hwsampbufsize) > + error_if_empty $arg $val > + S390_HW_SAMPLER_BUFSIZE=$val > + DO_HWSAMP_SETUP=yes > ;; > + > + *) > + echo "Unknown option \"$arg\". See opcontrol --help">&2 > + exit 1 > + ;; > esac > done > > @@ -987,7 +1081,7 @@ do_options() > exit 1 > fi > > - if test "$SETUP" = "yes" -a "$DO_SETUP" != "yes"; then > + if test "$SETUP" = "yes" -a "$DO_SETUP" != "yes" -a "$DO_HWSAMP_SETUP" != "yes"; then > echo "No options specified for --setup.">&2 > exit 1 > fi > @@ -999,8 +1093,8 @@ do_options() > fi > fi > > - if test "$DO_SETUP" = "yes"; then > - SETUP="$DO_SETUP" > + if test "$DO_SETUP" = "yes" -o "$DO_HWSAMP_SETUP" = "yes"; then > + SETUP="yes" > fi > > if test "$EXCLUSIVE_ARGC" -eq 1 -a "$SETUP" = "yes"; then > @@ -1033,6 +1127,10 @@ do_options() > vecho "CPU_BUF_SIZE default value" > fi > fi > + if test "$HAVE_HWSAMPLING" = "1"; then > + vecho "S390_HW_SAMPLER_INTERVAL $S390_HW_SAMPLER_INTERVAL" > + vecho "S390_HW_SAMPLER_BUFSIZE $S390_HW_SAMPLER_BUFSIZE" > + fi > > vecho "SEPARATE_LIB $SEPARATE_LIB" > vecho "SEPARATE_KERNEL $SEPARATE_KERNEL" > @@ -1228,15 +1326,15 @@ set_ctr_param() > is_non_cell_ppc64_variant() > { > case "$1" in > - ppc64/*cell*) > - return 0 > - ;; > - ppc64/*) > - return 1 > - ;; > - *) > - return 0 > - ;; > + ppc64/*cell*) > + return 0 > + ;; > + ppc64/*) > + return 1 > + ;; > + *) > + return 0 > + ;; > esac > } > > @@ -1414,7 +1512,7 @@ do_param_setup() > echo "Call-graph profiling not supported - ignored">&2 > fi > > - if test "$IS_TIMER" = 1; then > + if test "$HAVE_HWCOUNTERS" = "0"; then > return > fi > > @@ -1578,7 +1676,7 @@ do_start_daemon() > --separate-thread=$SEPARATE_THREAD \ > --separate-cpu=$SEPARATE_CPU" > > - if test "$IS_TIMER" = 1; then > + if test "$HAVE_HWCOUNTERS" = "0"; then > OPD_ARGS="$OPD_ARGS --events=" > else > if ! test -z "$OPROFILED_EVENTS"; then > @@ -1625,9 +1723,35 @@ do_start_daemon() > echo "Daemon started." > } > > +do_platform_start() > +{ > + case "$PLATFORM" in > + s390*) > + if test "$HAVE_HWSAMPLING" = "0"; then > + if test -f $MOUNT/hwsampling/hwsampler; then > + echo "Disabling Hardware sampling" > + echo 0> $MOUNT/hwsampling/hwsampler > + fi > + return > + fi > + echo "Enabling Hardware sampling" > + echo 1> $MOUNT/hwsampling/hwsampler > + if test "$S390_HW_SAMPLER_INTERVAL" != 0; then > + echo $S390_HW_SAMPLER_INTERVAL>$MOUNT/hwsampling/hw_interval > + fi > + if test "$S390_HW_SAMPLER_BUFSIZE" != 0; then > + echo $S390_HW_SAMPLER_BUFSIZE>$MOUNT/hwsampling/hw_sdbt_blocks > + fi > + ;; > + *) > + ;; > + esac > +} > + > do_start() > { > prep_jitdump; > + do_platform_start > if test "$KERNEL_SUPPORT" = "yes"; then > echo 1>$MOUNT/enable > fi > @@ -1636,6 +1760,27 @@ do_start() > } > > > +do_platform_status() > +{ > + case "$PLATFORM" in > + s390*) > + if test "$HAVE_HWSAMPLING" = "0"; then > + return > + fi > + echo -n "Hardware sampling interval: " > + echo -n $S390_HW_SAMPLER_INTERVAL > + echo -n " - current hardware setting: " > + cat $MOUNT/hwsampling/hw_interval > + echo -n "Hardware sampling buffer size: " > + echo -n $S390_HW_SAMPLER_BUFSIZE > + echo -n " - current hardware setting: " > + cat $MOUNT/hwsampling/hw_sdbt_blocks > + ;; > + *) > + ;; > + esac > +} > + > # print status > do_status() > { > @@ -1702,6 +1847,10 @@ do_status() > fi > fi > > + if test "$HAVE_HWSAMPLING" = "1"; then > + do_platform_status > + fi > + > exit 0 > } > > @@ -1855,6 +2004,9 @@ do_operations() > fi > > if test "$SETUP" = "yes"; then > + if test "$DO_HWSAMP_SETUP" = "yes"; then > + check_platform_args > + fi > check_valid_args > do_save_setup > fi > @@ -2161,6 +2313,7 @@ if test -z "$OPDIR"; then > fi > > PATH=$OPDIR:/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin > +PLATFORM=`uname -i` > > check_options_early $@ > > diff --git a/utils/ophelp.c b/utils/ophelp.c > index 5dcb217..a51be63 100644 > --- a/utils/ophelp.c > +++ b/utils/ophelp.c > @@ -33,6 +33,8 @@ static op_cpu cpu_type = CPU_NO_GOOD; > static char * cpu_string; > static int callgraph_depth; > static int want_xml; > +static int have_hwsamp; > +static int have_hwcounters; > > static poptContext optcon; > > @@ -339,9 +341,13 @@ static struct poptOption options[] = { > { "callgraph", '\0', POPT_ARG_INT,&callgraph_depth, 0, > "use this callgraph depth", "callgraph depth", }, > { "version", 'v', POPT_ARG_NONE,&show_vers, 0, > - "show version", NULL, }, > + "show version", NULL, }, > { "xml", 'X', POPT_ARG_NONE,&want_xml, 0, > - "list events as XML", NULL, }, > + "list events as XML", NULL, }, > + { "have-hwsampling", 's', POPT_ARG_NONE,&have_hwsamp, 0, > + "print 1 if the CPU supports hardware sampling", NULL, }, > + { "have-hwcounters", 'k', POPT_ARG_NONE,&have_hwcounters, 0, > + "print 1 if the CPU supports hardware counters", NULL, }, > { "extra-mask", 'E', POPT_ARG_NONE,&extra_mask, 0, > "print extra mask for event", NULL, }, > POPT_AUTOHELP > @@ -422,6 +428,20 @@ int main(int argc, char const * argv[]) > exit(EXIT_FAILURE); > } > > + if (have_hwsamp) { > + if (have_hwcounters) { > + fprintf(stderr, "-s and -k cannot be used in combination.\n"); > + exit(EXIT_FAILURE); > + } > + printf("%d", op_has_hardware_sampling(cpu_type)); > + exit(EXIT_SUCCESS); > + } > + > + if (have_hwcounters) { > + printf("%d", op_has_hardware_counters(cpu_type)); > + exit(EXIT_SUCCESS); > + } > + > parsed_events = (struct parsed_event *)xcalloc(num_chosen_events, > sizeof(struct parsed_event)); > > @@ -443,6 +463,12 @@ int main(int argc, char const * argv[]) > exit(EXIT_SUCCESS); > } > > + if (op_has_hardware_sampling(cpu_type)) > + printf("Using CPU hardware sampling support.\n"); > + > + if (!op_has_hardware_counters(cpu_type)) > + exit(EXIT_SUCCESS); > + > events = op_events(cpu_type); > > if (!chosen_events&& (unit_mask || check_events || extra_mask)) { > @@ -731,6 +757,10 @@ int main(int argc, char const * argv[]) > "Chapter 6: Performance Counters\n" > "http://www.atmel.com/dyn/resources/prod_documents/doc32000.pdf\n"; > > + case CPU_SYSTEMZ_HWSAMPV1: > + event_doc = "Hardware Basic Mode Sampling\n"; > + break; > + > case CPU_RTC: > break; > > > ------------------------------------------------------------------------------ > All the data continuously generated in your IT infrastructure contains a > definitive record of customers, application performance, security > threats, fraudulent activity and more. Splunk takes this data and makes > sense of it. Business sense. IT sense. Common sense. > http://p.sf.net/sfu/splunk-d2d-oct > _______________________________________________ > oprofile-list mailing list > opr...@li... > https://lists.sourceforge.net/lists/listinfo/oprofile-list > |
From: Andreas K. <kr...@li...> - 2011-10-20 09:10:00
|
On 10/19/2011 09:44 PM, Maynard Johnson wrote: > This patch seems way more intrusive than it needs to be. Please look at how > support for other new processor types have been added to oprofile -- for > example, the recently contributed tile<x> support. When contributing new > processor support for oprofile, we expect corresponding oprofile kernel code to > fit the model that oprofile userspace needs. A lot of the changes I see below > are the result of your oprofile kernel module not communicating with oprofile > userspace in the standard form. When the kernel part has been developed the target was to keep it working with existing user space. By using the timer mode sampling interface the usage of hardware sampling is fully transparent (actually too transparent) and does not depend on a specific OProfile user space version. That design decision looked pretty reasonable to me until I inherited the task to adjust the user space for better usability :( I agree that using hardware events probably would have allowed for a smoother integration. The user space here suffers a lot from the design decision made for the kernel part. Unfortunately I don't have the impression the kernel guys are willing to touch the OProfile hardware sampling support again. There seems to be much higher demand to support perf instead and we will most likely rather go that direction. So I'm somehow stuck with the interface I have. The patch therefore needs a lot of special cases for s390 in order to make everything look like expected. > Also, is there a reason why the existing 'buffer-size' option cannot be used > instead of the new 's390hwsampbufsize' option? buffer-size and s390hwsampbufsize have different semantics for timer base sampling and hardware sampling. For hardware sampling this value is the number of 2MB areas which apart from samples also contain control data structures. So they cannot easily be mapped to each other. > One final comment . . . There are a number of superflous changed lines that are > only whitespace changes. Please avoid that. The only thing I can see are some empty lines I've intentionally added to separate code snippets. I've tried to match the already used coding style regarding this. But the number can certainly be reduced. Bye, -Andreas- |
From: Robert R. <rob...@am...> - 2011-10-20 13:17:51
|
On 20.10.11 03:52:50, Andreas Krebbel wrote: > Unfortunately I don't have the impression the kernel guys are willing to touch the > OProfile hardware sampling support again. There seems to be much higher demand to support > perf instead and we will most likely rather go that direction. You could add s390 oprofile support based on the in-kernel perf api. This is implemented for arm and sh architectures, see drivers/oprofile/oprofile_perf.c. Oprofile identifies the cpu and generates the cpu_type string for it. Perf is used to setup and run the counters. Such code will likely go upstream. > So I'm somehow stuck with the interface I have. The patch therefore needs a lot of > special cases for s390 in order to make everything look like expected. Don't know what those special cases are, but if it is cpu specific my suggestion above would work. You could report cpu_types like "s390/cpuXX" or "s390/cpuYY" to the daemon to let it know which event tables to use. -Robert -- Advanced Micro Devices, Inc. Operating System Research Center |
From: Maynard J. <may...@us...> - 2011-10-20 16:28:39
|
Andreas Krebbel wrote: > On 10/19/2011 09:44 PM, Maynard Johnson wrote: >> This patch seems way more intrusive than it needs to be. Please look at how >> support for other new processor types have been added to oprofile -- for >> example, the recently contributed tile<x> support. When contributing new >> processor support for oprofile, we expect corresponding oprofile kernel code to >> fit the model that oprofile userspace needs. A lot of the changes I see below >> are the result of your oprofile kernel module not communicating with oprofile >> userspace in the standard form. > > When the kernel part has been developed the target was to keep it working with existing > user space. By using the timer mode sampling interface the usage of hardware sampling is > fully transparent (actually too transparent) and does not depend on a specific OProfile > user space version. That design decision looked pretty reasonable to me until I inherited > the task to adjust the user space for better usability :( I agree that using hardware > events probably would have allowed for a smoother integration. The user space here > suffers a lot from the design decision made for the kernel part. > > Unfortunately I don't have the impression the kernel guys are willing to touch the > OProfile hardware sampling support again. There seems to be much higher demand to support > perf instead and we will most likely rather go that direction. > > So I'm somehow stuck with the interface I have. The patch therefore needs a lot of > special cases for s390 in order to make everything look like expected. Andreas, OK, I think I over-stated the case that your userspace-to-kernel communication was non-standard. I don't think it's a big issue that you write to a unique file (hwsampler) in oprofilefs to enable/disable hardware sampling. I'm quite confident that if you create the events/s390/events file with the two pseudo events (one for h/w sampling and one for time-based sampling), you can avoid a lot of the special case code, the expansion of 'struct cpu_descr', and the new opcontrol options. Instead, use CPU_TYPE (and, when necessary) the chosen event to to execute unique behavior. > >> Also, is there a reason why the existing 'buffer-size' option cannot be used >> instead of the new 's390hwsampbufsize' option? > > buffer-size and s390hwsampbufsize have different semantics for timer base sampling and > hardware sampling. For hardware sampling this value is the number of 2MB areas which > apart from samples also contain control data structures. So they cannot easily be mapped > to each other. Can't we document that in the man page for opcontrol and then handle the difference in the code (again, using CPU_TYPE and chosen event to select proper behavior)? I *really* don't want to add new options if we can somehow avoid it. > >> One final comment . . . There are a number of superflous changed lines that are >> only whitespace changes. Please avoid that. > > The only thing I can see are some empty lines I've intentionally added to separate code > snippets. I've tried to match the already used coding style regarding this. But the > number can certainly be reduced. See the changes to is_non_cell_ppc64_variant() . . . all lines are shifted right. Feel free to ping me on IRC if you have any questions. -Maynard > > Bye, > > -Andreas- |
From: Andreas K. <kr...@li...> - 2011-11-02 15:12:45
|
Hi Maynard, here is an updated version of the patch. As you suggested I'm now using a pseudo counter with two separate events. The user can then disable/enable hwsampling by picking the proper event. I also tried to get away without adding S/390 specific options to opcontrol but ... * Use buffer-size also for the buffer size within the hardware sampling module. Actually it might makes sense to be able to specify both values separately. While buffer size specifies the number of samples which should fit into the oprofile kernel buffer the buffer size for the hardware sampling is given in number of 2MB areas allocated for the hardware sampling facility. However these values in the end will also pass through the oprofile kernel buffer so the buffer-size option still has a meaning in that case and to my opinion should not be overriden. * Use the count value for the samping rate. This values is multiplied with the callgraph depth what for a sampling rate doesn't make sense. Also I would not be able to give the user a proper error message in case the value does not fit into the range as specified by the hardware facility. So for now I still have two s390 specific options which need to be added to opcontrol. However thanks to the event interface the patch is much simpler now. Bye, -Andreas- |