You can subscribe to this list here.
2001 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
(7) |
Aug
(50) |
Sep
(210) |
Oct
(93) |
Nov
(99) |
Dec
(101) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2002 |
Jan
(283) |
Feb
(42) |
Mar
(148) |
Apr
(94) |
May
(256) |
Jun
(206) |
Jul
(101) |
Aug
(28) |
Sep
(159) |
Oct
(102) |
Nov
(216) |
Dec
(159) |
2003 |
Jan
(112) |
Feb
(149) |
Mar
(332) |
Apr
(261) |
May
(528) |
Jun
(270) |
Jul
(231) |
Aug
(231) |
Sep
(338) |
Oct
(445) |
Nov
(212) |
Dec
(26) |
2004 |
Jan
(179) |
Feb
(109) |
Mar
(20) |
Apr
(20) |
May
(55) |
Jun
(11) |
Jul
(38) |
Aug
(13) |
Sep
(28) |
Oct
(13) |
Nov
(41) |
Dec
(30) |
2005 |
Jan
(17) |
Feb
(4) |
Mar
(62) |
Apr
(176) |
May
(44) |
Jun
(13) |
Jul
(16) |
Aug
(154) |
Sep
(6) |
Oct
(13) |
Nov
(4) |
Dec
(6) |
2006 |
Jan
(12) |
Feb
(11) |
Mar
(9) |
Apr
(1) |
May
(10) |
Jun
(6) |
Jul
(10) |
Aug
(10) |
Sep
(27) |
Oct
(25) |
Nov
(40) |
Dec
(18) |
2007 |
Jan
(13) |
Feb
(25) |
Mar
(6) |
Apr
(14) |
May
(52) |
Jun
(22) |
Jul
(20) |
Aug
(8) |
Sep
(2) |
Oct
(138) |
Nov
(152) |
Dec
(73) |
2008 |
Jan
(52) |
Feb
(31) |
Mar
(5) |
Apr
(48) |
May
(20) |
Jun
(14) |
Jul
(36) |
Aug
(16) |
Sep
(1) |
Oct
(19) |
Nov
(13) |
Dec
(4) |
2009 |
Jan
(2) |
Feb
(13) |
Mar
(10) |
Apr
(28) |
May
(46) |
Jun
(21) |
Jul
(21) |
Aug
(22) |
Sep
(8) |
Oct
(25) |
Nov
(15) |
Dec
(2) |
2010 |
Jan
(12) |
Feb
|
Mar
(8) |
Apr
(3) |
May
(2) |
Jun
(5) |
Jul
(11) |
Aug
(17) |
Sep
|
Oct
(12) |
Nov
(14) |
Dec
(10) |
2011 |
Jan
(6) |
Feb
|
Mar
(8) |
Apr
(6) |
May
(17) |
Jun
(8) |
Jul
(4) |
Aug
(9) |
Sep
(2) |
Oct
(3) |
Nov
(4) |
Dec
(2) |
2012 |
Jan
(4) |
Feb
(7) |
Mar
(16) |
Apr
(9) |
May
(15) |
Jun
(22) |
Jul
(30) |
Aug
(36) |
Sep
(6) |
Oct
(5) |
Nov
(9) |
Dec
(11) |
2013 |
Jan
(17) |
Feb
(11) |
Mar
(7) |
Apr
(8) |
May
(15) |
Jun
(19) |
Jul
(27) |
Aug
(3) |
Sep
(3) |
Oct
(8) |
Nov
(6) |
Dec
(10) |
2014 |
Jan
(15) |
Feb
(16) |
Mar
(4) |
Apr
(3) |
May
(10) |
Jun
(9) |
Jul
(9) |
Aug
(31) |
Sep
(11) |
Oct
(6) |
Nov
(4) |
Dec
(3) |
2015 |
Jan
(2) |
Feb
(1) |
Mar
(2) |
Apr
(3) |
May
(4) |
Jun
(5) |
Jul
(14) |
Aug
(2) |
Sep
(2) |
Oct
(1) |
Nov
(4) |
Dec
(4) |
2016 |
Jan
|
Feb
(1) |
Mar
(1) |
Apr
(4) |
May
(2) |
Jun
|
Jul
(2) |
Aug
(1) |
Sep
(1) |
Oct
(3) |
Nov
(1) |
Dec
|
2017 |
Jan
(4) |
Feb
|
Mar
(1) |
Apr
(3) |
May
|
Jun
(9) |
Jul
(11) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
2018 |
Jan
(1) |
Feb
|
Mar
(1) |
Apr
|
May
|
Jun
(3) |
Jul
(10) |
Aug
(1) |
Sep
|
Oct
|
Nov
|
Dec
|
2019 |
Jan
|
Feb
|
Mar
(1) |
Apr
(1) |
May
(6) |
Jun
|
Jul
(2) |
Aug
(2) |
Sep
(1) |
Oct
|
Nov
|
Dec
(1) |
2020 |
Jan
|
Feb
|
Mar
(2) |
Apr
|
May
|
Jun
|
Jul
(4) |
Aug
|
Sep
(1) |
Oct
|
Nov
|
Dec
|
2021 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(1) |
Dec
|
2024 |
Jan
|
Feb
|
Mar
|
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
(2) |
Dec
|
From: John L. <mov...@us...> - 2001-09-02 00:32:32
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv14034 Modified Files: ChangeLog oprofile.c Log Message: philippe's patch Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.92 retrieving revision 1.93 diff -u -d -r1.92 -r1.93 --- ChangeLog 2001/09/01 02:03:34 1.92 +++ ChangeLog 2001/09/02 00:32:28 1.93 @@ -1,3 +1,10 @@ +2001-09-01 Philippe Elie <ph...@cl...> + + * oprofile.c: fix pmc_setup() + + * pp/Makefile.in: + * dae/Makefile.in: fix uninstall problem + 2001-08-31 Philippe Elie <ph...@cl...> * oprofile.h: Index: oprofile.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.c,v retrieving revision 1.76 retrieving revision 1.77 diff -u -d -r1.76 -r1.77 --- oprofile.c 2001/09/01 02:03:34 1.76 +++ oprofile.c 2001/09/02 00:32:28 1.77 @@ -441,10 +441,13 @@ /* Stop and clear all counter: IA32 use bit 22 of eventsel_msr0 to * enable/disable all counter, AMD use separate bit 22 in each msr, - * all other bits are cleared except the reserved bits 21 */ + * 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 & ~(3 << 22), high); + wrmsr(eventsel_msr[i], low & (1 << 22), high); + + /* avoid a false detection of ctr overflow in NMI handler */ + wrmsr(perfctr_msr[i], -1, -1); } /* setup each counter */ @@ -501,7 +504,8 @@ /* this is pretty bogus really. especially as we don't re-enable it. * Instead, save state set up, and restore with pmc_unsetup or similar */ #if !defined(CONFIG_X86_UP_APIC) || !defined(OP_EXPORTED_DO_NMI) - wrmsr(eventsel_msr[1], low, high); + /* PHE FIXME: on my config this start counter 1 with the new code */ +// wrmsr(eventsel_msr[1], low, high); #endif } |
From: Dave J. <da...@us...> - 2001-09-01 21:50:38
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv5883 Modified Files: .cvsignore Log Message: Update ignorance list. Index: .cvsignore =================================================================== RCS file: /cvsroot/oprofile/oprofile/.cvsignore,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- .cvsignore 2000/08/18 01:24:37 1.2 +++ .cvsignore 2001/09/01 21:50:35 1.3 @@ -3,6 +3,7 @@ version.h a.diff oprofile.s +confdefs.h config.log config.cache config.status |
From: John L. <mov...@us...> - 2001-09-01 02:03:43
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv19169 Modified Files: ChangeLog Makefile.in op_events.c op_user.h oprofile.c oprofile.h Log Message: philippe's huge patch Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.91 retrieving revision 1.92 diff -u -d -r1.91 -r1.92 --- ChangeLog 2001/08/31 17:16:35 1.91 +++ ChangeLog 2001/09/01 02:03:34 1.92 @@ -1,5 +1,63 @@ -2001-08-31 John Levon <mo...@co...> +2001-08-31 Philippe Elie <ph...@cl...> + + * oprofile.h: + * dae/oprofiled.h: + * op_user.h: + * oprofpp.h: + * dae/opd_util.h: share commmon declarations, put it in + op_user.h, include op_user.h in other .h when necessary. + * op_events.c: + * all Makefile.in: update dependancies. + +2001-08-30 Philippe Elie <ph...@cl...> + + * oprofile.c: use loop instead of fixed counter number + +2001-08-26 Philippe Elie <ph...@cl...> + + * op_events.c: add option to op_help for the gui + * gui/oprofile: use op_help to build description + of events, accept Athlon (only 2 counters) + +2001-08-25 Philippe Elie <ph...@cl...> + + * pp/oprofpp.c: + * dae/op_start: use loop instead of fixed number of counter. + +2001-08-24 Philippe Elie <ph...@cl...> + + * pp/oprof_convert.c: add v4 --> v5 conversion + +2001-08-23 Philippe Elie <ph...@cl...> + + * oprofile.c: correct some comment. + +2001-08-22 Philippe Elie <ph...@cl...> + + * op_user.h: + * dae/opd_proc.c: + * dae/opd_util.c: + * dae/opd_util.h: + * dae/oprofiled.h: + * dae/oprofiled.c: + * dae/oprofiled.c: row to column file format, lot of changes. + +2001-08-21 Philippe Elie <ph...@cl...> + + * op_events.c: Add Athlon string/unit maks description + +2001-08-20 Philippe Elie <ph...@cl...> + * op_events.c: change in handling of search/check events + * dae/oprofiled.c: + * dae/oprofiled.h: + * oprofile.c: + * oprofile.h: + * pp/oprofpp.c: + * pp/oprofpp.h: reflects caller/prototype, lot of changes. + +2001-08-31 John Levon <mo...@co...> + * Makefile.in: * op_x86.c: * oprofile.h: Index: Makefile.in =================================================================== RCS file: /cvsroot/oprofile/oprofile/Makefile.in,v retrieving revision 1.24 retrieving revision 1.25 diff -u -d -r1.24 -r1.25 --- Makefile.in 2001/08/31 17:16:35 1.24 +++ Makefile.in 2001/09/01 02:03:34 1.25 @@ -94,7 +94,7 @@ oprofile.s: oprofile.c oprofile.h $(CC) $(KCFLAGS) -S $< -op_events.o: op_events.c +op_events.o: op_events.c op_user.h $(CC) $(KCFLAGS) -c -o $@ $< oprofile_nmi.o: oprofile_nmi.S Index: op_events.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/op_events.c,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- op_events.c 2001/08/19 20:09:17 1.20 +++ op_events.c 2001/09/01 02:03:34 1.21 @@ -19,15 +19,6 @@ /* See IA32 Vol. 3 Appendix A */ -/* for allowed */ -#define OP_0_ONLY 0 -#define OP_1_ONLY 1 -#define OP_ANY 2 -#define OP_PII_PIII 3 -#define OP_PII_ONLY 4 -#define OP_PIII_ONLY 5 -#define OP_ATHLON_ONLY 6 - #ifdef __KERNEL__ #include <linux/string.h> #define strcmp(a,b) strnicmp((a),(b),strlen((b))) @@ -35,10 +26,10 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <limits.h> #endif -#define u8 unsigned char -#define uint unsigned int +#include "op_user.h" enum unit_mask_type { /* useless but required by the hardware */ @@ -50,186 +41,186 @@ }; struct op_event { - uint allowed; - u8 val; /* event number */ - u8 unit; /* which unit mask if any allowed */ + uint counter_mask; /* bitmask of allowed counter */ + u16 cpu_mask; /* bitmask of allowed cpu_type */ + u8 val; /* event number */ + u8 unit; /* which unit mask if any allowed */ const char *name; - int min_count; /* minimum counter value allowed */ + int min_count; /* minimum counter value allowed */ }; struct op_unit_mask { uint num; /* number of possible unit masks */ enum unit_mask_type unit_type_mask; + /* only the gui use it */ + u8 default_mask; /* up to seven allowed unit masks */ u8 um[7]; }; -int op_check_events_str(char *ctr0_type, char *ctr1_type, u8 ctr0_um, u8 ctr1_um, int p2, u8 *ctr0_t, u8 *ctr1_t); -int op_check_events(u8 ctr0_type, u8 ctr1_type, u8 ctr0_um, u8 ctr1_um, int proc); -int op_min_count(u8 ctr_type); -#ifdef OP_EVENTS_DESC -void op_get_event_desc(u8 type, u8 um, char **typenamep, char **typedescp, char **umdescp); -#endif - static struct op_unit_mask op_unit_masks[] = { - /* not used */ - { 1, utm_mandatory, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, + /* use by the gui */ + { 1, utm_mandatory, 0x0f, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, /* MESI counters */ - { 5, utm_bitmask, { 0x1, 0x2, 0x4, 0x8, 0xf, 0x0, 0x0 }, }, - /* EBL self/any */ - { 2, utm_exclusive, { 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, + { 5, utm_bitmask, 0x0f, { 0x8, 0x4, 0x2, 0x1, 0xf, 0x0, 0x0 }, }, + /* EBL self/any default to any transitions */ + { 2, utm_exclusive, 0x20, { 0x0, 0x20, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, /* MMX PII events */ - { 1, utm_mandatory, { 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, - { 7, utm_bitmask, { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x3f }, }, - { 2, utm_exclusive, { 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, - { 5, utm_bitmask, { 0x1, 0x2, 0x4, 0x8, 0xf, 0x0, 0x0 }, }, + { 1, utm_mandatory, 0xf, { 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, + { 7, utm_bitmask, 0x3f, { 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x3f }, }, + { 2, utm_exclusive, 0x0, { 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, + { 5, utm_bitmask, 0x0f, { 0x1, 0x2, 0x4, 0x8, 0xf, 0x0, 0x0 }, }, /* KNI PIII events */ - { 4, utm_exclusive, { 0x0, 0x1, 0x2, 0x3, 0x0, 0x0, 0x0 }, }, - { 2, utm_bitmask, { 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, + { 4, utm_exclusive, 0x0, { 0x0, 0x1, 0x2, 0x3, 0x0, 0x0, 0x0 }, }, + { 2, utm_bitmask, 0x1, { 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, + /* Athlon MOESI cache events */ + { 6, utm_bitmask, 0x1f, { 0x10, 0x8, 0x4, 0x2, 0x1, 0x1f }, } }; +/* the following are just short cut for filling the table of event */ +#define OP_ATHLON (1 << CPU_ATHLON) +#define OP_PPRO (1 << CPU_PPRO) +#define OP_PII (1 << CPU_PII) +#define OP_PIII (1 << CPU_PIII) +#define OP_PII_PIII (OP_PII | OP_PIII) +#define OP_IA_ALL (OP_PII_PIII | OP_PPRO) + +#define CTR_ALL (~0u) +#define CTR_0 (1 << 0) +#define CTR_1 (1 << 1) + /* Allowed, Event #, unit mask, name, minimum event value */ static struct op_event op_events[] = { + /* Clocks */ + { CTR_ALL, OP_IA_ALL, 0x79, 0, "CPU_CLK_UNHALTED", 6000 }, /* Data Cache Unit (DCU) */ - {OP_ATHLON_ONLY,0x40,0,"DATA_CACHE_ACCESSES", 500,}, - {OP_ATHLON_ONLY,0x41,0,"DATA_CACHE_MISSES", 500,}, - {OP_ATHLON_ONLY,0x42,0,"DATA_CACHE_REFILLS_FROM_L2", 500,}, - {OP_ATHLON_ONLY,0x43,0,"DATA_CACHE_REFILLS_FROM_SYSTEM", 500,}, - {OP_ATHLON_ONLY,0x44,0,"DATA_CACHE_WRITEBACKS", 500,}, - {OP_ATHLON_ONLY,0x45,0,"L1_DTLB_MISSES_L2_DTLD_HITS", 500,}, - {OP_ATHLON_ONLY,0x46,0,"L1_AND_L2_DTLB_MISSES", 500,}, - {OP_ATHLON_ONLY,0x47,0,"MISALIGNED_DATA_REFS", 500,}, - {OP_ATHLON_ONLY,0x80,0,"ICACHE_FETCHES", 500,}, - {OP_ATHLON_ONLY,0x81,0,"ICACHE_MISSES", 500,}, - {OP_ATHLON_ONLY,0x84,0,"L1_ITLB_MISSES_L2_ITLB_HITS", 500,}, - {OP_ATHLON_ONLY,0x85,0,"L1_AND_L2_ITLB_MISSES", 500,}, - {OP_ATHLON_ONLY,0xc0,0,"RETIRED_INSNS", 500,}, - {OP_ATHLON_ONLY,0xc1,0,"RETIRED_OPS", 500,}, - {OP_ATHLON_ONLY,0xc2,0,"RETIRED_BRANCHES", 500,}, - {OP_ATHLON_ONLY,0xc3,0,"RETIRED_BRANCHES_MISPREDICTED", 500,}, - {OP_ATHLON_ONLY,0xc4,0,"RETIRED_TAKEN_BRANCHES", 500,}, - {OP_ATHLON_ONLY,0xc5,0,"RETIRED_TAKEN_BRANCHES_MISPREDICTED", 500,}, - {OP_ATHLON_ONLY,0xc6,0,"RETIRED_FAR_CONTROL_TRANSFERS", 500,}, - {OP_ATHLON_ONLY,0xc7,0,"RETIRED_RESYNC_BRANCHES", 500,}, - {OP_ATHLON_ONLY,0xcd,0,"INTERRUPTS_MASKED", 500,}, - {OP_ATHLON_ONLY,0xce,0,"INTERRUPTS_MASKED_PENDING", 500,}, - {OP_ATHLON_ONLY,0xcf,0,"HARDWARE_INTERRUPTS", 500,}, - - {OP_ANY,0x43,0,"DATA_MEM_REFS", 500 }, - {OP_ANY,0x45,0,"DCU_LINES_IN", 500 }, - {OP_ANY,0x46,0,"DCU_M_LINES_IN", 500 }, - {OP_ANY,0x47,0,"DCU_M_LINES_OUT", 500}, - {OP_ANY,0x48,0,"DCU_MISS_OUTSTANDING", 500 }, - + { CTR_ALL, OP_IA_ALL, 0x43, 0, "DATA_MEM_REFS", 500 }, + { CTR_ALL, OP_IA_ALL, 0x45, 0, "DCU_LINES_IN", 500 }, + { CTR_ALL, OP_IA_ALL, 0x46, 0, "DCU_M_LINES_IN", 500 }, + { CTR_ALL, OP_IA_ALL, 0x47, 0, "DCU_M_LINES_OUT", 500}, + { CTR_ALL, OP_IA_ALL, 0x48, 0, "DCU_MISS_OUTSTANDING", 500 }, /* Intruction Fetch Unit (IFU) */ - {OP_ANY,0x80,0,"IFU_IFETCH", 500 }, - {OP_ANY,0x81,0,"IFU_IFETCH_MISS", 500 }, - {OP_ANY,0x85,0,"ITLB_MISS", 500}, - {OP_ANY,0x86,0,"IFU_MEM_STALL", 500 }, - {OP_ANY,0x87,0,"ILD_STALL", 500 }, + { CTR_ALL, OP_IA_ALL, 0x80, 0, "IFU_IFETCH", 500 }, + { CTR_ALL, OP_IA_ALL, 0x81, 0, "IFU_IFETCH_MISS", 500 }, + { CTR_ALL, OP_IA_ALL, 0x85, 0, "ITLB_MISS", 500}, + { CTR_ALL, OP_IA_ALL, 0x86, 0, "IFU_MEM_STALL", 500 }, + { CTR_ALL, OP_IA_ALL, 0x87, 0, "ILD_STALL", 500 }, /* L2 Cache */ - {OP_ANY,0x28,1,"L2_IFETCH", 500 }, - {OP_ANY,0x29,1,"L2_LD", 500 }, - {OP_ANY,0x2a,1,"L2_ST", 500 }, - {OP_ANY,0x24,0,"L2_LINES_IN", 500 }, - {OP_ANY,0x26,0,"L2_LINES_OUT", 500 }, - {OP_ANY,0x25,0,"L2_M_LINES_INM", 500 }, - {OP_ANY,0x27,0,"L2_M_LINES_OUTM", 500 }, - {OP_ANY,0x2e,1,"L2_RQSTS", 500 }, - {OP_ANY,0x21,0,"L2_ADS", 500 }, - {OP_ANY,0x22,0,"L2_DBUS_BUSY", 500 }, - {OP_ANY,0x23,0,"L2_DMUS_BUSY_RD", 500 }, + { CTR_ALL, OP_IA_ALL, 0x28, 1, "L2_IFETCH", 500 }, + { CTR_ALL, OP_IA_ALL, 0x29, 1, "L2_LD", 500 }, + { CTR_ALL, OP_IA_ALL, 0x2a, 1, "L2_ST", 500 }, + { CTR_ALL, OP_IA_ALL, 0x24, 0, "L2_LINES_IN", 500 }, + { CTR_ALL, OP_IA_ALL, 0x26, 0, "L2_LINES_OUT", 500 }, + { CTR_ALL, OP_IA_ALL, 0x25, 0, "L2_M_LINES_INM", 500 }, + { CTR_ALL, OP_IA_ALL, 0x27, 0, "L2_M_LINES_OUTM", 500 }, + { CTR_ALL, OP_IA_ALL, 0x2e, 1, "L2_RQSTS", 500 }, + { CTR_ALL, OP_IA_ALL, 0x21, 0, "L2_ADS", 500 }, + { CTR_ALL, OP_IA_ALL, 0x22, 0, "L2_DBUS_BUSY", 500 }, + { CTR_ALL, OP_IA_ALL, 0x23, 0, "L2_DMUS_BUSY_RD", 500 }, /* External Bus Logic (EBL) */ - {OP_ANY,0x62,2,"BUS_DRDY_CLOCKS", 500 }, - {OP_ANY,0x63,2,"BUS_LOCK_CLOCKS", 500 }, - {OP_ANY,0x60,0,"BUS_REQ_OUTSTANDING", 500 }, - {OP_ANY,0x65,2,"BUS_TRAN_BRD", 500 }, - {OP_ANY,0x66,2,"BUS_TRAN_RFO", 500 }, - {OP_ANY,0x67,2,"BUS_TRANS_WB", 500 }, - {OP_ANY,0x68,2,"BUS_TRAN_IFETCH", 500 }, - {OP_ANY,0x69,2,"BUS_TRAN_INVAL", 500 }, - {OP_ANY,0x6a,2,"BUS_TRAN_PWR", 500 }, - {OP_ANY,0x6b,2,"BUS_TRANS_P", 500 }, - {OP_ANY,0x6c,2,"BUS_TRANS_IO", 500 }, - {OP_ANY,0x6d,2,"BUS_TRANS_DEF", 500 }, - {OP_ANY,0x6e,2,"BUS_TRAN_BURST", 500 }, - {OP_ANY,0x70,2,"BUS_TRAN_ANY", 500 }, - {OP_ANY,0x6f,2,"BUS_TRAN_MEM", 500 }, - {OP_ANY,0x64,0,"BUS_DATA_RCV", 500 }, - {OP_ANY,0x61,0,"BUS_BNR_DRV", 500 }, - {OP_ANY,0x7a,0,"BUS_HIT_DRV", 500 }, - {OP_ANY,0x7b,0,"BUS_HITM_DRV", 500 }, - {OP_ANY,0x7e,0,"BUS_SNOOP_STALL", 500 }, + { CTR_ALL, OP_IA_ALL, 0x62, 2, "BUS_DRDY_CLOCKS", 500 }, + { CTR_ALL, OP_IA_ALL, 0x63, 2, "BUS_LOCK_CLOCKS", 500 }, + { CTR_ALL, OP_IA_ALL, 0x60, 0, "BUS_REQ_OUTSTANDING", 500 }, + { CTR_ALL, OP_IA_ALL, 0x65, 2, "BUS_TRAN_BRD", 500 }, + { CTR_ALL, OP_IA_ALL, 0x66, 2, "BUS_TRAN_RFO", 500 }, + { CTR_ALL, OP_IA_ALL, 0x67, 2, "BUS_TRANS_WB", 500 }, + { CTR_ALL, OP_IA_ALL, 0x68, 2, "BUS_TRAN_IFETCH", 500 }, + { CTR_ALL, OP_IA_ALL, 0x69, 2, "BUS_TRAN_INVAL", 500 }, + { CTR_ALL, OP_IA_ALL, 0x6a, 2, "BUS_TRAN_PWR", 500 }, + { CTR_ALL, OP_IA_ALL, 0x6b, 2, "BUS_TRANS_P", 500 }, + { CTR_ALL, OP_IA_ALL, 0x6c, 2, "BUS_TRANS_IO", 500 }, + { CTR_ALL, OP_IA_ALL, 0x6d, 2, "BUS_TRANS_DEF", 500 }, + { CTR_ALL, OP_IA_ALL, 0x6e, 2, "BUS_TRAN_BURST", 500 }, + { CTR_ALL, OP_IA_ALL, 0x70, 2, "BUS_TRAN_ANY", 500 }, + { CTR_ALL, OP_IA_ALL, 0x6f, 2, "BUS_TRAN_MEM", 500 }, + { CTR_ALL, OP_IA_ALL, 0x64, 0, "BUS_DATA_RCV", 500 }, + { CTR_ALL, OP_IA_ALL, 0x61, 0, "BUS_BNR_DRV", 500 }, + { CTR_ALL, OP_IA_ALL, 0x7a, 0, "BUS_HIT_DRV", 500 }, + { CTR_ALL, OP_IA_ALL, 0x7b, 0, "BUS_HITM_DRV", 500 }, + { CTR_ALL, OP_IA_ALL, 0x7e, 0, "BUS_SNOOP_STALL", 500 }, /* Floating Point Unit (FPU) */ - {OP_0_ONLY,0xc1,0,"COMP_FLOP_RET", 3000 }, - {OP_0_ONLY,0x10,0,"FLOPS", 3000 }, - {OP_1_ONLY,0x11,0,"FP_ASSIST", 500 }, - {OP_1_ONLY,0x12,0,"MUL", 1000 }, - {OP_1_ONLY,0x13,0,"DIV", 500 }, - {OP_0_ONLY,0x14,0,"CYCLES_DIV_BUSY", 1000 }, + { CTR_0, OP_IA_ALL, 0xc1, 0, "COMP_FLOP_RET", 3000 }, + { CTR_0, OP_IA_ALL, 0x10, 0, "FLOPS", 3000 }, + { CTR_1, OP_IA_ALL, 0x11, 0, "FP_ASSIST", 500 }, + { CTR_1, OP_IA_ALL, 0x12, 0, "MUL", 1000 }, + { CTR_1, OP_IA_ALL, 0x13, 0, "DIV", 500 }, + { CTR_0, OP_IA_ALL, 0x14, 0, "CYCLES_DIV_BUSY", 1000 }, /* Memory Ordering */ - {OP_ANY,0x03,0,"LD_BLOCKS", 500 }, - {OP_ANY,0x04,0,"SB_DRAINS", 500 }, - {OP_ANY,0x05,0,"MISALIGN_MEM_REF", 500 }, + { CTR_ALL, OP_IA_ALL, 0x03, 0, "LD_BLOCKS", 500 }, + { CTR_ALL, OP_IA_ALL, 0x04, 0, "SB_DRAINS", 500 }, + { CTR_ALL, OP_IA_ALL, 0x05, 0, "MISALIGN_MEM_REF", 500 }, /* PIII KNI */ - {OP_PIII_ONLY,0x07,7,"EMON_KNI_PREF_DISPATCHED", 500 }, - {OP_PIII_ONLY,0x4b,7,"EMON_KNI_PREF_MISS", 500 }, + { CTR_ALL, OP_PIII, 0x07, 7, "EMON_KNI_PREF_DISPATCHED", 500 }, + { CTR_ALL, OP_PIII, 0x4b, 7, "EMON_KNI_PREF_MISS", 500 }, /* Instruction Decoding and Retirement */ - {OP_ANY,0xc0,0,"INST_RETIRED", 6000 }, - {OP_ANY,0xc2,0,"UOPS_RETIRED", 6000 }, - {OP_ANY,0xd0,0,"INST_DECODED", 6000 }, + { CTR_ALL, OP_IA_ALL, 0xc0, 0, "INST_RETIRED", 6000 }, + { CTR_ALL, OP_IA_ALL, 0xc2, 0, "UOPS_RETIRED", 6000 }, + { CTR_ALL, OP_IA_ALL, 0xd0, 0, "INST_DECODED", 6000 }, /* PIII KNI */ - {OP_PIII_ONLY,0xd8,8,"EMON_KNI_INST_RETIRED", 3000 }, - {OP_PIII_ONLY,0xd9,8,"EMON_KNI_COMP_INST_RET", 3000 }, + { CTR_ALL, OP_PIII, 0xd8, 8, "EMON_KNI_INST_RETIRED", 3000 }, + { CTR_ALL, OP_PIII, 0xd9, 8, "EMON_KNI_COMP_INST_RET", 3000 }, /* Interrupts */ - {OP_ANY,0xc8,0,"HW_INT_RX", 500 }, - {OP_ANY,0xc6,0,"CYCLES_INT_MASKED", 500 }, - {OP_ANY,0xc7,0,"CYCLES_INT_PENDING_AND_MASKED", 500 }, + { CTR_ALL, OP_IA_ALL, 0xc8, 0, "HW_INT_RX", 500 }, + { CTR_ALL, OP_IA_ALL, 0xc6, 0, "CYCLES_INT_MASKED", 500 }, + { CTR_ALL, OP_IA_ALL, 0xc7, 0, "CYCLES_INT_PENDING_AND_MASKED", 500 }, /* Branches */ - {OP_ANY,0xc4,0,"BR_INST_RETIRED", 500 }, - {OP_ANY,0xc5,0,"BR_MISS_PRED_RETIRED", 500 }, - {OP_ANY,0xc9,0,"BR_TAKEN_RETIRED", 500 }, - {OP_ANY,0xca,0,"BR_MISS_PRED_TAKEN_RET", 500 }, - {OP_ANY,0xe0,0,"BR_INST_DECODED", 500 }, - {OP_ANY,0xe2,0,"BTB_MISSES", 500 }, - {OP_ANY,0xe4,0,"BR_BOGUS", 500 }, - {OP_ANY,0xe6,0,"BACLEARS", 500 }, + { CTR_ALL, OP_IA_ALL, 0xc4, 0, "BR_INST_RETIRED", 500 }, + { CTR_ALL, OP_IA_ALL, 0xc5, 0, "BR_MISS_PRED_RETIRED", 500 }, + { CTR_ALL, OP_IA_ALL, 0xc9, 0, "BR_TAKEN_RETIRED", 500 }, + { CTR_ALL, OP_IA_ALL, 0xca, 0, "BR_MISS_PRED_TAKEN_RET", 500 }, + { CTR_ALL, OP_IA_ALL, 0xe0, 0, "BR_INST_DECODED", 500 }, + { CTR_ALL, OP_IA_ALL, 0xe2, 0, "BTB_MISSES", 500 }, + { CTR_ALL, OP_IA_ALL, 0xe4, 0, "BR_BOGUS", 500 }, + { CTR_ALL, OP_IA_ALL, 0xe6, 0, "BACLEARS", 500 }, /* Stalls */ - {OP_ANY,0xa2,0,"RESOURCE_STALLS", 500 }, - {OP_ANY,0xd2,0,"PARTIAL_RAT_STALLS", 500 }, + { CTR_ALL, OP_IA_ALL, 0xa2, 0, "RESOURCE_STALLS", 500 }, + { CTR_ALL, OP_IA_ALL, 0xd2, 0, "PARTIAL_RAT_STALLS", 500 }, /* Segment Register Loads */ - {OP_ANY,0x06,0,"SEGMENT_REG_LOADS", 500 }, - /* Clocks */ - {OP_ANY,0x79,0,"CPU_CLK_UNHALTED", 6000 }, + { CTR_ALL, OP_IA_ALL, 0x06, 0, "SEGMENT_REG_LOADS", 500 }, /* MMX (Pentium II only) */ - {OP_PII_ONLY,0xb0,0,"MMX_INSTR_EXEC", 3000 }, - {OP_PII_PIII,0xb1,0,"MMX_SAT_INSTR_EXEC", 3000 }, - {OP_PII_PIII,0xb2,3,"MMX_UOPS_EXEC", 3000 }, - {OP_PII_PIII,0xb3,4,"MMX_INSTR_TYPE_EXEC", 3000 }, - {OP_PII_PIII,0xcc,5,"FP_MMX_TRANS", 3000 }, - {OP_PII_PIII,0xcd,0,"MMX_ASSIST", 500 }, - {OP_PII_ONLY,0xce,0,"MMX_INSTR_RET", 3000 }, + { CTR_ALL, OP_PII, 0xb0, 0, "MMX_INSTR_EXEC", 3000 }, + { CTR_ALL, OP_PII_PIII, 0xb1, 0, "MMX_SAT_INSTR_EXEC", 3000 }, + { CTR_ALL, OP_PII_PIII, 0xb2, 3, "MMX_UOPS_EXEC", 3000 }, + { CTR_ALL, OP_PII_PIII, 0xb3, 4, "MMX_INSTR_TYPE_EXEC", 3000 }, + { CTR_ALL, OP_PII_PIII, 0xcc, 5, "FP_MMX_TRANS", 3000 }, + { CTR_ALL, OP_PII_PIII, 0xcd, 0, "MMX_ASSIST", 500 }, + { CTR_ALL, OP_PII_PIII, 0xce, 0, "MMX_INSTR_RET", 3000 }, /* segment renaming (Pentium II only) */ - {OP_PII_PIII,0xd4,6,"SEG_RENAME_STALLS", 500 }, - {OP_PII_PIII,0xd5,6,"SEG_REG_RENAMES", 500 }, - {OP_PII_PIII,0xd6,0,"RET_SEG_RENAMES", 500 }, -}; + { CTR_ALL, OP_PII, 0xd4, 6, "SEG_RENAME_STALLS", 500 }, + { CTR_ALL, OP_PII, 0xd5, 6, "SEG_REG_RENAMES", 500 }, + { CTR_ALL, OP_PII, 0xd6, 0, "RET_SEG_RENAMES", 500 }, -uint op_nr_events = sizeof(op_events)/sizeof(struct op_event); + /* Data Cache Unit (DCU) */ + /* PHE FIXME : for athlon check the op_min count */ + /* PHE FIXME: Athlon put the most used entry at begin and update the + * description string, this is needed for the gui to display the most + * common used event first. */ + { CTR_ALL, OP_ATHLON, 0x40, 0, "DATA_CACHE_ACCESSES", 500,}, + { CTR_ALL, OP_ATHLON, 0x41, 0, "DATA_CACHE_MISSES", 500,}, + { CTR_ALL, OP_ATHLON, 0x42, 9, "DATA_CACHE_REFILLS_FROM_L2", 500,}, + { CTR_ALL, OP_ATHLON, 0x43, 9, "DATA_CACHE_REFILLS_FROM_SYSTEM", 500,}, + { CTR_ALL, OP_ATHLON, 0x44, 9, "DATA_CACHE_WRITEBACKS", 500,}, + { CTR_ALL, OP_ATHLON, 0x45, 0, "L1_DTLB_MISSES_L2_DTLD_HITS", 500,}, + { CTR_ALL, OP_ATHLON, 0x46, 0, "L1_AND_L2_DTLB_MISSES", 500,}, + { CTR_ALL, OP_ATHLON, 0x47, 0, "MISALIGNED_DATA_REFS", 500,}, + { CTR_ALL, OP_ATHLON, 0x80, 0, "ICACHE_FETCHES", 500,}, + { CTR_ALL, OP_ATHLON, 0x81, 0, "ICACHE_MISSES", 500,}, + { CTR_ALL, OP_ATHLON, 0x84, 0, "L1_ITLB_MISSES_L2_ITLB_HITS", 500,}, + { CTR_ALL, OP_ATHLON, 0x85, 0, "L1_AND_L2_ITLB_MISSES", 500,}, + { CTR_ALL, OP_ATHLON, 0xc0, 0, "RETIRED_INSNS", 500,}, + { CTR_ALL, OP_ATHLON, 0xc1, 0, "RETIRED_OPS", 500,}, + { CTR_ALL, OP_ATHLON, 0xc2, 0, "RETIRED_BRANCHES", 500,}, + { CTR_ALL, OP_ATHLON, 0xc3, 0, "RETIRED_BRANCHES_MISPREDICTED", 500,}, + { CTR_ALL, OP_ATHLON, 0xc4, 0, "RETIRED_TAKEN_BRANCHES", 500,}, + { CTR_ALL, OP_ATHLON, 0xc5, 0, "RETIRED_TAKEN_BRANCHES_MISPREDICTED", 500,}, + { CTR_ALL, OP_ATHLON, 0xc6, 0, "RETIRED_FAR_CONTROL_TRANSFERS", 500,}, + { CTR_ALL, OP_ATHLON, 0xc7, 0, "RETIRED_RESYNC_BRANCHES", 500,}, + { CTR_ALL, OP_ATHLON, 0xcd, 0, "INTERRUPTS_MASKED", 500,}, + { CTR_ALL, OP_ATHLON, 0xce, 0, "INTERRUPTS_MASKED_PENDING", 500,}, + { CTR_ALL, OP_ATHLON, 0xcf, 0, "HARDWARE_INTERRUPTS", 500,}, +}; -#define OP_EVENTS_OK 0x0 -#define OP_CTR0_NOT_FOUND 0x1 -#define OP_CTR1_NOT_FOUND 0x2 -#define OP_CTR0_NO_UM 0x4 -#define OP_CTR1_NO_UM 0x8 -#define OP_CTR0_NOT_ALLOWED 0x10 -#define OP_CTR1_NOT_ALLOWED 0x20 -#define OP_CTR0_PII_EVENT 0x40 -#define OP_CTR1_PII_EVENT 0x80 -#define OP_CTR0_PIII_EVENT 0x100 -#define OP_CTR1_PIII_EVENT 0x200 -#define OP_CTR0_ATHLON_EVENT 0x400 -#define OP_CTR1_ATHLON_EVENT 0x800 +#define op_nr_events (sizeof(op_events)/sizeof(op_events[0])) /** * op_check_unit_mask - sanity check unit mask value @@ -279,24 +270,32 @@ return -1; } - - /** * op_min_count - get the minimum count value. * @ctr_type: event value + * @cpu_type: + * + * 0 Pentium Pro + * + * 1 Pentium II + * + * 2 Pentium III * + * 3 AMD Athlon + * * The function returns > 0 if the event is found * 0 otherwise */ -int op_min_count(u8 ctr_type) { +int op_min_count(u8 ctr_type, int cpu_type) +{ int ret = 0; - int ctr_e = 0; uint i; + int cpu_mask = 1 << cpu_type; - for (i = 0; i < op_nr_events && !ctr_e; i++) { - if (op_events[i].val == ctr_type) { + for (i = 0; i < op_nr_events; i++) { + if (op_events[i].val == ctr_type && (op_events[i].cpu_mask & cpu_mask)) { ret = op_events[i].min_count; - ctr_e = 1; + break; } } @@ -305,14 +304,13 @@ /** * op_check_events - sanity check event values - * @ctr0_type: event value for counter 0 - * @ctr1_type: event value for counter 1 - * @ctr0_um: unit mask for counter 0 - * @ctr1_um: unit mask for counter 1 - * @proc: processor type + * @ctr: counter number + * @ctr_type: event value for counter 0 + * @ctr_um: unit mask for counter 0 + * @cpu_type: processor type * * Check that the counter event and unit mask values - * are allowed. @proc should be set as follows : + * are allowed. @cpu_type should be set as follows : * * 0 Pentium Pro * @@ -322,116 +320,48 @@ * * 3 AMD Athlon * - * Use 0 values for @ctr0_type and @ctr1_type if the - * counter is not used. + * Don't fail if ctr_type == 0. * - * The function returns 1 if the values are allowed, + * The function returns bitmask of failure cause * 0 otherwise */ -int op_check_events(u8 ctr0_type, u8 ctr1_type, u8 ctr0_um, u8 ctr1_um, int proc) +int op_check_events(int ctr, u8 ctr_type, u8 ctr_um, int cpu_type) { int ret = 0x0; - uint i; - int ctr0_e=0,ctr1_e=0; - - if (ctr0_type) { - for (i=0; i < op_nr_events && !ctr0_e; i++) { - if (op_events[i].val == ctr0_type) { - switch (op_events[i].allowed) { - case OP_1_ONLY: - ret |= OP_CTR0_NOT_ALLOWED; - break; - - case OP_PII_ONLY: - if (proc != 1) - ret |= OP_CTR0_PII_EVENT; - break; - - case OP_PIII_ONLY: - if (proc != 2) - ret |= OP_CTR0_PIII_EVENT; - break; + uint i = 0; + uint cpu_mask = 1 << cpu_type; + uint ctr_mask = 1 << ctr; - case OP_PII_PIII: - if (!proc) - ret |= OP_CTR0_PII_EVENT; - break; + if (ctr_type != 0) { + for ( ; i < op_nr_events; i++) { + if (op_events[i].val == ctr_type && (op_events[i].cpu_mask & cpu_mask)) { + if ((op_events[i].counter_mask & ctr_mask) == 0) + ret |= OP_EVT_CTR_NOT_ALLOWED; - case OP_ATHLON_ONLY: - if (proc != 3) - ret |= OP_CTR0_ATHLON_EVENT; - break; - default: - break; - } if (op_events[i].unit && - op_check_unit_mask(&op_unit_masks[op_events[i].unit], ctr0_um) < 0) - ret |= OP_CTR0_NO_UM; - ctr0_e=1; + op_check_unit_mask(&op_unit_masks[op_events[i].unit], ctr_um) < 0) + ret |= OP_EVT_NO_UM; break; } } } - if (ctr1_type) { - for (i=0; i<op_nr_events && !ctr1_e; i++) { - if (op_events[i].val == ctr1_type) { - switch (op_events[i].allowed) { - case OP_0_ONLY: - ret |= OP_CTR1_NOT_ALLOWED; - break; - - case OP_PII_ONLY: - if (proc != 1) - ret |= OP_CTR1_PII_EVENT; - break; - - case OP_PIII_ONLY: - if (proc != 2) - ret |= OP_CTR1_PIII_EVENT; - break; - - case OP_PII_PIII: - if (!proc) - ret |= OP_CTR1_PII_EVENT; - break; - - case OP_ATHLON_ONLY: - if (proc != 3) - ret |= OP_CTR1_ATHLON_EVENT; - break; - - default: - break; - } - if (op_events[i].unit && - op_check_unit_mask(&op_unit_masks[op_events[i].unit], ctr1_um) < 0) - ret |= OP_CTR1_NO_UM; - ctr1_e=1; - } - } - } - - if (!ctr0_e && ctr0_type) - ret |= OP_CTR0_NOT_FOUND; - if (!ctr1_e && ctr1_type) - ret |= OP_CTR1_NOT_FOUND; + if (i == op_nr_events) + ret |= OP_EVT_NOT_FOUND; return ret; } /** * op_check_events_str - sanity check event strings and unit masks - * @ctr0_type: event name for counter 0 - * @ctr1_type: event name for counter 1 - * @ctr0_um: unit mask for counter 0 - * @ctr1_um: unit mask for counter 1 - * @p2: processor type - * @ctr0_t: event value for counter 0 - * @ctr1_t: event value for counter 1 + * @ctr: ctr number + * @ctr_type: event name for counter + * @ctr_um: unit mask for counter + * @cpu_type: processor type + * @ctr_t: event value for counter * * Check that the counter event and unit mask values - * are allowed. @p2 should be set as follows : + * are allowed. @cpu_type should be set as follows : * * 0 Pentium Pro * @@ -441,54 +371,38 @@ * * 3 AMD Athlon * - * Use "" strings for @ctr0_type and @ctr1_type if the - * counter is not used. + * Use "" strings for @ctr_type if the counter is not used. * - * On successful return, @ctr0_t and @ctr1_t will contain - * the event values for counters 0 and 1 respectively + * On successful return, @ctr_t will contain + * the event values for counters ctr * * The function returns 1 if the values are allowed, * 0 otherwise */ -int op_check_events_str(char *ctr0_type, char *ctr1_type, u8 ctr0_um, u8 ctr1_um, int p2, u8 *ctr0_t, u8 *ctr1_t) +int op_check_events_str(int ctr, char *ctr_type, u8 ctr_um, int cpu_type, u8 *ctr_t) { uint i; - int ctr0_e=0; - int ctr1_e=0; - - if (!ctr0_type) - ctr0_type=""; - - if (!ctr1_type) - ctr1_type=""; + int ctr_found = 0; + uint cpu_mask = 1 << cpu_type; - if (strcmp(ctr0_type,"")) { - for (i=0; i < op_nr_events && !ctr0_e; i++) { - if (!strcmp(ctr0_type, op_events[i].name)) { - ctr0_e = 1; - *ctr0_t = op_events[i].val; - break; - } - } - } + if (!ctr_type) + ctr_type=""; - if (strcmp(ctr1_type,"")) { - for (i=0; i < op_nr_events && !ctr1_e; i++) { - if (!strcmp(ctr1_type, op_events[i].name)) { - ctr1_e = 1; - *ctr1_t = op_events[i].val; + if (strcmp(ctr_type,"")) { + for (i=0; i < op_nr_events; i++) { + if (!strcmp(ctr_type, op_events[i].name) && + (op_events[i].cpu_mask & cpu_mask)) { + *ctr_t = op_events[i].val; + ctr_found = 1; break; } } } - - if (strcmp(ctr0_type,"") && !ctr0_e) - return OP_CTR0_NOT_FOUND; - if (strcmp(ctr1_type,"") && !ctr1_e) - return OP_CTR1_NOT_FOUND; + if (strcmp(ctr_type,"") && !ctr_found) + return OP_EVT_NOT_FOUND; - return op_check_events(*ctr0_t, *ctr1_t, ctr0_um, ctr1_um, p2); + return op_check_events(ctr, *ctr_t, ctr_um, cpu_type); } #ifdef OP_EVENTS_DESC @@ -498,11 +412,11 @@ static struct op_unit_desc op_unit_descs[] = { { { NULL, NULL, NULL, NULL, NULL, NULL, NULL, }, }, - { { "(I)nvalid cache state", - "(S)hared cache state", + { { "(M)odified cache state", "(E)xclusive cache state", - "(M)odified cache state", - "MESI cache state", NULL, NULL, }, }, + "(S)hared cache state", + "(I)nvalid cache state", + "all MESI cache state", NULL, NULL, }, }, { { "self-generated transactions", "any transactions", NULL, NULL, NULL, NULL, NULL, }, }, { { "mandatory", NULL, NULL, NULL, NULL, NULL, NULL, }, }, @@ -528,10 +442,16 @@ "prefetch T2", "weakly ordered stores", NULL, NULL, NULL, }, }, { { "packed and scalar", "packed", NULL, NULL, NULL, NULL, NULL, }, }, - + { { "(M)odified cache state", + "(O)wner cache state", + "(E)xclusive cache state", + "(S)hared cache state", + "(I)nvalid cache state", + "all MOESI cache state", NULL, }, }, }; static char *op_event_descs[] = { + "clocks processor is not halted", /* Data Cache Unit (DCU) */ "all memory references, cachable and non", "total lines allocated in the DCU", @@ -616,7 +536,6 @@ "cycles or events for partial stalls", /* Segment Register Loads */ "number of segment register loads", - "clocks processor is not halted", /* MMX (Pentium II only) */ "number of MMX instructions executed", "number of MMX saturating instructions executed", @@ -629,6 +548,31 @@ "number of segment register renaming stalls", "number of segment register renames", "number of segment register rename events retired", + /* Athlon/Duron */ + /* Cache */ + "Data cache accesses", + "Data cache misses", + "Data cache refills from L2", + "Data cache refills from system", + "Data cache write backs", + "L1 DTLB misses and L2 DTLB hits", + "L1 and L2 DTLB misses", + "Misaligned data references", + "Instruction cache fetches)", + "Instruction cache misses)", + "L1 ITLB misses (and L2 ITLB hits)", + "(L1 and) L2 ITLB misses", + "Retired instructions (includes exceptions, interrupts, resyncs)", + "Retired Ops", + "Retired branches (conditional, unconditional, exceptions, interrupts)", + "Retired branches mispredicted", + "Retired taken branches", + "Retired taken branches mispredicted", + "Retired far control transfers", + "Retired resync branches (only non-control transfer branches counted)", + "Interrupts masked cycles (IF=0)", + "Interrupts masked while pending cycles (INTR while IF=0)", + "Number of taken hardware interrupts", }; /** @@ -658,9 +602,7 @@ if (um_mask_desc_index == -1) return NULL; else if (um_mask_desc_index == 0) { - /* FIXME: Perhaps needs to combine the different string? (this - * needs dynamic alloc and updating the code/comment of callers) - */ + /* avoid dynamic alloc to simplify caller's life */ return "set with multiple units, check the documentation"; } @@ -669,6 +611,7 @@ /** * op_get_event_desc - get event name and description + * @cpu_type: the cpu_type * @type: event value * @um: unit mask * @typenamep: returned event name string @@ -676,7 +619,7 @@ * @umdescp: returned unit mask description string * * Get the associated event name and descriptions given - * the event value and unit mask value. It is a fatal error + * the cpu type, event value and unit mask value. It is a fatal error * to supply a non-valid @type value, but an invalid @um * will not exit. * @@ -685,14 +628,15 @@ * NULL when @um is invalid for the given @type value. * These strings are in text section so should not be freed. */ -void op_get_event_desc(u8 type, u8 um, char **typenamep, char **typedescp, char **umdescp) +void op_get_event_desc(int cpu_type, u8 type, u8 um, char **typenamep, char **typedescp, char **umdescp) { uint i; + int cpu_mask = 1 << cpu_type; *typenamep = *typedescp = *umdescp = NULL; for (i=0; i < op_nr_events; i++) { - if (op_events[i].val == type) { + if (op_events[i].val == type && (op_events[i].cpu_mask & cpu_mask)) { *typenamep = (char *)op_events[i].name; *typedescp = op_event_descs[i]; @@ -713,49 +657,171 @@ #include "version.h" -int main(int argc, char *argv[]) +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 + * + * output an help string for the event @i + */ +static void help_for_event(int i) { - uint i; - uint j; + uint k, j; + uint mask; - if (argc>1) { - if ((!strcmp(argv[1],"--version") || !strcmp(argv[1],"-v"))) { - printf(VERSION_STRING " compiled on " __DATE__ " " __TIME__ "\n"); - exit(0); + printf("%s", op_events[i].name); + + printf(": (counter: "); + if (op_events[i].counter_mask == CTR_ALL) { + printf("all"); + } else { + mask = op_events[i].counter_mask; + for (k = 0; k < CHAR_BIT * sizeof(op_events[i].counter_mask); ++k) { + if (mask & (1 << k)) { + printf("%d", k); + mask &= ~(1 << k); + if (mask) + printf(", "); + } } + } + printf(")"); - /* interpret given string */ + printf(" (supported cpu: "); + mask = op_events[i].cpu_mask; + for (k = 0; k < MAX_CPU_TYPE; ++k) { + if (mask & (1 << k)) { + printf("%s", cpu_type_str[k]); + mask &= ~(1 << k); + if (mask) + printf(", "); + } + } - for (i=0; i < op_nr_events; i++) { - if (!strcmp(op_events[i].name, argv[1])) - printf("%d\n", op_events[i].val); + printf(")\n\t%s (min count: %d)\n", op_event_descs[i], op_events[i].min_count); + + if (op_events[i].unit) { + int unit_idx = op_events[i].unit; + + printf("\tUnit masks\n"); + printf("\t----------\n"); + + for (j=0; j < op_unit_masks[unit_idx].num; j++) { + printf("\t%.2x: %s\n", + op_unit_masks[unit_idx].um[j], + op_unit_descs[unit_idx].desc[j]); } - return 0; } +} - printf("oprofile: available events\n"); - printf("--------------------------\n\n"); - printf("See Intel Architecture Developer's Manual\nVol. 3, Appendix A\n\n"); +/** + * help_event_for_gui - output event name and description + * @i: event number + * + * output an help string for the event @i, in + * a manner adapted for use by the oprofile gui + */ +static void help_event_for_gui(int i) +{ + uint j; - for (i=0; i < op_nr_events; i++) { - printf("%s:", op_events[i].name); - printf("\n\t%s ", op_event_descs[i]); - switch (op_events[i].allowed) { - case 0: printf("- counter 0 only\n"); break; - case 1: printf("- counter 1 only\n"); break; - case 3: printf("- Pentium II/III only\n"); break; - case 4: printf("- Pentium II only\n"); break; - case 5: printf("- Pentium III only\n"); break; - case 6: printf("- AMD Athlon only\n"); break; - default: printf("\n"); break; + printf("{ %s", op_events[i].name); + + printf(" %d %d", op_events[i].cpu_mask, op_events[i].counter_mask); + + printf(" \"%s\" %d", op_event_descs[i], op_events[i].min_count); + + if (op_events[i].unit) { + int unit_idx = op_events[i].unit; + + printf("\n"); + + switch (op_unit_masks[unit_idx].unit_type_mask) { + case utm_mandatory: + printf("\tmandatory "); + break; + case utm_exclusive: + printf("\texclusive "); + break; + case utm_bitmask: + printf("\tbitmask "); + break; } - if (op_events[i].unit) { - printf("\tUnit masks\n"); - printf("\t----------\n"); - for (j=0; j < op_unit_masks[op_events[i].unit].num; j++) { - printf("\t%.2x: %s\n", - op_unit_masks[op_events[i].unit].um[j], - op_unit_descs[op_events[i].unit].desc[j]); + + printf("%d\n", op_unit_masks[unit_idx].default_mask); + printf("\t{\n"); + + for (j=0; j < op_unit_masks[unit_idx].num; j++) { + printf("\t { %d \"%s\" }\n", + op_unit_masks[unit_idx].um[j], + op_unit_descs[unit_idx].desc[j]); + } + + printf("\t}\n"); + } + + printf(" }\n"); +} + +int main(int argc, char *argv[]) +{ + int i; + uint j; + int cpu_type_mask; + int for_gui; + + for_gui = 0; + for (i = 1 ; i < argc ; ++i) { + if (!strcmp(argv[i], "--version")) { + printf(VERSION_STRING " compiled on " __DATE__ " " __TIME__ "\n"); + return 0; + } else if (!strcmp(argv[i], "--help")) { + printf("op_help [--version|--cpu-type] event_name"); + + return 0; + } else if (!strncmp(argv[i], "--cpu-type=", 11)) { + sscanf(argv[i] + 11, "%d", &cpu_type); + if (cpu_type < 0 || cpu_type >= MAX_CPU_TYPE) { + fprintf(stderr, "invalid cpu type %d, default to to %s\n", cpu_type, cpu_type_str[DEFAULT_CPU_TYPE]); + cpu_type = DEFAULT_CPU_TYPE; + } + } else if (!strcmp(argv[1], "--gui-description")) { + for_gui = 1; + } else { + cpu_type_mask = 1 << cpu_type; + for (j=0; j < op_nr_events; j++) { + if (!strcmp(op_events[j].name, argv[i]) && + (op_events[j].cpu_mask & cpu_type_mask)) { + printf("%d\n", op_events[j].val); + } + } + return 0; + } + } + + if (for_gui == 0) { + printf("oprofile: available events\n"); + printf("--------------------------\n\n"); + printf("See Intel Architecture Developer's Manual\nVol. 3, Appendix A\n\n"); + } else { + printf("{ DISABLED -1 -1 \"Select it to disable this counter\" 0 }\n"); + } + + cpu_type_mask = 1 << cpu_type; + for (j=0; j < op_nr_events; j++) { + if ((op_events[j].cpu_mask & cpu_type_mask) != 0) { + if (for_gui) { + help_event_for_gui(j); + } else { + help_for_event(j); } } } Index: op_user.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/op_user.h,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- op_user.h 2001/06/22 03:16:24 1.3 +++ op_user.h 2001/09/01 02:03:34 1.4 @@ -22,6 +22,31 @@ #include "version.h" +/* PHE FIXME: op_config.h, typedef it and prefix by op_ ? */ +#define u8 unsigned char +#define u16 unsigned short +#define u32 unsigned int +#define uint unsigned int +#define ulong unsigned long +#define fd_t int + +/* event check returns */ +#define OP_EVENTS_OK 0x0 +#define OP_EVT_NOT_FOUND 0x1 +#define OP_EVT_NO_UM 0x2 +#define OP_EVT_CTR_NOT_ALLOWED 0x4 + +/* supported cpu type */ +#define CPU_NO_GOOD -1 +#define CPU_PPRO 0 +#define CPU_PII 1 +#define CPU_PIII 2 +#define CPU_ATHLON 3 +#define MAX_CPU_TYPE 4 + +/* default value must be set by configure */ +#define DEFAULT_CPU_TYPE CPU_PII + #ifndef NR_CPUS #define NR_CPUS 32 #endif @@ -34,15 +59,47 @@ /* 65536 * 32 = 2097152 bytes default */ #define OP_DEFAULT_HASH_SIZE 65536 -#define OP_BITS 2 +/* kernel image entries are offset by this many entries */ +#define OPD_KERNEL_OFFSET 524288 + +/* FIXME ATHLON: four next #define can be tuned for full support to Athlon */ +/* PHE: I don't fix the problem "is these should be autoconf and/or runtime + * settings" so hack it at hand for now */ +/* maximum nr. of counters, up to 4 for Athlon (18 for P4). The primary use + * 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 + +/* the number of bits neccessary to store OP_MAX_COUNTERS values */ +#define OP_BITS_CTR 1 + +/* the number of reserved bits in count, + 1 is for the notification bit */ +#define OP_BITS (OP_BITS_CTR + 1) + +/* The number of bits available to store count */ +#define OP_BITS_COUNT (16 - OP_BITS) + +/* counter nr mask */ +#define OP_CTR_MASK ((~0U << OP_BITS_COUNT) >> 1) /* top OP_BITS bits of count are used as follows: */ /* is this actually a notification ? */ -#define OP_NOTE (1U<<15) +#define OP_NOTE (1U << (OP_BITS_COUNT + OP_BITS_CTR)) /* which perf counter the sample is from */ -#define OP_COUNTER (1U<<14) +#define OP_COUNTER(x) (((x) & OP_CTR_MASK) >> OP_BITS_COUNT) -#define OP_COUNT_MASK ((1U << (16 - OP_BITS)) - 1U) +#define OP_COUNT_MASK ((1U << OP_BITS_COUNT) - 1U) /* mapping notification types */ /* fork(),vfork(),clone() */ @@ -103,5 +160,12 @@ /* size of hash map in bytes */ #define OP_HASH_MAP_SIZE (OP_HASH_MAP_NR * sizeof(struct op_hash)) + +/* 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); +/* 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); #endif /* OP_USER_H */ Index: oprofile.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.c,v retrieving revision 1.75 retrieving revision 1.76 diff -u -d -r1.75 -r1.76 --- oprofile.c 2001/08/31 17:16:35 1.75 +++ oprofile.c 2001/09/01 02:03:34 1.76 @@ -39,14 +39,8 @@ pid_t pgrp_filter; /* the MSRs we need */ -static u32 ctrlreg0 = MSR_IA32_EVNTSEL0; -static u32 ctrlreg1 = MSR_IA32_EVNTSEL1; -static u32 ctrlreg2 = MSR_K7_PERFCTL2; -static u32 ctrlreg3 = MSR_K7_PERFCTL3; -static u32 ctrreg0 = MSR_IA32_PERFCTR0; -static u32 ctrreg1 = MSR_IA32_PERFCTR1; -static u32 ctrreg2 = MSR_K7_PERFCTR2; -static u32 ctrreg3 = MSR_K7_PERFCTR3; +static uint perfctr_msr[OP_MAX_COUNTERS]; +static uint eventsel_msr[OP_MAX_COUNTERS]; static u32 prof_on __cacheline_aligned; @@ -80,7 +74,7 @@ { ops->eip = regs->eip; ops->pid = current->pid; - ops->count = OP_COUNTER*ctr + 1; + ops->count = (1U << OP_BITS_COUNT)*ctr + 1; } inline static void op_do_profile(struct _oprof_data *data, struct pt_regs *regs, int ctr) @@ -123,16 +117,16 @@ asmlinkage void op_do_nmi(struct pt_regs *regs) { struct _oprof_data *data = &oprof_data[smp_processor_id()]; + int i; if (pid_filter && current->pid != pid_filter) return; if (pgrp_filter && current->pgrp != pgrp_filter) return; - if (data->ctrs & OP_CTR_0) - op_check_ctr(data, regs, 0); - if (data->ctrs & OP_CTR_1) - op_check_ctr(data, regs, 1); + for (i = 0 ; i < op_nr_counters ; ++i) { + op_check_ctr(data, regs, i); + } } /* ---------------- NMI handler setup ------------ */ @@ -202,7 +196,7 @@ /* PHE I think when the doc says : -if you disable the apic the bits * of LVT cannot be reset- it talk about the SW disable through bit 8 * of SPIV see 7.4.14 (7.5.14) not the hardware disable, so it is ok - * but I perhaps we need a software disable of the APIC at the end + * but perhaps we need a software disable of the APIC at the end */ /* first disable via MSR */ /* IA32 V3, 7.4.2 */ @@ -296,12 +290,6 @@ printk(KERN_INFO "oprofile: setting up APIC.\n"); /* ugly hack */ - /* PHE : the memory must be uncachable! this is perhaps more a - * problem for Athlon than for PII. - * Also this stuff probably mishandled SMP ? - * The _PAGE_GLOBAL attribute should be probably avoided but make - * this later - */ my_set_fixmap(); /* FIXME: NMI delivery for SMP ? */ @@ -419,80 +407,150 @@ static void pmc_setup(void *dummy) { uint low, high; + int i; // first, let's use the right MSRs switch (cpu_type) { case CPU_ATHLON: - ctrlreg0 = MSR_K7_PERFCTL0; - ctrlreg1 = MSR_K7_PERFCTL1; - ctrreg0 = MSR_K7_PERFCTR0; - ctrreg1 = MSR_K7_PERFCTR1; + 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:; + default: + eventsel_msr[0] = MSR_IA32_EVNTSEL0; + eventsel_msr[1] = MSR_IA32_EVNTSEL1; + perfctr_msr[0] = MSR_IA32_PERFCTR0; + perfctr_msr[1] = MSR_IA32_PERFCTR1; + break; } - - rdmsr(ctrlreg0, low, high); - // FIXME: enable bit is per-counter on athlon - wrmsr(ctrlreg0, low & ~(1<<22), high); + /* FIXME ATHLON: use #if 0 to get the old code, which would work on + * athlon. The new code would work but I had get a painfull debug so + * I prefer to keep the old code until Athlon tests are available. */ +#if 1 /* IA Vol. 3 Figure 15-3 */ - rdmsr(ctrlreg0, low, high); + /* Stop and clear all counter: IA32 use bit 22 of eventsel_msr0 to + * enable/disable all counter, AMD use separate bit 22 in each msr, + * all other 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 & ~(3 << 22), high); + } + + /* setup each counter */ + for (i = 0 ; i < op_nr_counters ; ++i) { + if (op_ctr_val[i]) { + rdmsr(eventsel_msr[i], low, high); + + low &= 1 << 21; /* do not touch the reserved bit */ + set_perfctr(op_ctr_count[i], i); + + pmc_fill_in(&low, op_ctr_kernel[i], op_ctr_user[i], + op_ctr_val[i], op_ctr_um[i]); + + wrmsr(eventsel_msr[i], low, high); + } + } + + /* Here all setup is made except the start/stop bit 21), counter + * disabled contains zeros in the eventsel msr except the reserved bit + * 21 */ +#else + rdmsr(eventsel_msr[0], low, high); + // FIXME: enable bit is per-counter on athlon + wrmsr(eventsel_msr[0], low & ~(1<<22), high); /* clear */ low &= (1<<21); + /* IA Vol. 3 Figure 15-3 */ + if (op_ctr_val[0]) { set_perfctr(op_ctr_count[0], 0); pmc_fill_in(&low, op_ctr_kernel[0], op_ctr_user[0], op_ctr_val[0], op_ctr_um[0]); } - wrmsr(ctrlreg0, low, 0); + wrmsr(eventsel_msr[0], low, 0); - rdmsr(ctrlreg1, low, high); + rdmsr(eventsel_msr[1], low, high); /* clear */ low &= (3<<21); if (op_ctr_val[1]) { set_perfctr(op_ctr_count[1], 1); pmc_fill_in(&low, op_ctr_kernel[1], op_ctr_user[1], op_ctr_val[1], op_ctr_um[1]); - wrmsr(ctrlreg1, low, high); + + wrmsr(eventsel_msr[1], low, high); } +#endif /* disable ctr1 if the UP oopser might be on, but we can't do anything * interesting with the NMIs */ - /* PHE FIXME Have always a meaning ? */ + /* PHE FIXME ATHLON bugged if running 3/4 counters ?, I really don't + * understand when and why this is executed */ /* this is pretty bogus really. especially as we don't re-enable it. * Instead, save state set up, and restore with pmc_unsetup or similar */ #if !defined(CONFIG_X86_UP_APIC) || !defined(OP_EXPORTED_DO_NMI) - wrmsr(ctrlreg1, low, high); + wrmsr(eventsel_msr[1], low, high); #endif } static void pmc_start(void *info) { uint low,high; + int i; if (info && (*((uint *)info) != smp_processor_id())) return; - /* enable counters */ - rdmsr(ctrlreg0, low, high); - // FIXME: bit 22 per-counter on athlon - wrmsr(ctrlreg0, low | (1<<22), high); + /* assert: all enable counter are setup except the bit start/stop, + * all counter disable contains zeroes (except perhaps the reserved + * bit 21) */ + + /* 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); + } + } + } } static void pmc_stop(void *info) { uint low,high; + int i; if (info && (*((uint *)info) != smp_processor_id())) return; /* disable counters */ - rdmsr(ctrlreg0, low, high); - // FIXME: bit 22 per-counter on athlon - wrmsr(ctrlreg0, low & ~(1<<22), high); + 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); + } + } + } } inline static void pmc_select_start(uint cpu) @@ -784,6 +842,11 @@ 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); @@ -807,61 +870,71 @@ int ret; int i; uint cpu; + int ok; struct _oprof_data *data; + int enabled; 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"); - /* FIXME: hardcoded 2 counters */ - for (i = 0; i < 2; i++) { + 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]); + int min_count = op_min_count(op_ctr_val[i], cpu_type); if (!op_ctr_user[i] && !op_ctr_kernel[i]) { printk(KERN_ERR "oprofile: neither kernel nor user set for counter %d\n", i); return 0; } op_check_range(op_ctr_count[i], min_count, OP_MAX_PERF_COUNT, "ctr count value %d not in range (%d %ld)\n"); + + enabled = 1; } } - /* FIXME: below needs generalising for multiple counters */ - - if (!op_ctr_on[0] && !op_ctr_on[1]) { + if (!enabled) { printk(KERN_ERR "oprofile: neither counter enabled.\n"); return 0; } /* hw_ok() has set cpu_type */ - ret = op_check_events(op_ctr_val[0], op_ctr_val[1], op_ctr_um[0], op_ctr_um[1], cpu_type); + ok = 1; + for (i = 0 ; i < op_nr_counters ; ++i) { + ret = op_check_events(i, op_ctr_val[i], op_ctr_um[i], cpu_type); - if (ret & OP_CTR0_NOT_FOUND) printk(KERN_ERR "oprofile: ctr0: no such event\n"); - if (ret & OP_CTR1_NOT_FOUND) printk(KERN_ERR "oprofile: ctr1: no such event\n"); - if (ret & OP_CTR0_NO_UM) printk(KERN_ERR "oprofile: ctr0: invalid unit mask\n"); - if (ret & OP_CTR1_NO_UM) printk(KERN_ERR "oprofile: ctr1: invalid unit mask\n"); - if (ret & OP_CTR0_NOT_ALLOWED) printk(KERN_ERR "oprofile: ctr0 can't count this event\n"); - if (ret & OP_CTR1_NOT_ALLOWED) printk(KERN_ERR "oprofile: ctr1 can't count this event\n"); - if (ret & OP_CTR0_PII_EVENT) printk(KERN_ERR "oprofile: ctr0: event only available on PII\n"); - if (ret & OP_CTR1_PII_EVENT) printk(KERN_ERR "oprofile: ctr1: event only available on PII\n"); - if (ret & OP_CTR0_PIII_EVENT) printk(KERN_ERR "oprofile: ctr0: event only available on PIII\n"); - if (ret & OP_CTR1_PIII_EVENT) printk(KERN_ERR "oprofile: ctr1: event only available on PIII\n"); - if (ret & OP_CTR0_ATHLON_EVENT) printk(KERN_ERR "oprofile: ctr1: event only available on Athlon\n"); - if (ret & OP_CTR1_ATHLON_EVENT) printk(KERN_ERR "oprofile: ctr1: event only available on Athlon\n"); + if (ret & OP_EVT_NOT_FOUND) + printk(KERN_ERR "oprofile: ctr%d: %d: no such event for cpu %d\n", + i, op_ctr_val[i], cpu_type); - if (ret) + if (ret & OP_EVT_NO_UM) + printk(KERN_ERR "oprofile: ctr%d: 0x%.2x: invalid unit mask for cpu %d\n", + i, op_ctr_um[i], cpu_type); + + if (ret & OP_EVT_CTR_NOT_ALLOWED) + printk(KERN_ERR "oprofile: ctr%d: %d: can't count event for this counter\n", + i, op_ctr_val[i]); + + if (ret != OP_EVENTS_OK) + ok = 0; + } + + if (!ok) return 0; for (cpu=0; cpu < smp_num_cpus; cpu++) { data = &oprof_data[cpu]; - data->ctrs |= OP_CTR_0 * (!!op_ctr_on[0]); - data->ctrs |= OP_CTR_1 * (!!op_ctr_on[1]); /* make sure the buffer and hash table have been set up */ if (!data->buffer || !data->entries) return 0; - data->ctr_count[0] = op_ctr_count[0]; - data->ctr_count[1] = op_ctr_count[1]; + for (i = 0 ; i < op_nr_counters ; ++i) { + if (op_ctr_on[i]) { + data->ctr_count[i] = op_ctr_count[i]; + } else { + data->ctr_count[i] = 0; + } + } } return 1; @@ -1055,7 +1128,7 @@ return err; } -static int nr_oprof_static = 6; +static int nr_oprof_static = 7; static ctl_table oprof_table[] = { { 1, "bufsize", &op_buf_size, sizeof(int), 0600, NULL, &lproc_dointvec, NULL, }, @@ -1064,6 +1137,7 @@ { 1, "kernel_only", &kernel_only, sizeof(int), 0600, NULL, &lproc_dointvec, NULL, }, { 1, "pid_filter", &pid_filter, sizeof(pid_t), 0600, NULL, &lproc_dointvec, NULL, }, { 1, "pgrp_filter", &pgrp_filter, sizeof(pid_t), 0600, NULL, &lproc_dointvec, NULL, }, + { 1, "cpu_type", &cpu_type, sizeof(int), 0400, NULL, &lproc_dointvec, NULL, }, { 0, }, { 0, }, { 0, }, { 0, }, { 0, }, }; @@ -1088,14 +1162,13 @@ static int __init init_sysctl(void) { ctl_table *next = &oprof_table[nr_oprof_static]; - ctl_table *counter_table[OP_MAX_COUNTERS + 1]; + ctl_table *counter_table[op_nr_counters + 1]; ctl_table *tab; int i,j; /* FIXME: no proper numbers, or verifiers (where possible) */ - /* for each counter - FIXME: hardcoded to 2 counters currently */ - for (i=0; i < 2; i++) { + for (i=0; i < op_nr_counters; i++) { next->ctl_name = 1; next->procname = names[i]; next->mode = 0700; Index: oprofile.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.h,v retrieving revision 1.47 retrieving revision 1.48 diff -u -d -r1.47 -r1.48 --- oprofile.h 2001/08/31 17:16:35 1.47 +++ oprofile.h 2001/09/01 02:03:34 1.48 @@ -47,21 +47,11 @@ struct op_sample *buffer; /* eviction buffer */ uint hash_size; /* nr. in hash table */ uint buf_size; /* nr. in buffer */ - uint ctr_count[2]; /* reset counter values */ uint nextbuf; /* next in buffer (atomic) */ - u16 next; /* next sample in entry */ - u16 ctrs; /* which counters are set */ + uint next; /* next sample in entry */ + uint ctr_count[OP_MAX_COUNTERS]; /* reset counter values */ } __attribute__((__aligned__(SMP_CACHE_BYTES))); -#define OP_CTR_0 0x1 -#define OP_CTR_1 0x2 - -#define CPU_NO_GOOD -1 -#define CPU_PPRO 0 -#define CPU_PII 1 -#define CPU_PIII 2 -#define CPU_ATHLON 3 - /* MSRs */ #ifndef MSR_IA32_PERFCTR0 #define MSR_IA32_PERFCTR0 0xc1 @@ -109,9 +99,6 @@ #define streqn(a, b, len) (!strncmp((a), (b), (len))) -/* maximum nr. of counters, up to 4 for Athlon (18 for P4) */ -#define OP_MAX_COUNTERS 4 - /* oprof_data->ready will be set this many samples * before the end of the eviction buffer. * The purpose of this is to avoid overflowing the sample @@ -146,25 +133,11 @@ ((((((eip&0xff000)>>3) ^ eip) ^ (pid&0xff)) ^ (eip<<9)) \ ^ (ctr<<8)) & (data->hash_size - 1) -/* relying on MSR numbers being neighbours */ -#define get_perfctr(l,h,c) do { rdmsr(ctrreg0 + c, (l), (h)); } while (0) -#define set_perfctr(l,c) do { wrmsr(ctrreg0 + c, -(u32)(l), -1); } while (0) +/* do not rely on MSR numbers being neighbours */ +#define get_perfctr(l,h,c) do { rdmsr(perfctr_msr[(c)], (l), (h)); } while (0) +#define set_perfctr(l,c) do { wrmsr(perfctr_msr[(c)], -(u32)(l), -1); } while (0) #define ctr_overflowed(n) (!((n) & (1U<<31))) -#define OP_EVENTS_OK 0x0 -#define OP_CTR0_NOT_FOUND 0x1 -#define OP_CTR1_NOT_FOUND 0x2 -#define OP_CTR0_NO_UM 0x4 -#define OP_CTR1_NO_UM 0x8 -#define OP_CTR0_NOT_ALLOWED 0x10 -#define OP_CTR1_NOT_ALLOWED 0x20 -#define OP_CTR0_PII_EVENT 0x40 -#define OP_CTR1_PII_EVENT 0x80 -#define OP_CTR0_PIII_EVENT 0x100 -#define OP_CTR1_PIII_EVENT 0x200 -#define OP_CTR0_ATHLON_EVENT 0x400 -#define OP_CTR1_ATHLON_EVENT 0x800 - #define op_check_range(val,l,h,str) do { \ if ((val) < (l) || (val) > (h)) { \ printk(str, (val), (l), (h)); \ @@ -218,22 +191,14 @@ #include <linux/completion.h> #endif -// FIXME: these names are too easy to mis-type ! -extern uint ctrlreg0; -extern uint ctrlreg1; -extern uint ctrlreg2; -extern uint ctrlreg3; -extern uint ctrreg0; -extern uint ctrreg1; -extern uint ctrreg2; -extern uint ctrreg3; +/* These arrays are filled by hw_ok() */ +extern uint perfctr_msr[OP_MAX_COUNTERS]; +extern uint eventsel_msr[OP_MAX_COUNTERS]; int oprof_init(void); int find_intel_smp(void); void oprof_exit(void); void my_set_fixmap(void); -int op_min_count(u8 ctr_type); -int op_check_events(u8 ctr0_type, u8 ctr1_type, u8 ctr0_um, u8 ctr1_um, int proc); void op_intercept_syscalls(void); void op_replace_syscalls(void); void op_save_syscalls(void); |
Update of /cvsroot/oprofile/oprofile/pp In directory usw-pr-cvs1:/tmp/cvs-serv19169/pp Modified Files: Makefile.in op_to_source opf_container.cpp opf_filter.cpp opf_filter.h oprof_convert.c oprofpp.c oprofpp.h Log Message: philippe's huge patch Index: Makefile.in =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/Makefile.in,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- Makefile.in 2001/08/18 16:11:17 1.14 +++ Makefile.in 2001/09/01 02:03:34 1.15 @@ -15,19 +15,19 @@ install: $(INSTALL_LIST) -$(MKDIR_P) $(BINDIR) - @for f in $(INSTALL_LIST); do \ + for f in $(INSTALL_LIST); do \ cp $$f $(BINDIR)/$$f && chmod 755 $(BINDIR)/$$f; \ done uninstall: - @for f in $(INSTALL_LIST); do \ - rm -f $(BINDIR)/$$f; \ + for f in $(INSTALL_LIST); do \ + -rm -f $(BINDIR)/$$f; \ done CFLAGS=-Wall -Wstrict-prototypes -W -pipe -DOP_EVENTS_DESC -L/usr/lib @CFLAGS@ LIBS=-lpopt -lbfd -liberty -ldl INCLUDES=@extra_includes@ -HEADERS=oprofpp.h ../dae/opd_util.h +HEADERS=oprofpp.h ../dae/opd_util.h ../op_user.h MY_SOURCES=oprofpp.c SOURCES=$(MY_SOURCES) ../dae/opd_util.c ../op_events.c @@ -40,17 +40,17 @@ $(CC) $(CFLAGS) $(INCLUDES) -o $@ $(SOURCES) $(LIBS) oprof_convert: oprof_convert.c ../dae/opd_util.c ../dae/opd_util.h - $(CC) oprof_convert.c ../dae/opd_util.c -Wall -o $@ + $(CC) -Wall oprof_convert.c ../dae/opd_util.c -o $@ #CXX_DEBUG_LIBS = -L/usr/src/STLport-4.0/lib -lm -lstlport_gcc_stldebug #CXXFLAGS_DEBUG_STL = -D__STL_DEBUG -I/usr/src/STLport-4.0/stlport -Wno-long-long OPF_CXXFLAGS=-Wall -pedantic -O2 -g $(CXXFLAGS_DEBUG_STL) -opf_container.o: opf_container.cpp opf_filter.h +opf_container.o: opf_container.cpp opf_filter.h ../op_user.h g++ -c $(OPF_CXXFLAGS) $< -o $@ -opf_filter.o : opf_filter.cpp opf_filter.h +opf_filter.o : opf_filter.cpp opf_filter.h ../op_user.h g++ -c $(OPF_CXXFLAGS) $< -o $@ opf_filter: opf_filter.o opf_container.o Index: op_to_source =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/op_to_source,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- op_to_source 2001/07/25 16:43:30 1.4 +++ op_to_source 2001/09/01 02:03:34 1.5 @@ -59,7 +59,6 @@ echo "see $0 --help" exit 1 fi - oprofpp_option="$oprofpp_option -f $1" sample_file=$1 ;; -i|--image-file) @@ -69,7 +68,6 @@ echo "see $0 --help" exit 1 fi - oprofpp_option="$oprofpp_option -i $1" object_file=$1 ;; -h|--help) @@ -103,6 +101,9 @@ shift done +# PHE FIXME : this checking need to be remade with the new samples files naming +# scheme + # Check than enough option has been given. if [ "$object_file" == "" -a "$sample_file" == "" ]; then echo "You need to give at least an object-file or a sample-file" @@ -115,9 +116,19 @@ exit 1 fi -if [ "$sample_file" != "" -a ! -f "$sample_file" ]; then - echo "sample file $sample_file does not exist" - exit 1 +# PHE FIXME: bogus here is case of passing sample_filename without the #x +# prefix. Should be rewrite perhaps. +#if [ "$sample_file" != "" -a ! -f "$sample_file" ]; then +# echo "sample file $sample_file does not exist" +# exit 1 +#fi + +if [ "$sample_file" != "" ]; then + oprofpp_option="$oprofpp_option -f $sample_file" +fi + +if [ "$object_file" != "" ]; then + oprofpp_option="$oprofpp_option -i $object_file" fi #echo "option : $op_filter_option" Index: opf_container.cpp =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/opf_container.cpp,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- opf_container.cpp 2001/07/22 13:51:06 1.3 +++ opf_container.cpp 2001/09/01 02:03:34 1.4 @@ -41,7 +41,7 @@ // Functors used as predicate for less than comparison of counter_array_t. There is no // multi-sort choice, ie the the counter number used is statically set at ctr time. struct less_sample_entry_by_samples_nr { - // Precondition: index < max_counter_number. Used also as default ctr. + // Precondition: index < op_nr_counters. Used also as default ctr. less_sample_entry_by_samples_nr(size_t index_ = 0) : index(index_) {} bool operator()(const sample_entry * lhs, const sample_entry * rhs) const { @@ -120,7 +120,7 @@ // the nth first symbols. // the nth first symbols that accumulate a certain amount of samples. std::multiset<const symbol_entry *, less_sample_entry_by_samples_nr> - symbol_entry_by_samples_nr[max_counter_number]; + symbol_entry_by_samples_nr[OP_MAX_COUNTERS]; std::set<const symbol_entry *, less_by_file_loc> symbol_entry_by_file_loc; }; @@ -128,7 +128,7 @@ symbol_container_impl::symbol_container_impl() { // symbol_entry_by_samples_nr has been setup by the default ctr, we need to // rebuild it. do not assume than index 0 is correctly build - for (size_t i = 0 ; i < max_counter_number ; ++i) { + for (size_t i = 0 ; i < op_nr_counters ; ++i) { less_sample_entry_by_samples_nr compare(i); symbol_entry_by_samples_nr[i] = multiset<const symbol_entry *, less_sample_entry_by_samples_nr>(compare); @@ -172,7 +172,7 @@ // Update the sets of symbols entries sorted by samples count and the set of // symbol entries sorted by file location. for (size_t i = 0 ; i < v.size() ; ++i) { - for (size_t counter = 0 ; counter < max_counter_number ; ++counter) + for (size_t counter = 0 ; counter < op_nr_counters ; ++counter) symbol_entry_by_samples_nr[counter].insert(&v[i]); symbol_entry_by_file_loc.insert(&v[i]); @@ -204,7 +204,7 @@ // get a vector of symbols sorted by increased count. void symbol_container_impl::get_symbols_by_count(size_t counter, vector<const symbol_entry*>& v) const { - if (counter >= max_counter_number) { + if (counter >= op_nr_counters) { throw "symbol_container_impl::get_symbols_by_count() : invalid counter number"; } @@ -321,7 +321,7 @@ counter += (*it1)->counter; } - for (size_t i = 0 ; i < max_counter_number ; ++i) + for (size_t i = 0 ; i < op_nr_counters ; ++i) if (counter[i] != 0) return true; Index: opf_filter.cpp =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/opf_filter.cpp,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- opf_filter.cpp 2001/07/22 13:51:06 1.3 +++ opf_filter.cpp 2001/09/01 02:03:34 1.4 @@ -155,7 +155,7 @@ // oprofpp give some info on the setting of the counters. These // are stored here. - counter_setup counter_info[max_counter_number]; + counter_setup counter_info[OP_MAX_COUNTERS]; // TODO : begin_comment, end_comment must be based on the current // extension and must be properties of source_file. @@ -223,13 +223,13 @@ counter_array_t::counter_array_t() { - for (size_t i = 0 ; i < max_counter_number ; ++i) + for (size_t i = 0 ; i < op_nr_counters ; ++i) value[i] = 0; } counter_array_t & counter_array_t::operator+=(const counter_array_t & rhs) { - for (size_t i = 0 ; i < max_counter_number ; ++i) + for (size_t i = 0 ; i < op_nr_counters ; ++i) value[i] += rhs.value[i]; return *this; @@ -243,7 +243,7 @@ out << hex << vma << dec << " "; - for (size_t i = 0 ; i < max_counter_number ; ++i) + for (size_t i = 0 ; i < op_nr_counters ; ++i) out << counter[i] << " "; } @@ -265,7 +265,7 @@ sscanf(str.c_str() + pos, "%lx%n", &vma, &number_of_char_read); - for (size_t i = 0 ; i < max_counter_number ; ++i) { + for (size_t i = 0 ; i < op_nr_counters ; ++i) { int temp; sscanf(str.c_str() + pos + number_of_char_read, "%u%n", &counter[i], &temp); @@ -352,7 +352,7 @@ out << "total samples :"; - for (size_t i = 0 ; i < max_counter_number ; ++i) + for (size_t i = 0 ; i < op_nr_counters ; ++i) cout << " " << counter_info[i].total_samples; cout << endl; @@ -382,7 +382,7 @@ if (pos == 0) { size_t counter_number; if (sscanf(str.c_str(), "Counter %u", &counter_number) == 1 && - counter_number < max_counter_number) { + counter_number < op_nr_counters) { counter_info[counter_number].enabled = true; size_t pos = str.find("counted "); @@ -439,11 +439,11 @@ bool output::calc_total_samples() { - for (size_t i = 0 ; i < max_counter_number ; ++i) + for (size_t i = 0 ; i < op_nr_counters ; ++i) counter_info[i].total_samples = 0; for (size_t i = 0 ; i < symbols.size() ; ++i) { - for (size_t j = 0 ; j < max_counter_number ; ++j) + for (size_t j = 0 ; j < op_nr_counters ; ++j) counter_info[j].total_samples += symbols[i].sample.counter[j]; } @@ -454,18 +454,19 @@ total_counter += samples[i].counter; } - for (size_t i = 0 ; i < max_counter_number ; ++i) { + for (size_t i = 0 ; i < op_nr_counters ; ++i) { if (total_counter[i] != counter_info[i].total_samples) { cerr << "output::calc_total_samples() : " << "bad counter accumulation" << " " << total_counter[i] - << " " << counter_info[i].total_samples; + << " " << counter_info[i].total_samples + << endl; exit(1); } } } - for (size_t i = 0 ; i < max_counter_number ; ++i) + for (size_t i = 0 ; i < op_nr_counters ; ++i) if (counter_info[i].total_samples != 0) return true; @@ -491,7 +492,7 @@ if (prefix.length()) out << " " << prefix; - for (size_t i = 0 ; i < max_counter_number ; ++i) + for (size_t i = 0 ; i < op_nr_counters ; ++i) if (counter_info[i].enabled) output_one_counter(counter[i], counter_info[i].total_samples); @@ -754,18 +755,18 @@ size_t output::get_sort_counter_nr() const { size_t index = sort_by_counter; - if (index >= max_counter_number || counter_info[index].enabled == false) { - cerr << "sort_by_counter invalid or counter[sort_by_counter] disabled : switch " - << "to the first valid counter" << endl; - - for (index = 0 ; index < max_counter_number ; ++index) { + if (index >= size_t(op_nr_counters) || counter_info[index].enabled == false) { + for (index = 0 ; index < op_nr_counters ; ++index) { if (counter_info[index].enabled) break; } + + cerr << "sort_by_counter invalid or counter[sort_by_counter] disabled : switch " + << "to the first valid counter " << index << endl; } // paranoid checking. - if (index == max_counter_number) + if (index == op_nr_counters) throw "output::output_source(input &) cannot find a counter enabled"; return index; @@ -925,7 +926,7 @@ } bool have_counter_info = false; - for (size_t i = 0 ; i < max_counter_number && !have_counter_info ; ++i) { + for (size_t i = 0 ; i < op_nr_counters && !have_counter_info ; ++i) { if (counter_info[i].enabled) have_counter_info = true; } @@ -938,6 +939,8 @@ read_input(in); +// debug_dump_vector(out); + if (calc_total_samples() == false) { cerr << "The input contains zero samples" << endl; @@ -948,7 +951,7 @@ output_command_line(); - for (size_t i = 0 ; i < max_counter_number ; ++i) { + for (size_t i = 0 ; i < op_nr_counters ; ++i) { if (i != 0) out << endl; @@ -1002,7 +1005,6 @@ poptContext optcon; char c; - // The cast to (char **) is neccessary on some version of popt. optcon = poptGetContext(NULL, argc, argv, options, 0); c=poptGetNextOpt(optcon); Index: opf_filter.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/opf_filter.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -d -r1.4 -r1.5 --- opf_filter.h 2001/07/22 13:51:06 1.4 +++ opf_filter.h 2001/09/01 02:03:34 1.5 @@ -5,8 +5,7 @@ #include <iostream> #include <string> -// The maximum number of counter. Would be a parameter coming from configure. -static const size_t max_counter_number = 2; +#include "../op_user.h" // Add run-time checking if true. static const bool sanity_check = true; @@ -30,7 +29,7 @@ counter_array_t & operator+=(const counter_array_t &); private: - size_t value[max_counter_number]; + size_t value[OP_MAX_COUNTERS]; }; //--------------------------------------------------------------------------- Index: oprof_convert.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/oprof_convert.c,v retrieving revision 1.8 retrieving revision 1.9 diff -u -d -r1.8 -r1.9 --- oprof_convert.c 2001/08/20 19:49:54 1.8 +++ oprof_convert.c 2001/09/01 02:03:34 1.9 @@ -14,19 +14,25 @@ * Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* Do not touch this file, the v5 samples files format make it easier to + * convert but the method used here is not adapated. This utilities can convert + * from version 2,3,4 to 5 newer version should use a new stuff */ + #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/mman.h> #include "../version.h" #include "../dae/opd_util.h" static char * filename; -#define OPD_MANGLE_CHAR '}' - -#define OPD_MAGIC 0xdeb6 +/* magic number <= v4 */ +#define OPD_MAGIC_V4 0xdeb6 +#define OPD_MAGIC_V5 "DAE\n" + /* at the end of the sample files */ struct opd_footer_v2 { u16 magic; @@ -60,6 +66,23 @@ u32 reserved[31]; }; +/* At the begin of samples files */ +struct opd_footer_v5 { + u8 magic[4]; + u32 version; + u8 is_kernel; + u32 ctr_event; + u32 ctr_um; + /* ctr number, used for sanity checking */ + u32 ctr; + u32 cpu_type; + u32 ctr_count; + double cpu_speed; + time_t mtime; + /* binary compatibility reserve */ + u32 reserved2[21]; +}; + /* * Precondition : fp is seeked on the begin of an opd_footer_vn, it is always ok to * read an opd_footer_v2 at the begin of function but the version number field is not @@ -92,6 +115,15 @@ fwrite(&footer_v3, sizeof(footer_v3), 1, fp); } +/* this function is used only between conversion from v3 to v4, (ChangeLog + * 2001-07-25), but backup of samples file has been added at 2001-07-15 (no + * release between this two date). This means than cvs between this can have + * backup and this files are mishandled by this function du the "-%d" suffix + * It is a don't take care case. + * + * Symptom is mtime checking loss (mtime is set to 0), people who have + * this problem have tried to use a cvs alpha version as a production tool + * let's fix themself the problem */ static char * get_binary_name(void) { char *file; @@ -149,72 +181,234 @@ fwrite(&footer_v4, sizeof(footer_v4), 1, fp); } -/* provide a default conversion function which just increase the version number, It may - * be used when a reserved field is used without changing the total sizeof of opd_footer - * *and* the zero value in the reserve work correctly with your new code */ -/* Not used for now so no static to avoid warning. This code has not been tested */ -/*static*/ void bump_version(FILE* fp) +/* the "old" samples file format */ +struct old_opd_fentry { + u32 count0; + u32 count1; +}; + +static int cpu_type = -1; + +/* PHE FIXME: really a fucking function, if you have problem with it flame + * me at <ph...@cl...> */ +/* create one row file during translate from colum to row format v4 --> v5 */ +static void do_mapping_transfer(uint nr_samples, int counter, + const char* filename, + const struct opd_footer_v4* footer_v4, + const struct old_opd_fentry* old_samples, + int session_number) { - struct opd_footer_v2 footer_v2; + char* out_filename; + int out_fd; + struct opd_footer_v5* footer; + u32* samples; + uint k; + u32 size; + int dirty; - fread(&footer_v2, sizeof(footer_v2), 1, fp); + if (cpu_type == -1 || cpu_type < 0 || cpu_type > 3) { + fprintf(stderr, "converting %s to new file format require option --cpu-type=[0|1|2|3]\n", filename); + return; + } - footer_v2.version++; + out_filename = opd_malloc(strlen(filename) + 32); + strcpy(out_filename, filename); + sprintf(out_filename + strlen(out_filename), "#%d", counter); - fseek(fp, -sizeof(footer_v2), SEEK_CUR); + size = (nr_samples * sizeof(u32)) + sizeof(struct opd_footer_v5); - fwrite(&footer_v2, sizeof(footer_v2), 1, fp); -} + /* New samples files are lazilly created, respect this behavior + * by not creating file with no valid ctr_type_val */ + dirty = 0; -static struct converter converter_array[] = { - { v2_to_v3, sizeof(struct opd_footer_v2), 2 }, - { v3_to_v4, sizeof(struct opd_footer_v3), 3 }, -}; + if ((counter == 0 && footer_v4->v2.ctr0_type_val) || + (counter == 1 && footer_v4->v2.ctr1_type_val)) { + if (session_number != -1) + sprintf(out_filename + strlen(filename), "-%d", + session_number); -/* This acts as a samples of how to add new conversion from version N to M : + unlink(out_filename); - define a : + out_fd = open(out_filename, O_CREAT|O_RDWR, 0644); + if (out_fd == -1) { + fprintf(stderr,"oprofiled: open of image sample file \"%s\" failed: %s\n", out_filename, strerror(errno)); + goto err1; + } -struct opd_footer_vM - { - struct opd_footer_v2 v2; - // additionnal field + /* PHE FIXME: same issue in opd_proc.c with more comments */ +#if 0 + /* ugly: mmap needs than fd size is sufficient. */ + if (lseek(out_fd, size - 1, SEEK_SET) == -1) { + fprintf(stderr, "oprofiled: seek failed for \"%s\". %s\n", out_filename, strerror(errno)); + goto err2; + } - }; + /* PHE FIXME: this unsparse the file by one memory page + * size at the end file :( An another way to grow a file ? */ + if (write(out_fd, "", 1) != 1) { + perror("oprof_convert: cannot grow sample file. "); + goto err2; + } +#else + if (ftruncate(out_fd, size) == -1) { + fprintf(stderr, "oprof_convert: ftruncate failed for \"%s\". %s\n", out_filename, strerror(errno)); + goto err2; + } +#endif - define a function : -void vN_to_vM(FILE* fp) { - // get inspiration from v2_to_v3 code ... + footer = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, out_fd, 0); + + if (footer == (void *)-1) { + fprintf(stderr,"oprof_convert: mmap of output sample file \"%s\" failed: %s\n", out_filename, strerror(errno)); + goto err2; + } + + samples = (void *)(footer + 1); + + memset(footer, '\0', sizeof(struct opd_footer_v5)); + memcpy(footer->magic, OPD_MAGIC_V5, sizeof(footer->magic)); + footer->version = 5; + footer->is_kernel = footer_v4->v2.is_kernel; + footer->ctr_event = (counter == 0) + ? footer_v4->v2.ctr0_type_val + : footer_v4->v2.ctr1_type_val; + + footer->ctr_um = (counter == 0) + ? footer_v4->v2.ctr0_um + : footer_v4->v2.ctr1_um; + + footer->ctr_count = (counter == 0) + ? footer_v4->ctr0_count + : footer_v4->ctr1_count; + + footer->ctr = counter; + + footer->cpu_type = cpu_type; + footer->cpu_speed = footer_v4->cpu_speed; + footer->mtime = footer_v4->mtime; + + for (k = 0 ; k < nr_samples ; ++k) { + u32 sample = counter + ? old_samples[k].count1 + : old_samples[k].count0; + + /* keep the sparse of the file */ + if (sample) { + samples[k] = sample; + dirty = 1; + } + } + + munmap(footer, size); + +err2: + close(out_fd); +err1: + } + + /* respect the new lazilly file creation behavior of the daemon */ + if (dirty == 0) { + unlink(out_filename); + } + + opd_free(out_filename); } - add the following entry at the end of converter_array: +/* PHE FIXME: really a fucking function, if you have problem with it flame + * me at <ph...@cl...> */ +static void v4_to_v5(FILE* fp) +{ + struct opd_footer_v4 footer_v4; + char *out_filename; + char *session_str; + int session_number; + int ok; + int counter; + int old_size, old_fd, nr_samples; + size_t len_filename; + struct old_opd_fentry *old_samples; - { vN_to_vM, sizeof(struct opd_footer_vN), N }, + fread(&footer_v4, sizeof(footer_v4), 1, fp); - Note than if you use the reserved field to add additionnal field *and* the 0 binary - value of the reserve acts as a default value for the new code which use this new - field then you do not have to write a converter, simply add the following line to the - conversion array: - { bump_version, sizeof(struct opd_footer_vN), N }, + ok = 1; + session_number = -1; - PHIL 20010623 : these features has not been tested. -*/ + session_str = strrchr(filename, '-'); + if (session_str) { + int read = 0; + if (sscanf(session_str + 1, "%d%n", &session_number, &read) == 1) { + + /* Dangerous if the bin filename end with "-%d" I + * prefer reject this corner case */ + ok = session_str[read] && !session_str[read + 1]; + } + } + + if (ok == 0) { + /* PHE FIXME: probably needs to remove this warning */ +// fprintf(stderr, "Bad file naming scheme %s\n", filename); + session_number = -1; + } + + old_fd = open(filename, O_RDONLY); + if (old_fd == -1) { + fprintf(stderr, "oprof_convert: Opening %s failed. %s\n", filename, strerror(errno)); + goto out; + } + + old_size = opd_get_fsize(filename, 1); + if (old_size < sizeof(struct opd_footer_v4)) { + fprintf(stderr, "oprof_convert: sample file %s not enough big %d, expected %d\n", filename, old_size, sizeof(struct opd_footer_v4)); + goto err1; + } + + old_samples = mmap(0, old_size, PROT_READ, MAP_PRIVATE, old_fd, 0); + if (old_samples == (void *)-1) { + fprintf(stderr, "oprof_convert: mmap of %s failed. %s\n", filename, strerror(errno)); + goto err1; + } + + nr_samples = (old_size - sizeof(struct opd_footer_v4)) / sizeof(struct old_opd_fentry); + + len_filename = strlen(filename); + out_filename = opd_malloc(len_filename + 32); + strcpy(out_filename, filename); + + for (counter = 0; counter < 2 ; ++counter) { + do_mapping_transfer(nr_samples, counter, filename, + &footer_v4, old_samples, + session_number); + } + + munmap(old_samples, old_size); + +err1: + close(old_fd); +out: + opd_free(out_filename); +} +static struct converter converter_array[] = { + { v2_to_v3, sizeof(struct opd_footer_v2), 2 }, + { v3_to_v4, sizeof(struct opd_footer_v3), 3 }, + { v4_to_v5, sizeof(struct opd_footer_v4), 4 }, +}; + #define nr_converter (signed int)((sizeof(converter_array) / sizeof(converter_array[0]))) /* return -1 if no converter are available, else return the index of the first * converter */ -static int get_converter_index(FILE* fp) +static int get_converter_index(FILE* fp, int last_index) { struct opd_footer_v2 footer_v2; int i; - for (i = 0 ; i < nr_converter ; ++i) { + for (i = last_index ; i < nr_converter ; ++i) { fseek(fp, -converter_array[i].sizeof_struct, SEEK_END); fread(&footer_v2, sizeof(footer_v2), 1, fp); - if (footer_v2.magic == OPD_MAGIC && + if (footer_v2.magic == OPD_MAGIC_V4 && footer_v2.version == converter_array[i].version) { fseek(fp, -converter_array[i].sizeof_struct, SEEK_END); @@ -253,7 +447,15 @@ exit(EXIT_SUCCESS); } - for (i = 1 ; i < argc ; ++i) { + i = 1; + + /* for v4 --> v5 */ + if (strncmp(argv[i], "--cpu-type", strlen("--cpu-type")) == 0) { + sscanf(argv[i] + strlen("--cpu-type="), "%d", &cpu_type); + ++i; + } + + for ( ; i < argc ; ++i) { // used in v3 conversion filename = argv[i]; @@ -265,13 +467,16 @@ } converted = 0; - while ((converter_index = get_converter_index(fp)) != -1) { + converter_index = 0; + while ((converter_index = get_converter_index(fp, converter_index)) != -1) { converter_array[converter_index].convert(fp); + converter_index++; converted = 1; } if (converted == 0) { fprintf(stderr, "no converter found for %s (file already converted ?)\n", argv[i]); + err++; } Index: oprofpp.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/oprofpp.c,v retrieving revision 1.36 retrieving revision 1.37 diff -u -d -r1.36 -r1.37 --- oprofpp.c 2001/08/20 19:46:13 1.36 +++ oprofpp.c 2001/09/01 02:03:34 1.37 @@ -40,16 +40,20 @@ static int list_all_symbols_details; static int output_linenr_info; -static struct opd_fentry *samples; +/* PHE FIXME would be an array of struct ? */ +/* indexed by samples[counter_nr][offset] */ +static struct opd_fentry *samples[OP_MAX_COUNTERS]; +static struct opd_footer *footer[OP_MAX_COUNTERS]; +static char *ctr_name[OP_MAX_COUNTERS]; +static char *ctr_desc[OP_MAX_COUNTERS]; +static char *ctr_um_desc[OP_MAX_COUNTERS]; static uint nr_samples; -static struct opd_footer footer; -static char *ctr0_name; -static char *ctr0_desc; -static char *ctr0_um_desc; -static char *ctr1_name; -static char *ctr1_desc; -static char *ctr1_um_desc; -static int ctr; +/* if != -1 appended to samples files with "-%d" format */ +static int session_number = -1; +/* PHE FIXME: check the logic and this comment */ +/* counter k is selected if (ctr == -1 || ctr == k), if ctr == -1 counter 0 + * is used for sort purpose */ +static int ctr = -1; static u32 sect_offset; static struct poptOption options[] = { @@ -65,6 +69,8 @@ { "base-dir", 'b', POPT_ARG_STRING, &basedir, 0, "base directory of profile daemon", NULL, }, { "list-all-symbols-details", 'L', POPT_ARG_NONE, &list_all_symbols_details, 0, "list samples for all symbols", NULL, }, { "output-linenr-info", 'o', POPT_ARG_NONE, &output_linenr_info, 0, "output filename:linenr info", NULL }, + /* PHE FIXME document later */ + { "session-number", 'S', POPT_ARG_INT, &session_number, 0, "which session use", "session number" }, POPT_AUTOHELP { NULL, 0, 0, NULL, 0, NULL, NULL, }, }; @@ -109,6 +115,9 @@ poptContext optcon; char c; const char *file; + const char *file_session_str; + char *file_ctr_str; + int counter; /* Some old version of popt needs the cast to char ** */ optcon = poptGetContext(NULL, argc, (char **)argv, options, 0); @@ -164,7 +173,55 @@ /* we'll "leak" this memory */ samplefile = remangle(imagefile); } - } + } + + /* We must get account 2 var : ctr, mangled filename, if ctr is not + * provided it can be provided inside the filename itself by the #%d + * terminateur, if ctr is given we check an eventual conflict */ + /* PHE FIXME: can be simplified probably ? */ + file_ctr_str = strrchr(samplefile, '#'); + counter = -1; + if (file_ctr_str) { + sscanf(file_ctr_str + 1, "%d", &counter); + } + + if (ctr != counter) { + /* PHE FIXME documentation of this behavior */ + /* a --counter=x have priority on the # suffixe of filename */ + if (ctr != -1 && counter != -1) { + /* conflict between #%d and --ctr option */ + fprintf(stderr, "oprofpp: conflict between %s filename counter nr and --ctr %d option, using --ctr option %d\n", file_ctr_str, ctr, ctr); + } + + } + + counter = ctr; + + if (ctr == -1) { + /* list_all_symbols_details always output all counter and do + * not made any sort, it is the responsability of the backend + * (op_to_source) to treat this */ + if (!list_all_symbols_details) + ctr = 0; + } + + /* Now record the session number */ + if (file_ctr_str) { + file_session_str = strchr(file_ctr_str, '-'); + if (file_session_str) { + sscanf(file_session_str + 1, "%d", &session_number); + } + } + + if (file_ctr_str) + file_ctr_str[0] = '\0'; + + if (ctr != -1 && (ctr < 0 || ctr >= op_nr_counters)) { + ctr = 0; + + fprintf(stderr, "oprofpp: invalid counter number, using %d\n", ctr); + + } } /** @@ -259,7 +316,6 @@ } newmtime = opd_get_mtime(file); - if (newmtime != mtime) { fprintf(stderr, "oprofpp: the last modified time of the binary file %s does not match " "that of the sample file. Either this is the wrong binary or the binary " @@ -282,7 +338,9 @@ if (!imagefile) free(file); - if (footer.is_kernel) { + /* PHE FIXME: this is broken, should search for a opended sample file + * */ + if (footer[ctr == -1 ? 0 : ctr]->is_kernel) { asection *sect; sect = bfd_get_section_by_name(ibfd, ".text"); @@ -438,24 +496,20 @@ struct opp_count { asymbol *sym; - u32 count0; - u32 count1; + u32 count[OP_MAX_COUNTERS]; }; - + int countcomp(const void *a, const void *b) { struct opp_count *ca= (struct opp_count *)a; struct opp_count *cb= (struct opp_count *)b; - if (ctr) { - if (ca->count1 < cb->count1) - return -1; - return (ca->count1 > cb->count1); - } else { - if (ca->count0 < cb->count0) - return -1; - return (ca->count0 > cb->count0); - } + /* PHE FIXME: I think it is correct... */ + int counter = ctr == -1 ? 0 : ctr; + + if (ca->count[counter] < cb->count[counter]) + return -1; + return (ca->count[counter] > cb->count[counter]); } /** @@ -465,26 +519,24 @@ * Lists all the symbols from the image specified by samplefile, * in decreasing sample count order, to standard out. */ -void do_list_symbols(bfd * ibfd) +void do_list_symbols(asymbol **syms, uint num) { - asymbol **syms; struct opp_count *scounts; u32 start, end; - uint num, tot0 = 0, tot1 = 0,i,j; - - num = get_symbols(ibfd, &syms); + uint tot[OP_MAX_COUNTERS],i,j; + int found_samples, k; - if (!num) { - fprintf(stderr, "oprofpp: couldn't get any symbols from image file.\n"); - exit(EXIT_FAILURE); + for (i = 0 ; i < op_nr_counters ; ++i) { + tot[i] = 0; } - scounts = opd_calloc0(num,sizeof(struct opp_count)); for (i=0; i < num; i++) { scounts[i].sym = syms[i]; get_symbol_range(syms[i], (i == num-1) ? NULL : syms[i+1], &start, &end); + /* FIXME PHE: was in old code, seems bad at my eyes (compare + * an adress with a number of samples) */ if (start >= nr_samples) { fprintf(stderr,"oprofpp: start 0x%x out of range (max 0x%x)\n", start, nr_samples); exit(EXIT_FAILURE); @@ -495,34 +547,39 @@ } for (j = start; j < end; j++) { - if (samples[j].count0) - verbprintf("Adding %u 0-samples for symbol $%s$ at pos j 0x%x\n", samples[j].count0, syms[i]->name, j); - else if (samples[j].count1) - verbprintf("Adding %u 1-samples for symbol $%s$ at pos j 0x%x\n", samples[j].count1, syms[i]->name, j); - scounts[i].count0 += samples[j].count0; - scounts[i].count1 += samples[j].count1; - tot0 += samples[j].count0; - tot1 += samples[j].count1; + /* PHE FIXME too imbrication level */ + for (k = 0 ; k < op_nr_counters ; ++k) { + if (samples[k] && samples[k][j].count) { + verbprintf("Adding %u 0-samples for symbol $%s$ at pos j 0x%x\n", + samples[k][j].count, syms[i]->name, j); + scounts[i].count[k] += samples[k][j].count; + tot[k] += samples[k][j].count; + } + } } } - + qsort(scounts, num, sizeof(struct opp_count), countcomp); for (i=0; i < num; i++) { printf_symbol(scounts[i].sym->name); - if (ctr && scounts[i].count1) { - printf("[0x%.8lx]: %2.4f%% (%u samples)\n", scounts[i].sym->value+scounts[i].sym->section->vma, - (((double)scounts[i].count1) / tot1)*100.0, scounts[i].count1); - } else if (!ctr && scounts[i].count0) { - printf("[0x%.8lx]: %2.4f%% (%u samples)\n", scounts[i].sym->value+scounts[i].sym->section->vma, - (((double)scounts[i].count0) / tot0)*100.0, scounts[i].count0); - } else if (!streq("", scounts[i].sym->name)) + + /* PHE FIXME too imbrication level */ + found_samples = 0; + for (k = 0; k < op_nr_counters ; ++k) { + if (scounts[i].count[k]) { + printf("[0x%.8lx]: %2.4f%% (%u samples)\n", scounts[i].sym->value+scounts[i].sym->section->vma, + (((double)scounts[i].count[k]) / tot[k])*100.0, scounts[i].count[k]); + found_samples = 1; + } + + } + if (found_samples == 0 && !streq("", scounts[i].sym->name)) { printf(" (0 samples)\n"); + } } opd_free(scounts); - opd_free(syms); - bfd_close(ibfd); } /** @@ -532,18 +589,11 @@ * Lists all the samples for the symbol specified by symbol, from the image * specified by @samplefile, in decreasing sample count order, to standard out. */ -void do_list_symbol(bfd * ibfd) +void do_list_symbol(bfd * ibfd, asymbol **syms, uint num) { - asymbol **syms; u32 start, end; - u32 num,i,j; - - num = get_symbols(ibfd,&syms); - - if (!num) { - fprintf(stderr, "oprofpp: couldn't get any symbols from image file.\n"); - exit(EXIT_FAILURE); - } + u32 i, j; + int k; for (i=0; i < num; i++) { if (streq(syms[i]->name, symbol)) @@ -556,14 +606,26 @@ printf("Samples for symbol \"%s\" in image %s\n", symbol, ibfd->filename); get_symbol_range(syms[i], (i == num-1) ? NULL : syms[i+1], &start, &end); for (j=start; j < end; j++) { - if (samples[j].count0 || samples[j].count1) { - printf("%s+%x/%x:\t%u \t%u\n", symbol, sym_offset(syms[i], j), end-start, - samples[j].count0, samples[j].count1); + for (k = 0 ; k < op_nr_counters ; ++k) { + if (samples[k] && samples[k][j].count) { + printf("%s+%x/%x:", symbol, sym_offset(syms[i], j), end-start); + break; + } + } + + /* k != op_nr_counters <==> one of the counter is not empty */ + if (k != op_nr_counters) { + for (k = 0 ; k < op_nr_counters ; ++k) { + if (samples[k]) + /* PHE: please keep this space a few + * time, I can't live without it ;) */ + printf("\t%u ", samples[k][j].count); + else + printf("\t%u", 0U); + } + printf("\n"); } } - - opd_free(syms); - bfd_close(ibfd); } #define GMON_VERSION 1 @@ -583,25 +645,18 @@ * Dump gprof-format samples for the image specified by samplefile to * the file specified by gproffile. */ -void do_dump_gprof(bfd * ibfd) +/* PHE: this fun has not been tested */ +void do_dump_gprof(asymbol **syms, uint num) { static struct gmon_hdr hdr = { "gmon", GMON_VERSION, {0,0,0,},}; FILE *fp; - asymbol **syms; u32 start, end; - uint num,i,j; + uint i, j; u32 low_pc = (u32)-1; u32 high_pc = 0; u16 * hist; u32 histsize; - num = get_symbols(ibfd,&syms); - - if (!num) { - fprintf(stderr, "oprofpp: couldn't get any symbols from image file.\n"); - exit(EXIT_FAILURE); - } - fp=opd_open_file(gproffile, "w"); opd_write_file(fp,&hdr, sizeof(struct gmon_hdr)); @@ -642,14 +697,12 @@ for (i=0; i < num; i++) { get_symbol_range(syms[i], (i == num-1) ? NULL : syms[i+1], &start, &end); for (j=start; j < end; j++) { - u32 count; + u32 count = 0; u32 pos; pos = (sym_offset(syms[i],j) + syms[i]->value + syms[i]->section->vma - low_pc) / MULTIPLIER; - if (ctr) - count = samples[j].count1; - else - count = samples[j].count0; + /* get_options have set ctr to one value != -1 */ + count = samples[ctr][j].count; if (count > (u16)-1) { printf("Warning: capping sample count !\n"); @@ -665,8 +718,6 @@ opd_write_file(fp, hist, histsize * sizeof(u16)); opd_close_file(fp); - opd_free(syms); - bfd_close(ibfd); } /** @@ -681,7 +732,7 @@ * that work with output from oprofpp. */ static void -translate_address (bfd* ibfd, asymbol** syms, asection* section, bfd_vma pc) +translate_address (bfd* ibfd, asymbol **syms, asection *section, bfd_vma pc) { int found; bfd_vma vma; @@ -709,6 +760,33 @@ } /** + * accumulate_samples - lookup and output linenr info from a vma address + * in a given section to standard output. + * @counter: where to accumulate the samples, can be %NULL + * @index: index number of the samples. + * + * if @counter != %NULL accumulate samples count in @counter + * else just return 0/1 if they exist samples at @index + * + * return non-zero if samples has been found + */ +static int accumulate_samples(u32 counter[OP_MAX_COUNTERS], int index) +{ + int k; + int found_samples = 0; + + for (k = 0; k < op_nr_counters; ++k) { + if (samples[k] && samples[k][index].count) { + found_samples = 1; + if (counter) + counter[k] += samples[k][index].count; + } + } + + return found_samples; +} + +/** * do_list_all_symbols_details - list all samples for all symbols. * @ibfd: the bfd * @@ -718,32 +796,30 @@ * Do not change output format without changing the corresponding tools * that work with output from oprofpp */ -void do_list_all_symbols_details(bfd* ibfd) { - uint num, i, j; +void do_list_all_symbols_details(bfd *ibfd, asymbol **syms, uint num) +{ + uint i, j; u32 start, end; - asymbol **syms; - num = get_symbols(ibfd, &syms); - - if (!num) { - fprintf(stderr, "oprofpp: couldn't get any symbols from image file.\n"); - exit(EXIT_FAILURE); - } - for (i = 0 ; i < num ; ++i) { - u32 ctr0, ctr1; + u32 counter[OP_MAX_COUNTERS]; + int k; + int found_samples; get_symbol_range(syms[i], (i == num-1) ? NULL : syms[i+1], &start, &end); + for (k = 0; k < op_nr_counters; ++k) { + counter[k] = 0; + } + /* To avoid outputing 0 samples symbols */ - ctr0 = ctr1 = 0; - for (j=start; j < end; j++) { - ctr0 += samples[j].count0; - ctr1 += samples[j].count1; + found_samples = 0; + for (j = start; j < end; ++j) { + found_samples |= accumulate_samples(counter, j); } - if (ctr0 || ctr1) { + if (found_samples) { bfd_vma vma, base_vma; base_vma = syms[i]->value + syms[i]->section->vma; @@ -757,12 +833,22 @@ printf(" "); } - printf("%.8lx %u %u ", base_vma, ctr0, ctr1); + printf("%.8lx ", base_vma); + for (k = 0 ; k < op_nr_counters ; ++k) { + printf("%u ", counter[k]); + } printf_symbol(syms[i]->name); printf("\n"); - for (j=start; j < end; j++) { - if (samples[j].count0 || samples[j].count1) { + for (j = start; j < end; j++) { + + for (k = 0; k < op_nr_counters; ++k) { + counter[k] = 0; + } + + found_samples = accumulate_samples(counter, j); + + if (found_samples) { vma = sym_offset(syms[i], j) + base_vma; @@ -773,99 +859,280 @@ syms[i]->section, vma); } - printf(" %.8lx %u %u\n", - vma, samples[j].count0, - samples[j].count1); + + printf(" %.8lx", vma); + + for (k = 0; k < op_nr_counters; ++k) { + printf(" %u", counter[k]); + } + + printf("\n"); } } } } - - opd_free(syms); - bfd_close(ibfd); } -int main(int argc, char const *argv[]) +/** + * open_samples_file - open a samples file + * @counter: the counter number + * @size: where to return the mapped size, this do NOT + * include the footer size + * @can_fail: allow to fail gracefully + * + * open and mmap the given samples files, return -1 + * the global var samples[@counter] and footer[@counter] + * are updated in case of success else a fatal error occur + * The following field of the footer are checked + * u8 magic[4]; + * u16 version; + * u8 ctr_event; + * u8 ctr_um; + * u8 ctr; + * u8 cpu_type; + * + * return the file descriptor (can be -1 if @can_fail) else + * produces a fatal error + */ +static fd_t open_samples_file(u32 counter, size_t *size, + int can_fail) { fd_t fd; - FILE *fp; - size_t size; - bfd *ibfd; - - get_options(argc, argv); + char* temp; - fp = fopen(samplefile,"r"); - if (!fp) { - fprintf(stderr, "oprofpp: fopen of %s failed. %s\n", samplefile, strerror(errno)); - exit(EXIT_FAILURE); + temp = opd_malloc(strlen(samplefile) + 32); + + strcpy(temp, samplefile); + + sprintf(temp + strlen(temp), "#%d", counter); + if (session_number != -1) + sprintf(temp + strlen(temp), "-%d", session_number); + + fd = open(temp, O_RDONLY); + if (fd == -1) { + if (!can_fail) { + fprintf(stderr, "oprofpp: Opening %s failed. %s\n", temp, strerror(errno)); + exit(EXIT_FAILURE); + } + + goto err1; } - - if (fseek(fp, -sizeof(struct opd_footer), SEEK_END) == -1) { - fprintf(stderr, "oprofpp: fseek of %s failed. %s\n", samplefile, strerror(errno)); - exit(EXIT_FAILURE); + + *size = opd_get_fsize(temp, 1) - sizeof(struct opd_footer); + if (*size < sizeof(struct opd_footer)) { + if (!can_fail) { + fprintf(stderr, "oprofpp: sample file %s not enough big %d, expected %d\n", temp, *size, sizeof(struct opd_footer)); + exit(EXIT_FAILURE); + } + + goto err2; } - - if (fread(&footer, sizeof(struct opd_footer), 1, fp) != 1) { - fprintf(stderr, "oprofpp: fread of %s failed. %s\n", samplefile, strerror(errno)); + + footer[counter] = mmap(0, *size + sizeof(struct opd_footer), PROT_READ, + MAP_PRIVATE, fd, 0); + if (footer[counter] == (void *)-1) { + if (!can_fail) { + fprintf(stderr, "oprofpp: mmap of %s failed. %s\n", temp, strerror(errno)); + exit(EXIT_FAILURE); + } + goto err2; + } + + /* need a cast here :( */ + samples[counter] = (struct opd_fentry *)(footer[counter] + 1); + + if (memcmp(footer[counter]->magic, OPD_MAGIC, sizeof(footer[0]->magic))) { + if (!can_fail) { + /* FIXME: is 4.4 ok : there is no zero terminator */ + fprintf(stderr, "oprofpp: wrong magic %4.4s, expected %s.\n", footer[counter]->magic, OPD_MAGIC); + exit(EXIT_FAILURE); + } + goto err3; + } + + if (footer[counter]->version != OPD_VERSION) { + if (!can_fail) { + fprintf(stderr, "oprofpp: wrong version 0x%x, expected 0x%x.\n", footer[counter]->version, OPD_VERSION); + exit(EXIT_FAILURE); + } + goto err3; + } + + /* This should be warrented by the daemon */ + if (footer[counter]->ctr != counter) { + if (!can_fail) { + fprintf(stderr, "oprofpp: sanity check counter number fail %d, expect %d.\n", footer[counter]->ctr, counter); + exit(EXIT_FAILURE); + } + goto err3; + } + + opd_free(temp); + + return fd; + +err3: + munmap(footer[counter], *size + sizeof(struct opd_footer)); +err2: + close(fd); +err1: + fd = -1; + footer[counter] = NULL; + samples[counter] = NULL; + *size = 0; + return fd; +} + +/** + * check_and_output_event - translate event number, um mask + * to string and output them. + * @counter: counter number + * + * if event is valid output to stdout the description + * of event. + */ +static void check_and_output_event(int i) +{ + op_get_event_desc(footer[i]->cpu_type, footer[i]->ctr_event, + footer[i]->ctr_um, &ctr_name[i], &ctr_desc[i], + &ctr_um_desc[i]); + + printf("Counter %d counted %s events (%s) with a unit mask of " + "0x%.2x (%s) count %u\n", + i, ctr_name[i], ctr_desc[i], footer[i]->ctr_um, + ctr_um_desc[i] ? ctr_um_desc[i] : "Not set", + footer[i]->ctr_count); +} + +/** + * check_footers - check coherence between two footers. + * @f1: first footer + * @f2: second footer + * + * verify than footer @f1 and @f2 are coherent. + * fatal error ocur if the footers are not coherent. + */ +static void check_footers(struct opd_footer* f1, struct opd_footer* f2) +{ + if (f1->mtime != f2->mtime) { + fprintf(stderr, "oprofpp: footer time stamp are different (%ld, %ld)\n", f1->mtime, f2->mtime); exit(EXIT_FAILURE); } - fclose(fp); - if (footer.magic != OPD_MAGIC) { - fprintf(stderr, "oprofpp: wrong magic 0x%x, expected 0x%x.\n", footer.magic, OPD_MAGIC); + if (f1->is_kernel != f2->is_kernel) { + fprintf(stderr, "oprofpp: footer is_kernel are different\n"); exit(EXIT_FAILURE); } - - if (footer.version != OPD_VERSION) { - fprintf(stderr, "oprofpp: wrong version 0x%x, expected 0x%x.\n", footer.version, OPD_VERSION); + + if (f1->cpu_speed != f2->cpu_speed) { + fprintf(stderr, "oprofpp: footer cpu speed are different (%f, %f)", + f2->cpu_speed, f2->cpu_speed); exit(EXIT_FAILURE); } +} + +int main(int argc, char const *argv[]) +{ + bfd *ibfd; + asymbol **syms; + int i, j; + fd_t fd[OP_MAX_COUNTERS]; + size_t size[OP_MAX_COUNTERS]; + uint num; + time_t mtime = 0; - if (footer.ctr0_type_val) { - op_get_event_desc(footer.ctr0_type_val, footer.ctr0_um, &ctr0_name, &ctr0_desc, &ctr0_um_desc); - printf("Counter 0 counted %s events (%s) with a unit mask of 0x%.2x (%s) count %u\n",ctr0_name, ctr0_desc, - footer.ctr0_um, ctr0_um_desc ? ctr0_um_desc : "Not set", footer.ctr0_count); + get_options(argc, argv); + + for (i = 0; i < op_nr_counters ; ++i) { + fd[i] = -1; + size[i] = 0; + samples[i] = NULL; + footer[i] = NULL; } - if (footer.ctr1_type_val) { - op_get_event_desc(footer.ctr1_type_val, footer.ctr1_um, &ctr1_name, &ctr1_desc, &ctr1_um_desc); - printf("Counter 1 counted %s events (%s) with a unit mask of 0x%.2x (%s) count %u\n",ctr1_name, ctr1_desc, - footer.ctr1_um, ctr1_um_desc ? ctr1_um_desc : "Not set", footer.ctr1_count); + for (i = 0; i < op_nr_counters ; ++i) { + if (ctr == -1 || ctr == i) + /* PHE FIXME: in some case we can pass 0 as can_fail + * to get better error message */ + fd[i] = open_samples_file(i, &size[i], 1); } - printf("Cpu speed was (MHz estimation) : %f\n", footer.cpu_speed); - - fd = open(samplefile, O_RDONLY); + for (i = 0; i < op_nr_counters ; ++i) { + if (fd[i] != -1) + break; + } - if (fd == -1) { - fprintf(stderr, "oprofpp: Opening %s failed. %s\n", samplefile, strerror(errno)); + if (i == op_nr_counters) { + fprintf(stderr, "Can not open any samples files for %s last error %s\n", samplefile, strerror(errno)); exit(EXIT_FAILURE); } - size = opd_get_fsize(samplefile, 1) - sizeof(struct opd_footer); - samples = (struct opd_fentry *)mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0); + /* sanity check between the different samples files */ + for (i = 0 ; i < op_nr_counters; ++i) { + if (fd[i] != -1) + break; + } - if (samples == (void *)-1) { - fprintf(stderr, "oprofpp: mmap of %s failed. %s\n", samplefile, strerror(errno)); + for (j = i + 1; j < op_nr_counters ; ++j) { + if (fd[j] != -1) { + if (size[i] != size[j]) { + fprintf(stderr, "oprofpp: mapping file size " + "for ctr (%d, %d) are different " + "(%d, %d)\n", i, j, size[i], size[j]); + + exit(EXIT_FAILURE); + } + + check_footers(footer[i], footer[j]); + } + } + + /* output and sanity check on ctr_um, ctr_event and cpu_type */ + for (i = 0 ; i < op_nr_counters ; ++i) { + if (fd[i] != -1) { + check_and_output_event(i); + + /* redundant set but correct and simplify the code */ + nr_samples = size[i] / sizeof(struct opd_fentry); + mtime = footer[i]->mtime; + } + } + + verbprintf("nr_samples %d\n", nr_samples); + + ibfd = open_image_file(samplefile, mtime); + + num = get_symbols(ibfd, &syms); + + verbprintf("nr symbols %u\n", num); + + if (!num) { + fprintf(stderr, "oprofpp: couldn't get any symbols from image file.\n"); exit(EXIT_FAILURE); } - nr_samples = size/sizeof(struct opd_fentry); + printf("Cpu speed was (MHz estimation) : %f\n", + footer[ctr == -1 ? 0 : ctr]->cpu_speed); - ibfd = open_image_file(samplefile, footer.mtime); - if (list_symbols) { - do_list_symbols(ibfd); + do_list_symbols(syms, num); } else if (symbol) { - do_list_symbol(ibfd); + do_list_symbol(ibfd, syms, num); } else if (gproffile) { - do_dump_gprof(ibfd); + do_dump_gprof(syms, num); } else if (list_all_symbols_details) { - do_list_all_symbols_details(ibfd); + do_list_all_symbols_details(ibfd, syms, num); } - - munmap(samples, size); - close(fd); + + opd_free(syms); + bfd_close(ibfd); + + for (i = 0 ; i < op_nr_counters ; ++i) { + if (footer[i]) { + munmap(footer[i], size[i] + sizeof(struct opd_footer)); + close(fd[i]); + } + } return 0; } Index: oprofpp.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/oprofpp.h,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- oprofpp.h 2001/07/25 16:43:30 1.14 +++ oprofpp.h 2001/09/01 02:03:34 1.15 @@ -30,6 +30,7 @@ #include <sys/mman.h> #include "../dae/opd_util.h" +#include "../op_user.h" #include "../version.h" /* missing from libiberty.h */ @@ -40,18 +41,6 @@ # define DMGL_ANSI (1 << 1) /* Include const, volatile, etc */ #endif char *cplus_demangle (const char *mangled, int options); - -void op_get_event_desc(u8 type, u8 um, char **typenamep, char **typedescp, char **umdescp); - - -#define FALSE 0 -#define TRUE 1 -#define uint unsigned int -#define ulong unsigned long -#define u8 unsigned char -#define u16 u_int16_t -#define u32 u_int32_t -#define fd_t int #define verbprintf(args...) \ do { \ @@ -59,36 +48,5 @@ printf(args); \ } while (0) -/* kernel image entries are offset by this many entries */ -#define OPD_KERNEL_OFFSET 524288 - -/* this char replaces '/' in sample filenames */ -#define OPD_MANGLE_CHAR '}' - -struct opd_fentry { - u32 count0; - u32 count1; -}; -/* FIXME : Carefull these are also present in dae/oprofiled.h */ -#define OPD_MAGIC 0xdeb6 -#define OPD_VERSION 0x4 -/* at the end of the sample files */ -struct opd_footer { - u16 magic; - u16 version; - u8 is_kernel; - u8 ctr0_type_val; - u8 ctr1_type_val; - u8 ctr0_um; - u8 ctr1_um; - u8 reserved1[16]; - u32 ctr0_count; - u32 ctr1_count; - /* Set to 0.0 if not available */ - double cpu_speed; - time_t mtime; - /* binary compatibility reserve */ - u32 reserved2[31]; -}; |
From: John L. <mov...@us...> - 2001-09-01 02:03:38
|
Update of /cvsroot/oprofile/oprofile/dae In directory usw-pr-cvs1:/tmp/cvs-serv19169/dae Modified Files: Makefile.in op_start opd_proc.c opd_util.c opd_util.h oprofiled.c oprofiled.h Log Message: philippe's huge patch Index: Makefile.in =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/Makefile.in,v retrieving revision 1.14 retrieving revision 1.15 diff -u -d -r1.14 -r1.15 --- Makefile.in 2001/08/18 16:11:17 1.14 +++ Makefile.in 2001/09/01 02:03:34 1.15 @@ -14,13 +14,13 @@ install: $(INSTALL_LIST) -$(MKDIR_P) $(BINDIR) - @for f in $(INSTALL_LIST); do \ + for f in $(INSTALL_LIST); do \ cp $$f $(BINDIR)/$$f && chmod 755 $(BINDIR)/$$f; \ done uninstall: - @for f in $(INSTALL_LIST); do \ - rm -f $(BINDIR)/$$f; \ + for f in $(INSTALL_LIST); do \ + -rm -f $(BINDIR)/$$f; \ done clean: Index: op_start =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/op_start,v retrieving revision 1.36 retrieving revision 1.37 diff -u -d -r1.36 -r1.37 --- op_start 2001/08/19 20:23:02 1.36 +++ op_start 2001/09/01 02:03:34 1.37 @@ -23,17 +23,7 @@ BUF_SIZE=262144 HASH_SIZE=65536 -CTR0_EVENT= -CTR1_EVENT= KERNEL_ONLY=0 -CTR0_UM=0 -CTR1_UM=0 -CTR0_COUNT=600000 -CTR1_COUNT=600000 -CTR0_USER=1 -CTR0_KERNEL=1 -CTR1_USER=1 -CTR1_KERNEL=1 IGNORE_MYSELF=0 DIR="/var/opd" MAP_FILE= @@ -42,6 +32,18 @@ PGRP_FILTER=0 VERBOSE=0 +# PHE FIXME: too many changes needs a redesign. Proposition: +# 1) check for a cpu_type switch, +# 2) stop the daemon +# 3) modprobe oprofile [cpu_type=xx] +# 4) if --cpu-type not given get it from /proc/sys/dev/oprofile/cpu_type +# 5) default init +# 6) parse parameter +# 7) launch the daemon +# this avoid passing cpu_type in the common case and allow in case or module +# misdetect the used core to overwrite it through an init parameters to the +# module + if test -f /proc/cpuinfo; then modelname=`cat /proc/cpuinfo | grep "model\ name\ :" | sed -e 's/ //g' | cut -d':' -f2` case $modelname in @@ -74,29 +76,41 @@ CPUTYPE=0 fi -# FIXME: needs to be generalised for more counters (e.g. athlon) +case $CPUTYPE in + 0|1|2) + OP_MAX_COUNTERS=2 + ;; + 3) + OP_MAX_COUNTERS=4 + ;; +esac + +# we can now default define individual counter setup variable. +f=0 +while (( $f < $OP_MAX_COUNTERS )); do + CTR_COUNT[$f]=600000 + CTR_USER[$f]=1 + CTR_KERNEL[$f]=1 + f=$(($f+1)) +done do_help() { -echo 'op_start: usage: +echo "op_start: usage: Module options --buffer-size=num number of samples in kernel buffer --hash-table-size=num number of entries in kernel hash table --kernel-only=[0|1] profile only the kernel - --ctr0-event=name symbolic event name for ctr0 - --ctr1-event=name symbolic event name for ctr1 - --ctr0-count=val number of events between samples for ctr0 - --ctr1-count=val number of events between samples for ctr1 - --ctr0-unit-mask=val unit mask for ctr0 - --ctr1-unit-mask=val unit mask for ctr1 - --ctr0-kernel=[0|1] whether to count kernel events for ctr 0 - --ctr0-user=[0|1] whether to count user events for ctr 0 - --ctr1-kernel=[0|1] whether to count kernel events for ctr 1 - --ctr1-user=[0|1] whether to count user events for ctr1 - --pid-filter=pid Only profile process pid (if compiled in) - --pgrp-filter=pgrp Only profile process group pgrp (if compiled in) + --ctrN-event=name symbolic event name for ctr N + --ctrN-count=val number of events between samples for ctr N + --ctrN-unit-mask=val unit mask for ctr N + --ctrN-kernel=[0|1] whether to count kernel events for ctr N + --ctrN-user=[0|1] whether to count user events for ctr N +Allowed range for N is [0-$OP_MAX_COUNTERS[ + --pid-filter=pid Only profile process pid + --pgrp-filter=pgrp Only profile process group pgrp Daemon options - --use-cpu=[0|1|2|3] 0 or PPro, 1 for PII, 2 for PIII, 3 for AMD Athlon. + --use-cpu=[0|1|2|3] 0: PPro, 1: PII, 2: PIII, 3: AMD Athlon. --ignore-myself=[0|1] ignore samples for oprofiled --log-file=file log file --base-dir=dir base directory of daemon @@ -109,7 +123,7 @@ General options --list-events list event types and unit masks - --help this message' + --help this message" } # utilities functions. @@ -135,10 +149,17 @@ echo "/proc/sys/$dev_name does not exist or is not a regular file" >&2 exit 1 fi - echo $val > /proc/sys/$dev_name } +# PHE FIXME: assume ctr < 9, how from an awk expr extract the int field? +# probably needs to use bash string manipulation. +# extract the field N from --ctrN-xxxxxx +extract_int() +{ + echo $1 | awk '{print substr($0, 6, 1)}' +} + LOG_FILE= SAMPLES_DIR= DEVICE_FILE= @@ -150,6 +171,10 @@ arg=`echo $1 | awk -F= '{print $1}'` val=`echo $1 | awk -F= '{print $2}'` case "$arg" in + # PHE FIXME: this work actually but if the forced cpu type have + # more counter than OP_MAX_COUNTERS only OP_NR_MAX_COUNTERS + # can be used. if less the script do not work and you can + # get many trouble. --use-cpu) if [ "$val" != "" ]; then CPUTYPE=$val @@ -175,35 +200,21 @@ KERNEL_ONLY=1 fi ;; - --ctr0-unit-mask) - CTR0_UM=$val - ;; - --ctr1-unit-mask) - CTR1_UM=$val - ;; - --ctr0-event) - CTR0_EVENT=$val - ;; - --ctr1-event) - CTR1_EVENT=$val - ;; - --ctr0-count) - CTR0_COUNT=$val - ;; - --ctr1-count) - CTR1_COUNT=$val + # PHE FIXME: see comment at extract_int + --ctr*-unit-mask) + CTR_UM[`extract_int $1`]=$val ;; - --ctr0-user) - CTR0_USER=$val + --ctr*-event) + CTR_EVENT[`extract_int $1`]=$val ;; - --ctr0-kernel) - CTR0_KERNEL=$val + --ctr*-count) + CTR_COUNT[`extract_int $1`]=$val ;; - --ctr1-user) - CTR1_USER=$val + --ctr*-user) + CTR_USER[`extract_int $1`]=$val ;; - --ctr1-kernel) - CTR1_KERNEL=$val + --ctr*-kernel) + CTR_KERNEL[`extract_int $1`]=$val ;; --base-dir) DIR=$val @@ -251,33 +262,24 @@ shift done -if [ -z "$CTR0_EVENT" -a -z "$CTR1_EVENT" ]; then +if [[ ${#CTR_EVENT[*]} == 0 ]]; then echo "You haven't specified what events you would like to count, e.g." echo "op_start ... --ctr0-event=CPU_CLK_UNHALTED --ctr0-count=600000" echo "Enter op_start --help for full options" exit 1 fi - - -CTR0_EVENT_VAL= -if [ ! -z "$CTR0_EVENT" ]; then - CTR0_EVENT_VAL=`op_help $CTR0_EVENT` -fi - -CTR1_EVENT_VAL= -if [ ! -z "$CTR1_EVENT" ]; then - CTR1_EVENT_VAL=`op_help $CTR1_EVENT` -fi - -if [ -z "$CTR0_EVENT_VAL" -a ! -z "$CTR0_EVENT" ]; then - echo "Unknown event \"$CTR0_EVENT\"" - exit 1 -fi -if [ -z "$CTR1_EVENT_VAL" -a ! -z "$CTR1_EVENT" ]; then - echo "Unknown event \"$CTR1_EVENT\"" - exit 1 -fi +f=0 +while (( $f < $OP_MAX_COUNTERS )); do + if [[ ${#CTR_EVENT[$f]} != 0 ]]; then + CTR_EVENT_VAL[$f]=`op_help --cpu-type=$CPU_TYPE ${CTR_EVENT[$f]}` + if [ -z "${CTR_EVENT_VAL[$f]}" -a ! -z "${CTR_EVENT[$f]}" ]; then + echo "Unknown event \"${CTR_EVENT[$f]}\"" + exit 1 + fi + fi + f=$(($f+1)) +done # stop any existing daemon @@ -326,14 +328,15 @@ echo "Parameters used:" echo "BUF_SIZE $BUF_SIZE" echo "HASH_SIZE $HASH_SIZE" - echo "CTR0_EVENT $CTR0_EVENT" - echo "CTR1_EVENT $CTR1_EVENT" - echo "CTR0_UM $CTR0_UM" - echo "CTR1_UM $CTR1_UM" - echo "CTR0_COUNT $CTR0_COUNT" - echo "CTR1_COUNT $CTR1_COUNT" - echo "CTR0_OSUSR $CTR0_OSUSR" - echo "CTR1_OSUSR $CTR1_OSUSR" + f=0 + while (( $f < $OP_MAX_COUNTERS )); do + echo "CTR${f}_EVENT ${CTR_EVENT[$f]}" + echo "CTR${f}_COUNT ${CTR_COUNT[$f]}" + echo "CTR${f}_UM ${CTR_UM[$f]}" + echo "CTR${f}_USER ${CTR_USER[$f]}" + echo "CTR${f}_KERNEL ${CTR_KERNEL[$f]}" + f=$(($f+1)) + done echo "CPUTYPE $CPUTYPE" echo "IGNORE_MYSELF $IGNORE_MYSELF" echo "DIR $DIR" @@ -365,8 +368,8 @@ exit 1 fi -if [ ! -f "$MAP_FILE" ]; then - echo "The specified map file \"$MAP_FILE\" doesn't exist." +if [ ! -f "$VMLINUX" ]; then + echo "The specified vmlinux file \"$VMLINUX\" doesn't exist." exit 1 fi @@ -419,36 +422,32 @@ chmod 700 "$HASH_MAP_DEVICE_FILE" # Necessary in this case : -# op_start ctr0-on ctr1-on -# op_start ctr0-on -$SYSCTL -w dev.oprofile.0.enabled=0 >/dev/null -$SYSCTL -w dev.oprofile.1.enabled=0 >/dev/null -$SYSCTL -w dev.oprofile.0.event=0 >/dev/null -$SYSCTL -w dev.oprofile.1.event=0 >/dev/null +# op_start ctr0-on ctr1-on then op_start ctr0-on +f=0 +while (( $f < $OP_MAX_COUNTERS )); do + $SYSCTL -w dev.oprofile.$f.enabled=0 >/dev/null + $SYSCTL -w dev.oprofile.$f.event=0 >/dev/null + f=$(($f+1)) +done -$SYSCTL -w dev.oprofile.hashsize=$HASH_SIZE >/dev/null -$SYSCTL -w dev.oprofile.bufsize=$BUF_SIZE >/dev/null -$SYSCTL -w dev.oprofile.kernel_only=$KERNEL_ONLY >/dev/null -$SYSCTL -w dev.oprofile.pid_filter=$PID_FILTER >/dev/null -$SYSCTL -w dev.oprofile.pgrp_filter=$PGRP_FILTER >/dev/null +$SYSCTL -w dev.oprofile.hashsize=$HASH_SIZE +$SYSCTL -w dev.oprofile.bufsize=$BUF_SIZE +$SYSCTL -w dev.oprofile.kernel_only=$KERNEL_ONLY +$SYSCTL -w dev.oprofile.pid_filter=$PID_FILTER +$SYSCTL -w dev.oprofile.pgrp_filter=$PGRP_FILTER -# FIXME do something for all CPUs -if [ "$CTR0_EVENT" != "" ]; then - $SYSCTL -w dev.oprofile.0.enabled=1 >/dev/null - $SYSCTL -w dev.oprofile.0.count=$CTR0_COUNT >/dev/null - $SYSCTL -w dev.oprofile.0.kernel=$CTR0_KERNEL >/dev/null - $SYSCTL -w dev.oprofile.0.user=$CTR0_USER >/dev/null - $SYSCTL -w dev.oprofile.0.unit_mask=$CTR0_UM >/dev/null - $SYSCTL -w dev.oprofile.0.event=$CTR0_EVENT_VAL >/dev/null -fi -if [ "$CTR1_EVENT" != "" ]; then - $SYSCTL -w dev.oprofile.1.enabled=1 >/dev/null - $SYSCTL -w dev.oprofile.1.count=$CTR1_COUNT >/dev/null - $SYSCTL -w dev.oprofile.1.kernel=$CTR1_KERNEL >/dev/null - $SYSCTL -w dev.oprofile.1.user=$CTR1_USER >/dev/null - $SYSCTL -w dev.oprofile.1.unit_mask=$CTR1_UM >/dev/null - $SYSCTL -w dev.oprofile.1.event=$CTR1_EVENT_VAL >/dev/null -fi +f=0 +while (( $f < $OP_MAX_COUNTERS )); do + if [ "${CTR_EVENT[$f]}" != "" ]; then + $SYSCTL -w dev.oprofile.$f.enabled=1 + $SYSCTL -w dev.oprofile.$f.count=${CTR_COUNT[$f]} + $SYSCTL -w dev.oprofile.$f.kernel=${CTR_KERNEL[$f]} + $SYSCTL -w dev.oprofile.$f.user=${CTR_USER[$f]} + $SYSCTL -w dev.oprofile.$f.unit_mask=${CTR_UM[$f]} + $SYSCTL -w dev.oprofile.$f.event=${CTR_EVENT_VAL[$f]} + fi + f=$(($f+1)) +done OPD_ARGS="--buffer-size=$BUF_SIZE --use-cpu=$CPUTYPE --ignore-myself=$IGNORE_MYSELF \ --log-file=$LOG_FILE --base-dir=$DIR --samples-dir=$SAMPLES_DIR \ Index: opd_proc.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/opd_proc.c,v retrieving revision 1.64 retrieving revision 1.65 diff -u -d -r1.64 -r1.65 --- opd_proc.c 2001/08/18 15:58:31 1.64 +++ opd_proc.c 2001/09/01 02:03:34 1.65 @@ -23,9 +23,6 @@ #define OPD_DEFAULT_MAPS 16 #define OPD_MAP_INC 8 -/* kernel image entries are offset by this many entries */ -#define OPD_KERNEL_OFFSET 524288 - extern int kernel_only; extern int verbose; extern unsigned long opd_stats[]; @@ -36,7 +33,11 @@ /* hash of process lists */ static struct opd_proc *opd_procs[OPD_MAX_PROC_HASH]; -struct opd_footer footer; +u32 ctr_count[OP_MAX_COUNTERS]; +u8 ctr_event[OP_MAX_COUNTERS]; +u8 ctr_um[OP_MAX_COUNTERS]; +extern u32 cpu_type; +double cpu_speed; /* image structure */ static struct opd_image *opd_images; @@ -52,7 +53,8 @@ static struct opd_proc *opd_add_proc(u16 pid); static void opd_grow_images(void); -static void opd_open_image(struct opd_image *image); +static void opd_open_sample_file(struct opd_image *image, int counter); +static void opd_open_image(struct opd_image *image, const char *name, int kernl); static int opd_find_image(const char *name); static int opd_add_image(const char *name, int kernel); static int opd_get_image(const char *name, int kernel); @@ -62,7 +64,8 @@ static void opd_put_mapping(struct opd_proc *proc, int image_nr, u32 start, u32 offset, u32 end); static struct opd_proc *opd_get_proc(u16 pid); static void opd_delete_proc(struct opd_proc *proc); -static void opd_handle_old_sample_file(char * mangled, time_t mtime); +static void opd_handle_old_sample_file(int counter, const char * mangled, time_t mtime); +static void opd_handle_old_sample_files(const char * mangled, time_t mtime); /* every so many minutes, clean up old procs, msync mmaps, and report stats */ @@ -71,10 +74,14 @@ struct opd_proc *proc; struct opd_proc *next; uint i; + int j; - for (i=0; i < nr_images; i++) { - if (opd_images[i].fd != -1) - msync(opd_images[i].start, opd_images[i].len, MS_ASYNC); + for (i = 0; i < nr_images; i++) { + struct opd_image* image = &opd_images[i]; + for (j = 0 ; j < op_nr_counters ; ++j) { + if (image->sample_files[j].fd > 1) + msync(image->sample_files[i].start, image->len + sizeof(struct opd_footer), MS_ASYNC); + } } for (i=0; i < OPD_MAX_PROC_HASH; i++) { @@ -169,19 +176,13 @@ opd_close_file(fp); } -struct opd_fentry { - u32 count0; - u32 count1; -}; - - /** * opd_save_old_sample_file - back up the sample file * @file: the file name of the sample * * Back up a sample file. */ -static void opd_save_old_sample_file(char * file) +static void opd_save_old_sample_file(const char *file) { char * savename; int gen = 0; @@ -199,8 +200,7 @@ opd_free(savename); } - - + /** * opd_handle_old_sample_file - deal with old sample file * @mangled: the sample file name @@ -209,11 +209,11 @@ * If an old sample file exists, verify it is usable. * If not, move or delete it. */ -static void opd_handle_old_sample_file(char * mangled, time_t mtime) +static void opd_handle_old_sample_file(int counter, const char * mangled, time_t mtime) { struct opd_footer oldfooter; FILE * fp; - + if (!opd_get_fsize(mangled, 0)) return; @@ -221,25 +221,20 @@ if (!fp) goto del; - if (fseek(fp, -sizeof(struct opd_footer), SEEK_END) == -1) - goto closedel; - if (fread(&oldfooter, sizeof(struct opd_footer), 1, fp) != 1) goto closedel; - if (oldfooter.magic != OPD_MAGIC || oldfooter.version != OPD_VERSION) - goto closedel; + if (memcmp(&oldfooter.magic, OPD_MAGIC, sizeof(oldfooter.magic)) || oldfooter.version != OPD_VERSION) + goto closedel; if (difftime(mtime, oldfooter.mtime)) goto closedel; /* versions match, but we might be using different values */ - if (oldfooter.ctr0_type_val != footer.ctr0_type_val || - oldfooter.ctr1_type_val != footer.ctr1_type_val || - oldfooter.ctr0_um != footer.ctr0_um || - oldfooter.ctr1_um != footer.ctr1_um || - oldfooter.ctr0_count != footer.ctr0_count || - oldfooter.ctr1_count != footer.ctr1_count) { + if (oldfooter.ctr_event != ctr_event[counter] || + oldfooter.ctr_um != ctr_um[counter] || + oldfooter.ctr_count != ctr_count[counter] || + oldfooter.cpu_type != cpu_type) { fclose(fp); opd_save_old_sample_file(mangled); return; @@ -255,91 +250,86 @@ verbprintf("Deleting old sample file \"%s\".\n", mangled); unlink(mangled); } + + +/** + * opd_handle_old_sample_files - deal with old sample file + * @image_name: image to open file for + * @mtime: the new mtime of the binary + * + * to simplify admin of sample file we rename or remove sample + * files for each counter. + * + * If an old sample file exists, verify it is usable. + * If not, move or delete it. + */ +static void opd_handle_old_sample_files(const char *image_name, time_t mtime) +{ + int i; + char *mangled; + + mangled = opd_mangle_filename(smpdir, image_name); + + for (i = 0 ; i < op_nr_counters ; ++i) { + sprintf(mangled + strlen(mangled), "#%d", i); + + opd_handle_old_sample_file(i, mangled, mtime); + } + + free(mangled); +} /** * opd_open_image - open an image sample file * @image: image to open file for + * @name: name of the image to add + * @kernel: is the image a kernel/module image * - * Open and initialise an image sample file for - * the image @image and set up memory mappings for - * it. image->kernel and image->name must have meaningful - * values. + * @image at funtion entry is uninitialised + * @name is copied i.e. should be GC'd separately from the + * image structure if appropriate. + * + * Initialise an opd_image struct for the image @image + * without opening the associated samples files. At return + * the @image is fully initialized. */ -static void opd_open_image(struct opd_image *image) +static void opd_open_image(struct opd_image *image, const char *name, int kernel) { - char *mangled; - char *c; - char *c2; + int i; - mangled = opd_malloc(strlen(smpdir) + 2 + strlen(image->name)); - strcpy(mangled, smpdir); - strcat(mangled, "/"); - c = mangled + strlen(smpdir) + 1; - c2 = image->name; - do { - if (*c2 == '/') - *c++ = OPD_MANGLE_CHAR; - else - *c++ = *c2; - } while (*++c2); - *c = '\0'; + /* PHE FIXME : store the mangled name ? */ + image->name = opd_strdup(name); + image->kernel = kernel; + image->len = 0; - verbprintf("Statting $%s$\n", image->name); + for (i = 0 ; i < op_nr_counters ; ++i) { + image->sample_files[i].fd = -1; + image->sample_files[i].start = (void *)-1; + image->sample_files[i].footer = (void *)-1; + } - /* for each byte in original, two u32 counters */ - image->len = opd_get_fsize(image->name, 0) * sizeof(u32) * 2; + verbprintf("Statting \"%s\"\n", name); + + /* for each byte in original one counter */ + image->len = opd_get_fsize(name, 0) * sizeof(struct opd_fentry); if (!image->len) { - fprintf(stderr, "stat failed for %s\n", image->name); - image->fd = -1; - opd_free(mangled); + fprintf(stderr, "stat failed for %s\n", name); return; } - footer.mtime = opd_get_mtime(image->name); + image->mtime = opd_get_mtime(name); /* give space for "negative" entries. This is because we * don't know about kernel/module sections other than .text so * a sample could be before our nominal start of image, or * after the start */ if (image->kernel) - image->len += OPD_KERNEL_OFFSET * sizeof(struct opd_fentry) * 2; - - opd_handle_old_sample_file(mangled, footer.mtime); - - verbprintf("Opening $%s$\n", mangled); - - image->fd = open(mangled, O_CREAT|O_RDWR, 0644); - if (image->fd == -1) { - fprintf(stderr,"oprofiled: open of image sample file \"%s\" failed: %s\n", mangled, strerror(errno)); - goto out; - } - - if (lseek(image->fd, image->len, SEEK_SET) == -1) { - fprintf(stderr, "oprofiled: seek failed for \"%s\". %s\n", mangled, strerror(errno)); - goto err; - } - - footer.is_kernel = image->kernel; - - if ((write(image->fd, &footer, sizeof(struct opd_footer))) < (int)sizeof(struct opd_footer)) { - perror("oprofiled: wrote less than expected opd_footer. "); - goto err; - } + image->len += OPD_KERNEL_OFFSET * sizeof(struct opd_fentry); - image->start = mmap(0, image->len, PROT_READ|PROT_WRITE, MAP_SHARED, image->fd, 0); + opd_handle_old_sample_files(name, image->mtime); - if (image->start == (void *)-1) { - perror("oprofiled: mmap() failed. "); - goto err; - } -out: - opd_free(mangled); - return; -err: - close(image->fd); - image->fd=-1; - goto out; + /* samples files are lazilly openeded */ } /** @@ -361,9 +351,103 @@ */ inline static u16 opd_get_counter(const u16 count) { - return (count & OP_COUNTER); + return OP_COUNTER(count); } +/* + * opd_open_sample_file - open an image sample file + * @image: image to open file for + * @counter: counter number + * + * Open image sample file for the image @image, counter + * @counter and set up memory mappings for it. + * image->kernel and image->name must have meaningful + * values. + */ +static void opd_open_sample_file(struct opd_image *image, int counter) +{ + char* mangled; + struct opd_sample_file *sample_file; + + sample_file = &image->sample_files[counter]; + + /* avoid flood of error messages */ + if (sample_file->fd == -2) + return; + + mangled = opd_mangle_filename(smpdir, image->name); + + sprintf(mangled + strlen(mangled), "#%d", counter); + + verbprintf("Opening \"%s\"\n", mangled); + + sample_file->fd = open(mangled, O_CREAT|O_RDWR, 0644); + if (sample_file->fd == -1) { + fprintf(stderr,"oprofiled: open of image sample file \"%s\" failed: %s\n", mangled, strerror(errno)); + goto err1; + } + + /* PHE FIXME: keep it, I need opinion on the two manner to do the job + * I am unsure if there is no a thrid way to make this */ +#if 0 + /* ugly: mmap needs than fd size is sufficient, bugs in this area + * is difficult to understand, mmap sucess but the returned pointer + * cause a segfault, then the daemon is killed without coredump nor + * message error. PHE FIXME: why this mmap behavior, and why daemon die + * silently ? */ + if (lseek(sample_file->fd, image->len + sizeof(struct opd_footer) - 1, SEEK_SET) == -1) { + fprintf(stderr, "oprofiled: seek failed for \"%s\". %s\n", mangled, strerror(errno)); + goto err2; + } + + /* PHE FIXME: this unsparse the file by one memory page size at the + * end of file :( An another way to grow the file ?, 0 write size do + * not work. try a write from the zero page? */ + if (write(sample_file->fd, "", 1) != 1) { + perror("oprofiled: cannot grow sample file. "); + goto err2; + } +#else + /* PHE FIXME: perhaps this is equivalent to the code above other #if + * alternative */ + if (ftruncate(sample_file->fd, image->len + sizeof(struct opd_footer) - 1) == -1) { + fprintf(stderr, "oprofiled: ftruncate failed for \"%s\". %s\n", mangled, strerror(errno)); + goto err2; + } +#endif + + sample_file->footer = mmap(0, image->len + sizeof(struct opd_footer), + PROT_READ|PROT_WRITE, MAP_SHARED, sample_file->fd, 0); + + if (sample_file->footer == (void *)-1) { + fprintf(stderr,"oprofiled: mmap of image sample file \"%s\" failed: %s\n", mangled, strerror(errno)); + goto err2; + } + + sample_file->start = sample_file->footer + 1; + + memset(sample_file->footer, '\0', sizeof(struct opd_footer)); + sample_file->footer->version = OPD_VERSION; + memcpy(&sample_file->footer->magic, OPD_MAGIC, sizeof(sample_file->footer->magic)); + sample_file->footer->is_kernel = image->kernel; + sample_file->footer->ctr_event = ctr_event[counter]; + sample_file->footer->ctr_um = ctr_um[counter]; + sample_file->footer->ctr = counter; + sample_file->footer->cpu_type = cpu_type; + sample_file->footer->ctr_count = ctr_count[counter]; + sample_file->footer->cpu_speed = cpu_speed; + sample_file->footer->mtime = image->mtime; +out: + opd_free(mangled); + return; +err2: + close(sample_file->fd); +err1: + /* avoid flood of error messages */ + sample_file->fd = -2; + goto out; +} + /** * opd_put_image_sample - write sample to file * @image: image for sample @@ -382,35 +466,36 @@ inline static void opd_put_image_sample(struct opd_image *image, u32 offset, u16 count) { struct opd_fentry *fentry; + struct opd_sample_file* sample_file; + int counter; - if (image->fd < 1) { - verbprintf("Trying to write to non-opened image %s\n", image->name); - return; + counter = opd_get_counter(count); + sample_file = &image->sample_files[counter]; + + if (sample_file->fd < 1) { + opd_open_sample_file(image, counter); + if (sample_file->fd < 1) { + /* opd_open_sample_file output an error message */ + return; + } } - fentry = image->start + (offset*sizeof(struct opd_fentry)); + fentry = sample_file->start + (offset*sizeof(struct opd_fentry)); if (image->kernel) fentry += OPD_KERNEL_OFFSET; - if (((u32)fentry) > ((u32)(image->start + image->len))) { + if (((u32)fentry) > ((u32)(sample_file->start + image->len))) { fprintf(stderr, "fentry %p out of bounds for \"%s\" (start %p, len 0x%.8lx, " - "end %p, orig offset 0x%.8x, kernel %d)\n", fentry, image->name, image->start, - image->len, image->start + image->len, offset, image->kernel); + "end %p, orig offset 0x%.8x, kernel %d)\n", fentry, image->name, sample_file->start, + image->len, sample_file->start + image->len, offset, image->kernel); return; } - if (opd_get_counter(count)) { - if (fentry->count1 + opd_get_count(count) < fentry->count1) - fentry->count1 = (u32)-1; - else - fentry->count1 += opd_get_count(count); - } else { - if (fentry->count0 + opd_get_count(count) < fentry->count0) - fentry->count0 = (u32)-1; - else - fentry->count0 += opd_get_count(count); - } + if (fentry->count + opd_get_count(count) < fentry->count) + fentry->count = (u32)-1; + else + fentry->count += opd_get_count(count); } @@ -424,11 +509,11 @@ { /* 0 is reserved for the kernel image */ opd_images = opd_calloc0(sizeof(struct opd_image), OPD_DEFAULT_IMAGES); - opd_images[0].name = opd_malloc(strlen(vmlinux) + 1); - strncpy(opd_images[0].name,vmlinux,strlen(vmlinux) + 1); - + + opd_images[0].name = opd_strdup(vmlinux); opd_images[0].kernel = 1; - opd_open_image(&opd_images[0]); + + opd_open_image(&opd_images[0], vmlinux, 1); nr_images = 1; } @@ -502,11 +587,7 @@ */ static int opd_add_image(const char *name, int kernel) { - opd_images[nr_images].name = opd_malloc(strlen(name)+1); - strncpy(opd_images[nr_images].name, name, strlen(name)+1); - - opd_images[nr_images].kernel = kernel; - opd_open_image(&opd_images[nr_images]); + opd_open_image(&opd_images[nr_images], name, kernel); nr_images++; if (nr_images == max_nr_images) @@ -1050,7 +1131,7 @@ return; printf("DO_PUT_SAMPLE (LAST_MAP): calc offset 0x%.8x, map start 0x%.8x," - " end 0x%.8x, offset 0x%.8x, name $%s$\n", + " end 0x%.8x, offset 0x%.8x, name \"%s\"\n", offset, map->start, map->end, map->offset, opd_images[map->image].name); } @@ -1145,7 +1226,7 @@ */ void opd_put_mapping(struct opd_proc *proc, int image_nr, u32 start, u32 offset, u32 end) { - verbprintf("Placing mapping for process %d: 0x%.8x-0x%.8x, off 0x%.8x, $%s$\n", + verbprintf("Placing mapping for process %d: 0x%.8x-0x%.8x, off 0x%.8x, \"%s\"\n", proc->pid, start, end, offset, opd_images[image_nr].name); proc->maps[proc->nr_maps].image = image_nr; Index: opd_util.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/opd_util.c,v retrieving revision 1.18 retrieving revision 1.19 diff -u -d -r1.18 -r1.19 --- opd_util.c 2001/07/27 00:28:44 1.18 +++ opd_util.c 2001/09/01 02:03:34 1.19 @@ -143,7 +143,7 @@ * * Returns a char* pointer to the duplicated string. */ -char *opd_strdup(const char* str) +char *opd_strdup(const char *str) { char *temp = opd_malloc(strlen(str) + 1); memcpy(temp, str, strlen(str) + 1); @@ -151,6 +151,44 @@ return temp; } +/** + * opd_mangle_filename - mangle a file filename + * @smpdir: base directory name + * @image_name: a path name to the image file + * @extra_size: an extra size to allocate + * + * allocate memory of size strlen(@image_name) + + * strlen(@smpdir) + 2 + 32 then concat + * @smpdir and the mangled name of @filename + * the 32 bytes added are assumed to concat + * something like "-%d" + * + * Returns a char* pointer to the mangled string. + * + */ +char* opd_mangle_filename(const char *smpdir, const char* image_name) +{ + char *mangled; + char *c; + const char *c2; + + mangled = opd_malloc(strlen(smpdir) + 2 + strlen(image_name) + 32); + strcpy(mangled, smpdir); + strcat(mangled, "/"); + c = mangled + strlen(smpdir) + 1; + c2 = image_name; + do { + if (*c2 == '/') + *c++ = OPD_MANGLE_CHAR; + else + *c++ = *c2; + } while (*++c2); + *c = '\0'; + + return mangled; +} + + /* remove_component_p() and op_simlify_pathname() comes from the gcc preprocessor */ @@ -582,13 +620,15 @@ struct stat st; if (stat(file, &st)) { - if (!fatal) + if (!fatal) return 0; fprintf(stderr,"opd_get_fsize: stat failed\n"); exit(1); } + /* PHE FIXME caller can not make any difference between failure and + * zero file size when fatal != 0 */ return st.st_size; } Index: opd_util.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/opd_util.h,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- opd_util.h 2001/07/27 00:28:44 1.13 +++ opd_util.h 2001/09/01 02:03:34 1.14 @@ -27,15 +27,40 @@ #include <time.h> #include <fcntl.h> +#include "../op_user.h" + +/* this char replaces '/' in sample filenames */ +#define OPD_MANGLE_CHAR '}' + #define FALSE 0 #define TRUE 1 -#define u8 unsigned char -#define u16 u_int16_t -#define u32 u_int32_t -#define fd_t int #define streq(a,b) (!strcmp((a), (b))) +#define OPD_MAGIC "DAE\n" +#define OPD_VERSION 0x5 + +/* header of the sample files */ +struct opd_footer { + u8 magic[4]; + u32 version; + u8 is_kernel; + u32 ctr_event; + u32 ctr_um; + /* ctr number, used for sanity checking */ + u32 ctr; + u32 cpu_type; + u32 ctr_count; + double cpu_speed; + time_t mtime; + /* binary compatibility reserve */ + u32 reserved2[21]; +}; + +struct opd_fentry { + u32 count; +}; + /* utility functions */ #define opd_calloc(memb, size) opd_malloc(memb*size) #define opd_calloc0(memb, size) opd_malloc0(memb*size) @@ -50,6 +75,7 @@ void *opd_realloc(void *buf, size_t size); void opd_free(void *p); char *opd_strdup(const char* str); +char* opd_mangle_filename(const char *smpdir, const char* filename); char *opd_simplify_pathname(char *path); char *opd_relative_to_absolute_path(const char *path, const char *base_dir); Index: oprofiled.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/oprofiled.c,v retrieving revision 1.39 retrieving revision 1.40 diff -u -d -r1.39 -r1.40 --- oprofiled.c 2001/08/19 20:09:17 1.39 +++ oprofiled.c 2001/09/01 02:03:34 1.40 @@ -17,7 +17,10 @@ #include "oprofiled.h" -extern struct opd_footer footer; +extern double cpu_speed; +extern u32 ctr_count[OP_MAX_COUNTERS]; +extern u8 ctr_event[OP_MAX_COUNTERS]; +extern u8 ctr_um[OP_MAX_COUNTERS]; static int showvers; int verbose; @@ -26,7 +29,7 @@ /* Unfortunately popt does not have, on many versions, the POPT_ARG_DOUBLE type * so I must first store it as a string. */ static const char *cpu_speed_str; -static int cpu_type; +u32 cpu_type; static int ignore_myself; static int opd_buf_size=OP_DEFAULT_BUF_SIZE; static char *opd_dir="/var/opd/"; @@ -48,7 +51,7 @@ static struct poptOption options[] = { { "buffer-size", 'b', POPT_ARG_INT, &opd_buf_size, 0, "nr. of entries in kernel buffer", "num", }, - { "use-cpu", 'p', POPT_ARG_INT, &cpu_type, 0, "0 for PPro, 1 for PII, 2 for PIII", "[0|1|2]" }, + { "use-cpu", 'p', POPT_ARG_INT, &cpu_type, 0, "0 for PPro, 1 for PII, 2 for PIII, 3 for Athlon", "[0|1|2|3]" }, { "ignore-myself", 'm', POPT_ARG_INT, &ignore_myself, 0, "ignore samples of oprofile driver", "[0|1]"}, { "log-file", 'l', POPT_ARG_STRING, &logfilename, 0, "log file", "file", }, { "base-dir", 'd', POPT_ARG_STRING, &opd_dir, 0, "base directory of daemon", "dir", }, @@ -152,7 +155,10 @@ { poptContext optcon; int ret; + int i, ok; char c; + /* should be sufficient to hold /proc/sys/dev/oprofile/%d/yyyy */ + char filename[PATH_MAX + 1]; /* Some old version of popt need the cast to char ** */ optcon = poptGetContext(NULL, argc, (char **)argv, options, 0); @@ -184,38 +190,49 @@ exit(1); } - footer.magic = OPD_MAGIC; - footer.version = OPD_VERSION; - footer.ctr0_type_val = opd_read_int_from_file("/proc/sys/dev/oprofile/0/event"); - footer.ctr0_um = (u8) opd_read_int_from_file("/proc/sys/dev/oprofile/0/unit_mask"); - footer.ctr1_type_val = opd_read_int_from_file("/proc/sys/dev/oprofile/1/event"); - footer.ctr1_um = (u8) opd_read_int_from_file("/proc/sys/dev/oprofile/1/unit_mask"); - - footer.ctr0_count = opd_read_int_from_file("/proc/sys/dev/oprofile/0/count"); - footer.ctr1_count = opd_read_int_from_file("/proc/sys/dev/oprofile/1/count"); + for (i = 0 ; i < op_nr_counters ; ++i) { + sprintf(filename, "/proc/sys/dev/oprofile/%d/event", i); + ctr_event[i]= opd_read_int_from_file(filename); - ret = op_check_events(footer.ctr0_type_val, footer.ctr1_type_val, footer.ctr0_um, footer.ctr1_um, cpu_type); + sprintf(filename, "/proc/sys/dev/oprofile/%d/count", i); + ctr_count[i]= opd_read_int_from_file(filename); - if (ret & OP_CTR0_NOT_FOUND) fprintf(stderr, "oprofiled: ctr0: %d: no such event\n",footer. ctr0_type_val); - if (ret & OP_CTR1_NOT_FOUND) fprintf(stderr, "oprofiled: ctr1: %d: no such event\n", footer.ctr1_type_val); - if (ret & OP_CTR0_NO_UM) fprintf(stderr, "oprofiled: ctr0: 0x%.2x: invalid unit mask\n", footer.ctr0_um); - if (ret & OP_CTR1_NO_UM) fprintf(stderr, "oprofiled: ctr1: 0x%.2x: invalid unit mask\n", footer.ctr1_um); - if (ret & OP_CTR0_NOT_ALLOWED) fprintf(stderr, "oprofiled: ctr0: %d: can't count event\n", footer.ctr0_type_val); - if (ret & OP_CTR1_NOT_ALLOWED) fprintf(stderr, "oprofiled: ctr1: %d: can't count event\n", footer.ctr1_type_val); - if (ret & OP_CTR0_PII_EVENT) fprintf(stderr, "oprofiled: ctr0: %d: event only available on PII\n", footer.ctr0_type_val); - if (ret & OP_CTR1_PII_EVENT) fprintf(stderr, "oprofiled: ctr1: %d: event only available on PII\n", footer.ctr1_type_val); - if (ret & OP_CTR0_PIII_EVENT) fprintf(stderr, "oprofiled: ctr0: %d: event only available on PIII\n", footer.ctr0_type_val); - if (ret & OP_CTR1_PIII_EVENT) fprintf(stderr, "oprofiled: ctr1: %d: event only available on PIII\n", footer.ctr1_type_val); - if (ret & OP_CTR0_ATHLON_EVENT) fprintf(stderr, "oprofiled: ctr0: %d: event only available on AMD Athlon\n", footer.ctr0_type_val); - if (ret & OP_CTR1_ATHLON_EVENT) fprintf(stderr, "oprofiled: ctr1: %d: event only available on AMD Athlon\n", footer.ctr1_type_val); + sprintf(filename, "/proc/sys/dev/oprofile/%d/unit_mask", i); + ctr_um[i]= opd_read_int_from_file(filename); + } - if (ret != OP_EVENTS_OK) { + cpu_type = opd_read_int_from_file("/proc/sys/dev/oprofile/cpu_type"); + + + ok = 1; + /* PHE FIXME : We need to translate cpu_type to a string, see + * cpu_typ_str in op_events.c */ + for (i = 0 ; i < op_nr_counters ; ++i) { + ret = op_check_events(i, ctr_event[i], ctr_um[i], cpu_type); + + if (ret & OP_EVT_NOT_FOUND) + fprintf(stderr, "oprofiled: ctr%d: %d: no such event for cpu %d\n", + i, ctr_event[i], cpu_type); + + if (ret & OP_EVT_NO_UM) + fprintf(stderr, "oprofiled: ctr%d: 0x%.2x: invalid unit mask for cpu %d\n", + i, ctr_um[i], cpu_type); + + if (ret & OP_EVT_CTR_NOT_ALLOWED) + fprintf(stderr, "oprofiled: ctr%d: %d: can't count event for this counter\n", + i, ctr_count[i]); + + if (ret != OP_EVENTS_OK) + ok = 0; + } + + if (!ok) { poptPrintHelp(optcon, stderr, 0); exit(1); } if (cpu_speed_str && strlen(cpu_speed_str)) { - sscanf(cpu_speed_str, "%lf", &footer.cpu_speed); + sscanf(cpu_speed_str, "%lf", &cpu_speed); } } @@ -339,7 +356,7 @@ struct op_mapping mapping; /* prevent signals from messing us up */ - sigprocmask(SIG_BLOCK, &maskset, NULL); + sigprocmask(SIG_UNBLOCK, &maskset, NULL); opd_stats[OPD_DUMP_COUNT]++; Index: oprofiled.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/oprofiled.h,v retrieving revision 1.30 retrieving revision 1.31 diff -u -d -r1.30 -r1.31 --- oprofiled.h 2001/08/19 20:09:17 1.30 +++ oprofiled.h 2001/09/01 02:03:34 1.31 @@ -61,9 +61,6 @@ #define streq(a,b) (!strcmp((a), (b))) #define streqn(a,b,n) (!strncmp((a), (b), (n))) -/* this char replaces '/' in sample filenames */ -#define OPD_MANGLE_CHAR '}' - /* maximum nr. of kernel modules */ #define OPD_MAX_MODULES 64 @@ -84,48 +81,20 @@ OPD_MAX_STATS /* end of stats */ }; -/* event check returns */ -#define OP_EVENTS_OK 0x0 -#define OP_CTR0_NOT_FOUND 0x1 -#define OP_CTR1_NOT_FOUND 0x2 -#define OP_CTR0_NO_UM 0x4 -#define OP_CTR1_NO_UM 0x8 -#define OP_CTR0_NOT_ALLOWED 0x10 -#define OP_CTR1_NOT_ALLOWED 0x20 -#define OP_CTR0_PII_EVENT 0x40 -#define OP_CTR1_PII_EVENT 0x80 -#define OP_CTR0_PIII_EVENT 0x100 -#define OP_CTR1_PIII_EVENT 0x200 -#define OP_CTR0_ATHLON_EVENT 0x400 -#define OP_CTR1_ATHLON_EVENT 0x800 - -/* FIXME : Carefull these are also present in pp/oprofpp.h */ -#define OPD_MAGIC 0xdeb6 -#define OPD_VERSION 0x4 - -/* at the end of the sample files */ -struct opd_footer { - u16 magic; - u16 version; - u8 is_kernel; - u8 ctr0_type_val; - u8 ctr1_type_val; - u8 ctr0_um; - u8 ctr1_um; - u8 reserved1[16]; - u32 ctr0_count; - u32 ctr1_count; - /* Set to 0.0 if not available */ - double cpu_speed; - time_t mtime; - /* binary compatibility reserve */ - u32 reserved2[31]; +struct opd_sample_file { + fd_t fd; + /* mapped memory begin here */ + struct opd_footer *footer; + /* start + sizeof(footer) ie. begin of map of samples */ + void *start; + /* the size of mapped memory comes from the opd_image */ }; struct opd_image { - fd_t fd; - void *start; + struct opd_sample_file sample_files[OP_MAX_COUNTERS]; + /* NOT counted the size of footer, to allow quick access check */ off_t len; + time_t mtime; /* image file mtime */ u8 kernel; char *name; }; @@ -155,8 +124,6 @@ struct opd_proc *prev; struct opd_proc *next; }; - -int op_check_events(u8 ctr0_type, u8 ctr1_type, u8 ctr0_um, u8 ctr1_um, int proc); void opd_get_ascii_procs(void); void opd_init_images(void); |
From: John L. <mov...@us...> - 2001-09-01 02:03:38
|
Update of /cvsroot/oprofile/oprofile/gui In directory usw-pr-cvs1:/tmp/cvs-serv19169/gui Modified Files: Makefile.in oprofile Log Message: philippe's huge patch Index: Makefile.in =================================================================== RCS file: /cvsroot/oprofile/oprofile/gui/Makefile.in,v retrieving revision 1.3 retrieving revision 1.4 diff -u -d -r1.3 -r1.4 --- Makefile.in 2001/08/18 16:11:17 1.3 +++ Makefile.in 2001/09/01 02:03:34 1.4 @@ -15,7 +15,7 @@ cd $(BINDIR) && chmod 755 oprofile uninstall: - rm -f $(BINDIR)/oprofile + -rm -f $(BINDIR)/oprofile @echo "---------------------------------------------------------------" @echo "The uninstall target does not remove your ~/.oprofile directory" @echo "---------------------------------------------------------------" Index: oprofile =================================================================== RCS file: /cvsroot/oprofile/oprofile/gui/oprofile,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- oprofile 2001/08/16 02:23:01 1.10 +++ oprofile 2001/09/01 02:03:34 1.11 @@ -18,20 +18,55 @@ # To manipulate the global var needed by each counter. set counter_setup_var { event_type counter unit_mask usr_count kernel_count } -# This list is here to avoid maintaining separate list for each processor -# type / counter number. It is the main data structure which describe all -# counter event. When adding new processor/event/counter only this data -# structure need update (adding counter require also work in the code). +set processor_type -1 +set title "" -# TODO : this must be shared in some way with op_events.c +# Fixme : Celeron Copermine string ?, how to != between a celeron with +# a PII core and a PIII core ? TODO look into the core source file. + +set cpuinfo_file [open /proc/cpuinfo r] +while { [gets $cpuinfo_file var] != -1 } { + + switch -regexp "$var" { + ".*Pentium Pro.*|.*PentiumPro.*" { set processor_type 0; set title "Pentium Pro" } + ".*Athlon.*|.*Duron.*|.*K7.*" { set processor_type 3; set title "K7/TB core" } + ".*Pentium III.*" { set processor_type 2; set title "Pentium III" } + ".*Coppermine.*" { set processor_type 2; set title "Pentium III (Coppermine)" } + ".*Celeron.*" { set processsor_type 2; set title "Pentium III (Coppermine)" } + ".*Pentium II.*" { set processor_type 1; set title "Pentium II" } + ".*Celeron.*" { set processor_type 1; set title "Celeron" } + } +} + +# Add this line later when the profiler core support the P4. +# ".*Pentium IV.*" { set processor_type 4; set title "Pentium IV" } + +close $cpuinfo_file + +if { [expr $processor_type == -1] } then { + set answer [tk_messageBox \ + -message "Cannot detect processor : default to P2" -type okcancel] + switch $answer { + cancel { exit 1 } + } + set processor_type 1 + set title "Pentium II" +} +# This list is the main data structure which describe all events available +# for this cpu_type. The list is build from the output of: +# op_help --gui-description +# When adding new processor/event/counter only data struct in op_events.c +# needs to be updated. +# # list entry item : # 1 event type/name # 2 bit mask # 1 : avail for PPro # 2 : avail for P2 # 4 : avail for P3 -# 8 : avail for P4 currently not supported. +# 8 : AMD K7/Duron +# 16 : avail for P4 currently not supported. # 3 bit mask # 1 : available for counter 0 # 2 : available for counter 1 @@ -45,291 +80,13 @@ # exclusive means than only one of the value can be passed to the profiler. # 7 the default value # 8 a list of : { unit_bit_mask_or_value string }+ -set event_type_list { - { DISABLED -1 -1 "Select it to disable this counter" 0 } - { CPU_CLK_UNHALTED 7 3 "Clock processor not halted" 6000 } - { DATA_MEM_REFS 7 3 "All memory reference, cachable and non" 500 } - { DCU_LINES_IN 7 3 "Total line allocated in DCU" 500 } - { DCU_M_LINES_IN 7 3 "Number of M state lines allocated in DCU" 500 } - { DCU_M_LINES_OUT 7 3 "Number of M lines evicted from the DCU" 500 } - { DCU_MISS_OUTSTANDING 7 3 "Number of cycles while DCU miss outstanding" 500 } - { IFU_IFETCH 7 3 "Number of non/cachable instruction fetches" 500 } - { IFU_IFETCH_MISS 7 3 "Number of instruction fetch misses" 500 } - { ITLB_MISS 7 3 "Number of ITLB misses" 500 } - { IFU_MEM_STALL 7 3 "Cycles instruction fetch pipe is stalled" 500 } - { ILD_STALL 7 3 "Cycles instruction length decoder is stalled" 500 } - { L2_IFETCH 7 3 "Number of L2 instruction fetches" 500 - bit_mask 15 - { - { 1 "(I)nvalid cache state" } - { 2 "(S)hared cache state" } - { 4 "(E)xclusive cache state" } - { 8 "(M)odified cache state" } - { 15 "MESI cache state" } - } - } - { L2_LD 7 3 "Number of L2 data load" 500 - bit_mask 15 - { - { 1 "(I)nvalid cache state" } - { 2 "(S)hared cache state" } - { 4 "(E)xclusive cache state" } - { 8 "(M)odified cache state" } - { 15 "MESI cache state" } - } - } - { L2_ST 7 3 "Number of L2 data stores" 500 - bit_mask 15 - { - { 1 "(I)nvalid cache state" } - { 2 "(S)hared cache state" } - { 4 "(E)xclusive cache state" } - { 8 "(M)odified cache state" } - { 15 "MESI cache state" } - } - } - { L2_LINES_IN 7 3 "Number of allocated lines in L2" 500 } - { L2_LINES_OUT 7 3 "Number of recovered lines from L2" 500 } - { L2_M_LINES_INM 7 3 "Number of modified lines allocated in L2" 500 } - { L2_M_LINES_OUTM 7 3 "Number of modified lines removed from L2" 500 } - { L2_RQSTS 7 3 "Number of L2 requests" 500 - bit_mask 15 - { - { 1 "(I)nvalid cache state" } - { 2 "(S)hared cache state" } - { 4 "(E)xclusive cache state" } - { 8 "(M)odified cache state" } - { 15 "MESI cache state" } - } - } - { L2_ADS 7 3 "Number of L2 address strobes" 500 } - { L2_DBUS_BUSY 7 3 "Number of cycles data bus was busy" 500 } - { L2_DMUS_BUSY_RD 7 3 "Cycles data bus was busy in xfer from L2 to cpu" 500 } - { BUS_DRDY_CLOCKS 7 3 "Number of clocks DRDY is asserted" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_LOCK_CLOCKS 7 3 "Number of clocks LOCK is asserted" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_REQ_OUTSTANDING 7 3 "Number of outstanding bus request" 500 } - { BUS_TRAN_BRD 7 3 "Number of burst read transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRAN_RFO 7 3 "Number of read for ownership transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRANS_WB 7 3 "Number of write back transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRAN_IFETCH 7 3 "Number of instruction fetch transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRAN_INVAL 7 3 "Number of invalid transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRAN_PWR 7 3 "Number of partial write transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRANS_P 7 3 "Number of partial transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRANS_IO 7 3 "Number of I/O transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRANS_DEF 7 3 "Number of deferred transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRAN_BURST 7 3 "Number of burst transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRAN_ANY 7 3 "Number of all transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_TRAN_MEM 7 3 "Number of memory transactions" 500 - exclusive 32 - { - { 0 "self-generated transactions" } - { 32 "any transitions" } - } - } - { BUS_DATA_RCV 7 3 "Bus cycles this processor is receiving data" 500 } - { BUS_BNR_DRV 7 3 "bus cycles this processor is driving BNR pin" 500 } - { BUS_HIT_DRV 7 3 "bus cycles this processor is driving HIT pin" 500 } - { BUS_HITM_DRV 7 3 "bus cycles this processor is driving HITM pin" 500 } - { BUS_SNOOP_STALL 7 3 "cycles during bus snoop stall" 500 } - { COMP_FLOP_RET 7 1 - "Number of computational FP operations retired - Counter 0 only" 3000 } - { FLOPS 7 1 - "Number of computational FP operations executed - Counter 0 only" 3000 } - { FP_ASSIST 7 2 - "Number of exceptions handled by microcode - Counter 1 only" 500 } - { MUL 7 2 "Number of multiplies - Counter 1 only" 1000 } - { DIV 7 2 "Number of divides - Counter 1 only" 500 } - { CYCLES_DIV_BUSY 7 1 "Cycles divider is busy - Counter 0 only" 1000 } - { LD_BLOCKS 7 3 "Number of store blocks" 500 } - { SB_DRAINS 7 3 "Number of store buffer drain cycles" 500 } - { MISALIGN_MEM_REF 7 3 "Number of misaligned data memory references" 500 } - { EMON_KNI_PREF_DISPATCHED 4 3 - "Number KNI pre-fetch/weakly ordered insns dispatch - P3 only" 500 - exclusive 0 - { - { 0 "Prefecth NTA" } - { 1 "Prefetch T1" } - { 2 "Prefetch T2" } - { 3 "weakly ordered stores" } - } - } - { EMON_KNI_PREF_MISS 4 3 - "Number KNI pre-fetch/weakly ordered insns that miss all cache - P3 only" 500 - exclusive 0 - { - { 0 "Prefecth NTA" } - { 1 "Prefetch T1" } - { 2 "Prefetch T2" } - { 3 "weakly ordered stores" } - } - } - { INST_RETIRED 7 3 "Number of instructions retired" 6000 } - { UOPS_RETIRED 7 3 "Number of UOPs retired" 6000 } - { INST_DECODED 7 3 "Number of instructions decoded" 6000 } - { EMON_KNI_INST_RETIRED 4 3 "Number of KNI instructions retired - P3 only" 3000 - exclusive 0 - { - { 0 "Packed and scalar" } - { 1 "Packed" } - } - } - { EMON_KNI_COMP_INST_RET 4 3 - "Number of KNI instructions computation retired - P3 only" 3000 - exclusive 0 - { - { 0 "Packed and scalar" } - { 1 "Packed" } - } - } - { HW_INT_RX 7 3 "Number of hardware interrupts received" 500 } - { CYCLES_INT_MASKED 7 3 "Cycles interrupt are disabled" 500 } - { CYCLES_INT_PENDING_AND_MASKED 7 3 - "Cycles interrupts are disabled with pending interrupts" 500 } - { BR_INST_RETIRED 7 3 "Number of branch instructions retired" 500 } - { BR_MISS_PRED_RETIRED 7 3 "Number of mispredicted branches retired" 500 } - { BR_TAKEN_RETIRED 7 3 "Number of taken branches retired" 500 } - { BR_MISS_PRED_TAKEN_RET 7 3 - "Number of taken mispredictions branches retired" 500 } - { BR_INST_DECODED 7 3 "Number of branches instructions decoded" 500 } - { BTB_MISSES 7 3 "Number of branches that miss the BTB" 500 } - { BR_BOGUS 7 3 "Number of bogus branches" 500 } - { BACLEARS 7 3 "Number of times BACLEAR is asserted" 500 } - { RESOURCE_STALLS 7 3 "Cycles during resource related stalls" 500 } - { PARTIAL_RAT_STALLS 7 3 "cycles or event for partial stalls" 500 } - { SEGMENT_REG_LOADS 7 3 "Number of segment register loads" 500 } - { MMX_INSTR_EXEC 2 3 "Number of MMX instructions executed - P2 only" 3000 } - { MMX_SAT_INSTR_EXEC 6 3 - "Number of MMX saturating instructions executed - P2/P3 only" 3000 } - { MMX_UOPS_EXEC 6 3 "Number of MMX UOPs executed - P2/P3 only" 3000 - mandatory 15 - { - { 15 "Mandatory" } - } - } - { MMX_INSTR_TYPE_EXEC 6 3 "Number of MMX packing instructions - P2/P3 only" 3000 - bit_mask 63 - { - { 1 "MMX packed multiplies" } - { 2 "MMX packed shifts" } - { 4 "MMX pack operations" } - { 8 "MMX unpack operations" } - { 16 "MMX packed logical" } - { 32 "MMX packed arithmetic" } - { 63 "MMX pack/unpack and all operations" } - } - } - { FP_MMX_TRANS 6 3 "MMX-floating point transitions - P2/P3 only" 3000 - exclusive 0 - { - { 0 "Transitions from MMX to floating point" } - { 1 "Transitions from floating point to MMX" } - } - } - { MMX_ASSIST 6 3 "Number of EMMS instructions executed - P2/P3 only" 500 } - { MMX_INSTR_RET 2 3 "Number of MMX instructions retired - P2 only" 3000 } - { SEG_RENAME_STALLS 6 3 - "Number of segment register renaming stalls - P2/P3 only" 3000 - bit_mask 15 - { - { 1 "ES register" } - { 2 "DS register" } - { 4 "FS register" } - { 8 "GS register" } - { 15 "ES, DS, FS, GS register" } - } - } - { SEG_REG_RENAMES 6 3 "Number of segment register renames - P2/P3 only" 3000 - bit_mask 15 - { - { 1 "ES register" } - { 2 "DS register" } - { 4 "FS register" } - { 8 "GS register" } - { 15 "ES, DS, FS, GS register" } - } - } - { RET_SEG_RENAMES 6 3 - "Number of segment register rename events retired - P2/P3 only" 3000 } -} +# +# use op_help --gui-description to see the exact format +#set processor_type 3 + +set event_type_list [exec op_help --gui-description --cpu-type=$processor_type] + # This is defined in oprofile.h set OP_MAX_PERF_COUNT 2147483647 @@ -358,8 +115,6 @@ } } -set event_type_0 "CPU_CLK_UNHALTED" - # In some situation it is incorrect to get the System.map and kernel # filename from here but this provide a correct default value in many case. set build_dir /lib/modules/[exec uname -r]/build @@ -1408,7 +1163,6 @@ # The main procedure. proc setup_event_frame { } { - create_event_frame .f_event_type 0 create_event_frame .f_event_type 1 @@ -1439,6 +1193,10 @@ } } + set width [expr ([winfo reqw $f.f] + [winfo reqw $f.sb1] + 4) * 2] + set height [expr [winfo screenh .] * 3 / 4] + wm geometry . ${width}x${height} + # see comment on wm withdraw and update idletasks wm deiconify . } @@ -1452,9 +1210,6 @@ # TODO : put all this code in setup_event_frame -# TODO : how to get dynamically the correct width ? -wm geometry . 576x600 - frame .f_config_and_start_stop set f .f_config_and_start_stop @@ -1466,7 +1221,7 @@ frame .f_unit_mask -borderwidth 2 -relief sunken create_text . status_bar 1 1 -pack .status_bar -side bottom -anchor w -fill y -expand yes +pack .status_bar -side bottom -anchor w -fill both -expand yes bind . <Motion> { onMouseMotion %W } @@ -1489,38 +1244,6 @@ pack $f.b_advanced_setup $f.b_default_setup $f.b_quit_and_save_setup \ -side left -expand yes - -set processor_type -1 -set title "" - -# Fixme : Celeron Copermine string ?, how to != between a celeron with -# a PII core and a PIII core ? TODO look into the core source file. - -set cpuinfo_file [open /proc/cpuinfo r] -while { [gets $cpuinfo_file var] != -1 } { - - switch -regexp "$var" { - ".*Pentium Pro .*" { set processor_type 0; set title "Pentium Pro" } - ".*Pentium II .*" { set processor_type 1; set title "Pentium II" } - ".*Celeron .*" { set processor_type 1; set title "Celeron" } - ".*Pentium III .*" { set processor_type 2; set title "Pentium III" } - } -} - -# Add this line later when the profiler core support the P4. -# ".*Pentium IV .*" { set processor_type 3; set title "Pentium IV" } - -close $cpuinfo_file - -if { [expr $processor_type == -1] } then { - set answer [tk_messageBox \ - -message "Cannot detect processor : default to P2" -type okcancel] - switch $answer { - cancel { exit 1 } - } - set processor_type 1 - set title "Pentium II" -} wm title . "Profiling option for $title processor" |
From: John L. <mov...@us...> - 2001-08-31 17:16:38
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv5151 Modified Files: ChangeLog Makefile.in oprofile.c oprofile.h Added Files: op_x86.c Log Message: mptable parse --- NEW FILE: op_x86.c --- /* * op_x86.c * * A variety of Intel hardware grubbery. * * Based in part on arch/i386/kernel/mpparse.c */ #include <linux/mm.h> #include <linux/init.h> #include <linux/config.h> #include <asm/smp.h> #include <asm/mpspec.h> #include <asm/io.h> static int __init mpf_checksum(unsigned char *mp, int len) { int sum = 0; while (len--) sum += *mp++; return sum & 0xFF; } static int __init mpf_table_ok(struct intel_mp_floating * mpf, unsigned long *bp) { if (*bp != SMP_MAGIC_IDENT) return 0; if (mpf->mpf_length != 1) return 0; if (mpf_checksum((unsigned char *)bp, 16)) return 0; return (mpf->mpf_specification == 1 || mpf->mpf_specification == 4); } static int __init smp_scan_config (unsigned long base, unsigned long length) { unsigned long *bp = phys_to_virt(base); struct intel_mp_floating *mpf; while (length > 0) { mpf = (struct intel_mp_floating *)bp; if (mpf_table_ok(mpf, bp)) return 1; bp += 4; length -= 16; } return 0; } int __init find_intel_smp (void) { unsigned int address; /* * FIXME: Linux assumes you have 640K of base ram.. * this continues the error... * * 1) Scan the bottom 1K for a signature * 2) Scan the top 1K of base RAM * 3) Scan the 64K of bios */ if (smp_scan_config(0x0,0x400) || smp_scan_config(639*0x400,0x400) || smp_scan_config(0xF0000,0x10000)) return 1; /* * If it is an SMP machine we should know now, unless the * configuration is in an EISA/MCA bus machine with an * extended bios data area. * * there is a real-mode segmented pointer pointing to the * 4K EBDA area at 0x40E, calculate and scan it here. * * NOTE! There are Linux loaders that will corrupt the EBDA * area, and as such this kind of SMP config may be less * trustworthy, simply because the SMP table may have been * stomped on during early boot. These loaders are buggy and * should be fixed. */ address = *(unsigned short *)phys_to_virt(0x40E); address <<= 4; return smp_scan_config(address, 0x1000); } Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.90 retrieving revision 1.91 diff -u -d -r1.90 -r1.91 --- ChangeLog 2001/08/20 20:05:19 1.90 +++ ChangeLog 2001/08/31 17:16:35 1.91 @@ -1,3 +1,11 @@ +2001-08-31 John Levon <mo...@co...> + + * Makefile.in: + * op_x86.c: + * oprofile.h: + * oprofile.c: a prototype detector for SMP hardware, + some small cleanup + 2001-08-20 Dave Jones <da...@su...> * doc/oprofile.sgml: Index: Makefile.in =================================================================== RCS file: /cvsroot/oprofile/oprofile/Makefile.in,v retrieving revision 1.23 retrieving revision 1.24 diff -u -d -r1.23 -r1.24 --- Makefile.in 2001/08/18 16:11:17 1.23 +++ Makefile.in 2001/08/31 17:16:35 1.24 @@ -74,8 +74,8 @@ KCFLAGS := $(BKCFLAGS) -march=i686 ASMFLAGS := -D__ASSEMBLY__ -DMODULE -D__KERNEL__ -traditional -oprofile.o: op_init.o oprofile_c.o oprofile_nmi.o op_syscalls.o op_events.o - ld -r -o $@ op_init.o oprofile_c.o oprofile_nmi.o op_syscalls.o op_events.o +oprofile.o: op_init.o oprofile_c.o oprofile_nmi.o op_syscalls.o op_events.o op_x86.o + ld -r -o $@ op_init.o oprofile_c.o oprofile_nmi.o op_syscalls.o op_events.o op_x86.o oprofile.h: op_user.h version.h @@ -83,6 +83,9 @@ $(CC) $(BKCFLAGS) -c -o $@ $< oprofile_c.o: oprofile.c oprofile.h + $(CC) $(KCFLAGS) -c -o $@ $< + +op_x86.o: op_x86.c $(CC) $(KCFLAGS) -c -o $@ $< op_syscalls.o: op_syscalls.c oprofile.h Index: oprofile.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.c,v retrieving revision 1.74 retrieving revision 1.75 diff -u -d -r1.74 -r1.75 --- oprofile.c 2001/08/20 19:46:13 1.74 +++ oprofile.c 2001/08/31 17:16:35 1.75 @@ -50,6 +50,7 @@ static u32 prof_on __cacheline_aligned; +static int smp_hardware; static int op_major; int cpu_type; @@ -261,48 +262,15 @@ apic_write(APIC_LVTPC, old_lvtpc[smp_processor_id()]); } -/* PHE bit 8 of APIC_BASE_MSR is the BSP flags, it is set by harware at boot - * up sequence and would be keeped ok by software to allow #INIT or #ERR, else - * all the processor on the next MP sequence fall in shutdown. - * - * On UP architecture it should always be zero (ok for my PII) 7.4.8 (7.5.8), - * I am unsure but I have presumption than kernel cannot boot properly if bsp - * flags is set on UP machine. - * - * I think it is ok in all case, perhaps corner case on SMP with only one - * processor plugged ? - */ -inline static int is_bsp_proc(void) -{ - uint l; - uint h; - rdmsr(MSR_IA32_APICBASE, l, h); - wrmsr(MSR_IA32_APICBASE, l & ~(1<<11), h); - - return (h & (1 << 8)) ? 1 : 0; -} - static int __init apic_needs_setup(void) { - /* FIXME: we need to detect UP kernel, SMP hardware, and - * return 0 here, to avoid screwing up the APIC - */ - /* PHE: for UP kernel SMP machine this processor should have the bsp - * flags set, something like: - -#ifndef X86_UP_APIC - if (smp_num_cpus == 1) { - return !is_bsp_proc(); - } -#endif - return 0; - - would work - */ return /* if enabled, the kernel has already set it up */ #ifdef CONFIG_X86_UP_APIC 0 && +#else +/* otherwise, we detect SMP hardware via the MP table */ + !smp_hardware && #endif smp_num_cpus == 1; } @@ -320,10 +288,12 @@ uint val; if (!apic_needs_setup()) { + printk(KERN_INFO "oprofile: no APIC setup needed.\n"); lvtpc_apic_setup(NULL); return 0; } + printk(KERN_INFO "oprofile: setting up APIC.\n"); /* ugly hack */ /* PHE : the memory must be uncachable! this is perhaps more a @@ -555,8 +525,7 @@ { int i; - threadpid = current->pid; - + // FIXME: kernel lock ? daemonize(); sprintf(current->comm, "oprof-thread"); siginitsetinv(¤t->blocked, sigmask(SIGKILL)); @@ -575,6 +544,7 @@ /* FIXME: determine best value here */ schedule_timeout(HZ/10); + // FIXME: signal pending if (diethreaddie) break; } @@ -587,7 +557,7 @@ { init_completion(&threadstop); diethreaddie = 0; - if (kernel_thread(oprof_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND)<0) + if ((threadpid = kernel_thread(oprof_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND)) < 0) printk(KERN_ERR "oprofile: couldn't spawn wakeup thread.\n"); } @@ -1186,7 +1156,9 @@ { int err; - printk(KERN_INFO "%s\n",op_version); + printk(KERN_INFO "%s\n", op_version); + + smp_hardware = find_intel_smp(); if ((err = apic_setup())) return err; Index: oprofile.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.h,v retrieving revision 1.46 retrieving revision 1.47 diff -u -d -r1.46 -r1.47 --- oprofile.h 2001/08/19 20:09:17 1.46 +++ oprofile.h 2001/08/31 17:16:35 1.47 @@ -32,6 +32,9 @@ /* userspace/module interface */ #include "op_user.h" +#undef min +#undef max + #define OP_NR_ENTRY (SMP_CACHE_BYTES/sizeof(struct op_sample)) struct op_entry { @@ -226,6 +229,7 @@ extern uint ctrreg3; int oprof_init(void); +int find_intel_smp(void); void oprof_exit(void); void my_set_fixmap(void); int op_min_count(u8 ctr_type); |
From: Dave J. <da...@us...> - 2001-08-20 20:05:22
|
Update of /cvsroot/oprofile/oprofile/doc In directory usw-pr-cvs1:/tmp/cvs-serv31594/doc Modified Files: oprofile.sgml Log Message: Film at 11: Programmer updates documentation. Index: oprofile.sgml =================================================================== RCS file: /cvsroot/oprofile/oprofile/doc/oprofile.sgml,v retrieving revision 1.20 retrieving revision 1.21 diff -u -d -r1.20 -r1.21 --- oprofile.sgml 2001/08/18 16:11:17 1.20 +++ oprofile.sgml 2001/08/20 20:05:19 1.21 @@ -53,11 +53,15 @@ </para></listitem> </varlistentry> <varlistentry> - <term>Intel P6 processor</term> + <term>Intel P6 processor or AMD Athlon/Duron.</term> <listitem><para> - An Intel P6 processor is required. In marketing terms this translates to anything between a Pentium Pro - (NOT Pentium Classics) and a Pentium III. Specifically, Pentium IVs are not yet supported due to different - hardware. Also note that Mobile P6 processors lack the necessary CPU features and are also not supported. + A CPU with a P6 generation core is required. In marketing terms this translates to anything between an Intel + Pentium Pro (NOT Pentium Classics) and a Pentium III. Specifically, Pentium IVs are not yet supported due to + different hardware. + Also note that Mobile P6 processors lack the necessary CPU features and are also not supported. + The AMD Athlon & Duron CPUs are also supported, as their <acronym>APIC</acronym> and performance counters + are very similar. These CPUs offer 4 seperate counters as opposed to the 2 provided by the Intel P6 family. + OProfile currently only supports using 2 of these available counters. </para></listitem> </varlistentry> <varlistentry> @@ -334,8 +338,8 @@ <varlistentry> <term><option>--use-cpu</option></term> <listitem><para> - Specify 0 for Pentium Pros, 1 for Pentium II and 2 for Pentium III. This is only needed if you use - an event not available on the Pentium Pro. + Specify 0 for Pentium Pros, 1 for Pentium II, 2 for Pentium III and 3 for AMD Athlon/Duron. + This is only needed if you use an event not available on the Pentium Pro. </para></listitem> </varlistentry> <varlistentry> @@ -379,9 +383,11 @@ <title>Intel P6 Performance Counters</title> <para> The hardware performance counters are detailed in the Intel IA-32 Architecture Manual, Volume 3, available -from <ulink url="http://developer.intel.com/">http://developer.intel.com/</ulink>. P6-core processors are capable -of delivering an interrupt to the local <acronym>APIC</acronym> <acronym>LVTPC</acronym> vector -when a counter overflows. This is the basic mechanism on which OProfile is based. The kernel module +from <ulink url="http://developer.intel.com/">http://developer.intel.com/</ulink>. The AMD Athlon/Duron +implementation is detailed in <ulink url="http://www.amd.com/products/cpg/athlon/techdocs/pdf/22007.pdf"> +http://www.amd.com/products/cpg/athlon/techdocs/pdf/22007.pdf</ulink>. +P6-core processors are capable of delivering an interrupt to the local <acronym>APIC</acronym> <acronym>LVTPC</acronym> +vector when a counter overflows. This is the basic mechanism on which OProfile is based. The kernel module installs an interrupt handler for this vector. The delivery mode is set to <acronym>NMI</acronym> so that blocking interrupts in the kernel does not prevent profiling. When the interrupt handler is called, the current <acronym>EIP</acronym> <acronym>PC</acronym> value, process id, and counter (there are only |
From: Dave J. <da...@us...> - 2001-08-20 20:05:22
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv31594 Modified Files: ChangeLog Log Message: Film at 11: Programmer updates documentation. Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.89 retrieving revision 1.90 diff -u -d -r1.89 -r1.90 --- ChangeLog 2001/08/20 19:49:54 1.89 +++ ChangeLog 2001/08/20 20:05:19 1.90 @@ -1,5 +1,7 @@ 2001-08-20 Dave Jones <da...@su...> + * doc/oprofile.sgml: + Updated to reflect new Athlon/Duron capabilities. * pp/oprof_convert.c: * pp/oprofpp.c: use EXIT_FAILURE | EXIT_SUCCESS in exit() calls. |
From: Dave J. <da...@us...> - 2001-08-20 19:49:57
|
Update of /cvsroot/oprofile/oprofile/pp In directory usw-pr-cvs1:/tmp/cvs-serv24720/pp Modified Files: oprof_convert.c Log Message: Oops. Missed these ones. More EXIT_FAILURE | EXIT_SUCCESS changes. Index: oprof_convert.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/oprof_convert.c,v retrieving revision 1.7 retrieving revision 1.8 diff -u -d -r1.7 -r1.8 --- oprof_convert.c 2001/07/27 23:22:39 1.7 +++ oprof_convert.c 2001/08/20 19:49:54 1.8 @@ -237,20 +237,20 @@ if (argc <= 1) { fprintf(stderr, "Syntax: %s filename [filenames]\n", argv[0]); - exit(1); + exit(EXIT_FAILURE); } /* Should use popt in future if new options are added */ if (strcmp(argv[1], "--version") == 0 || strcmp(argv[1], "-v") == 0) { printf("%s : " VERSION_STRING " compiled on " __DATE__ " " __TIME__ "\n", argv[0]); - exit(0); + exit(EXIT_SUCCESS); } if (strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0) { printf("Syntax : %s filename [filenames]\n", argv[0]); - exit(0); + exit(EXIT_SUCCESS); } for (i = 1 ; i < argc ; ++i) { |
From: Dave J. <da...@us...> - 2001-08-20 19:49:57
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv24720 Modified Files: ChangeLog Log Message: Oops. Missed these ones. More EXIT_FAILURE | EXIT_SUCCESS changes. Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.88 retrieving revision 1.89 diff -u -d -r1.88 -r1.89 --- ChangeLog 2001/08/20 19:46:13 1.88 +++ ChangeLog 2001/08/20 19:49:54 1.89 @@ -1,5 +1,6 @@ 2001-08-20 Dave Jones <da...@su...> + * pp/oprof_convert.c: * pp/oprofpp.c: use EXIT_FAILURE | EXIT_SUCCESS in exit() calls. * oprofile.c: Make non-exported functions static |
From: Dave J. <da...@us...> - 2001-08-20 19:46:17
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv23028 Modified Files: ChangeLog oprofile.c Log Message: * pp/oprofpp.c: use EXIT_FAILURE | EXIT_SUCCESS in exit() calls. * oprofile.c: Make non-exported functions static and remove some duplicate definitions. Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.87 retrieving revision 1.88 diff -u -d -r1.87 -r1.88 --- ChangeLog 2001/08/19 20:23:02 1.87 +++ ChangeLog 2001/08/20 19:46:13 1.88 @@ -1,3 +1,10 @@ +2001-08-20 Dave Jones <da...@su...> + + * pp/oprofpp.c: use EXIT_FAILURE | EXIT_SUCCESS + in exit() calls. + * oprofile.c: Make non-exported functions static + and remove duplicate definitions. + 2001-08-19 John Levon <mo...@co...> * dae/op_start: handle celeries in cpu type Index: oprofile.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.c,v retrieving revision 1.73 retrieving revision 1.74 diff -u -d -r1.73 -r1.74 --- oprofile.c 2001/08/19 20:09:17 1.73 +++ oprofile.c 2001/08/20 19:46:13 1.74 @@ -39,16 +39,16 @@ pid_t pgrp_filter; /* the MSRs we need */ -uint ctrlreg0 = MSR_IA32_EVNTSEL0; -uint ctrlreg1 = MSR_IA32_EVNTSEL1; -uint ctrlreg2 = MSR_K7_PERFCTL2; -uint ctrlreg3 = MSR_K7_PERFCTL3; -uint ctrreg0 = MSR_IA32_PERFCTR0; -uint ctrreg1 = MSR_IA32_PERFCTR1; -uint ctrreg2 = MSR_K7_PERFCTR2; -uint ctrreg3 = MSR_K7_PERFCTR3; +static u32 ctrlreg0 = MSR_IA32_EVNTSEL0; +static u32 ctrlreg1 = MSR_IA32_EVNTSEL1; +static u32 ctrlreg2 = MSR_K7_PERFCTL2; +static u32 ctrlreg3 = MSR_K7_PERFCTL3; +static u32 ctrreg0 = MSR_IA32_PERFCTR0; +static u32 ctrreg1 = MSR_IA32_PERFCTR1; +static u32 ctrreg2 = MSR_K7_PERFCTR2; +static u32 ctrreg3 = MSR_K7_PERFCTR3; -u32 prof_on __cacheline_aligned; +static u32 prof_on __cacheline_aligned; static int op_major; int cpu_type; @@ -61,15 +61,6 @@ extern spinlock_t map_lock; -extern unsigned int ctrlreg0; -extern unsigned int ctrlreg1; -extern unsigned int ctrlreg2; -extern unsigned int ctrlreg3; -extern unsigned int ctrreg0; -extern unsigned int ctrreg1; -extern unsigned int ctrreg2; -extern unsigned int ctrreg3; - /* ---------------- NMI handler ------------------ */ /* FIXME: this whole handler would probably be better in straight asm */ @@ -152,14 +143,14 @@ /* this masking code is unsafe and nasty but might deal with the small * race when installing the NMI entry into the IDT */ -void mask_lvtpc(void * e) +static void mask_lvtpc(void * e) { ulong v = apic_read(APIC_LVTPC); lvtpc_masked = v & APIC_LVT_MASKED; apic_write(APIC_LVTPC, v | APIC_LVT_MASKED); } -void unmask_lvtpc(void * e) +static void unmask_lvtpc(void * e) { if (!lvtpc_masked) apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED); @@ -560,7 +551,7 @@ /* we have to have another thread because we can't * do wake_up() from NMI due to no locking */ -int oprof_thread(void *arg) +static int oprof_thread(void *arg) { int i; @@ -592,7 +583,7 @@ return 0; } -void oprof_start_thread(void) +static void oprof_start_thread(void) { init_completion(&threadstop); diethreaddie = 0; @@ -600,7 +591,7 @@ printk(KERN_ERR "oprofile: couldn't spawn wakeup thread.\n"); } -void oprof_stop_thread(void) +static void oprof_stop_thread(void) { diethreaddie = 1; kill_proc(SIGKILL, threadpid, 1); @@ -1124,7 +1115,7 @@ /* NOTE: we do *not* support sysctl() syscall */ -int __init init_sysctl(void) +static int __init init_sysctl(void) { ctl_table *next = &oprof_table[nr_oprof_static]; ctl_table *counter_table[OP_MAX_COUNTERS + 1]; @@ -1166,7 +1157,7 @@ return -EFAULT; } -void __exit cleanup_sysctl(void) +static void __exit cleanup_sysctl(void) { int i; ctl_table *next = &oprof_table[nr_oprof_static]; |
From: Dave J. <da...@us...> - 2001-08-20 19:46:17
|
Update of /cvsroot/oprofile/oprofile/pp In directory usw-pr-cvs1:/tmp/cvs-serv23028/pp Modified Files: oprofpp.c Log Message: * pp/oprofpp.c: use EXIT_FAILURE | EXIT_SUCCESS in exit() calls. * oprofile.c: Make non-exported functions static and remove some duplicate definitions. Index: oprofpp.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/oprofpp.c,v retrieving revision 1.35 retrieving revision 1.36 diff -u -d -r1.35 -r1.36 --- oprofpp.c 2001/07/25 03:51:33 1.35 +++ oprofpp.c 2001/08/20 19:46:13 1.36 @@ -120,19 +120,19 @@ poptBadOption(optcon, POPT_BADOPTION_NOALIAS), poptStrerror(c)); poptPrintHelp(optcon, stderr, 0); - exit(1); + exit(EXIT_FAILURE); } if (showvers) { printf(VERSION_STRING " compiled on " __DATE__ " " __TIME__ "\n"); - exit(0); + exit(EXIT_SUCCESS); } if (!list_all_symbols_details && !list_symbols && !gproffile && !symbol) { fprintf(stderr, "oprofpp: no mode specified. What do you want from me ?\n"); poptPrintHelp(optcon, stderr, 0); - exit(1); + exit(EXIT_FAILURE); } /* non-option file, either a sample or binary image file */ @@ -159,7 +159,7 @@ if (!imagefile) { fprintf(stderr, "oprofpp: no samples file specified.\n"); poptPrintHelp(optcon, stderr, 0); - exit(1); + exit(EXIT_FAILURE); } else { /* we'll "leak" this memory */ samplefile = remangle(imagefile); @@ -264,19 +264,19 @@ fprintf(stderr, "oprofpp: the last modified time of the binary file %s does not match " "that of the sample file. Either this is the wrong binary or the binary " "has been modified since the sample file was created.\n", file); - exit(1); + exit(EXIT_FAILURE); } ibfd = bfd_openr(file, NULL); if (!ibfd) { fprintf(stderr,"oprofpp: bfd_openr of %s failed.\n", file); - exit(1); + exit(EXIT_FAILURE); } if (!bfd_check_format_matches(ibfd, bfd_object, &matching)) { fprintf(stderr,"oprofpp: BFD format failure for %s.\n", file); - exit(1); + exit(EXIT_FAILURE); } if (!imagefile) @@ -305,7 +305,7 @@ { if (num - sect_offset > num) { fprintf(stderr,"oprofpp: less than zero offset ? \n"); - exit(1); + exit(EXIT_FAILURE); } /* adjust for kernel images */ @@ -476,7 +476,7 @@ if (!num) { fprintf(stderr, "oprofpp: couldn't get any symbols from image file.\n"); - exit(1); + exit(EXIT_FAILURE); } @@ -487,11 +487,11 @@ get_symbol_range(syms[i], (i == num-1) ? NULL : syms[i+1], &start, &end); if (start >= nr_samples) { fprintf(stderr,"oprofpp: start 0x%x out of range (max 0x%x)\n", start, nr_samples); - exit(1); + exit(EXIT_FAILURE); } if (end > nr_samples) { fprintf(stderr,"oprofpp: end 0x%x out of range (max 0x%x)\n", end, nr_samples); - exit(1); + exit(EXIT_FAILURE); } for (j = start; j < end; j++) { @@ -542,7 +542,7 @@ if (!num) { fprintf(stderr, "oprofpp: couldn't get any symbols from image file.\n"); - exit(1); + exit(EXIT_FAILURE); } for (i=0; i < num; i++) { @@ -599,7 +599,7 @@ if (!num) { fprintf(stderr, "oprofpp: couldn't get any symbols from image file.\n"); - exit(1); + exit(EXIT_FAILURE); } fp=opd_open_file(gproffile, "w"); @@ -727,7 +727,7 @@ if (!num) { fprintf(stderr, "oprofpp: couldn't get any symbols from image file.\n"); - exit(1); + exit(EXIT_FAILURE); } for (i = 0 ; i < num ; ++i) { @@ -797,28 +797,28 @@ fp = fopen(samplefile,"r"); if (!fp) { fprintf(stderr, "oprofpp: fopen of %s failed. %s\n", samplefile, strerror(errno)); - exit(1); + exit(EXIT_FAILURE); } if (fseek(fp, -sizeof(struct opd_footer), SEEK_END) == -1) { fprintf(stderr, "oprofpp: fseek of %s failed. %s\n", samplefile, strerror(errno)); - exit(1); + exit(EXIT_FAILURE); } if (fread(&footer, sizeof(struct opd_footer), 1, fp) != 1) { fprintf(stderr, "oprofpp: fread of %s failed. %s\n", samplefile, strerror(errno)); - exit(1); + exit(EXIT_FAILURE); } fclose(fp); if (footer.magic != OPD_MAGIC) { fprintf(stderr, "oprofpp: wrong magic 0x%x, expected 0x%x.\n", footer.magic, OPD_MAGIC); - exit(1); + exit(EXIT_FAILURE); } if (footer.version != OPD_VERSION) { fprintf(stderr, "oprofpp: wrong version 0x%x, expected 0x%x.\n", footer.version, OPD_VERSION); - exit(1); + exit(EXIT_FAILURE); } if (footer.ctr0_type_val) { @@ -839,7 +839,7 @@ if (fd == -1) { fprintf(stderr, "oprofpp: Opening %s failed. %s\n", samplefile, strerror(errno)); - exit(1); + exit(EXIT_FAILURE); } size = opd_get_fsize(samplefile, 1) - sizeof(struct opd_footer); @@ -847,7 +847,7 @@ if (samples == (void *)-1) { fprintf(stderr, "oprofpp: mmap of %s failed. %s\n", samplefile, strerror(errno)); - exit(1); + exit(EXIT_FAILURE); } nr_samples = size/sizeof(struct opd_fentry); |
From: John L. <mov...@us...> - 2001-08-19 20:23:05
|
Update of /cvsroot/oprofile/oprofile/dae In directory usw-pr-cvs1:/tmp/cvs-serv6244/dae Modified Files: op_start Log Message: recognise celerons in cpu type Index: op_start =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/op_start,v retrieving revision 1.35 retrieving revision 1.36 diff -u -d -r1.35 -r1.36 --- op_start 2001/08/19 20:09:17 1.35 +++ op_start 2001/08/19 20:23:02 1.36 @@ -57,7 +57,15 @@ *Athlon* | *Duron* | *K7*) CPUTYPE=3 ;; + # FIXME: I'm not sure this is right ... + *Coppermine*) + CPUTYPE=2 + ;; + *Celeron*) + CPUTYPE=1 + ;; *) + echo "Unknown CPU type. Please send /proc/cpuinfo to mo...@co..." CPUTYPE=0 ;; esac |
From: John L. <mov...@us...> - 2001-08-19 20:23:05
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv6244 Modified Files: ChangeLog Log Message: recognise celerons in cpu type Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.86 retrieving revision 1.87 diff -u -d -r1.86 -r1.87 --- ChangeLog 2001/08/19 20:09:17 1.86 +++ ChangeLog 2001/08/19 20:23:02 1.87 @@ -1,5 +1,9 @@ 2001-08-19 John Levon <mo...@co...> + * dae/op_start: handle celeries in cpu type + +2001-08-19 John Levon <mo...@co...> + * op_init.c: * oprofile.h: * oprofile.c: small tidies of the Athlon support |
From: John L. <mov...@us...> - 2001-08-19 20:09:20
|
Update of /cvsroot/oprofile/oprofile/dae In directory usw-pr-cvs1:/tmp/cvs-serv3584/dae Modified Files: op_start oprofiled.c oprofiled.h Log Message: the athlon patch. more work needed, but it works. Thanks Dave !! Index: op_start =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/op_start,v retrieving revision 1.34 retrieving revision 1.35 diff -u -d -r1.34 -r1.35 --- op_start 2001/08/16 02:23:01 1.34 +++ op_start 2001/08/19 20:09:17 1.35 @@ -34,7 +34,6 @@ CTR0_KERNEL=1 CTR1_USER=1 CTR1_KERNEL=1 -USE_PII=0 IGNORE_MYSELF=0 DIR="/var/opd" MAP_FILE= @@ -43,6 +42,30 @@ PGRP_FILTER=0 VERBOSE=0 +if test -f /proc/cpuinfo; then + modelname=`cat /proc/cpuinfo | grep "model\ name\ :" | sed -e 's/ //g' | cut -d':' -f2` + case $modelname in + *PentiumPro*) + CPUTYPE=0 + ;; + *PentiumIII*) + CPUTYPE=2 + ;; + *PentiumII*) + CPUTYPE=1 + ;; + *Athlon* | *Duron* | *K7*) + CPUTYPE=3 + ;; + *) + CPUTYPE=0 + ;; + esac + +else + CPUTYPE=0 +fi + # FIXME: needs to be generalised for more counters (e.g. athlon) do_help() { @@ -65,7 +88,7 @@ --pgrp-filter=pgrp Only profile process group pgrp (if compiled in) Daemon options - --use-cpu=[0|1|2] 0 or PPro, 1 for PII, 2 for PIII + --use-cpu=[0|1|2|3] 0 or PPro, 1 for PII, 2 for PIII, 3 for AMD Athlon. --ignore-myself=[0|1] ignore samples for oprofiled --log-file=file log file --base-dir=dir base directory of daemon @@ -121,9 +144,7 @@ case "$arg" in --use-cpu) if [ "$val" != "" ]; then - USE_PII=$val - else - USE_PII=1 + CPUTYPE=$val fi ;; --ignore-myself) @@ -305,7 +326,7 @@ echo "CTR1_COUNT $CTR1_COUNT" echo "CTR0_OSUSR $CTR0_OSUSR" echo "CTR1_OSUSR $CTR1_OSUSR" - echo "USE_PII $USE_PII" + echo "CPUTYPE $CPUTYPE" echo "IGNORE_MYSELF $IGNORE_MYSELF" echo "DIR $DIR" echo "LOG_FILE $LOG_FILE" @@ -421,7 +442,7 @@ $SYSCTL -w dev.oprofile.1.event=$CTR1_EVENT_VAL >/dev/null fi -OPD_ARGS="--buffer-size=$BUF_SIZE --use-cpu=$USE_PII --ignore-myself=$IGNORE_MYSELF \ +OPD_ARGS="--buffer-size=$BUF_SIZE --use-cpu=$CPUTYPE --ignore-myself=$IGNORE_MYSELF \ --log-file=$LOG_FILE --base-dir=$DIR --samples-dir=$SAMPLES_DIR \ --device-file=$DEVICE_FILE --kernel-only=$KERNEL_ONLY \ --hash-map-device-file=$HASH_MAP_DEVICE_FILE --vmlinux=$VMLINUX" Index: oprofiled.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/oprofiled.c,v retrieving revision 1.38 retrieving revision 1.39 diff -u -d -r1.38 -r1.39 --- oprofiled.c 2001/07/25 02:22:44 1.38 +++ oprofiled.c 2001/08/19 20:09:17 1.39 @@ -206,6 +206,8 @@ if (ret & OP_CTR1_PII_EVENT) fprintf(stderr, "oprofiled: ctr1: %d: event only available on PII\n", footer.ctr1_type_val); if (ret & OP_CTR0_PIII_EVENT) fprintf(stderr, "oprofiled: ctr0: %d: event only available on PIII\n", footer.ctr0_type_val); if (ret & OP_CTR1_PIII_EVENT) fprintf(stderr, "oprofiled: ctr1: %d: event only available on PIII\n", footer.ctr1_type_val); + if (ret & OP_CTR0_ATHLON_EVENT) fprintf(stderr, "oprofiled: ctr0: %d: event only available on AMD Athlon\n", footer.ctr0_type_val); + if (ret & OP_CTR1_ATHLON_EVENT) fprintf(stderr, "oprofiled: ctr1: %d: event only available on AMD Athlon\n", footer.ctr1_type_val); if (ret != OP_EVENTS_OK) { poptPrintHelp(optcon, stderr, 0); Index: oprofiled.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/oprofiled.h,v retrieving revision 1.29 retrieving revision 1.30 diff -u -d -r1.29 -r1.30 --- oprofiled.h 2001/08/10 13:36:37 1.29 +++ oprofiled.h 2001/08/19 20:09:17 1.30 @@ -96,6 +96,8 @@ #define OP_CTR1_PII_EVENT 0x80 #define OP_CTR0_PIII_EVENT 0x100 #define OP_CTR1_PIII_EVENT 0x200 +#define OP_CTR0_ATHLON_EVENT 0x400 +#define OP_CTR1_ATHLON_EVENT 0x800 /* FIXME : Carefull these are also present in pp/oprofpp.h */ #define OPD_MAGIC 0xdeb6 |
From: John L. <mov...@us...> - 2001-08-19 20:09:20
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv3584 Modified Files: ChangeLog README TODO op_events.c op_init.c oprofile.c oprofile.h Log Message: the athlon patch. more work needed, but it works. Thanks Dave !! Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.85 retrieving revision 1.86 diff -u -d -r1.85 -r1.86 --- ChangeLog 2001/08/19 18:50:54 1.85 +++ ChangeLog 2001/08/19 20:09:17 1.86 @@ -1,3 +1,19 @@ +2001-08-19 John Levon <mo...@co...> + + * op_init.c: + * oprofile.h: + * oprofile.c: small tidies of the Athlon support + +2001-08-19 Dave Jones <da...@su...> + + * op_events.c: + * op_init.c: + * oprofile.h: + * oprofile.c: + * dae/op_start: + * dae/oprofiled.h: + * dae/oprofiled.c: initial Athlon support + 2001-08-19 Philippe Elie <ph...@cl...> * oprofile.c: use symbolic constant for all apic setup, no generated Index: README =================================================================== RCS file: /cvsroot/oprofile/oprofile/README,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- README 2001/08/11 01:38:29 1.11 +++ README 2001/08/19 20:09:17 1.12 @@ -11,5 +11,6 @@ wrote the tcl/tk oprofile interface and the source annotation facility, and more. -Dave Jones <da...@su...> and Bob Montgomery <bo...@fc...> provided -bug fixes and useful testing. +Dave Jones <da...@su...> provided bug fixes and the Athlon support. + +Bob Montgomery <bo...@fc...> provided bug fixes and useful testing. Index: TODO =================================================================== RCS file: /cvsroot/oprofile/oprofile/TODO,v retrieving revision 1.11 retrieving revision 1.12 diff -u -d -r1.11 -r1.12 --- TODO 2001/08/19 18:50:54 1.11 +++ TODO 2001/08/19 20:09:17 1.12 @@ -2,8 +2,7 @@ ----------- o Save counter state and restore on a finish -o Athlon: values in oprofile.c not op_init.c, bit 22 is per-counter, determine working event types, - fix ctr_overflowed(), fix set_perfctr to set high to -1 +o Athlon: bit 22 is per-counter, determine working event types, support 4 counters, documentation o SMP mappings - place in all buffers perhaps ? o check chroot() processes and the path hash stuff o There is no need for the daemon to run as root as long as every binary image Index: op_events.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/op_events.c,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- op_events.c 2001/07/21 22:53:38 1.19 +++ op_events.c 2001/08/19 20:09:17 1.20 @@ -26,6 +26,7 @@ #define OP_PII_PIII 3 #define OP_PII_ONLY 4 #define OP_PIII_ONLY 5 +#define OP_ATHLON_ONLY 6 #ifdef __KERNEL__ #include <linux/string.h> @@ -87,13 +88,39 @@ { 2, utm_bitmask, { 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0 }, }, }; +/* Allowed, Event #, unit mask, name, minimum event value */ static struct op_event op_events[] = { /* Data Cache Unit (DCU) */ + {OP_ATHLON_ONLY,0x40,0,"DATA_CACHE_ACCESSES", 500,}, + {OP_ATHLON_ONLY,0x41,0,"DATA_CACHE_MISSES", 500,}, + {OP_ATHLON_ONLY,0x42,0,"DATA_CACHE_REFILLS_FROM_L2", 500,}, + {OP_ATHLON_ONLY,0x43,0,"DATA_CACHE_REFILLS_FROM_SYSTEM", 500,}, + {OP_ATHLON_ONLY,0x44,0,"DATA_CACHE_WRITEBACKS", 500,}, + {OP_ATHLON_ONLY,0x45,0,"L1_DTLB_MISSES_L2_DTLD_HITS", 500,}, + {OP_ATHLON_ONLY,0x46,0,"L1_AND_L2_DTLB_MISSES", 500,}, + {OP_ATHLON_ONLY,0x47,0,"MISALIGNED_DATA_REFS", 500,}, + {OP_ATHLON_ONLY,0x80,0,"ICACHE_FETCHES", 500,}, + {OP_ATHLON_ONLY,0x81,0,"ICACHE_MISSES", 500,}, + {OP_ATHLON_ONLY,0x84,0,"L1_ITLB_MISSES_L2_ITLB_HITS", 500,}, + {OP_ATHLON_ONLY,0x85,0,"L1_AND_L2_ITLB_MISSES", 500,}, + {OP_ATHLON_ONLY,0xc0,0,"RETIRED_INSNS", 500,}, + {OP_ATHLON_ONLY,0xc1,0,"RETIRED_OPS", 500,}, + {OP_ATHLON_ONLY,0xc2,0,"RETIRED_BRANCHES", 500,}, + {OP_ATHLON_ONLY,0xc3,0,"RETIRED_BRANCHES_MISPREDICTED", 500,}, + {OP_ATHLON_ONLY,0xc4,0,"RETIRED_TAKEN_BRANCHES", 500,}, + {OP_ATHLON_ONLY,0xc5,0,"RETIRED_TAKEN_BRANCHES_MISPREDICTED", 500,}, + {OP_ATHLON_ONLY,0xc6,0,"RETIRED_FAR_CONTROL_TRANSFERS", 500,}, + {OP_ATHLON_ONLY,0xc7,0,"RETIRED_RESYNC_BRANCHES", 500,}, + {OP_ATHLON_ONLY,0xcd,0,"INTERRUPTS_MASKED", 500,}, + {OP_ATHLON_ONLY,0xce,0,"INTERRUPTS_MASKED_PENDING", 500,}, + {OP_ATHLON_ONLY,0xcf,0,"HARDWARE_INTERRUPTS", 500,}, + {OP_ANY,0x43,0,"DATA_MEM_REFS", 500 }, {OP_ANY,0x45,0,"DCU_LINES_IN", 500 }, {OP_ANY,0x46,0,"DCU_M_LINES_IN", 500 }, {OP_ANY,0x47,0,"DCU_M_LINES_OUT", 500}, {OP_ANY,0x48,0,"DCU_MISS_OUTSTANDING", 500 }, + /* Intruction Fetch Unit (IFU) */ {OP_ANY,0x80,0,"IFU_IFETCH", 500 }, {OP_ANY,0x81,0,"IFU_IFETCH_MISS", 500 }, @@ -201,6 +228,8 @@ #define OP_CTR1_PII_EVENT 0x80 #define OP_CTR0_PIII_EVENT 0x100 #define OP_CTR1_PIII_EVENT 0x200 +#define OP_CTR0_ATHLON_EVENT 0x400 +#define OP_CTR1_ATHLON_EVENT 0x800 /** * op_check_unit_mask - sanity check unit mask value @@ -291,6 +320,8 @@ * * 2 Pentium III * + * 3 AMD Athlon + * * Use 0 values for @ctr0_type and @ctr1_type if the * counter is not used. * @@ -325,6 +356,11 @@ if (!proc) ret |= OP_CTR0_PII_EVENT; break; + + case OP_ATHLON_ONLY: + if (proc != 3) + ret |= OP_CTR0_ATHLON_EVENT; + break; default: break; } @@ -359,6 +395,12 @@ if (!proc) ret |= OP_CTR1_PII_EVENT; break; + + case OP_ATHLON_ONLY: + if (proc != 3) + ret |= OP_CTR1_ATHLON_EVENT; + break; + default: break; } @@ -397,6 +439,8 @@ * * 2 Pentium III * + * 3 AMD Athlon + * * Use "" strings for @ctr0_type and @ctr1_type if the * counter is not used. * @@ -702,6 +746,7 @@ case 3: printf("- Pentium II/III only\n"); break; case 4: printf("- Pentium II only\n"); break; case 5: printf("- Pentium III only\n"); break; + case 6: printf("- AMD Athlon only\n"); break; default: printf("\n"); break; } if (op_events[i].unit) { Index: op_init.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/op_init.c,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- op_init.c 2001/06/22 00:19:31 1.5 +++ op_init.c 2001/08/19 20:09:17 1.6 @@ -26,21 +26,26 @@ /* we want to include all P6 processors (i.e. > Pentium Classic, * < Pentium IV */ - if (current_cpu_data.x86_vendor != X86_VENDOR_INTEL || - current_cpu_data.x86 != 6) { - printk(KERN_ERR "oprofile: not an Intel P6 processor. Sorry.\n"); - return 0; + if ((current_cpu_data.x86_vendor != X86_VENDOR_INTEL && + current_cpu_data.x86 != 6) || + (current_cpu_data.x86_vendor != X86_VENDOR_AMD && + current_cpu_data.x86 != 6)) { + printk(KERN_ERR "oprofile: not an Intel P6 or AMD Athlon processor. Sorry.\n"); + return CPU_NO_GOOD; } - /* 0 if PPro, 1 if PII, 2 if PIII */ - cpu_type = (current_cpu_data.x86_model > 5) ? 2 : - (current_cpu_data.x86_model > 2); - return 1; + /* 0 if PPro, 1 if PII, 2 if PIII, 3 if Athlon */ + if (current_cpu_data.x86_vendor == X86_VENDOR_AMD) + cpu_type = CPU_ATHLON; + else + cpu_type = (current_cpu_data.x86_model > 5) ? CPU_PIII : + (current_cpu_data.x86_model > 2); + return cpu_type; } int __init stub_init(void) { - if (!hw_ok()) + if (hw_ok() == CPU_NO_GOOD) return -EINVAL; return oprof_init(); Index: oprofile.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.c,v retrieving revision 1.72 retrieving revision 1.73 diff -u -d -r1.72 -r1.73 --- oprofile.c 2001/08/19 18:50:54 1.72 +++ oprofile.c 2001/08/19 20:09:17 1.73 @@ -34,9 +34,20 @@ static int op_ctr_val[OP_MAX_COUNTERS]; static int op_ctr_kernel[OP_MAX_COUNTERS]; static int op_ctr_user[OP_MAX_COUNTERS]; + pid_t pid_filter; pid_t pgrp_filter; +/* the MSRs we need */ +uint ctrlreg0 = MSR_IA32_EVNTSEL0; +uint ctrlreg1 = MSR_IA32_EVNTSEL1; +uint ctrlreg2 = MSR_K7_PERFCTL2; +uint ctrlreg3 = MSR_K7_PERFCTL3; +uint ctrreg0 = MSR_IA32_PERFCTR0; +uint ctrreg1 = MSR_IA32_PERFCTR1; +uint ctrreg2 = MSR_K7_PERFCTR2; +uint ctrreg3 = MSR_K7_PERFCTR3; + u32 prof_on __cacheline_aligned; static int op_major; @@ -50,6 +61,15 @@ extern spinlock_t map_lock; +extern unsigned int ctrlreg0; +extern unsigned int ctrlreg1; +extern unsigned int ctrlreg2; +extern unsigned int ctrlreg3; +extern unsigned int ctrreg0; +extern unsigned int ctrreg1; +extern unsigned int ctrreg2; +extern unsigned int ctrreg3; + /* ---------------- NMI handler ------------------ */ /* FIXME: this whole handler would probably be better in straight asm */ @@ -313,6 +333,7 @@ return 0; } + /* ugly hack */ /* PHE : the memory must be uncachable! this is perhaps more a * problem for Athlon than for PII. @@ -409,7 +430,7 @@ return 0; not_local_p6_apic: - printk(KERN_ERR "oprofile: no local P6 APIC\n"); + printk(KERN_ERR "oprofile: no local P6 APIC. Your laptop doesn't have one !\n"); /* IA32 V3, 7.4.2 */ rdmsr(MSR_IA32_APICBASE, msr_low, msr_high); wrmsr(MSR_IA32_APICBASE, msr_low & ~(1<<11), msr_high); @@ -438,12 +459,24 @@ { uint low, high; - rdmsr(MSR_IA32_EVNTSEL0, low, high); - wrmsr(MSR_IA32_EVNTSEL0, low & ~(1<<22), high); + // first, let's use the right MSRs + switch (cpu_type) { + case CPU_ATHLON: + ctrlreg0 = MSR_K7_PERFCTL0; + ctrlreg1 = MSR_K7_PERFCTL1; + ctrreg0 = MSR_K7_PERFCTR0; + ctrreg1 = MSR_K7_PERFCTR1; + break; + default:; + } + + rdmsr(ctrlreg0, low, high); + // FIXME: enable bit is per-counter on athlon + wrmsr(ctrlreg0, low & ~(1<<22), high); /* IA Vol. 3 Figure 15-3 */ - rdmsr(MSR_IA32_EVNTSEL0, low, high); + rdmsr(ctrlreg0, low, high); /* clear */ low &= (1<<21); @@ -452,24 +485,26 @@ pmc_fill_in(&low, op_ctr_kernel[0], op_ctr_user[0], op_ctr_val[0], op_ctr_um[0]); } - wrmsr(MSR_IA32_EVNTSEL0, low, 0); + wrmsr(ctrlreg0, low, 0); - rdmsr(MSR_IA32_EVNTSEL1, low, high); + rdmsr(ctrlreg1, low, high); /* clear */ low &= (3<<21); if (op_ctr_val[1]) { set_perfctr(op_ctr_count[1], 1); pmc_fill_in(&low, op_ctr_kernel[1], op_ctr_user[1], op_ctr_val[1], op_ctr_um[1]); - wrmsr(MSR_IA32_EVNTSEL1, low, high); + wrmsr(ctrlreg1, low, high); } /* disable ctr1 if the UP oopser might be on, but we can't do anything * interesting with the NMIs */ /* PHE FIXME Have always a meaning ? */ + /* this is pretty bogus really. especially as we don't re-enable it. + * Instead, save state set up, and restore with pmc_unsetup or similar */ #if !defined(CONFIG_X86_UP_APIC) || !defined(OP_EXPORTED_DO_NMI) - wrmsr(MSR_IA32_EVNTSEL1, low, high); + wrmsr(ctrlreg1, low, high); #endif } @@ -481,8 +516,9 @@ return; /* enable counters */ - rdmsr(MSR_IA32_EVNTSEL0, low, high); - wrmsr(MSR_IA32_EVNTSEL0, low | (1<<22), high); + rdmsr(ctrlreg0, low, high); + // FIXME: bit 22 per-counter on athlon + wrmsr(ctrlreg0, low | (1<<22), high); } static void pmc_stop(void *info) @@ -493,8 +529,9 @@ return; /* disable counters */ - rdmsr(MSR_IA32_EVNTSEL0, low, high); - wrmsr(MSR_IA32_EVNTSEL0, low & ~(1<<22), high); + rdmsr(ctrlreg0, low, high); + // FIXME: bit 22 per-counter on athlon + wrmsr(ctrlreg0, low & ~(1<<22), high); } inline static void pmc_select_start(uint cpu) @@ -847,6 +884,8 @@ if (ret & OP_CTR1_PII_EVENT) printk(KERN_ERR "oprofile: ctr1: event only available on PII\n"); if (ret & OP_CTR0_PIII_EVENT) printk(KERN_ERR "oprofile: ctr0: event only available on PIII\n"); if (ret & OP_CTR1_PIII_EVENT) printk(KERN_ERR "oprofile: ctr1: event only available on PIII\n"); + if (ret & OP_CTR0_ATHLON_EVENT) printk(KERN_ERR "oprofile: ctr1: event only available on Athlon\n"); + if (ret & OP_CTR1_ATHLON_EVENT) printk(KERN_ERR "oprofile: ctr1: event only available on Athlon\n"); if (ret) return 0; @@ -874,7 +913,7 @@ static int oprof_start(void) { int err = 0; - + down(&sysctlsem); if ((err = oprof_init_data())) @@ -885,7 +924,7 @@ err = -EINVAL; goto out; } - + if ((smp_call_function(pmc_setup, NULL, 0, 1))) { oprof_free_mem(smp_num_cpus); err = -EINVAL; @@ -893,7 +932,7 @@ } pmc_setup(NULL); - + install_nmi(); if (!kernel_only) @@ -905,7 +944,7 @@ pmc_start(NULL); prof_on = 1; - + out: up(&sysctlsem); return err; Index: oprofile.h =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.h,v retrieving revision 1.45 retrieving revision 1.46 diff -u -d -r1.45 -r1.46 --- oprofile.h 2001/08/11 12:37:56 1.45 +++ oprofile.h 2001/08/19 20:09:17 1.46 @@ -53,6 +53,12 @@ #define OP_CTR_0 0x1 #define OP_CTR_1 0x2 +#define CPU_NO_GOOD -1 +#define CPU_PPRO 0 +#define CPU_PII 1 +#define CPU_PIII 2 +#define CPU_ATHLON 3 + /* MSRs */ #ifndef MSR_IA32_PERFCTR0 #define MSR_IA32_PERFCTR0 0xc1 @@ -69,6 +75,30 @@ #ifndef MSR_IA32_APICBASE #define MSR_IA32_APICBASE 0x1B #endif +#ifndef MSR_K7_PERFCTL0 +#define MSR_K7_PERFCTL0 0xc0010000 +#endif +#ifndef MSR_K7_PERFCTL1 +#define MSR_K7_PERFCTL1 0xc0010001 +#endif +#ifndef MSR_K7_PERFCTL2 +#define MSR_K7_PERFCTL2 0xc0010002 +#endif +#ifndef MSR_K7_PERFCTL3 +#define MSR_K7_PERFCTL3 0xc0010003 +#endif +#ifndef MSR_K7_PERFCTR0 +#define MSR_K7_PERFCTR0 0xc0010004 +#endif +#ifndef MSR_K7_PERFCTR1 +#define MSR_K7_PERFCTR1 0xc0010005 +#endif +#ifndef MSR_K7_PERFCTR2 +#define MSR_K7_PERFCTR2 0xc0010006 +#endif +#ifndef MSR_K7_PERFCTR3 +#define MSR_K7_PERFCTR3 0xc0010007 +#endif #ifndef APIC_SPIV_APIC_ENABLED #define APIC_SPIV_APIC_ENABLED (1<<8) @@ -114,8 +144,8 @@ ^ (ctr<<8)) & (data->hash_size - 1) /* relying on MSR numbers being neighbours */ -#define get_perfctr(l,h,c) do { rdmsr(MSR_IA32_PERFCTR0 + c, (l), (h)); } while (0) -#define set_perfctr(l,c) do { wrmsr(MSR_IA32_PERFCTR0 + c, -(u32)(l), 0); } while (0) +#define get_perfctr(l,h,c) do { rdmsr(ctrreg0 + c, (l), (h)); } while (0) +#define set_perfctr(l,c) do { wrmsr(ctrreg0 + c, -(u32)(l), -1); } while (0) #define ctr_overflowed(n) (!((n) & (1U<<31))) #define OP_EVENTS_OK 0x0 @@ -129,6 +159,8 @@ #define OP_CTR1_PII_EVENT 0x80 #define OP_CTR0_PIII_EVENT 0x100 #define OP_CTR1_PIII_EVENT 0x200 +#define OP_CTR0_ATHLON_EVENT 0x400 +#define OP_CTR1_ATHLON_EVENT 0x800 #define op_check_range(val,l,h,str) do { \ if ((val) < (l) || (val) > (h)) { \ @@ -182,6 +214,16 @@ #else #include <linux/completion.h> #endif + +// FIXME: these names are too easy to mis-type ! +extern uint ctrlreg0; +extern uint ctrlreg1; +extern uint ctrlreg2; +extern uint ctrlreg3; +extern uint ctrreg0; +extern uint ctrreg1; +extern uint ctrreg2; +extern uint ctrreg3; int oprof_init(void); void oprof_exit(void); |
From: John L. <mov...@us...> - 2001-08-19 18:50:59
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv21972 Modified Files: ChangeLog TODO oprofile.c Log Message: symbolic changes from philippe. lots of stuff TODO ;) Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.84 retrieving revision 1.85 diff -u -d -r1.84 -r1.85 --- ChangeLog 2001/08/18 16:11:17 1.84 +++ ChangeLog 2001/08/19 18:50:54 1.85 @@ -1,3 +1,8 @@ +2001-08-19 Philippe Elie <ph...@cl...> + + * oprofile.c: use symbolic constant for all apic setup, no generated + code change + 2001-08-18 Philippe Elie <ph...@cl...> * Makefile.in: Index: TODO =================================================================== RCS file: /cvsroot/oprofile/oprofile/TODO,v retrieving revision 1.10 retrieving revision 1.11 diff -u -d -r1.10 -r1.11 --- TODO 2001/08/17 16:47:10 1.10 +++ TODO 2001/08/19 18:50:54 1.11 @@ -1,6 +1,9 @@ Correctness ----------- +o Save counter state and restore on a finish +o Athlon: values in oprofile.c not op_init.c, bit 22 is per-counter, determine working event types, + fix ctr_overflowed(), fix set_perfctr to set high to -1 o SMP mappings - place in all buffers perhaps ? o check chroot() processes and the path hash stuff o There is no need for the daemon to run as root as long as every binary image @@ -22,6 +25,7 @@ WBNI ---- +o good support for determining changed profiles o compile-time interrupt accounting (sysctl-read/writeable) - then re-do results/rates/ o we don't really need a vmlinux file during profiling ... o Other x86 processors Index: oprofile.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/oprofile.c,v retrieving revision 1.71 retrieving revision 1.72 diff -u -d -r1.71 -r1.72 --- oprofile.c 2001/08/14 02:38:29 1.71 +++ oprofile.c 2001/08/19 18:50:54 1.72 @@ -176,6 +176,9 @@ /* ---------------- APIC setup ------------------ */ +/* PHE : this would be probably an unconditionnaly restore state from a saved + *state + */ static void disable_local_P6_APIC(void *dummy) { #ifndef CONFIG_X86_UP_APIC @@ -184,6 +187,11 @@ uint h; /* FIXME: maybe this should go at end of function ? */ + /* PHE I think when the doc says : -if you disable the apic the bits + * of LVT cannot be reset- it talk about the SW disable through bit 8 + * of SPIV see 7.4.14 (7.5.14) not the hardware disable, so it is ok + * but I perhaps we need a software disable of the APIC at the end + */ /* first disable via MSR */ /* IA32 V3, 7.4.2 */ rdmsr(MSR_IA32_APICBASE, l, h); @@ -231,11 +239,9 @@ /* IA32 V3, Figure 7.8 */ old_lvtpc[smp_processor_id()] = val = apic_read(APIC_LVTPC); /* allow PC overflow interrupts */ - val &= ~(1<<16); + val &= ~APIC_LVT_MASKED; /* set delivery to NMI */ - val |= (1<<10); - val &= ~(1<<9); - val &= ~(1<<8); + val = SET_APIC_DELIVERY_MODE(val, APIC_MODE_NMI); apic_write(APIC_LVTPC, val); } @@ -244,11 +250,44 @@ apic_write(APIC_LVTPC, old_lvtpc[smp_processor_id()]); } +/* PHE bit 8 of APIC_BASE_MSR is the BSP flags, it is set by harware at boot + * up sequence and would be keeped ok by software to allow #INIT or #ERR, else + * all the processor on the next MP sequence fall in shutdown. + * + * On UP architecture it should always be zero (ok for my PII) 7.4.8 (7.5.8), + * I am unsure but I have presumption than kernel cannot boot properly if bsp + * flags is set on UP machine. + * + * I think it is ok in all case, perhaps corner case on SMP with only one + * processor plugged ? + */ +inline static int is_bsp_proc(void) +{ + uint l; + uint h; + rdmsr(MSR_IA32_APICBASE, l, h); + wrmsr(MSR_IA32_APICBASE, l & ~(1<<11), h); + + return (h & (1 << 8)) ? 1 : 0; +} + static int __init apic_needs_setup(void) { /* FIXME: we need to detect UP kernel, SMP hardware, and * return 0 here, to avoid screwing up the APIC */ + /* PHE: for UP kernel SMP machine this processor should have the bsp + * flags set, something like: + +#ifndef X86_UP_APIC + if (smp_num_cpus == 1) { + return !is_bsp_proc(); + } +#endif + return 0; + + would work + */ return /* if enabled, the kernel has already set it up */ #ifdef CONFIG_X86_UP_APIC @@ -257,6 +296,13 @@ smp_num_cpus == 1; } +/* PHE, would : save all state change for later restoration, minimalise the + * amount of change. Basically we need to test if apic is HW disable, SW + * disable, and change only the LVTPC setup, all other must be keep as it + * (except the LINT1 for bsp ?) We must rely on the kernel to setup all things. + * also : do we need write_apic --> write_apic_around to support + * GOOD_APIC/BAD_APIC ? + */ static int __init apic_setup(void) { uint msr_low, msr_high; @@ -268,6 +314,12 @@ } /* ugly hack */ + /* PHE : the memory must be uncachable! this is perhaps more a + * problem for Athlon than for PII. + * Also this stuff probably mishandled SMP ? + * The _PAGE_GLOBAL attribute should be probably avoided but make + * this later + */ my_set_fixmap(); /* FIXME: NMI delivery for SMP ? */ @@ -288,6 +340,7 @@ if (GET_APIC_MAXLVT(apic_read(APIC_LVR)) != 4) goto not_local_p6_apic; + /* __global_cli(); ? an IPI can occur inside this stuff ? */ __cli(); /* enable APIC locally */ @@ -296,36 +349,59 @@ apic_write(APIC_SPIV, val | APIC_SPIV_APIC_ENABLED); /* FIXME: examine this stuff */ - val = 0x00008700; + val = APIC_LVT_LEVEL_TRIGGER; + val = SET_APIC_DELIVERY_MODE(val, APIC_MODE_EXINT); apic_write(APIC_LVT0, val); - val = 0x00000400; + /* edge triggered, IA 7.4.11 */ + /* PHE SMP: only the BSP must see the LINT1 IRQ (from kernel source) + * recheck this later + */ + val = SET_APIC_DELIVERY_MODE(0, APIC_MODE_NMI); apic_write(APIC_LVT1, val); /* clear error register */ /* IA32 V3, 7.4.17 */ + /* PHE must be cleared after unmasking by a back-to-back write, + * but it is probably ok because we mask only, the ESR is not updated + * is this a real problem ? + */ apic_write(APIC_ESR, 0); /* mask error interrupt */ /* IA32 V3, Figure 7.8 */ val = apic_read(APIC_LVTERR); - val |= 0x00010000; + val |= APIC_LVT_MASKED; apic_write(APIC_LVTERR, val); /* setup timer vector */ /* IA32 V3, 7.4.8 */ - apic_write(APIC_LVTT, 0x0001031); + /* PHE actually it is ok but kernel change can hang up the machine + * after this point. + */ + apic_write(APIC_LVTT, APIC_SEND_PENDING | 0x31); /* Divide configuration register */ + /* PHE the apic clock is based on the FSB. This should only changed + * with a calibration method. + */ val = APIC_TDR_DIV_1; apic_write(APIC_TDCR, val); + /* PHE __global_sti() probably */ __sti(); /* If the local APIC NMI watchdog has been disabled, we'll need * to set up NMI delivery anyway ... */ + /* PHE : ? why not use a FixedMode rather than NMI mode for profiling, + * this avoid all problem with parity error nmi and watchdog, but this + * implies than the actual nmi handler must be hardware interruptible, + * basically this is better at my eyes but there is a few visible + * (and hidden) problem with this issue. This can probably wait unless + * hidden problem occur on SMP, recheck doc about NMI + */ lvtpc_apic_setup(NULL); printk(KERN_INFO "oprofile: enabled local APIC\n"); @@ -391,6 +467,7 @@ /* disable ctr1 if the UP oopser might be on, but we can't do anything * interesting with the NMIs */ + /* PHE FIXME Have always a meaning ? */ #if !defined(CONFIG_X86_UP_APIC) || !defined(OP_EXPORTED_DO_NMI) wrmsr(MSR_IA32_EVNTSEL1, low, high); #endif |
From: John L. <mov...@us...> - 2001-08-18 16:11:21
|
Update of /cvsroot/oprofile/oprofile/doc In directory usw-pr-cvs1:/tmp/cvs-serv29460/doc Modified Files: Makefile.in oprofile.sgml Log Message: uninstall patch from philippe Index: Makefile.in =================================================================== RCS file: /cvsroot/oprofile/oprofile/doc/Makefile.in,v retrieving revision 1.5 retrieving revision 1.6 diff -u -d -r1.5 -r1.6 --- Makefile.in 2001/08/16 01:57:58 1.5 +++ Makefile.in 2001/08/18 16:11:17 1.6 @@ -1,15 +1,17 @@ # $Id$ prefix=@prefix@ -MANDIR=@mandir@ +MANDIR=@mandir@/man1 +CATDIR=@mandir@/cat1 LN_SF=ln -sf RM=rm MKDIR=mkdir MKDIR_P=$(MKDIR) -p DB2HTML=db2html +LINK_LIST=oprofiled.1 op_start.1 op_stop.1 op_help.1 oprofpp.1 -.PHONY: all clean install - +.PHONY: all clean install uninstall + all: -$(RM) -rf oprofile.junk $(DB2HTML) oprofile.sgml @@ -20,12 +22,18 @@ -$(RM) -rf oprofile install: - -$(MKDIR_P) $(MANDIR)/man1 - cp oprofile.1 $(MANDIR)/man1/oprofile.1 - -$(LN_SF) $(MANDIR)/man1/oprofile.1 $(MANDIR)/man1/oprofiled.1 - -$(LN_SF) $(MANDIR)/man1/oprofile.1 $(MANDIR)/man1/op_start.1 - -$(LN_SF) $(MANDIR)/man1/oprofile.1 $(MANDIR)/man1/op_stop.1 - -$(LN_SF) $(MANDIR)/man1/oprofile.1 $(MANDIR)/man1/op_help.1 - -$(LN_SF) $(MANDIR)/man1/oprofile.1 $(MANDIR)/man1/oprofpp.1 - + -$(MKDIR_P) $(MANDIR) + cp oprofile.1 $(MANDIR)/oprofile.1 + @for f in $(LINK_LIST); do \ + $(LN_SF) $(MANDIR)/oprofile.1 $(MANDIR)/$$f; \ + done + +uninstall: + rm -f $(MANDIR)/oprofile.1 + rm -f @mandir@/cat1/oprofile.1.gz + @for f in $(LINK_LIST); do \ + rm -f $(MANDIR)/$$f; \ + rm -f $(CATDIR)/cat1/$$f.gz; \ + done + clean: Index: oprofile.sgml =================================================================== RCS file: /cvsroot/oprofile/oprofile/doc/oprofile.sgml,v retrieving revision 1.19 retrieving revision 1.20 diff -u -d -r1.19 -r1.20 --- oprofile.sgml 2001/08/11 01:45:54 1.19 +++ oprofile.sgml 2001/08/18 16:11:17 1.20 @@ -181,6 +181,14 @@ <para>Be warned than you cannot convert from new version to old version. If you convert to new version you cannot reverse the conversion. </sect1> + +<sect1 id="uninstall"> +<title>Uninstalling oprofile</title> +<para> +You must have the source tree installed to uninstall oprofile, then a <command>make uninstall</command> will +remove all installed file except your configuration file in the directory <filename>~/.oprofile</filename> +</para> +</sect1> </chapter> |
From: John L. <mov...@us...> - 2001-08-18 16:11:21
|
Update of /cvsroot/oprofile/oprofile/gui In directory usw-pr-cvs1:/tmp/cvs-serv29460/gui Modified Files: Makefile.in Log Message: uninstall patch from philippe Index: Makefile.in =================================================================== RCS file: /cvsroot/oprofile/oprofile/gui/Makefile.in,v retrieving revision 1.2 retrieving revision 1.3 diff -u -d -r1.2 -r1.3 --- Makefile.in 2001/08/16 01:57:58 1.2 +++ Makefile.in 2001/08/18 16:11:17 1.3 @@ -1,9 +1,9 @@ all: - -.PHONY: all clean - + +.PHONY: all clean install uninstall + clean: - + prefix=@prefix@ exec_prefix=@exec_prefix@ BINDIR=@bindir@ @@ -13,3 +13,10 @@ -$(MKDIR_P) $(BINDIR) cp oprofile $(BINDIR)/oprofile cd $(BINDIR) && chmod 755 oprofile + +uninstall: + rm -f $(BINDIR)/oprofile + @echo "---------------------------------------------------------------" + @echo "The uninstall target does not remove your ~/.oprofile directory" + @echo "---------------------------------------------------------------" + |
From: John L. <mov...@us...> - 2001-08-18 16:11:21
|
Update of /cvsroot/oprofile/oprofile/dae In directory usw-pr-cvs1:/tmp/cvs-serv29460/dae Modified Files: Makefile.in Log Message: uninstall patch from philippe Index: Makefile.in =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/Makefile.in,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- Makefile.in 2001/08/16 01:57:58 1.13 +++ Makefile.in 2001/08/18 16:11:17 1.14 @@ -1,7 +1,7 @@ # $Id$ -.PHONY: all clean srcdoc install - +.PHONY: all clean srcdoc install uninstall + all: oprofiled op_help prefix=@prefix@ @@ -10,19 +10,22 @@ MANDIR=@mandir@ CC=@CC@ MKDIR_P=mkdir -p +INSTALL_LIST=oprofiled op_start op_dump op_stop op_help -install: oprofiled op_start op_dump op_stop op_help +install: $(INSTALL_LIST) -$(MKDIR_P) $(BINDIR) - cp oprofiled $(BINDIR)/oprofiled - cp op_start $(BINDIR)/op_start - cp op_dump $(BINDIR)/op_dump - cp op_stop $(BINDIR)/op_stop - cp op_help $(BINDIR)/op_help - cd $(BINDIR) && chmod 755 oprofiled op_start op_dump op_stop op_help - + @for f in $(INSTALL_LIST); do \ + cp $$f $(BINDIR)/$$f && chmod 755 $(BINDIR)/$$f; \ + done + +uninstall: + @for f in $(INSTALL_LIST); do \ + rm -f $(BINDIR)/$$f; \ + done + clean: rm -f oprofiled op_help *.o oprofiled-src.html - + CFLAGS=-Wall -Wstrict-prototypes -O2 -pipe -Wstrict-prototypes -Wunused -W -Wshadow -Wmissing-prototypes -Winline @CFLAGS@ LIBS=@extra_libraries@ -lpopt INCLUDES=-I. @extra_includes@ |
From: John L. <mov...@us...> - 2001-08-18 16:11:21
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv29460 Modified Files: ChangeLog Makefile.in Log Message: uninstall patch from philippe Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.83 retrieving revision 1.84 diff -u -d -r1.83 -r1.84 --- ChangeLog 2001/08/18 15:58:31 1.83 +++ ChangeLog 2001/08/18 16:11:17 1.84 @@ -1,3 +1,11 @@ +2001-08-18 Philippe Elie <ph...@cl...> + + * Makefile.in: + * dae/Makefile.in: + * pp/Makefile.in: + * doc/Makefile.in: + * gui/Makefile.in: add uninstall target + 2001-08-18 John Levon <mo...@co...> * dae/opd_proc.c: tiny cleanup Index: Makefile.in =================================================================== RCS file: /cvsroot/oprofile/oprofile/Makefile.in,v retrieving revision 1.22 retrieving revision 1.23 diff -u -d -r1.22 -r1.23 --- Makefile.in 2001/08/16 01:57:58 1.22 +++ Makefile.in 2001/08/18 16:11:17 1.23 @@ -6,18 +6,20 @@ CC=@CC@ LD=@LD@ -.PHONY: all install clean distclean tags +.PHONY: all install clean distclean maintainerclean uninstall tags all: oprofile.o $(MAKE) -C dae $(MAKE) -C pp $(MAKE) -C gui +# doc/Makefile is deleted here but should be deleted in distclean. +# When the dist target works move it as action of distclean. maintainerclean: distclean - rm -f configure + rm -f configure doc/Makefile distclean: clean - rm -f Makefile dae/Makefile pp/Makefile tags + rm -f Makefile dae/Makefile pp/Makefile gui/Makefile tags # broken dist: @@ -30,7 +32,7 @@ ./configure ; \ cp doc/Makefile doc/Makefile.tmp ; \ make distclean ; \ - cd doc && make && rm -f Makefile && cd .. ; \ + cd doc && make -f Makefile.tmp && rm -f Makefile.tmp && cd .. ; \ cd .. ; \ mv oprofile oprofile-@VERSION@ ; \ tar cvfz ../oprofile-@VERSION@.tar.gz oprofile-@VERSION@ ; \ @@ -49,6 +51,16 @@ $(MAKE) -C pp install $(MAKE) -C doc install $(MAKE) -C gui install + +uninstall: + -rm -f $(MODINSTALLDIR)/oprofile.o + -rmdir --ignore-fail-on-non-empty $(MODINSTALLDIR) + depmod -a + $(MAKE) -C dae uninstall + $(MAKE) -C pp uninstall + $(MAKE) -C doc uninstall + $(MAKE) -C gui uninstall + @echo "Goodbye." clean: rm -f *.o config.status config.log config.cache |
From: John L. <mov...@us...> - 2001-08-18 16:11:21
|
Update of /cvsroot/oprofile/oprofile/pp In directory usw-pr-cvs1:/tmp/cvs-serv29460/pp Modified Files: Makefile.in Log Message: uninstall patch from philippe Index: Makefile.in =================================================================== RCS file: /cvsroot/oprofile/oprofile/pp/Makefile.in,v retrieving revision 1.13 retrieving revision 1.14 diff -u -d -r1.13 -r1.14 --- Makefile.in 2001/08/16 01:57:58 1.13 +++ Makefile.in 2001/08/18 16:11:17 1.14 @@ -1,6 +1,6 @@ all: oprofpp oprof_convert opf_filter -.PHONY: all clean srcdoc +.PHONY: all clean srcdoc install uninstall clean: rm -f oprofpp *.o oprofpp-src.html oprof_convert opf_filter @@ -11,17 +11,18 @@ BINDIR=@bindir@ MANDIR=@mandir@ MKDIR_P=mkdir -p +INSTALL_LIST=oprofpp oprof_convert opf_filter op_to_source -install: oprofpp oprof_convert opf_filter op_to_source +install: $(INSTALL_LIST) -$(MKDIR_P) $(BINDIR) - cp oprofpp $(BINDIR)/oprofpp - chmod 755 $(BINDIR)/oprofpp - cp oprof_convert $(BINDIR)/oprof_convert - chmod 755 $(BINDIR)/oprof_convert - cp opf_filter $(BINDIR)/opf_filter - chmod 755 $(BINDIR)/opf_filter - cp op_to_source $(BINDIR)/op_to_source - chmod 755 $(BINDIR)/op_to_source + @for f in $(INSTALL_LIST); do \ + cp $$f $(BINDIR)/$$f && chmod 755 $(BINDIR)/$$f; \ + done + +uninstall: + @for f in $(INSTALL_LIST); do \ + rm -f $(BINDIR)/$$f; \ + done CFLAGS=-Wall -Wstrict-prototypes -W -pipe -DOP_EVENTS_DESC -L/usr/lib @CFLAGS@ LIBS=-lpopt -lbfd -liberty -ldl |
From: John L. <mov...@us...> - 2001-08-18 15:58:35
|
Update of /cvsroot/oprofile/oprofile In directory usw-pr-cvs1:/tmp/cvs-serv26988 Modified Files: ChangeLog Log Message: small fix Index: ChangeLog =================================================================== RCS file: /cvsroot/oprofile/oprofile/ChangeLog,v retrieving revision 1.82 retrieving revision 1.83 diff -u -d -r1.82 -r1.83 --- ChangeLog 2001/08/17 16:47:10 1.82 +++ ChangeLog 2001/08/18 15:58:31 1.83 @@ -1,3 +1,7 @@ +2001-08-18 John Levon <mo...@co...> + + * dae/opd_proc.c: tiny cleanup + 2001-08-17 Philippe Elie <ph...@cl...> * dae/opd_proc.c: |
From: John L. <mov...@us...> - 2001-08-18 15:58:35
|
Update of /cvsroot/oprofile/oprofile/dae In directory usw-pr-cvs1:/tmp/cvs-serv26988/dae Modified Files: opd_proc.c Log Message: small fix Index: opd_proc.c =================================================================== RCS file: /cvsroot/oprofile/oprofile/dae/opd_proc.c,v retrieving revision 1.63 retrieving revision 1.64 diff -u -d -r1.63 -r1.64 --- opd_proc.c 2001/08/17 16:47:10 1.63 +++ opd_proc.c 2001/08/18 15:58:31 1.64 @@ -1040,6 +1040,21 @@ } /** + * verb_show_sample - print the sample out to the log + * @offset: the offset value + * @map: map to print + */ +inline static void verb_show_sample(u32 offset, struct opd_map *map) +{ + if (!verbose) + return; + + printf("DO_PUT_SAMPLE (LAST_MAP): calc offset 0x%.8x, map start 0x%.8x," + " end 0x%.8x, offset 0x%.8x, name $%s$\n", + offset, map->start, map->end, map->offset, opd_images[map->image].name); +} + +/** * opd_map_offset - return offset of sample against map * @map: map to use * @eip: EIP value to use @@ -1090,8 +1105,7 @@ if (opd_is_in_map(&proc->maps[proc->last_map], sample->eip)) { i = proc->last_map; if (proc->maps[i].image != -1) { - verbprintf("DO_PUT_SAMPLE (LAST_MAP): calc offset 0x%.8x, map start 0x%.8x, end 0x%.8x, offset 0x%.8x, name $%s$\n", - opd_map_offset(&proc->maps[i], sample->eip), proc->maps[i].start, proc->maps[i].end, proc->maps[i].offset, opd_images[proc->maps[i].image].name); + verb_show_sample(opd_map_offset(&proc->maps[i], sample->eip), &proc->maps[i]); opd_put_image_sample(&opd_images[proc->maps[i].image], opd_map_offset(&proc->maps[i], sample->eip), sample->count); } opd_stats[OPD_PROCESS]++; @@ -1103,8 +1117,7 @@ if (opd_is_in_map(&proc->maps[i], sample->eip)) { u32 offset = opd_map_offset(&proc->maps[i], sample->eip); if (proc->maps[i].image != -1) { - verbprintf("DO_PUT_SAMPLE: calc offset 0x%.8x, map start 0x%.8x, end 0x%.8x, offset 0x%.8x, name $%s$\n", - offset, proc->maps[i].start, proc->maps[i].end, proc->maps[i].offset, opd_images[proc->maps[i].image].name); + verb_show_sample(offset, &proc->maps[i]); opd_put_image_sample(&opd_images[proc->maps[i].image], offset, sample->count); } proc->last_map = i; |