From: John L. <mov...@us...> - 2001-09-06 18:13:31
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv22397 Modified Files: ChangeLog op_events.c op_init.c op_user.h oprofile.c oprofile.h Log Message: philippe's cleanup, and several fixes from me. Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.100 retrieving revision 1.101 diff -u -d -r1.100 -r1.101 --- ChangeLog 2001/09/04 21:11:00 1.100 +++ ChangeLog 2001/09/06 18:13:28 1.101 @@ -1,3 +1,38 @@ +2001-09-06 John Levon <mo...@co...> + + * doc/oprofile.sgml: update a bit + +2001-09-06 John Levon <mo...@co...> + + * <most files>: make op_nr_counters a var (no pp support for > 2 yet) + + * dae/oprofiled.c: don't print help when counter event etc. are wrong + +2001-09-06 John Levon <mo...@co...> + + * oprofile.h: + * oprofile.c: use MODULE_LICENSE + +2001-09-06 John Levon <mo...@co...> + + * op_user.h: add missing prototype + + * dae/op_start: fix counter extraction + +2001-09-05 Philippe Elie <ph...@cl...> + + * pp/oprofpp.c: fix a few corner case, cleanup. + * dae/opd_proc: ditto. + + * dae/op_start: better handling of counter number + + * dae/opd_proc: minor change. + + * op_user.h: enable support for four counters + * oprofile.c: ditto. Split functions + + * op_events.c: expose op_get_cpu_type_str(int) to world. + 2001-09-04 John Levon <mo...@co...> * oprofile.h: Index: op_events.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/op_events.c,v retrieving revision 1.21 retrieving revision 1.22 diff -u -d -r1.21 -r1.22 --- op_events.c 2001/09/01 02:03:34 1.21 +++ op_events.c 2001/09/06 18:13:28 1.22 @@ -58,6 +58,13 @@ u8 um[7]; }; +static const char* cpu_type_str[MAX_CPU_TYPE] = { + "Pentium Pro", + "PII", + "PIII", + "Athlon" +}; + static struct op_unit_mask op_unit_masks[] = { /* use by the gui */ { 1, utm_mandatory, 0x0f, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, @@ -405,6 +412,23 @@ return op_check_events(ctr, *ctr_t, ctr_um, cpu_type); } +/** + * op_get_cpu_type_str - get the cpu string. + * @cpu_type: the cpu type identifier + * + * The function always return a valid const char* + * the core cpu denomination or "invalid cpu type" if + * @cpu_type is not valid. + */ +const char* op_get_cpu_type_str(int cpu_type) +{ + if (cpu_type < 0 || cpu_type > MAX_CPU_TYPE) { + return "invalid cpu type"; + } + + return cpu_type_str[cpu_type]; +} + #ifdef OP_EVENTS_DESC struct op_unit_desc { char *desc[7]; @@ -659,13 +683,6 @@ static int cpu_type = DEFAULT_CPU_TYPE; -static const char* cpu_type_str[MAX_CPU_TYPE] = { - "Pentium Pro", - "PII", - "PIII", - "Athlon" -}; - /** * help_for_event - output event name and description * @i: event number @@ -784,7 +801,7 @@ printf(VERSION_STRING " compiled on " __DATE__ " " __TIME__ "\n"); return 0; } else if (!strcmp(argv[i], "--help")) { - printf("op_help [--version|--cpu-type] event_name"); + printf("op_help [--version|--cpu-type] event_name\n"); return 0; } else if (!strncmp(argv[i], "--cpu-type=", 11)) { Index: op_init.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/op_init.c,v retrieving revision 1.6 retrieving revision 1.7 diff -u -d -r1.6 -r1.7 --- op_init.c 2001/08/19 20:09:17 1.6 +++ op_init.c 2001/09/06 18:13:28 1.7 @@ -20,6 +20,8 @@ EXPORT_NO_SYMBOLS; extern int cpu_type; +extern uint op_nr_counters; +extern int separate_running_bit; static int __init hw_ok(void) { @@ -40,6 +42,11 @@ else cpu_type = (current_cpu_data.x86_model > 5) ? CPU_PIII : (current_cpu_data.x86_model > 2); + + if (cpu_type == CPU_ATHLON) { + op_nr_counters = 4; + separate_running_bit = 1; + } return cpu_type; } Index: op_user.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/op_user.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- op_user.h 2001/09/01 02:03:34 1.4 +++ op_user.h 2001/09/06 18:13:28 1.5 @@ -22,13 +22,24 @@ #include "version.h" -/* PHE FIXME: op_config.h, typedef it and prefix by op_ ? */ +#ifndef u8 #define u8 unsigned char +#endif +#ifndef u16 #define u16 unsigned short +#endif +#ifndef u32 #define u32 unsigned int +#endif +#ifndef uint #define uint unsigned int +#endif +#ifndef ulong #define ulong unsigned long +#endif +#ifndef fd_t #define fd_t int +#endif /* event check returns */ #define OP_EVENTS_OK 0x0 @@ -69,20 +80,10 @@ * of this variable is for static/local array dimension. Never use it in loop * or in array index acccess/index checking. Don't change it without updating * OP_BITS_CTR! */ -#define OP_MAX_COUNTERS 2 - -/* The real number of counters supported for the running cpu, I define it - * separately to allow using a variable rather a constant so distribution can - * provide a generic binary for oprofile. This need also a few additional - * fixes */ -#define op_nr_counters 2 - -/* IA32 have only one bit to start/stop all counter, AMD have separate bit - * inside each event select MSR */ -#define separate_running_bit 0 +#define OP_MAX_COUNTERS 4 /* the number of bits neccessary to store OP_MAX_COUNTERS values */ -#define OP_BITS_CTR 1 +#define OP_BITS_CTR 2 /* the number of reserved bits in count, + 1 is for the notification bit */ #define OP_BITS (OP_BITS_CTR + 1) @@ -91,7 +92,7 @@ #define OP_BITS_COUNT (16 - OP_BITS) /* counter nr mask */ -#define OP_CTR_MASK ((~0U << OP_BITS_COUNT) >> 1) +#define OP_CTR_MASK ((~0U << (OP_BITS_COUNT + 1)) >> 1) /* top OP_BITS bits of count are used as follows: */ /* is this actually a notification ? */ @@ -164,6 +165,7 @@ /* op_events.c */ int op_min_count(u8 ctr_type, int cpu_type); int op_check_events(int ctr, u8 ctr_type, u8 ctr_um, int cpu_type); +const char* op_get_cpu_type_str(int cpu_type); /* not used currently */ int op_check_events_str(int ctr, char *ctr_type, u8 ctr_um, int cpu_type, u8 *ctr_t); void op_get_event_desc(int cpu_type, u8 type, u8 um, char **typenamep, char **typedescp, char **umdescp); Index: oprofile.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.c,v retrieving revision 1.81 retrieving revision 1.82 diff -u -d -r1.81 -r1.82 --- oprofile.c 2001/09/04 21:11:00 1.81 +++ oprofile.c 2001/09/06 18:13:28 1.82 @@ -22,6 +22,7 @@ static char *op_version = VERSION_STRING; MODULE_AUTHOR("John Levon (mo...@co...)"); MODULE_DESCRIPTION("Continuous Profiling Module"); +MODULE_LICENSE("GPL"); #ifdef CONFIG_SMP MODULE_PARM(allow_unload, "i"); @@ -48,6 +49,12 @@ static uint perfctr_msr[OP_MAX_COUNTERS]; static uint eventsel_msr[OP_MAX_COUNTERS]; +/* number of counters physically present */ +uint op_nr_counters = 2; + +/* whether we enable for each counter (athlon) or globally (intel) */ +int separate_running_bit; + static u32 prof_on __cacheline_aligned; static int smp_hardware; @@ -308,8 +315,6 @@ /* ugly hack */ my_set_fixmap(); - /* FIXME: NMI delivery for SMP ? */ - /* enable local APIC via MSR. Forgetting this is a fun way to lock the box */ /* IA32 V3, 7.4.2 */ @@ -430,16 +435,12 @@ case CPU_ATHLON: eventsel_msr[0] = MSR_K7_PERFCTL0; eventsel_msr[1] = MSR_K7_PERFCTL1; -/* FIXME ATHLON enable only with OP_MAX_COUNTERS 4 and an athlon to test this eventsel_msr[2] = MSR_K7_PERFCTL2; eventsel_msr[3] = MSR_K7_PERFCTL3; -*/ perfctr_msr[0] = MSR_K7_PERFCTR0; perfctr_msr[1] = MSR_K7_PERFCTR1; -/* FIXME ATHLON ditto perfctr_msr[2] = MSR_K7_PERFCTR2; perfctr_msr[3] = MSR_K7_PERFCTR3; -*/ break; default: eventsel_msr[0] = MSR_IA32_EVNTSEL0; @@ -460,7 +461,7 @@ * all bits are cleared except the reserved bits 21 */ for (i = 0 ; i < op_nr_counters ; ++i) { rdmsr(eventsel_msr[i], low, high); - wrmsr(eventsel_msr[i], low & (1 << 22), high); + wrmsr(eventsel_msr[i], low & (1 << 21), high); /* avoid a false detection of ctr overflow in NMI handler */ wrmsr(perfctr_msr[i], -1, -1); @@ -513,52 +514,74 @@ #endif } -static void pmc_start(void *info) +inline static void pmc_start_P6(void) +{ + uint low,high; + + rdmsr(eventsel_msr[0], low, high); + wrmsr(eventsel_msr[0], low | (1 << 22), high); +} + +inline static void pmc_start_Athlon(void) { uint low,high; int i; + for (i = 0 ; i < op_nr_counters ; ++i) { + if (op_ctr_count[i]) { + rdmsr(eventsel_msr[i], low, high); + wrmsr(eventsel_msr[i], low | (1 << 22), high); + } + } +} + +static void pmc_start(void *info) +{ if (info && (*((uint *)info) != smp_processor_id())) return; /* assert: all enable counter are setup except the bit start/stop, * all counter disable contains zeroes (except perhaps the reserved - * bit 21) */ + * bit 21), counter disable contains -1 sign extended in msr count */ /* enable all needed counter */ - if (separate_running_bit == 0) { - rdmsr(eventsel_msr[0], low, high); - wrmsr(eventsel_msr[0], low | (1 << 22), high); - } else { - for (i = 0 ; i < op_nr_counters ; ++i) { - if (op_ctr_count[i]) { - rdmsr(eventsel_msr[i], low, high); - wrmsr(eventsel_msr[i], low | (1 << 22), high); - } - } - } + if (separate_running_bit == 0) + pmc_start_P6(); + else + pmc_start_Athlon(); } -static void pmc_stop(void *info) +inline static void pmc_stop_P6(void) { uint low,high; + + rdmsr(eventsel_msr[0], low, high); + wrmsr(eventsel_msr[0], low & ~(1 << 22), high); +} + +inline static void pmc_stop_Athlon(void) +{ + uint low,high; int i; + for (i = 0 ; i < op_nr_counters ; ++i) { + if (op_ctr_count[i]) { + rdmsr(eventsel_msr[i], low, high); + wrmsr(eventsel_msr[i], low & ~(1 << 22), high); + } + } +} + +static void pmc_stop(void *info) +{ if (info && (*((uint *)info) != smp_processor_id())) return; /* disable counters */ - if (separate_running_bit == 0) { - rdmsr(eventsel_msr[0], low, high); - wrmsr(eventsel_msr[0], low & ~(1 << 22), high); - } else { - for (i = 0 ; i < op_nr_counters ; ++i) { - if (op_ctr_count[i]) { - rdmsr(eventsel_msr[i], low, high); - wrmsr(eventsel_msr[i], low & ~(1 << 22), high); - } - } - } + if (separate_running_bit == 0) + pmc_stop_P6(); + else + pmc_stop_Athlon(); } inline static void pmc_select_start(uint cpu) @@ -850,11 +873,6 @@ return -EFAULT; } - /* PHE FIXME: this is inefficient if only few counter are - * enable. Some other place in the code must be fixed if we - * allocate only on demand, take care than note currently are - * always put in data[0]->buffer even if the counter 0 is - * disable */ data->buffer = vmalloc(buf_size); if (!data->buffer) { printk(KERN_ERR "oprofile: failed to allocate eviction buffer of %lu bytes\n",buf_size); @@ -880,12 +898,11 @@ uint cpu; int ok; struct _oprof_data *data; - int enabled; + int enabled = 0; op_check_range(op_hash_size, 256, 262144, "op_hash_size value %d not in range (%d %d)\n"); op_check_range(op_buf_size, 1024, 1048576, "op_buf_size value %d not in range (%d %d)\n"); - enabled = 0; for (i = 0; i < op_nr_counters ; i++) { if (op_ctr_on[i]) { int min_count = op_min_count(op_ctr_val[i], cpu_type); @@ -901,7 +918,7 @@ } if (!enabled) { - printk(KERN_ERR "oprofile: neither counter enabled.\n"); + printk(KERN_ERR "oprofile: no counters have been enabled.\n"); return 0; } @@ -1170,7 +1187,6 @@ static int __init init_sysctl(void) { ctl_table *next = &oprof_table[nr_oprof_static]; - ctl_table *counter_table[op_nr_counters + 1]; ctl_table *tab; int i,j; @@ -1192,7 +1208,6 @@ tab[3] = ((ctl_table){ 1, "unit_mask", &op_ctr_um[i], sizeof(int), 0600, NULL, lproc_dointvec, NULL, }); tab[4] = ((ctl_table){ 1, "kernel", &op_ctr_kernel[i], sizeof(int), 0600, NULL, lproc_dointvec, NULL, }); tab[5] = ((ctl_table){ 1, "user", &op_ctr_user[i], sizeof(int), 0600, NULL, lproc_dointvec, NULL, }); - counter_table[i] = tab; next++; } Index: oprofile.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.h,v retrieving revision 1.49 retrieving revision 1.50 diff -u -d -r1.49 -r1.50 --- oprofile.h 2001/09/04 21:11:00 1.49 +++ oprofile.h 2001/09/06 18:13:28 1.50 @@ -198,6 +198,11 @@ #include <linux/completion.h> #endif +// 2.4.10 introduced MODULE_LICENSE +#ifndef MODULE_LICENSE +#define MODULE_LICENSE(x) +#endif + /* These arrays are filled by hw_ok() */ extern uint perfctr_msr[OP_MAX_COUNTERS]; extern uint eventsel_msr[OP_MAX_COUNTERS]; |