2003-02-11 11:22:56

by John Levon

[permalink] [raw]
Subject: [PATCH 1/4] oprofile update: Pentium IV support


The below patch implements a P4 driver for OProfile, mostly written
by Graydon Hoare.

Please apply

regards
john


diff -Naur -X dontdiff linux-linus/arch/i386/kernel/nmi.c linux/arch/i386/kernel/nmi.c
--- linux-linus/arch/i386/kernel/nmi.c 2003-01-13 22:42:58.000000000 +0000
+++ linux/arch/i386/kernel/nmi.c 2003-01-03 03:23:10.000000000 +0000
@@ -63,8 +63,6 @@
CRU_ESCR0 (with any non-null event selector) through a complemented
max threshold. [IA32-Vol3, Section 14.9.9] */
#define MSR_P4_IQ_COUNTER0 0x30C
-#define MSR_P4_IQ_CCCR0 0x36C
-#define MSR_P4_CRU_ESCR0 0x3B8
#define P4_NMI_CRU_ESCR0 (P4_ESCR_EVENT_SELECT(0x3F)|P4_ESCR_OS|P4_ESCR_USR)
#define P4_NMI_IQ_CCCR0 \
(P4_CCCR_OVF_PMI|P4_CCCR_THRESHOLD(15)|P4_CCCR_COMPLEMENT| \
diff -Naur -X dontdiff linux-linus/arch/i386/oprofile/Makefile linux/arch/i386/oprofile/Makefile
--- linux-linus/arch/i386/oprofile/Makefile 2003-01-13 22:42:58.000000000 +0000
+++ linux/arch/i386/oprofile/Makefile 2003-01-10 20:30:27.000000000 +0000
@@ -7,4 +7,4 @@

oprofile-y := $(DRIVER_OBJS) init.o timer_int.o
oprofile-$(CONFIG_X86_LOCAL_APIC) += nmi_int.o op_model_athlon.o \
- op_model_ppro.o
+ op_model_ppro.o op_model_p4.o
diff -Naur -X dontdiff linux-linus/arch/i386/oprofile/nmi_int.c linux/arch/i386/oprofile/nmi_int.c
--- linux-linus/arch/i386/oprofile/nmi_int.c 2003-01-13 22:42:58.000000000 +0000
+++ linux/arch/i386/oprofile/nmi_int.c 2003-02-10 19:34:56.000000000 +0000
@@ -214,12 +214,62 @@
.stop = nmi_stop
};

+
+#if !defined(CONFIG_X86_64)
+
+static int __init p4_init(enum oprofile_cpu * cpu)
+{
+ __u8 cpu_model = current_cpu_data.x86_model;
+
+ if (cpu_model > 3)
+ return 0;
+
+#ifndef CONFIG_SMP
+ *cpu = OPROFILE_CPU_P4;
+ model = &op_p4_spec;
+ return 1;
+#else
+ switch (smp_num_siblings) {
+ case 1:
+ *cpu = OPROFILE_CPU_P4;
+ model = &op_p4_spec;
+ return 1;
+
+ case 2:
+ *cpu = OPROFILE_CPU_P4_HT2;
+ model = &op_p4_ht2_spec;
+ return 1;
+ }
+#endif
+
+ printk(KERN_INFO "oprofile: P4 HyperThreading detected with > 2 threads\n");
+ printk(KERN_INFO "oprofile: Reverting to timer mode.\n");
+ return 0;
+}
+
+
+static int __init ppro_init(enum oprofile_cpu * cpu)
+{
+ __u8 cpu_model = current_cpu_data.x86_model;
+
+ if (cpu_model > 5) {
+ *cpu = OPROFILE_CPU_PIII;
+ } else if (cpu_model > 2) {
+ *cpu = OPROFILE_CPU_PII;
+ } else {
+ *cpu = OPROFILE_CPU_PPRO;
+ }
+
+ model = &op_ppro_spec;
+ return 1;
+}
+
+#endif /* !CONFIG_X86_64 */

int __init nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
{
__u8 vendor = current_cpu_data.x86_vendor;
__u8 family = current_cpu_data.x86;
- __u8 cpu_model = current_cpu_data.x86_model;

if (!cpu_has_apic)
return 0;
@@ -233,23 +283,26 @@
*cpu = OPROFILE_CPU_ATHLON;
break;

-#ifndef CONFIG_X86_64
+#if !defined(CONFIG_X86_64)
case X86_VENDOR_INTEL:
- /* Less than a P6-class processor */
- if (family != 6)
- return 0;
-
- if (cpu_model > 5) {
- *cpu = OPROFILE_CPU_PIII;
- } else if (cpu_model > 2) {
- *cpu = OPROFILE_CPU_PII;
- } else {
- *cpu = OPROFILE_CPU_PPRO;
+ switch (family) {
+ /* Pentium IV */
+ case 0xf:
+ if (!p4_init(cpu))
+ return 0;
+ break;
+
+ /* A P6-class processor */
+ case 6:
+ if (!ppro_init(cpu))
+ return 0;
+ break;
+
+ default:
+ return 0;
}
-
- model = &op_ppro_spec;
break;
-#endif
+#endif /* !CONFIG_X86_64 */

default:
return 0;
diff -Naur -X dontdiff linux-linus/arch/i386/oprofile/op_counter.h linux/arch/i386/oprofile/op_counter.h
--- linux-linus/arch/i386/oprofile/op_counter.h 2003-01-13 22:42:58.000000000 +0000
+++ linux/arch/i386/oprofile/op_counter.h 2003-01-03 03:07:21.000000000 +0000
@@ -10,7 +10,7 @@
#ifndef OP_COUNTER_H
#define OP_COUNTER_H

-#define OP_MAX_COUNTER 4
+#define OP_MAX_COUNTER 8

/* Per-perfctr configuration as set via
* oprofilefs.
diff -Naur -X dontdiff linux-linus/arch/i386/oprofile/op_model_p4.c linux/arch/i386/oprofile/op_model_p4.c
--- linux-linus/arch/i386/oprofile/op_model_p4.c 1970-01-01 01:00:00.000000000 +0100
+++ linux/arch/i386/oprofile/op_model_p4.c 2003-01-15 19:26:32.000000000 +0000
@@ -0,0 +1,670 @@
+/**
+ * @file op_model_p4.c
+ * P4 model-specific MSR operations
+ *
+ * @remark Copyright 2002 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * @author Graydon Hoare
+ */
+
+#include <linux/oprofile.h>
+#include <linux/smp.h>
+#include <asm/msr.h>
+#include <asm/ptrace.h>
+#include <asm/fixmap.h>
+#include <asm/apic.h>
+
+#include "op_x86_model.h"
+#include "op_counter.h"
+
+#define NUM_EVENTS 39
+
+#define NUM_COUNTERS_NON_HT 8
+#define NUM_ESCRS_NON_HT 45
+#define NUM_CCCRS_NON_HT 18
+#define NUM_CONTROLS_NON_HT (NUM_ESCRS_NON_HT + NUM_CCCRS_NON_HT)
+
+#define NUM_COUNTERS_HT2 4
+#define NUM_ESCRS_HT2 23
+#define NUM_CCCRS_HT2 9
+#define NUM_CONTROLS_HT2 (NUM_ESCRS_HT2 + NUM_CCCRS_HT2)
+
+static unsigned int num_counters = NUM_COUNTERS_NON_HT;
+static unsigned int num_cccrs = NUM_CCCRS_NON_HT;
+
+
+/* this has to be checked dynamically since the
+ hyper-threadedness of a chip is discovered at
+ kernel boot-time. */
+static inline void setup_num_counters(void)
+{
+#ifdef CONFIG_SMP
+ if (smp_num_siblings == 2) {
+ num_counters = NUM_COUNTERS_HT2;
+ num_cccrs = NUM_CCCRS_HT2;
+ }
+#endif
+}
+
+
+/* tables to simulate simplified hardware view of p4 registers */
+struct p4_counter_binding {
+ int virt_counter;
+ int counter_address;
+ int cccr_address;
+};
+
+struct p4_event_binding {
+ int escr_select; /* value to put in CCCR */
+ int event_select; /* value to put in ESCR */
+ struct {
+ int virt_counter; /* for this counter... */
+ int escr_address; /* use this ESCR */
+ } bindings[2];
+};
+
+/* nb: these CTR_* defines are a duplicate of defines in
+ libop/op_events.c. */
+
+
+#define CTR_BPU_0 (1 << 0)
+#define CTR_MS_0 (1 << 1)
+#define CTR_FLAME_0 (1 << 2)
+#define CTR_IQ_4 (1 << 3)
+#define CTR_BPU_2 (1 << 4)
+#define CTR_MS_2 (1 << 5)
+#define CTR_FLAME_2 (1 << 6)
+#define CTR_IQ_5 (1 << 7)
+
+static struct p4_counter_binding p4_counters [NUM_COUNTERS_NON_HT] = {
+ { CTR_BPU_0, MSR_P4_BPU_PERFCTR0, MSR_P4_BPU_CCCR0 },
+ { CTR_MS_0, MSR_P4_MS_PERFCTR0, MSR_P4_MS_CCCR0 },
+ { CTR_FLAME_0, MSR_P4_FLAME_PERFCTR0, MSR_P4_FLAME_CCCR0 },
+ { CTR_IQ_4, MSR_P4_IQ_PERFCTR4, MSR_P4_IQ_CCCR4 },
+ { CTR_BPU_2, MSR_P4_BPU_PERFCTR2, MSR_P4_BPU_CCCR2 },
+ { CTR_MS_2, MSR_P4_MS_PERFCTR2, MSR_P4_MS_CCCR2 },
+ { CTR_FLAME_2, MSR_P4_FLAME_PERFCTR2, MSR_P4_FLAME_CCCR2 },
+ { CTR_IQ_5, MSR_P4_IQ_PERFCTR5, MSR_P4_IQ_CCCR5 }
+};
+
+/* p4 event codes in libop/op_event.h are indices into this table. */
+
+static struct p4_event_binding p4_events[NUM_EVENTS] = {
+
+ { /* BRANCH_RETIRED */
+ 0x05, 0x06,
+ { {CTR_IQ_4, MSR_P4_CRU_ESCR2},
+ {CTR_IQ_5, MSR_P4_CRU_ESCR3} }
+ },
+
+ { /* MISPRED_BRANCH_RETIRED */
+ 0x04, 0x03,
+ { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
+ { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
+ },
+
+ { /* TC_DELIVER_MODE */
+ 0x01, 0x01,
+ { { CTR_MS_0, MSR_P4_TC_ESCR0},
+ { CTR_MS_2, MSR_P4_TC_ESCR1} }
+ },
+
+ { /* BPU_FETCH_REQUEST */
+ 0x00, 0x03,
+ { { CTR_BPU_0, MSR_P4_BPU_ESCR0},
+ { CTR_BPU_2, MSR_P4_BPU_ESCR1} }
+ },
+
+ { /* ITLB_REFERENCE */
+ 0x03, 0x18,
+ { { CTR_BPU_0, MSR_P4_ITLB_ESCR0},
+ { CTR_BPU_2, MSR_P4_ITLB_ESCR1} }
+ },
+
+ { /* MEMORY_CANCEL */
+ 0x05, 0x02,
+ { { CTR_FLAME_0, MSR_P4_DAC_ESCR0},
+ { CTR_FLAME_2, MSR_P4_DAC_ESCR1} }
+ },
+
+ { /* MEMORY_COMPLETE */
+ 0x02, 0x08,
+ { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
+ { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
+ },
+
+ { /* LOAD_PORT_REPLAY */
+ 0x02, 0x04,
+ { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
+ { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
+ },
+
+ { /* STORE_PORT_REPLAY */
+ 0x02, 0x05,
+ { { CTR_FLAME_0, MSR_P4_SAAT_ESCR0},
+ { CTR_FLAME_2, MSR_P4_SAAT_ESCR1} }
+ },
+
+ { /* MOB_LOAD_REPLAY */
+ 0x02, 0x03,
+ { { CTR_BPU_0, MSR_P4_MOB_ESCR0},
+ { CTR_BPU_2, MSR_P4_MOB_ESCR1} }
+ },
+
+ { /* PAGE_WALK_TYPE */
+ 0x04, 0x01,
+ { { CTR_BPU_0, MSR_P4_PMH_ESCR0},
+ { CTR_BPU_2, MSR_P4_PMH_ESCR1} }
+ },
+
+ { /* BSQ_CACHE_REFERENCE */
+ 0x07, 0x0c,
+ { { CTR_BPU_0, MSR_P4_BSU_ESCR0},
+ { CTR_BPU_2, MSR_P4_BSU_ESCR1} }
+ },
+
+ { /* IOQ_ALLOCATION */
+ 0x06, 0x03,
+ { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
+ {-1,-1} }
+ },
+
+ { /* IOQ_ACTIVE_ENTRIES */
+ 0x06, 0x1a,
+ { { CTR_BPU_2, MSR_P4_FSB_ESCR1},
+ {-1,-1} }
+ },
+
+ { /* FSB_DATA_ACTIVITY */
+ 0x06, 0x17,
+ { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
+ { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
+ },
+
+ { /* BSQ_ALLOCATION */
+ 0x07, 0x05,
+ { { CTR_BPU_0, MSR_P4_BSU_ESCR0},
+ {-1,-1} }
+ },
+
+ { /* BSQ_ACTIVE_ENTRIES */
+ 0x07, 0x06,
+ { { CTR_BPU_2, MSR_P4_BSU_ESCR1 /* guess */},
+ {-1,-1} }
+ },
+
+ { /* X87_ASSIST */
+ 0x05, 0x03,
+ { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
+ { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
+ },
+
+ { /* SSE_INPUT_ASSIST */
+ 0x01, 0x34,
+ { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
+ { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
+ },
+
+ { /* PACKED_SP_UOP */
+ 0x01, 0x08,
+ { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
+ { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
+ },
+
+ { /* PACKED_DP_UOP */
+ 0x01, 0x0c,
+ { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
+ { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
+ },
+
+ { /* SCALAR_SP_UOP */
+ 0x01, 0x0a,
+ { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
+ { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
+ },
+
+ { /* SCALAR_DP_UOP */
+ 0x01, 0x0e,
+ { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
+ { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
+ },
+
+ { /* 64BIT_MMX_UOP */
+ 0x01, 0x02,
+ { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
+ { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
+ },
+
+ { /* 128BIT_MMX_UOP */
+ 0x01, 0x1a,
+ { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
+ { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
+ },
+
+ { /* X87_FP_UOP */
+ 0x01, 0x04,
+ { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
+ { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
+ },
+
+ { /* X87_SIMD_MOVES_UOP */
+ 0x01, 0x2e,
+ { { CTR_FLAME_0, MSR_P4_FIRM_ESCR0},
+ { CTR_FLAME_2, MSR_P4_FIRM_ESCR1} }
+ },
+
+ { /* MACHINE_CLEAR */
+ 0x05, 0x02,
+ { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
+ { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
+ },
+
+ { /* GLOBAL_POWER_EVENTS */
+ 0x06, 0x13 /* manual says 0x05 */,
+ { { CTR_BPU_0, MSR_P4_FSB_ESCR0},
+ { CTR_BPU_2, MSR_P4_FSB_ESCR1} }
+ },
+
+ { /* TC_MS_XFER */
+ 0x00, 0x05,
+ { { CTR_MS_0, MSR_P4_MS_ESCR0},
+ { CTR_MS_2, MSR_P4_MS_ESCR1} }
+ },
+
+ { /* UOP_QUEUE_WRITES */
+ 0x00, 0x09,
+ { { CTR_MS_0, MSR_P4_MS_ESCR0},
+ { CTR_MS_2, MSR_P4_MS_ESCR1} }
+ },
+
+ { /* FRONT_END_EVENT */
+ 0x05, 0x08,
+ { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
+ { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
+ },
+
+ { /* EXECUTION_EVENT */
+ 0x05, 0x0c,
+ { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
+ { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
+ },
+
+ { /* REPLAY_EVENT */
+ 0x05, 0x09,
+ { { CTR_IQ_4, MSR_P4_CRU_ESCR2},
+ { CTR_IQ_5, MSR_P4_CRU_ESCR3} }
+ },
+
+ { /* INSTR_RETIRED */
+ 0x04, 0x02,
+ { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
+ { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
+ },
+
+ { /* UOPS_RETIRED */
+ 0x04, 0x01,
+ { { CTR_IQ_4, MSR_P4_CRU_ESCR0},
+ { CTR_IQ_5, MSR_P4_CRU_ESCR1} }
+ },
+
+ { /* UOP_TYPE */
+ 0x02, 0x02,
+ { { CTR_IQ_4, MSR_P4_RAT_ESCR0},
+ { CTR_IQ_5, MSR_P4_RAT_ESCR1} }
+ },
+
+ { /* RETIRED_MISPRED_BRANCH_TYPE */
+ 0x02, 0x05,
+ { { CTR_MS_0, MSR_P4_TBPU_ESCR0},
+ { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
+ },
+
+ { /* RETIRED_BRANCH_TYPE */
+ 0x02, 0x04,
+ { { CTR_MS_0, MSR_P4_TBPU_ESCR0},
+ { CTR_MS_2, MSR_P4_TBPU_ESCR1} }
+ }
+};
+
+
+#define MISC_PMC_ENABLED_P(x) ((x) & 1 << 7)
+
+#define ESCR_RESERVED_BITS 0x80000003
+#define ESCR_CLEAR(escr) ((escr) &= ESCR_RESERVED_BITS)
+#define ESCR_SET_USR_0(escr, usr) ((escr) |= (((usr) & 1) << 2))
+#define ESCR_SET_OS_0(escr, os) ((escr) |= (((os) & 1) << 3))
+#define ESCR_SET_USR_1(escr, usr) ((escr) |= (((usr) & 1)))
+#define ESCR_SET_OS_1(escr, os) ((escr) |= (((os) & 1) << 1))
+#define ESCR_SET_EVENT_SELECT(escr, sel) ((escr) |= (((sel) & 0x1f) << 25))
+#define ESCR_SET_EVENT_MASK(escr, mask) ((escr) |= (((mask) & 0xffff) << 9))
+#define ESCR_READ(escr,high,ev,i) do {rdmsr(ev->bindings[(i)].escr_address, (escr), (high));} while (0);
+#define ESCR_WRITE(escr,high,ev,i) do {wrmsr(ev->bindings[(i)].escr_address, (escr), (high));} while (0);
+
+#define CCCR_RESERVED_BITS 0x38030FFF
+#define CCCR_CLEAR(cccr) ((cccr) &= CCCR_RESERVED_BITS)
+#define CCCR_SET_REQUIRED_BITS(cccr) ((cccr) |= 0x00030000)
+#define CCCR_SET_ESCR_SELECT(cccr, sel) ((cccr) |= (((sel) & 0x07) << 13))
+#define CCCR_SET_PMI_OVF_0(cccr) ((cccr) |= (1<<26))
+#define CCCR_SET_PMI_OVF_1(cccr) ((cccr) |= (1<<27))
+#define CCCR_SET_ENABLE(cccr) ((cccr) |= (1<<12))
+#define CCCR_SET_DISABLE(cccr) ((cccr) &= ~(1<<12))
+#define CCCR_READ(low, high, i) do {rdmsr (p4_counters[(i)].cccr_address, (low), (high));} while (0);
+#define CCCR_WRITE(low, high, i) do {wrmsr (p4_counters[(i)].cccr_address, (low), (high));} while (0);
+#define CCCR_OVF_P(cccr) ((cccr) & (1U<<31))
+#define CCCR_CLEAR_OVF(cccr) ((cccr) &= (~(1U<<31)))
+
+#define CTR_READ(l,h,i) do {rdmsr(p4_counters[(i)].counter_address, (l), (h));} while (0);
+#define CTR_WRITE(l,i) do {wrmsr(p4_counters[(i)].counter_address, -(u32)(l), -1);} while (0);
+#define CTR_OVERFLOW_P(ctr) (!((ctr) & 0x80000000))
+
+/* these access the underlying cccrs 1-18, not the subset of 8 bound to "virtual counters" */
+#define RAW_CCCR_READ(low, high, i) do {rdmsr (MSR_P4_BPU_CCCR0 + (i), (low), (high));} while (0);
+#define RAW_CCCR_WRITE(low, high, i) do {wrmsr (MSR_P4_BPU_CCCR0 + (i), (low), (high));} while (0);
+
+
+/* this assigns a "stagger" to the current CPU, which is used throughout
+ the code in this module as an extra array offset, to select the "even"
+ or "odd" part of all the divided resources. */
+static inline unsigned int get_stagger(void)
+{
+#ifdef CONFIG_SMP
+ int cpu;
+ if (smp_num_siblings > 1) {
+ cpu = smp_processor_id();
+ return (cpu_sibling_map[cpu] > cpu) ? 0 : 1;
+ }
+#endif
+ return 0;
+}
+
+
+/* finally, mediate access to a real hardware counter
+ by passing a "virtual" counter numer to this macro,
+ along with your stagger setting. */
+#define VIRT_CTR(stagger, i) ((i) + ((num_counters) * (stagger)))
+
+static unsigned long reset_value[NUM_COUNTERS_NON_HT];
+
+
+static void p4_fill_in_addresses(struct op_msrs * const msrs)
+{
+ int i;
+ unsigned int addr, stag;
+
+ setup_num_counters();
+ stag = get_stagger();
+
+ /* the 8 counter registers we pay attention to */
+ for (i = 0; i < num_counters; ++i)
+ msrs->counters.addrs[i] =
+ p4_counters[VIRT_CTR(stag, i)].counter_address;
+
+ /* 18 CCCR registers */
+ for (i=stag, addr = MSR_P4_BPU_CCCR0;
+ addr <= MSR_P4_IQ_CCCR5; ++i, addr += (1 + stag))
+ msrs->controls.addrs[i] = addr;
+
+ /* 43 ESCR registers */
+ for (addr = MSR_P4_BSU_ESCR0;
+ addr <= MSR_P4_SSU_ESCR0; ++i, addr += (1 + stag)){
+ msrs->controls.addrs[i] = addr;
+ }
+
+ for (addr = MSR_P4_MS_ESCR0;
+ addr <= MSR_P4_TC_ESCR1; ++i, addr += (1 + stag)){
+ msrs->controls.addrs[i] = addr;
+ }
+
+ for (addr = MSR_P4_IX_ESCR0;
+ addr <= MSR_P4_CRU_ESCR3; ++i, addr += (1 + stag)){
+ msrs->controls.addrs[i] = addr;
+ }
+
+ /* there are 2 remaining non-contiguously located ESCRs */
+
+ if (num_counters == NUM_COUNTERS_NON_HT) {
+ /* standard non-HT CPUs handle both remaining ESCRs*/
+ msrs->controls.addrs[i++] = MSR_P4_CRU_ESCR5;
+ msrs->controls.addrs[i++] = MSR_P4_CRU_ESCR4;
+
+ } else if (stag == 0) {
+ /* HT CPUs give the first remainder to the even thread, as
+ the 32nd control register */
+ msrs->controls.addrs[i++] = MSR_P4_CRU_ESCR4;
+
+ } else {
+ /* and two copies of the second to the odd thread,
+ for the 31st and 32nd control registers */
+ msrs->controls.addrs[i++] = MSR_P4_CRU_ESCR5;
+ msrs->controls.addrs[i++] = MSR_P4_CRU_ESCR5;
+ }
+}
+
+
+static void pmc_setup_one_p4_counter(unsigned int ctr)
+{
+ int i;
+ int const maxbind = 2;
+ unsigned int cccr = 0;
+ unsigned int escr = 0;
+ unsigned int high = 0;
+ unsigned int counter_bit;
+ struct p4_event_binding * ev = 0;
+ unsigned int stag;
+
+ stag = get_stagger();
+
+ /* convert from counter *number* to counter *bit* */
+ counter_bit = 1 << ctr;
+
+ /* find our event binding structure. */
+ if (counter_config[ctr].event <= 0 || counter_config[ctr].event > NUM_EVENTS) {
+ printk(KERN_ERR
+ "oprofile: P4 event code 0x%lx out of range\n",
+ counter_config[ctr].event);
+ return;
+ }
+
+ ev = &(p4_events[counter_config[ctr].event - 1]);
+
+ for (i = 0; i < maxbind; i++) {
+ if (ev->bindings[i].virt_counter & counter_bit) {
+
+ /* modify ESCR */
+ ESCR_READ(escr, high, ev, i);
+ ESCR_CLEAR(escr);
+ if (stag == 0) {
+ ESCR_SET_USR_0(escr, counter_config[ctr].user);
+ ESCR_SET_OS_0(escr, counter_config[ctr].kernel);
+ } else {
+ ESCR_SET_USR_1(escr, counter_config[ctr].user);
+ ESCR_SET_OS_1(escr, counter_config[ctr].kernel);
+ }
+ ESCR_SET_EVENT_SELECT(escr, ev->event_select);
+ ESCR_SET_EVENT_MASK(escr, counter_config[ctr].unit_mask);
+ ESCR_WRITE(escr, high, ev, i);
+
+ /* modify CCCR */
+ CCCR_READ(cccr, high, VIRT_CTR(stag, ctr));
+ CCCR_CLEAR(cccr);
+ CCCR_SET_REQUIRED_BITS(cccr);
+ CCCR_SET_ESCR_SELECT(cccr, ev->escr_select);
+ if (stag == 0) {
+ CCCR_SET_PMI_OVF_0(cccr);
+ } else {
+ CCCR_SET_PMI_OVF_1(cccr);
+ }
+ CCCR_WRITE(cccr, high, VIRT_CTR(stag, ctr));
+ return;
+ }
+ }
+}
+
+
+static void p4_setup_ctrs(struct op_msrs const * const msrs)
+{
+ unsigned int i;
+ unsigned int low, high;
+ unsigned int addr;
+ unsigned int stag;
+
+ stag = get_stagger();
+
+ rdmsr(MSR_IA32_MISC_ENABLE, low, high);
+ if (! MISC_PMC_ENABLED_P(low)) {
+ printk(KERN_ERR "oprofile: P4 PMC not available\n");
+ return;
+ }
+
+ /* clear all cccrs (including those outside our concern) */
+ for (i = stag ; i < num_cccrs ; i += (1 + stag)) {
+ RAW_CCCR_READ(low, high, i);
+ CCCR_CLEAR(low);
+ CCCR_SET_REQUIRED_BITS(low);
+ RAW_CCCR_WRITE(low, high, i);
+ }
+
+ /* clear all escrs (including those outside out concern) */
+ for (addr = MSR_P4_BSU_ESCR0 + stag;
+ addr <= MSR_P4_SSU_ESCR0; addr += (1 + stag)){
+ wrmsr(addr, 0, 0);
+ }
+
+ for (addr = MSR_P4_MS_ESCR0 + stag;
+ addr <= MSR_P4_TC_ESCR1; addr += (1 + stag)){
+ wrmsr(addr, 0, 0);
+ }
+
+ for (addr = MSR_P4_IX_ESCR0 + stag;
+ addr <= MSR_P4_CRU_ESCR3; addr += (1 + stag)){
+ wrmsr(addr, 0, 0);
+ }
+
+ if (num_counters == NUM_COUNTERS_NON_HT) {
+ wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
+ wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
+ } else if (stag == 0) {
+ wrmsr(MSR_P4_CRU_ESCR4, 0, 0);
+ } else {
+ wrmsr(MSR_P4_CRU_ESCR5, 0, 0);
+ }
+
+ /* setup all counters */
+ for (i = 0 ; i < num_counters ; ++i) {
+ if (counter_config[i].event) {
+ reset_value[i] = counter_config[i].count;
+ pmc_setup_one_p4_counter(i);
+ CTR_WRITE(counter_config[i].count, VIRT_CTR(stag, i));
+ } else {
+ reset_value[i] = 0;
+ }
+ }
+}
+
+
+static int p4_check_ctrs(unsigned int const cpu,
+ struct op_msrs const * const msrs,
+ struct pt_regs * const regs)
+{
+ unsigned long ctr, low, high, stag, real;
+ int i;
+
+ stag = get_stagger();
+
+ for (i = 0; i < num_counters; ++i) {
+
+ if (!counter_config[i].event)
+ continue;
+
+ /*
+ * there is some eccentricity in the hardware which
+ * requires that we perform 2 extra corrections:
+ *
+ * - check both the CCCR:OVF flag for overflow and the
+ * counter high bit for un-flagged overflows.
+ *
+ * - write the counter back twice to ensure it gets
+ * updated properly.
+ *
+ * the former seems to be related to extra NMIs happening
+ * during the current NMI; the latter is reported as errata
+ * N15 in intel doc 249199-029, pentium 4 specification
+ * update, though their suggested work-around does not
+ * appear to solve the problem.
+ */
+
+ real = VIRT_CTR(stag, i);
+
+ CCCR_READ(low, high, real);
+ CTR_READ(ctr, high, real);
+ if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) {
+ oprofile_add_sample(regs->eip, i, cpu);
+ CTR_WRITE(reset_value[i], real);
+ CCCR_CLEAR_OVF(low);
+ CCCR_WRITE(low, high, real);
+ CTR_WRITE(reset_value[i], real);
+ /* P4 quirk: you have to re-unmask the apic vector */
+ apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
+ return 1;
+ }
+ }
+
+ /* P4 quirk: you have to re-unmask the apic vector */
+ apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
+ return 0;
+}
+
+
+static void p4_start(struct op_msrs const * const msrs)
+{
+ unsigned int low, high, stag;
+ int i;
+
+ stag = get_stagger();
+
+ for (i = 0; i < num_counters; ++i) {
+ if (!reset_value[i]) continue;
+ CCCR_READ(low, high, VIRT_CTR(stag, i));
+ CCCR_SET_ENABLE(low);
+ CCCR_WRITE(low, high, VIRT_CTR(stag, i));
+ }
+}
+
+
+static void p4_stop(struct op_msrs const * const msrs)
+{
+ unsigned int low, high, stag;
+ int i;
+
+ stag = get_stagger();
+
+ for (i = 0; i < num_counters; ++i) {
+ CCCR_READ(low, high, VIRT_CTR(stag, i));
+ CCCR_SET_DISABLE(low);
+ CCCR_WRITE(low, high, VIRT_CTR(stag, i));
+ }
+}
+
+
+#ifdef CONFIG_SMP
+struct op_x86_model_spec const op_p4_ht2_spec = {
+ .num_counters = NUM_COUNTERS_HT2,
+ .num_controls = NUM_CONTROLS_HT2,
+ .fill_in_addresses = &p4_fill_in_addresses,
+ .setup_ctrs = &p4_setup_ctrs,
+ .check_ctrs = &p4_check_ctrs,
+ .start = &p4_start,
+ .stop = &p4_stop
+};
+#endif
+
+struct op_x86_model_spec const op_p4_spec = {
+ .num_counters = NUM_COUNTERS_NON_HT,
+ .num_controls = NUM_CONTROLS_NON_HT,
+ .fill_in_addresses = &p4_fill_in_addresses,
+ .setup_ctrs = &p4_setup_ctrs,
+ .check_ctrs = &p4_check_ctrs,
+ .start = &p4_start,
+ .stop = &p4_stop
+};
diff -Naur -X dontdiff linux-linus/arch/i386/oprofile/op_x86_model.h linux/arch/i386/oprofile/op_x86_model.h
--- linux-linus/arch/i386/oprofile/op_x86_model.h 2003-01-13 22:42:58.000000000 +0000
+++ linux/arch/i386/oprofile/op_x86_model.h 2003-01-08 23:02:47.000000000 +0000
@@ -11,8 +11,8 @@
#ifndef OP_X86_MODEL_H
#define OP_X86_MODEL_H

-/* will need re-working for Pentium IV */
-#define MAX_MSR 4
+/* Pentium IV needs all these */
+#define MAX_MSR 63

struct op_saved_msr {
unsigned int high;
@@ -47,6 +47,8 @@
};

extern struct op_x86_model_spec const op_ppro_spec;
+extern struct op_x86_model_spec const op_p4_spec;
+extern struct op_x86_model_spec const op_p4_ht2_spec;
extern struct op_x86_model_spec const op_athlon_spec;

#endif /* OP_X86_MODEL_H */
diff -Naur -X dontdiff linux-linus/include/asm-i386/msr.h linux/include/asm-i386/msr.h
--- linux-linus/include/asm-i386/msr.h 2003-01-13 22:42:58.000000000 +0000
+++ linux/include/asm-i386/msr.h 2003-01-03 03:18:54.000000000 +0000
@@ -93,6 +93,90 @@
#define MSR_IA32_MC0_ADDR 0x402
#define MSR_IA32_MC0_MISC 0x403

+/* Pentium IV performance counter MSRs */
+#define MSR_P4_BPU_PERFCTR0 0x300
+#define MSR_P4_BPU_PERFCTR1 0x301
+#define MSR_P4_BPU_PERFCTR2 0x302
+#define MSR_P4_BPU_PERFCTR3 0x303
+#define MSR_P4_MS_PERFCTR0 0x304
+#define MSR_P4_MS_PERFCTR1 0x305
+#define MSR_P4_MS_PERFCTR2 0x306
+#define MSR_P4_MS_PERFCTR3 0x307
+#define MSR_P4_FLAME_PERFCTR0 0x308
+#define MSR_P4_FLAME_PERFCTR1 0x309
+#define MSR_P4_FLAME_PERFCTR2 0x30a
+#define MSR_P4_FLAME_PERFCTR3 0x30b
+#define MSR_P4_IQ_PERFCTR0 0x30c
+#define MSR_P4_IQ_PERFCTR1 0x30d
+#define MSR_P4_IQ_PERFCTR2 0x30e
+#define MSR_P4_IQ_PERFCTR3 0x30f
+#define MSR_P4_IQ_PERFCTR4 0x310
+#define MSR_P4_IQ_PERFCTR5 0x311
+#define MSR_P4_BPU_CCCR0 0x360
+#define MSR_P4_BPU_CCCR1 0x361
+#define MSR_P4_BPU_CCCR2 0x362
+#define MSR_P4_BPU_CCCR3 0x363
+#define MSR_P4_MS_CCCR0 0x364
+#define MSR_P4_MS_CCCR1 0x365
+#define MSR_P4_MS_CCCR2 0x366
+#define MSR_P4_MS_CCCR3 0x367
+#define MSR_P4_FLAME_CCCR0 0x368
+#define MSR_P4_FLAME_CCCR1 0x369
+#define MSR_P4_FLAME_CCCR2 0x36a
+#define MSR_P4_FLAME_CCCR3 0x36b
+#define MSR_P4_IQ_CCCR0 0x36c
+#define MSR_P4_IQ_CCCR1 0x36d
+#define MSR_P4_IQ_CCCR2 0x36e
+#define MSR_P4_IQ_CCCR3 0x36f
+#define MSR_P4_IQ_CCCR4 0x370
+#define MSR_P4_IQ_CCCR5 0x371
+#define MSR_P4_ALF_ESCR0 0x3ca
+#define MSR_P4_ALF_ESCR1 0x3cb
+#define MSR_P4_BPU_ESCR0 0x3b2
+#define MSR_P4_BPU_ESCR1 0x3b3
+#define MSR_P4_BSU_ESCR0 0x3a0
+#define MSR_P4_BSU_ESCR1 0x3a1
+#define MSR_P4_CRU_ESCR0 0x3b8
+#define MSR_P4_CRU_ESCR1 0x3b9
+#define MSR_P4_CRU_ESCR2 0x3cc
+#define MSR_P4_CRU_ESCR3 0x3cd
+#define MSR_P4_CRU_ESCR4 0x3e0
+#define MSR_P4_CRU_ESCR5 0x3e1
+#define MSR_P4_DAC_ESCR0 0x3a8
+#define MSR_P4_DAC_ESCR1 0x3a9
+#define MSR_P4_FIRM_ESCR0 0x3a4
+#define MSR_P4_FIRM_ESCR1 0x3a5
+#define MSR_P4_FLAME_ESCR0 0x3a6
+#define MSR_P4_FLAME_ESCR1 0x3a7
+#define MSR_P4_FSB_ESCR0 0x3a2
+#define MSR_P4_FSB_ESCR1 0x3a3
+#define MSR_P4_IQ_ESCR0 0x3ba
+#define MSR_P4_IQ_ESCR1 0x3bb
+#define MSR_P4_IS_ESCR0 0x3b4
+#define MSR_P4_IS_ESCR1 0x3b5
+#define MSR_P4_ITLB_ESCR0 0x3b6
+#define MSR_P4_ITLB_ESCR1 0x3b7
+#define MSR_P4_IX_ESCR0 0x3c8
+#define MSR_P4_IX_ESCR1 0x3c9
+#define MSR_P4_MOB_ESCR0 0x3aa
+#define MSR_P4_MOB_ESCR1 0x3ab
+#define MSR_P4_MS_ESCR0 0x3c0
+#define MSR_P4_MS_ESCR1 0x3c1
+#define MSR_P4_PMH_ESCR0 0x3ac
+#define MSR_P4_PMH_ESCR1 0x3ad
+#define MSR_P4_RAT_ESCR0 0x3bc
+#define MSR_P4_RAT_ESCR1 0x3bd
+#define MSR_P4_SAAT_ESCR0 0x3ae
+#define MSR_P4_SAAT_ESCR1 0x3af
+#define MSR_P4_SSU_ESCR0 0x3be
+#define MSR_P4_SSU_ESCR1 0x3bf /* guess: not defined in manual */
+#define MSR_P4_TBPU_ESCR0 0x3c2
+#define MSR_P4_TBPU_ESCR1 0x3c3
+#define MSR_P4_TC_ESCR0 0x3c4
+#define MSR_P4_TC_ESCR1 0x3c5
+#define MSR_P4_U2L_ESCR0 0x3b0
+#define MSR_P4_U2L_ESCR1 0x3b1
+
/* AMD Defined MSRs */
#define MSR_K6_EFER 0xC0000080
#define MSR_K6_STAR 0xC0000081
diff -Naur -X dontdiff linux-linus/include/linux/oprofile.h linux/include/linux/oprofile.h
--- linux-linus/include/linux/oprofile.h 2003-01-13 22:42:58.000000000 +0000
+++ linux/include/linux/oprofile.h 2003-02-10 19:34:44.000000000 +0000
@@ -21,12 +21,22 @@
struct dentry;
struct file_operations;

+/* This is duplicated from user-space so
+ * must be kept in sync :(
+ */
enum oprofile_cpu {
OPROFILE_CPU_PPRO,
OPROFILE_CPU_PII,
OPROFILE_CPU_PIII,
OPROFILE_CPU_ATHLON,
- OPROFILE_CPU_TIMER
+ OPROFILE_CPU_TIMER,
+ OPROFILE_UNUSED1, /* 2.4's RTC mode */
+ OPROFILE_CPU_P4,
+ OPROFILE_CPU_IA64,
+ OPROFILE_CPU_IA64_1,
+ OPROFILE_CPU_IA64_2,
+ OPROFILE_CPU_HAMMER,
+ OPROFILE_CPU_P4_HT2
};

/* Operations structure to be filled in */


2003-02-11 11:34:28

by John Levon

[permalink] [raw]
Subject: [PATCH 3/4] oprofile update: fix oprofilefs integer files base


This patch allows the oprofilefs files to take entry in any base
instead of just base 10


diff -Naur -X dontdiff linux/drivers/oprofile/oprofilefs.c linux2/drivers/oprofile/oprofilefs.c
--- linux/drivers/oprofile/oprofilefs.c 2003-02-10 19:40:25.000000000 +0000
+++ linux2/drivers/oprofile/oprofilefs.c 2003-02-09 23:46:03.000000000 +0000
@@ -114,7 +114,7 @@
return -EFAULT;

spin_lock(&oprofilefs_lock);
- *val = simple_strtoul(tmpbuf, NULL, 10);
+ *val = simple_strtoul(tmpbuf, NULL, 0);
spin_unlock(&oprofilefs_lock);
return 0;
}

2003-02-11 11:36:15

by John Levon

[permalink] [raw]
Subject: [PATCH 4/4] oprofile update: kernel/user addresses fix


This patch replaces the assumption that > PAGE_OFFSET == kernel address
with testing for user_mode(regs) and inserting switch codes instead.


diff -Naur -X dontdiff linux/arch/i386/oprofile/op_model_athlon.c linux2/arch/i386/oprofile/op_model_athlon.c
--- linux/arch/i386/oprofile/op_model_athlon.c 2003-01-03 03:15:26.000000000 +0000
+++ linux2/arch/i386/oprofile/op_model_athlon.c 2003-01-23 20:24:53.000000000 +0000
@@ -96,10 +96,13 @@
{
unsigned int low, high;
int i;
+ unsigned long eip = instruction_pointer(regs);
+ int is_kernel = !user_mode(regs);
+
for (i = 0 ; i < NUM_COUNTERS; ++i) {
CTR_READ(low, high, msrs, i);
if (CTR_OVERFLOWED(low)) {
- oprofile_add_sample(instruction_pointer(regs), i, cpu);
+ oprofile_add_sample(eip, is_kernel, i, cpu);
CTR_WRITE(reset_value[i], msrs, i);
return 1;
}
diff -Naur -X dontdiff linux/arch/i386/oprofile/op_model_p4.c linux2/arch/i386/oprofile/op_model_p4.c
--- linux/arch/i386/oprofile/op_model_p4.c 2003-01-15 19:26:32.000000000 +0000
+++ linux2/arch/i386/oprofile/op_model_p4.c 2003-01-31 03:57:28.000000000 +0000
@@ -569,6 +569,8 @@
{
unsigned long ctr, low, high, stag, real;
int i;
+ unsigned long eip = instruction_pointer(regs);
+ int is_kernel = !user_mode(regs);

stag = get_stagger();

@@ -599,7 +601,7 @@
CCCR_READ(low, high, real);
CTR_READ(ctr, high, real);
if (CCCR_OVF_P(low) || CTR_OVERFLOW_P(ctr)) {
- oprofile_add_sample(regs->eip, i, cpu);
+ oprofile_add_sample(eip, is_kernel, i, cpu);
CTR_WRITE(reset_value[i], real);
CCCR_CLEAR_OVF(low);
CCCR_WRITE(low, high, real);
@@ -624,7 +626,8 @@
stag = get_stagger();

for (i = 0; i < num_counters; ++i) {
- if (!reset_value[i]) continue;
+ if (!reset_value[i])
+ continue;
CCCR_READ(low, high, VIRT_CTR(stag, i));
CCCR_SET_ENABLE(low);
CCCR_WRITE(low, high, VIRT_CTR(stag, i));
diff -Naur -X dontdiff linux/arch/i386/oprofile/op_model_ppro.c linux2/arch/i386/oprofile/op_model_ppro.c
--- linux/arch/i386/oprofile/op_model_ppro.c 2003-01-03 03:15:26.000000000 +0000
+++ linux2/arch/i386/oprofile/op_model_ppro.c 2003-01-23 20:24:53.000000000 +0000
@@ -90,11 +90,13 @@
{
unsigned int low, high;
int i;
+ unsigned long eip = instruction_pointer(regs);
+ int is_kernel = !user_mode(regs);

for (i = 0 ; i < NUM_COUNTERS; ++i) {
CTR_READ(low, high, msrs, i);
if (CTR_OVERFLOWED(low)) {
- oprofile_add_sample(instruction_pointer(regs), i, cpu);
+ oprofile_add_sample(eip, is_kernel, i, cpu);
CTR_WRITE(reset_value[i], msrs, i);
return 1;
}
diff -Naur -X dontdiff linux/arch/i386/oprofile/timer_int.c linux2/arch/i386/oprofile/timer_int.c
--- linux/arch/i386/oprofile/timer_int.c 2003-02-10 19:40:25.000000000 +0000
+++ linux2/arch/i386/oprofile/timer_int.c 2003-01-23 20:24:53.000000000 +0000
@@ -20,8 +20,9 @@
{
struct pt_regs * regs = (struct pt_regs *)data;
int cpu = smp_processor_id();
+ unsigned long eip = instruction_pointer(regs);

- oprofile_add_sample(instruction_pointer(regs), 0, cpu);
+ oprofile_add_sample(eip, !user_mode(regs), 0, cpu);
return 0;
}

diff -Naur -X dontdiff linux/arch/parisc/oprofile/timer_int.c linux2/arch/parisc/oprofile/timer_int.c
--- linux/arch/parisc/oprofile/timer_int.c 2003-02-11 10:53:30.000000000 +0000
+++ linux2/arch/parisc/oprofile/timer_int.c 2003-01-23 20:30:56.000000000 +0000
@@ -19,8 +19,10 @@
{
struct pt_regs * regs = (struct pt_regs *)data;
int cpu = smp_processor_id();
+ unsigned long pc = regs->iaoq[0];
+ int is_kernel = !user_mode(regs);

- oprofile_add_sample(regs->iaoq[0], 0, cpu);
+ oprofile_add_sample(pc, is_kernel, 0, cpu);
return 0;
}

diff -Naur -X dontdiff linux/arch/ppc64/oprofile/timer_int.c linux2/arch/ppc64/oprofile/timer_int.c
--- linux/arch/ppc64/oprofile/timer_int.c 2003-02-10 19:40:25.000000000 +0000
+++ linux2/arch/ppc64/oprofile/timer_int.c 2003-01-23 20:28:39.000000000 +0000
@@ -19,8 +19,10 @@
{
struct pt_regs * regs = (struct pt_regs *)data;
int cpu = smp_processor_id();
+ unsigned long pc = instruction_pointer(regs);
+ int is_kernel = !user_mode(regs);

- oprofile_add_sample(instruction_pointer(regs), 0, cpu);
+ oprofile_add_sample(pc, is_kernel, 0, cpu);
return 0;
}

diff -Naur -X dontdiff linux/arch/sparc64/oprofile/timer_int.c linux2/arch/sparc64/oprofile/timer_int.c
--- linux/arch/sparc64/oprofile/timer_int.c 2003-02-10 19:40:25.000000000 +0000
+++ linux2/arch/sparc64/oprofile/timer_int.c 2003-01-23 20:27:54.000000000 +0000
@@ -19,8 +19,10 @@
{
struct pt_regs * regs = (struct pt_regs *)data;
int cpu = smp_processor_id();
+ unsigned long pc = instruction_pointer(regs);
+ int is_kernel = !user_mode(regs);

- oprofile_add_sample(instruction_pointer(regs), 0, cpu);
+ oprofile_add_sample(pc, is_kernel, 0, cpu);
return 0;
}

diff -Naur -X dontdiff linux/drivers/oprofile/buffer_sync.c linux2/drivers/oprofile/buffer_sync.c
--- linux/drivers/oprofile/buffer_sync.c 2003-01-11 20:04:17.000000000 +0000
+++ linux2/drivers/oprofile/buffer_sync.c 2003-02-10 19:47:30.000000000 +0000
@@ -199,8 +199,16 @@
last_cookie = ~0UL;
}

+static void add_kernel_ctx_switch(unsigned int in_kernel)
+{
+ add_event_entry(ESCAPE_CODE);
+ if (in_kernel)
+ add_event_entry(KERNEL_ENTER_SWITCH_CODE);
+ else
+ add_event_entry(KERNEL_EXIT_SWITCH_CODE);
+}

-static void add_ctx_switch(pid_t pid, unsigned long cookie)
+static void add_user_ctx_switch(pid_t pid, unsigned long cookie)
{
add_event_entry(ESCAPE_CODE);
add_event_entry(CTX_SWITCH_CODE);
@@ -243,19 +251,13 @@
}


-static inline int is_kernel(unsigned long val)
-{
- return val > PAGE_OFFSET;
-}
-
-
/* Add a sample to the global event buffer. If possible the
* sample is converted into a persistent dentry/offset pair
* for later lookup from userspace.
*/
-static void add_sample(struct mm_struct * mm, struct op_sample * s)
+static void add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
{
- if (is_kernel(s->eip)) {
+ if (in_kernel) {
add_sample_entry(s->eip, s->event);
} else if (mm) {
add_us_sample(mm, s);
@@ -319,26 +321,34 @@
struct mm_struct * mm = 0;
struct task_struct * new;
unsigned long cookie;
+ int in_kernel = 1;
int i;

for (i=0; i < cpu_buf->pos; ++i) {
struct op_sample * s = &cpu_buf->buffer[i];

if (is_ctx_switch(s->eip)) {
- new = (struct task_struct *)s->event;
-
- release_mm(mm);
- mm = take_task_mm(new);
-
- cookie = get_exec_dcookie(mm);
- add_ctx_switch(new->pid, cookie);
+ if (s->event <= 1) {
+ /* kernel/userspace switch */
+ in_kernel = s->event;
+ add_kernel_ctx_switch(s->event);
+ } else {
+ /* userspace context switch */
+ new = (struct task_struct *)s->event;
+
+ release_mm(mm);
+ mm = take_task_mm(new);
+
+ cookie = get_exec_dcookie(mm);
+ add_user_ctx_switch(new->pid, cookie);
+ }
} else {
- add_sample(mm, s);
+ add_sample(mm, s, in_kernel);
}
}
release_mm(mm);

- cpu_buf->pos = 0;
+ cpu_buffer_reset(cpu_buf);
}


@@ -364,10 +374,12 @@
* lockers only, and this region is already
* protected by buffer_sem. It's raw to prevent
* the preempt bogometer firing. Fruity, huh ? */
- _raw_spin_lock(&cpu_buf->int_lock);
- add_cpu_switch(i);
- sync_buffer(cpu_buf);
- _raw_spin_unlock(&cpu_buf->int_lock);
+ if (cpu_buf->pos > 0) {
+ _raw_spin_lock(&cpu_buf->int_lock);
+ add_cpu_switch(i);
+ sync_buffer(cpu_buf);
+ _raw_spin_unlock(&cpu_buf->int_lock);
+ }
}

up(&buffer_sem);
@@ -393,3 +405,4 @@
schedule_work(&sync_wq);
/* timer is re-added by the scheduled task */
}
+
diff -Naur -X dontdiff linux/drivers/oprofile/cpu_buffer.c linux2/drivers/oprofile/cpu_buffer.c
--- linux/drivers/oprofile/cpu_buffer.c 2002-12-17 16:59:03.000000000 +0000
+++ linux2/drivers/oprofile/cpu_buffer.c 2003-01-23 20:24:53.000000000 +0000
@@ -62,6 +62,7 @@
spin_lock_init(&b->int_lock);
b->pos = 0;
b->last_task = 0;
+ b->last_is_kernel = -1;
b->sample_received = 0;
b->sample_lost_locked = 0;
b->sample_lost_overflow = 0;
@@ -84,12 +85,20 @@
* be safe from any context. Instead we trylock the CPU's int_lock.
* int_lock is taken by the processing code in sync_cpu_buffers()
* so we avoid disturbing that.
+ *
+ * is_kernel is needed because on some architectures you cannot
+ * tell if you are in kernel or user space simply by looking at
+ * eip. We tag this in the buffer by generating kernel enter/exit
+ * events whenever is_kernel changes
*/
-void oprofile_add_sample(unsigned long eip, unsigned long event, int cpu)
+void oprofile_add_sample(unsigned long eip, unsigned int is_kernel,
+ unsigned long event, int cpu)
{
struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[cpu];
struct task_struct * task;

+ is_kernel = !!is_kernel;
+
cpu_buf->sample_received++;

if (!spin_trylock(&cpu_buf->int_lock)) {
@@ -101,9 +110,17 @@
cpu_buf->sample_lost_overflow++;
goto out;
}
-
+
task = current;

+ /* notice a switch from user->kernel or vice versa */
+ if (cpu_buf->last_is_kernel != is_kernel) {
+ cpu_buf->last_is_kernel = is_kernel;
+ cpu_buf->buffer[cpu_buf->pos].eip = ~0UL;
+ cpu_buf->buffer[cpu_buf->pos].event = is_kernel;
+ cpu_buf->pos++;
+ }
+
/* notice a task switch */
if (cpu_buf->last_task != task) {
cpu_buf->last_task = task;
@@ -130,3 +147,19 @@
out:
spin_unlock(&cpu_buf->int_lock);
}
+
+/* resets the cpu buffer to a sane state - should be called with
+ * cpu_buf->int_lock held
+ */
+void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf)
+{
+ cpu_buf->pos = 0;
+
+ /* reset these to invalid values; the next sample
+ * collected will populate the buffer with proper
+ * values to initialize the buffer
+ */
+ cpu_buf->last_is_kernel = -1;
+ cpu_buf->last_task = 0;
+}
+
diff -Naur -X dontdiff linux/drivers/oprofile/cpu_buffer.h linux2/drivers/oprofile/cpu_buffer.h
--- linux/drivers/oprofile/cpu_buffer.h 2002-12-16 03:53:07.000000000 +0000
+++ linux2/drivers/oprofile/cpu_buffer.h 2003-01-23 20:24:53.000000000 +0000
@@ -20,7 +20,7 @@
int alloc_cpu_buffers(void);

void free_cpu_buffers(void);
-
+
/* CPU buffer is composed of such entries (which are
* also used for context switch notes)
*/
@@ -34,6 +34,7 @@
/* protected by int_lock */
unsigned long pos;
struct task_struct * last_task;
+ int last_is_kernel;
struct op_sample * buffer;
unsigned long sample_received;
unsigned long sample_lost_locked;
@@ -43,4 +44,6 @@

extern struct oprofile_cpu_buffer cpu_buffer[];

+void cpu_buffer_reset(struct oprofile_cpu_buffer *cpu_buf);
+
#endif /* OPROFILE_CPU_BUFFER_H */
diff -Naur -X dontdiff linux/drivers/oprofile/event_buffer.h linux2/drivers/oprofile/event_buffer.h
--- linux/drivers/oprofile/event_buffer.h 2002-12-16 03:53:07.000000000 +0000
+++ linux2/drivers/oprofile/event_buffer.h 2003-01-23 20:24:53.000000000 +0000
@@ -25,9 +25,11 @@
* relevant data.
*/
#define ESCAPE_CODE ~0UL
-#define CTX_SWITCH_CODE 1
-#define CPU_SWITCH_CODE 2
-#define COOKIE_SWITCH_CODE 3
+#define CTX_SWITCH_CODE 1
+#define CPU_SWITCH_CODE 2
+#define COOKIE_SWITCH_CODE 3
+#define KERNEL_ENTER_SWITCH_CODE 4
+#define KERNEL_EXIT_SWITCH_CODE 5

/* add data to the event buffer */
void add_event_entry(unsigned long data);
diff -Naur -X dontdiff linux/include/linux/oprofile.h linux2/include/linux/oprofile.h
--- linux/include/linux/oprofile.h 2003-02-10 19:40:25.000000000 +0000
+++ linux2/include/linux/oprofile.h 2003-01-23 20:24:53.000000000 +0000
@@ -49,7 +49,8 @@
* Add a sample. This may be called from any context. Pass
* smp_processor_id() as cpu.
*/
-extern void oprofile_add_sample(unsigned long eip, unsigned long event, int cpu);
+extern void oprofile_add_sample(unsigned long eip, unsigned int is_kernel,
+ unsigned long event, int cpu);

/**
* Create a file of the given name as a child of the given root, with

2003-02-11 11:33:20

by John Levon

[permalink] [raw]
Subject: [PATCH 2/4] oprofile update: CPU type as string


This patch updates the horrible enum for the logical CPU type with a
string instead.


diff -X dontdiff -Naur linux-linus/arch/i386/oprofile/init.c linux/arch/i386/oprofile/init.c
--- linux-linus/arch/i386/oprofile/init.c 2003-01-03 02:59:08.000000000 +0000
+++ linux/arch/i386/oprofile/init.c 2003-02-10 19:40:25.000000000 +0000
@@ -16,14 +16,14 @@
* code unlike the NMI-based code.
*/

-extern int nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
-extern void timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
+extern int nmi_init(struct oprofile_operations ** ops);
+extern void timer_init(struct oprofile_operations ** ops);

-int __init oprofile_arch_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+int __init oprofile_arch_init(struct oprofile_operations ** ops)
{
#ifdef CONFIG_X86_LOCAL_APIC
- if (!nmi_init(ops, cpu))
+ if (!nmi_init(ops))
#endif
- timer_init(ops, cpu);
+ timer_init(ops);
return 0;
}
diff -X dontdiff -Naur linux-linus/arch/i386/oprofile/nmi_int.c linux/arch/i386/oprofile/nmi_int.c
--- linux-linus/arch/i386/oprofile/nmi_int.c 2003-02-10 19:40:10.000000000 +0000
+++ linux/arch/i386/oprofile/nmi_int.c 2003-02-10 19:40:33.000000000 +0000
@@ -217,7 +217,7 @@

#if !defined(CONFIG_X86_64)

-static int __init p4_init(enum oprofile_cpu * cpu)
+static int __init p4_init(void)
{
__u8 cpu_model = current_cpu_data.x86_model;

@@ -225,18 +225,18 @@
return 0;

#ifndef CONFIG_SMP
- *cpu = OPROFILE_CPU_P4;
+ nmi_ops.cpu_type = "i386/p4";
model = &op_p4_spec;
return 1;
#else
switch (smp_num_siblings) {
case 1:
- *cpu = OPROFILE_CPU_P4;
+ nmi_ops.cpu_type = "i386/p4";
model = &op_p4_spec;
return 1;

case 2:
- *cpu = OPROFILE_CPU_P4_HT2;
+ nmi_ops.cpu_type = "i386/p4-ht";
model = &op_p4_ht2_spec;
return 1;
}
@@ -248,16 +248,16 @@
}


-static int __init ppro_init(enum oprofile_cpu * cpu)
+static int __init ppro_init(void)
{
__u8 cpu_model = current_cpu_data.x86_model;

if (cpu_model > 5) {
- *cpu = OPROFILE_CPU_PIII;
+ nmi_ops.cpu_type = "i386/piii";
} else if (cpu_model > 2) {
- *cpu = OPROFILE_CPU_PII;
+ nmi_ops.cpu_type = "i386/pii";
} else {
- *cpu = OPROFILE_CPU_PPRO;
+ nmi_ops.cpu_type = "i386/ppro";
}

model = &op_ppro_spec;
@@ -266,7 +266,7 @@

#endif /* !CONFIG_X86_64 */

-int __init nmi_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+int __init nmi_init(struct oprofile_operations ** ops)
{
__u8 vendor = current_cpu_data.x86_vendor;
__u8 family = current_cpu_data.x86;
@@ -280,7 +280,7 @@
if (family < 6)
return 0;
model = &op_athlon_spec;
- *cpu = OPROFILE_CPU_ATHLON;
+ nmi_ops.cpu_type = "i386/athlon";
break;

#if !defined(CONFIG_X86_64)
@@ -288,13 +288,13 @@
switch (family) {
/* Pentium IV */
case 0xf:
- if (!p4_init(cpu))
+ if (!p4_init())
return 0;
break;

/* A P6-class processor */
case 6:
- if (!ppro_init(cpu))
+ if (!ppro_init())
return 0;
break;

diff -X dontdiff -Naur linux-linus/arch/i386/oprofile/timer_int.c linux/arch/i386/oprofile/timer_int.c
--- linux-linus/arch/i386/oprofile/timer_int.c 2003-01-03 03:06:40.000000000 +0000
+++ linux/arch/i386/oprofile/timer_int.c 2003-02-10 19:40:25.000000000 +0000
@@ -45,13 +45,13 @@

static struct oprofile_operations timer_ops = {
.start = timer_start,
- .stop = timer_stop
+ .stop = timer_stop,
+ .cpu_type = "timer"
};


-void __init timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+void __init timer_init(struct oprofile_operations ** ops)
{
*ops = &timer_ops;
- *cpu = OPROFILE_CPU_TIMER;
printk(KERN_INFO "oprofile: using timer interrupt.\n");
}
diff -X dontdiff -Naur linux-linus/arch/parisc/oprofile/init.c linux/arch/parisc/oprofile/init.c
--- linux-linus/arch/parisc/oprofile/init.c 2003-01-15 11:00:46.000000000 +0000
+++ linux/arch/parisc/oprofile/init.c 2003-02-11 10:53:47.000000000 +0000
@@ -11,10 +11,10 @@
#include <linux/oprofile.h>
#include <linux/init.h>

-extern void timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
+extern void timer_init(struct oprofile_operations ** ops);

-int __init oprofile_arch_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+int __init oprofile_arch_init(struct oprofile_operations ** ops)
{
- timer_init(ops, cpu);
+ timer_init(ops);
return 0;
}
diff -X dontdiff -Naur linux-linus/arch/parisc/oprofile/timer_int.c linux/arch/parisc/oprofile/timer_int.c
--- linux-linus/arch/parisc/oprofile/timer_int.c 2003-01-15 11:00:46.000000000 +0000
+++ linux/arch/parisc/oprofile/timer_int.c 2003-02-11 10:53:30.000000000 +0000
@@ -44,13 +44,13 @@

static struct oprofile_operations timer_ops = {
.start = timer_start,
- .stop = timer_stop
+ .stop = timer_stop,
+ .cpu_type = "timer"
};


-void __init timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+void __init timer_init(struct oprofile_operations ** ops)
{
*ops = &timer_ops;
- *cpu = OPROFILE_CPU_TIMER;
printk(KERN_INFO "oprofile: using timer interrupt.\n");
}
diff -X dontdiff -Naur linux-linus/arch/ppc64/oprofile/init.c linux/arch/ppc64/oprofile/init.c
--- linux-linus/arch/ppc64/oprofile/init.c 2002-12-16 03:47:32.000000000 +0000
+++ linux/arch/ppc64/oprofile/init.c 2003-02-10 19:40:25.000000000 +0000
@@ -11,10 +11,10 @@
#include <linux/oprofile.h>
#include <linux/init.h>

-extern void timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
+extern void timer_init(struct oprofile_operations ** ops);

-int __init oprofile_arch_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+int __init oprofile_arch_init(struct oprofile_operations ** ops)
{
- timer_init(ops, cpu);
+ timer_init(ops);
return 0;
}
diff -X dontdiff -Naur linux-linus/arch/ppc64/oprofile/timer_int.c linux/arch/ppc64/oprofile/timer_int.c
--- linux-linus/arch/ppc64/oprofile/timer_int.c 2002-12-16 03:47:32.000000000 +0000
+++ linux/arch/ppc64/oprofile/timer_int.c 2003-02-10 19:40:25.000000000 +0000
@@ -44,13 +44,13 @@

static struct oprofile_operations timer_ops = {
.start = timer_start,
- .stop = timer_stop
+ .stop = timer_stop,
+ .cpu_type = "timer"
};


-void __init timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+void __init timer_init(struct oprofile_operations ** ops)
{
*ops = &timer_ops;
- *cpu = OPROFILE_CPU_TIMER;
printk(KERN_INFO "oprofile: using timer interrupt.\n");
}
diff -X dontdiff -Naur linux-linus/arch/sparc64/oprofile/init.c linux/arch/sparc64/oprofile/init.c
--- linux-linus/arch/sparc64/oprofile/init.c 2002-12-16 03:45:58.000000000 +0000
+++ linux/arch/sparc64/oprofile/init.c 2003-02-10 19:40:25.000000000 +0000
@@ -11,10 +11,10 @@
#include <linux/oprofile.h>
#include <linux/init.h>

-extern void timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
+extern void timer_init(struct oprofile_operations ** ops);

-int __init oprofile_arch_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+int __init oprofile_arch_init(struct oprofile_operations ** ops)
{
- timer_init(ops, cpu);
+ timer_init(ops);
return 0;
}
diff -X dontdiff -Naur linux-linus/arch/sparc64/oprofile/timer_int.c linux/arch/sparc64/oprofile/timer_int.c
--- linux-linus/arch/sparc64/oprofile/timer_int.c 2002-12-16 03:45:58.000000000 +0000
+++ linux/arch/sparc64/oprofile/timer_int.c 2003-02-10 19:40:25.000000000 +0000
@@ -44,13 +44,13 @@

static struct oprofile_operations timer_ops = {
.start = timer_start,
- .stop = timer_stop
+ .stop = timer_stop,
+ .cpu_type = "timer"
};


-void __init timer_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu)
+void __init timer_init(struct oprofile_operations ** ops)
{
*ops = &timer_ops;
- *cpu = OPROFILE_CPU_TIMER;
printk(KERN_INFO "oprofile: using timer interrupt.\n");
}
diff -X dontdiff -Naur linux-linus/drivers/oprofile/oprof.c linux/drivers/oprofile/oprof.c
--- linux-linus/drivers/oprofile/oprof.c 2003-01-03 02:59:11.000000000 +0000
+++ linux/drivers/oprofile/oprof.c 2003-02-10 19:40:25.000000000 +0000
@@ -20,7 +20,6 @@
#include "oprofile_stats.h"

struct oprofile_operations * oprofile_ops;
-enum oprofile_cpu oprofile_cpu_type;
unsigned long oprofile_started;
static unsigned long is_setup;
static DECLARE_MUTEX(start_sem);
@@ -127,10 +126,16 @@
/* Architecture must fill in the interrupt ops and the
* logical CPU type.
*/
- err = oprofile_arch_init(&oprofile_ops, &oprofile_cpu_type);
+ err = oprofile_arch_init(&oprofile_ops);
if (err)
goto out;

+ if (!oprofile_ops->cpu_type) {
+ printk(KERN_ERR "oprofile: cpu_type not set !\n");
+ err = -EFAULT;
+ goto out;
+ }
+
err = oprofilefs_register();
if (err)
goto out;
diff -X dontdiff -Naur linux-linus/drivers/oprofile/oprof.h linux/drivers/oprofile/oprof.h
--- linux-linus/drivers/oprofile/oprof.h 2003-01-03 02:59:11.000000000 +0000
+++ linux/drivers/oprofile/oprof.h 2003-02-10 19:40:25.000000000 +0000
@@ -24,7 +24,6 @@
extern unsigned long fs_buffer_size;
extern unsigned long fs_cpu_buffer_size;
extern unsigned long fs_buffer_watershed;
-extern enum oprofile_cpu oprofile_cpu_type;
extern struct oprofile_operations * oprofile_ops;
extern unsigned long oprofile_started;

diff -X dontdiff -Naur linux-linus/drivers/oprofile/oprofile_files.c linux/drivers/oprofile/oprofile_files.c
--- linux-linus/drivers/oprofile/oprofile_files.c 2003-01-03 02:59:11.000000000 +0000
+++ linux/drivers/oprofile/oprofile_files.c 2003-02-10 19:40:25.000000000 +0000
@@ -21,9 +21,7 @@

static ssize_t cpu_type_read(struct file * file, char * buf, size_t count, loff_t * offset)
{
- unsigned long cpu_type = oprofile_cpu_type;
-
- return oprofilefs_ulong_to_user(&cpu_type, buf, count, offset);
+ return oprofilefs_str_to_user(oprofile_ops->cpu_type, buf, count, offset);
}


diff -X dontdiff -Naur linux-linus/drivers/oprofile/oprofilefs.c linux/drivers/oprofile/oprofilefs.c
--- linux-linus/drivers/oprofile/oprofilefs.c 2003-01-03 02:59:11.000000000 +0000
+++ linux/drivers/oprofile/oprofilefs.c 2003-02-10 19:40:25.000000000 +0000
@@ -44,6 +44,29 @@
.drop_inode = generic_delete_inode,
};

+
+ssize_t oprofilefs_str_to_user(char const * str, char * buf, size_t count, loff_t * offset)
+{
+ size_t len = strlen(str);
+
+ if (!count)
+ return 0;
+
+ if (*offset > len)
+ return 0;
+
+ if (count > len - *offset)
+ count = len - *offset;
+
+ if (copy_to_user(buf, str + *offset, count))
+ return -EFAULT;
+
+ *offset += count;
+
+ return count;
+}
+
+
#define TMPBUFSIZE 50

ssize_t oprofilefs_ulong_to_user(unsigned long * val, char * buf, size_t count, loff_t * offset)
diff -X dontdiff -Naur linux-linus/include/linux/oprofile.h linux/include/linux/oprofile.h
--- linux-linus/include/linux/oprofile.h 2003-02-10 19:40:10.000000000 +0000
+++ linux/include/linux/oprofile.h 2003-02-10 19:40:25.000000000 +0000
@@ -21,24 +21,6 @@
struct dentry;
struct file_operations;

-/* This is duplicated from user-space so
- * must be kept in sync :(
- */
-enum oprofile_cpu {
- OPROFILE_CPU_PPRO,
- OPROFILE_CPU_PII,
- OPROFILE_CPU_PIII,
- OPROFILE_CPU_ATHLON,
- OPROFILE_CPU_TIMER,
- OPROFILE_UNUSED1, /* 2.4's RTC mode */
- OPROFILE_CPU_P4,
- OPROFILE_CPU_IA64,
- OPROFILE_CPU_IA64_1,
- OPROFILE_CPU_IA64_2,
- OPROFILE_CPU_HAMMER,
- OPROFILE_CPU_P4_HT2
-};
-
/* Operations structure to be filled in */
struct oprofile_operations {
/* create any necessary configuration files in the oprofile fs.
@@ -52,14 +34,16 @@
int (*start)(void);
/* Stop delivering interrupts. */
void (*stop)(void);
+ /* CPU identification string. */
+ char * cpu_type;
};

/**
* One-time initialisation. *ops must be set to a filled-in
- * operations structure. oprofile_cpu_type must be set.
+ * operations structure.
* Return 0 on success.
*/
-int oprofile_arch_init(struct oprofile_operations ** ops, enum oprofile_cpu * cpu);
+int oprofile_arch_init(struct oprofile_operations ** ops);

/**
* Add a sample. This may be called from any context. Pass
@@ -91,6 +75,12 @@
char const * name);

/**
+ * Write the given asciz string to the given user buffer @buf, updating *offset
+ * appropriately. Returns bytes written or -EFAULT.
+ */
+ssize_t oprofilefs_str_to_user(char const * str, char * buf, size_t count, loff_t * offset);
+
+/**
* Convert an unsigned long value into ASCII and copy it to the user buffer @buf,
* updating *offset appropriately. Returns bytes written or -EFAULT.
*/

2003-02-11 12:25:41

by Horst von Brand

[permalink] [raw]
Subject: Re: [PATCH 2/4] oprofile update: CPU type as string

John Levon <[email protected]> said:
> This patch updates the horrible enum for the logical CPU type with a
> string instead.

Better use "ia32/P4" and so on, "i386/P4" makes little sense ;-)

You could (should?) place the CPU ID into the model spec too...

BTW, if nobody (except masochistic kernel source readers) sees this stuff,
what is the point? An enum uses less space than a char * + the string.
--
Dr. Horst H. von Brand User #22616 counter.li.org
Departamento de Informatica Fono: +56 32 654431
Universidad Tecnica Federico Santa Maria +56 32 654239
Casilla 110-V, Valparaiso, Chile Fax: +56 32 797513

2003-02-11 12:32:28

by John Levon

[permalink] [raw]
Subject: Re: [PATCH 2/4] oprofile update: CPU type as string

On Tue, Feb 11, 2003 at 01:34:52PM +0100, Horst von Brand wrote:

> Better use "ia32/P4" and so on, "i386/P4" makes little sense ;-)

It's modelled after linux/arch/<blah>

> You could (should?) place the CPU ID into the model spec too...

eh ?

> BTW, if nobody (except masochistic kernel source readers) sees this stuff,
> what is the point? An enum uses less space than a char * + the string.

The type is used by the userspace to determine what counters are
available.

john