Stefane,
How did you handle the processor type detection? I had to change lots of
the oprofile kernel code to do this... Attached is my patch that works
on the PIII (and most likely MIPS). This patch is probably significantly
less involved that Stefanes.
The one thing that's missing from Oprofile for MIPS is to use BogoMIPS
for MHZ. There is no MHZ in the output of /proc/cpuinfo, but bogomips is
as correct as can be.
Note there are numerous corrections for 64 bit ints and stuff.
Phil
On Mon, 2007-01-08 at 13:17 -0800, Stephane Eranian wrote:
> Will,
>
> The last couple of days, I have been working on plugging the hole
> we have with perfmon and OProfile support on x86. I started with
> your patch and the 2.6.19 perfmon codebase.
>
> I fixed the kernel portion to work with the latest changes, including
> the disappearance of UUID. I kept your /dev/oprofile/implementation.
> I have also completed the get_cpu_type() function to work with both
> x86-64 and i386.
>
> At the user level, I simplified opcontrol because we now have automatic
> loading of the perfmon PMU description module.
>
> I also rewrote a fair amount of opd_perfmon.c in the daemon code. I have
> separated the old (v2.0) IA-64 code into a new file. I fixed a couple
> of bugs and added detection of available PMC registers.
>
> I changed the logic so that the legacy perfmonctl() is ONLY used on IA-64
> when perfmon v2.0 is detected. In other words, on IA-64 with v2.3 the
> new interface is used.
>
> As of today, I was able to collect samples on Opteron and my Pentium M
> laptop.
>
> This little exercise raised a few questions:
>
> - the code that uses the v2.3 interface (for all architectures) now relies
> on libpfm. You pass to pfm_dispatch_events() OProfile event names. So
> that assumes that OProfile and libpfm events match. I am not sure this
> is the case for all events on all x86 processors. We need to solve this.
>
> - In the current code the legacy v2.0 IA-64 support does not use libpfm.
> There is no real reason for this. The library and kernel interface are
> distinct.
>
>
> Any opinion on this?
>
> Thanks for your contributions.
>
>
> On Mon, Mar 27, 2006 at 11:09:57AM -0500, William Cohen wrote:
> > I have gotten oprofile to make use of the new perfmon2 mechanism to
> > collect samples. I currently have this running on my AMD64 laptop. The
> > oprof_perfmon2-20060327.diff patches the oprofile user space code and
> > perfmon2_oprof20060327.diff is for the kernel. The patches are still
> > "work in progress" and there are certainly things that need to be
> > corrected. The patches borrow heavily from the previous ia64
> > oprofile/perfmon support.
> >
> > Due to the different sampling mechanism that could be used for x86,
> > /dev/oprofile/implement has been added so the sampling mechanism being
> > used can be identify how the samples are being collected.
> >
> > Rather than directly setting up the bits for the performance monitoring
> > hardware libpfm is used to map the name to the appropriate bits. For
> > processors with complicated constraints on the performance monitoring
> > hardware this makes more sense than trying to duplicate the constraints
> > mechanism in oprofile.
> >
> > Below are issues that still need to be fixed in the various areas of the
> > oprofile/perfmon2 monitoring.
> >
> > kernel:
> > - separating oprofiles processor id code from i386 nmi mechanism setup
> > - have oprofile/perfmon2 identify cpu for real (currently just hardwired
> > to amd64)
> > - oprofile always uses perfmon2 if kernel configured with perfmon
> > - module installation a bit odd:
> > -install oprofile modules
> > -opcontrol reads information to determine if perfmon2 used
> > -opcontrol install appropropriate perfmon module
> > - oprofile lies that it needs buffer space (perfmon_get_size()) so
> > perfmon2 actually calls oprofile's perfmon_handler()
> >
> > oprofile:
> > - make translation of events names to bit patterns more robust:
> > can hang if event is not found
> > - verify that the event masking support works
> > - get rid of fatal_error() function in opd_perfmon.c
> > - ophelp get the available events from libpfm when possible
> >
> > libpfm:
> > -make event mapping complete (lots of events missing for various processors)
> > -libpfm isn't available on some procesors that perfmon supports (e.g.
> > p4/ppc64)
> >
> >
> > -Will
>
>
>
> > _______________________________________________
> > perfmon mailing list
> > [email protected]
> > http://www.hpl.hp.com/hosted/linux/mail-archives/perfmon/
>
? .svn
? out
? daemon/.svn
? daemon/liblegacy/.svn
? doc/.svn
? doc/srcdoc/.svn
? doc/xsl/.svn
? events/.svn
? events/alpha/.svn
? events/alpha/ev4/.svn
? events/alpha/ev5/.svn
? events/alpha/ev6/.svn
? events/alpha/ev67/.svn
? events/alpha/pca56/.svn
? events/arm/.svn
? events/arm/xscale1/.svn
? events/arm/xscale2/.svn
? events/i386/.svn
? events/i386/athlon/.svn
? events/i386/core/.svn
? events/i386/core_2/.svn
? events/i386/p4/.svn
? events/i386/p4-ht/.svn
? events/i386/p6_mobile/.svn
? events/i386/pii/.svn
? events/i386/piii/.svn
? events/i386/ppro/.svn
? events/ia64/.svn
? events/ia64/ia64/.svn
? events/ia64/itanium/.svn
? events/ia64/itanium2/.svn
? events/mips/.svn
? events/mips/20K/.svn
? events/mips/24K/.svn
? events/mips/25K/.svn
? events/mips/34K/.svn
? events/mips/5K/.svn
? events/mips/r10000/.svn
? events/mips/r12000/.svn
? events/mips/rm7000/.svn
? events/mips/rm9000/.svn
? events/mips/sb1/.svn
? events/mips/vr5432/.svn
? events/mips/vr5500/.svn
? events/ppc/.svn
? events/ppc/7450/.svn
? events/ppc/e500/.svn
? events/ppc/e500v2/.svn
? events/ppc64/.svn
? events/ppc64/970/.svn
? events/ppc64/power4/.svn
? events/ppc64/power5/.svn
? events/ppc64/power5+/.svn
? events/rtc/.svn
? events/x86-64/.svn
? events/x86-64/hammer/.svn
? gui/.svn
? gui/ui/.svn
? include/.svn
? libabi/.svn
? libabi/tests/.svn
? libdb/.svn
? libdb/tests/.svn
? libop/.svn
? libop/tests/.svn
? libopt++/.svn
? libpp/.svn
? libregex/.svn
? libregex/tests/.svn
? libutil/.svn
? libutil/tests/.svn
? libutil++/.svn
? libutil++/tests/.svn
? m4/.svn
? module/.svn
? module/ia64/.svn
? module/x86/.svn
? pp/.svn
? utils/.svn
Index: configure.in
===================================================================
RCS file: /cvsroot/oprofile/oprofile/configure.in,v
retrieving revision 1.227
diff -r1.227 configure.in
135a136,147
> dnl enable option to use perfmon use on processors other than ia64
> AC_ARG_ENABLE(perfmon2,
> [ --enable-perfmon2 enable option for perfmon2 use on non-ia64 processors (default is disabled)],
> enable_perfmon2=$enableval, enable_perfmon2=no)
> if test "$enable_perfmon2" = yes; then
> AC_CHECK_LIB(pfm, pfm_start,, AC_MSG_ERROR([pfm library not found]))
> PFM_LIBS="-lpfm"
> AC_SUBST(PFM_LIBS)
> AX_CFLAGS_OPTION(OP_CFLAGS,[-DOPROF_PERFMON2])
> AX_CXXFLAGS_OPTION(OP_CXXFLAGS,[-DOPROF_PERFMON2])
> fi
>
Index: daemon/Makefile.am
===================================================================
RCS file: /cvsroot/oprofile/oprofile/daemon/Makefile.am,v
retrieving revision 1.30
diff -r1.30 Makefile.am
28c28
< [EMAIL PROTECTED]@ @LIBERTY_LIBS@
---
> [EMAIL PROTECTED]@ @LIBERTY_LIBS@ @PFM_LIBS@
Index: daemon/opd_perfmon.c
===================================================================
RCS file: /cvsroot/oprofile/oprofile/daemon/opd_perfmon.c,v
retrieving revision 1.19
diff -r1.19 opd_perfmon.c
11c11
< #ifdef __ia64__
---
> #if defined( __ia64__) || defined(OPROF_PERFMON2)
35a36,54
> #ifdef OPROF_PERFMON2
> #include <perfmon/perfmon.h>
> #include <perfmon/pfmlib.h>
> #endif
>
> /* FIXME fatal_error is just temporary */
> static void fatal_error(char *fmt,...) __attribute__((noreturn));
>
> static void
> fatal_error(char *fmt, ...)
> {
> va_list ap;
>
> va_start(ap, fmt);
> vfprintf(stderr, fmt, ap);
> va_end(ap);
>
> exit(1);
> }
66c85
<
---
> #ifndef OPROF_PERFMON2
77,78d95
<
<
80,81c97,98
< 0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69,
< 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c
---
> 0x77, 0x7a, 0x6e, 0x61, 0x20, 0x65, 0x73, 0x69,
> 0x74, 0x6e, 0x72, 0x20, 0x61, 0x65, 0x0a, 0x6c
83c100
<
---
> #endif
100,103c117,122
< if (perfmonctl(ctx_fd, PFM_START, 0, 0) == -1) {
< perror("Couldn't start perfmon: ");
< exit(EXIT_FAILURE);
< }
---
> int ret;
>
> if ((ret = op_pfm_start(ctx_fd, NULL)) == -1) {
> op_pfm_perror("oprofiled: pfm_start failed: ",ret);
> exit(EXIT_FAILURE);
> }
109,112c128,133
< if (perfmonctl(ctx_fd, PFM_STOP, 0, 0) == -1) {
< perror("Couldn't stop perfmon: ");
< exit(EXIT_FAILURE);
< }
---
> int ret;
>
> if ((ret = op_pfm_stop(ctx_fd)) == -1) {
> op_pfm_perror("oprofiled: pfm_stop failed: ",ret);
> exit(EXIT_FAILURE);
> }
144c165
< printf("Child received SIGTERM, killing parent.\n");
---
> printf("oprofiled: Child received SIGTERM, killing parent.\n");
151a173
> int err;
156c178
< int err = sched_setaffinity(getpid(), sizeof(set), &set);
---
> err = sched_setaffinity(getpid(), sizeof(set), &set);
159c181
< fprintf(stderr, "Failed to set affinity: %s\n",
---
> fprintf(stderr, "oprofiled: sched_setaffinity failed: %s\n",
207a230,232
> #ifdef OPROF_PERFMON2
> pfarg_ctx_t ctx;
> #else
208a234
> #endif
211c237,238
< memset(&ctx, 0, sizeof(pfarg_context_t));
---
> memset(&ctx, 0, sizeof(ctx));
> #ifndef OPROF_PERFMON2
212a240
> #endif
215c243
< err = perfmonctl(0, PFM_CREATE_CONTEXT, &ctx, 1);
---
> err = op_pfm_create_context(&ctx);
217,219c245,246
< fprintf(stderr, "CREATE_CONTEXT failed: %s\n",
< strerror(errno));
< exit(EXIT_FAILURE);
---
> op_pfm_perror("oprofiled: pfm_create_context failed: ",err);
> exit(EXIT_FAILURE);
221a249,251
> #ifdef OPROF_PERFMON2
> self->ctx_fd = err;
> #else
222a253
> #endif
225a257
> /* FIXME need to factor out machine specific ia64 stuff */
229,230d260
< pfarg_reg_t pc[OP_MAX_COUNTERS];
< pfarg_reg_t pd[OP_MAX_COUNTERS];
232a263,280
> #ifndef OPROF_PERFMON2
> size_t j;
> pfarg_reg_t pc[OP_MAX_COUNTERS];
> pfarg_reg_t pd[OP_MAX_COUNTERS];
> #else
> pfmlib_input_param_t inp;
> pfmlib_output_param_t outp;
> pfarg_pmc_t pc[OP_MAX_COUNTERS];
> pfarg_pmd_t pd[OP_MAX_COUNTERS];
> pfmlib_options_t pfmlib_options;
>
> /*
> * pass options to library (optional)
> */
> memset(&pfmlib_options, 0, sizeof(pfmlib_options));
> pfmlib_options.pfm_debug = 0; /* set to 1 for debug */
> pfmlib_options.pfm_verbose = 0; /* set to 1 for debug */
> pfm_set_options(&pfmlib_options);
233a282,285
> memset(&inp,0, sizeof(inp));
> memset(&outp,0, sizeof(outp));
>
> #endif /* OPROF_PERFMON2 */
236a289,290
> #ifndef OPROF_PERFMON2
>
260d313
< }
262,263d314
< for (i = 0; i < op_nr_counters && opd_events[i].name; ++i) {
< struct opd_event * event = &opd_events[i];
266a318
> pd[i].reg_smpl_eventid = event->counter;
267a320
> #else
269,271c322,345
< err = perfmonctl(self->ctx_fd, PFM_WRITE_PMCS, pc, i);
< if (err == -1) {
< perror("Couldn't write PMCs: ");
---
> /* setup inp */
> inp.pfp_dfl_plm = PFM_PLM0;
>
> for (i = 0; i < op_nr_counters && opd_events[i].name; ++i) {
> struct opd_event * event = &opd_events[i];
> /* Find the matching event */
> if (pfm_find_event(event->name, &inp.pfp_events[i].event)
> != PFMLIB_SUCCESS) {
> fatal_error("oprofiled: Cannot find %s event\n", event->name);
> }
> (event->user) ? (inp.pfp_events[i].plm |= PFM_PLM3)
> : (inp.pfp_events[i].plm &= ~PFM_PLM3);
> (event->kernel) ? (inp.pfp_events[i].plm |= PFM_PLM0)
> : (inp.pfp_events[i].plm &= ~PFM_PLM0);
>
> /* set to sampling */
> /* interval between samples */
> }
> inp.pfp_event_count = i;
>
> /* generate outp */
> err = pfm_dispatch_events(&inp, NULL, &outp, NULL);
> if (err != PFMLIB_SUCCESS) {
> fatal_error("oprofiled: cannot configure events: %s\n", pfm_strerror(err));
275c349,369
< err = perfmonctl(self->ctx_fd, PFM_WRITE_PMDS, pd, i);
---
> /* copy outp over */
> for (i=0; i < outp.pfp_pmc_count; i++) {
> pc[i].reg_num = outp.pfp_pmcs[i].reg_num;
> pc[i].reg_value = outp.pfp_pmcs[i].reg_value;
> }
>
> for (i=0; i < outp.pfp_pmd_count; i++) {
> struct opd_event * event = &opd_events[i];
> /* figure out pmd mapping from output pmc */
> pd[i].reg_num = outp.pfp_pmds[i].reg_num;
> /* fill out the rest of the information pmd */
> pd[i].reg_smpl_pmds[0] = 0;
> pd[i].reg_flags |= PFM_REGFL_OVFL_NOTIFY;
> pd[i].reg_reset_pmds[0] = 0;
> pd[i].reg_value = - (unsigned long long)event->count;
> pd[i].reg_short_reset = - (unsigned long long)event->count;
> pd[i].reg_long_reset = - (unsigned long long)event->count;
> }
> #endif
>
> err = op_pfm_write_pmcs(self->ctx_fd, pc, i);
277,278c371,378
< perror("Couldn't write PMDs: ");
< exit(EXIT_FAILURE);
---
> op_pfm_perror("oprofiled: pfm_write_pmcs failed: ",err);
> exit(EXIT_FAILURE);
> }
>
> err = op_pfm_write_pmds(self->ctx_fd, pd, i);
> if (err == -1) {
> op_pfm_perror("oprofiled: pfm_write_pmds failed: ",err);
> exit(EXIT_FAILURE);
283c383
< static void load_context(struct child * self)
---
> static void load_context(size_t cpu, struct child * self)
289c389
< load_args.load_pid = self->pid;
---
> load_args.load_pid = cpu;
291c391
< err = perfmonctl(self->ctx_fd, PFM_LOAD_CONTEXT, &load_args, 1);
---
> err = op_pfm_load_context(self->ctx_fd, &load_args);
293,294c393,394
< perror("Couldn't load context: ");
< exit(EXIT_FAILURE);
---
> op_pfm_perror("oprofiled: pfm_load_context failed: ",err);
> exit(EXIT_FAILURE);
307c407
< fprintf(stderr, "Failed to write child pipe with %s\n",
---
> fprintf(stderr, "oprofiled: Failed to write child pipe with %s\n",
318a419,423
> if (pfm_initialize() != PFMLIB_SUCCESS) {
> fprintf(stderr,"oprofiled: Can't initialize PFM library\n");
> exit(EXIT_FAILURE);
> }
>
332c437
< load_context(self);
---
> load_context(cpu, self);
344d448
< printf("PFM_START on CPU%d\n", (int)cpu);
351d454
< printf("PFM_STOP on CPU%d\n", (int)cpu);
371c474
< fprintf(stderr, "Failed to read child pipe with %s\n",
---
> fprintf(stderr, "oprofiled: Failed to read child pipe with %s\n",
376d478
< printf("Perfmon child up on CPU%d\n", (int)tmp);
394c496
< fprintf(stderr, "Couldn't determine number of CPUs.\n");
---
> fprintf(stderr, "oprofiled: Couldn't determine number of CPUs.\n");
406c508
< perror("Couldn't create child pipe.\n");
---
> perror("oprofiled: Couldn't create child pipe.\n");
412c514
< fprintf(stderr, "Couldn't fork perfmon child.\n");
---
> fprintf(stderr, "oprofiled: Couldn't fork perfmon child.\n");
415c517
< printf("Running perfmon child on CPU%d.\n", (int)i);
---
> printf("oprofiled: Running perfmon child on CPU%d.\n", (int)i);
420c522
< printf("Waiting on CPU%d\n", (int)i);
---
> printf("oprofiled: Waiting on CPU%d\n", (int)i);
464c566
< #endif /* __ia64__ */
---
> #endif /* defined(__ia64__) || defined(OPROF_PERFMON2) */
Index: daemon/opd_perfmon.h
===================================================================
RCS file: /cvsroot/oprofile/oprofile/daemon/opd_perfmon.h,v
retrieving revision 1.4
diff -r1.4 opd_perfmon.h
14c14
< #ifdef __ia64__
---
> #if defined(__ia64__) || defined(OPROF_PERFMON2)
16a17
> #include <string.h>
22a24,25
> #if (!defined(OPROF_PERFMON2))
>
28c31
< typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type */
---
> typedef unsigned char pfm_uuid_t[16]; /* custom sampling buffer identifier type */
82a86,134
> /* wrapper to allow older perfmon interface to be used */
> /* FIXME need to be set correcly for older perfmon */
> #define op_pfm_create_context(ctx) perfmonctl(0, PFM_CREATE_CONTEXT, ctx, 1)
> #define op_pfm_write_pmcs(fd, pmcs, count) \
> perfmonctl(fd, PFM_WRITE_PMCS, pmcs, count)
> #define op_pfm_write_pmds(fd, pmds, count) \
> perfmonctl(fd, PFM_WRITE_PMDS, pmds, count)
> #define op_pfm_read_pmds(fd, pmds, count) \
> perfmonctl(fd, PFM_READ_PMDS, pmds, count)
> #define op_pfm_load_context(fd, load) \
> perfmonctl(fd, PFM_LOAD_CONTEXT, load, 1)
> #define op_pfm_start(fd, start) \
> perfmonctl(fd, PFM_START, start, 1)
> #define op_pfm_stop(fd) \
> perfmonctl(fd, PFM_STOP, NULL, 0)
> #define op_pfm_restart(fd) \
> perfmonctl(fd, PFM_RESTART, NULL, 0)
> #define op_pfm_create_evtsets(fd, setd, count) \
> perfmonctl(fd, PFM_CREATE_EVTSETS, setd, count)
> #define op_pfm_getinfo_evtsets(fd, info, count) \
> perfmonctl(fd, PFM_GETINOF, info, count)
> #define op_pfm_delete_evtsets(fd, setd, count) \
> perfmonctl(fd, PFM_DELETE_EVTSETS, setd, count)
> #define op_pfm_unload_context(fd) \
> perfmonctl(fd, PFM_UNLOAD_CONTEXT, NULL, 0)
> #define op_pfm_perror(str,ret) \
> perror(str)
> #else
>
> /* wrapper to allow older perfmon interface to be used */
> #define op_pfm_create_context(ctx) pfm_create_context(ctx, "oprofile_format", NULL, 0)
> #define op_pfm_write_pmcs(fd, pmcs, count) pfm_write_pmcs(fd, pmcs, count)
> #define op_pfm_write_pmds(fd, pmds, count) pfm_write_pmds(fd, pmds, count)
> #define op_pfm_read_pmds(fd, pmds, count) pfm_read_pmds(fd, pmds, count)
> #define op_pfm_load_context(fd, load) pfm_load_context(fd, load)
> #define op_pfm_start(fd, start) pfm_start(fd, start)
> #define op_pfm_stop(fd) pfm_stop(fd)
> #define op_pfm_restart(fd) pfm_restart(fd)
> #define op_pfm_create_evtsets(fd, setd, count) \
> pfm_create_evtsets(fd, setd, count)
> #define op_pfm_getinfo_evtsets(fd, info, count) \
> pfm_getinfo_evtsets(fd, info, count)
> #define op_pfm_delete_evtsets(fd, setd, count) \
> pfm_delete_evtsets(fd, setd, count)
> #define op_pfm_unload_context(fd) pfm_unload_context(fd)
> #define op_pfm_perror(str,ret) \
> fprintf(stderr,"%s%s\n",str,pfm_strerror(ret))
> #endif /* (!defined(OPROF_PERFMON2)) */
>
104c156
< #endif /* __ia64__ */
---
> #endif /* defined(__ia64__) || defined(OPROF_PERFMON2) */
Index: libop/op_cpu_type.c
===================================================================
RCS file: /cvsroot/oprofile/oprofile/libop/op_cpu_type.c,v
retrieving revision 1.39
diff -r1.39 op_cpu_type.c
25c25
< static struct cpu_descr const cpu_descrs[MAX_CPU_TYPE] = {
---
> static struct cpu_descr const cpu_descrs[] = {
Index: libutil/op_cpufreq.c
===================================================================
RCS file: /cvsroot/oprofile/oprofile/libutil/op_cpufreq.c,v
retrieving revision 1.5
diff -r1.5 op_cpufreq.c
48a49,53
> #if defined(__mips__)
> /* mips only provides BogoMIPS*/
> if (sscanf(line, "BogoMIPS : %lf", &fval) == 1)
> break;
> #endif
Index: utils/opcontrol
===================================================================
RCS file: /cvsroot/oprofile/oprofile/utils/opcontrol,v
retrieving revision 1.133
diff -r1.133 opcontrol
297a298,304
> OP_IMPLEMENTATION=$MOUNT/implementation
> if test -f $OP_IMPLEMENTATION; then
> OP_IMPLEMENTATION=`cat $OP_IMPLEMENTATION`
> else
> OP_IMPLEMENTATION="unspecified"
> fi
>
308c315,349
< case "$CPUTYPE" in
---
> case $OP_IMPLEMENTATION in
> perfmon2)
> IS_PERFMON=$KERNEL_SUPPORT
> # need to get the appropriate perfmon module installed
> # FIXME need to remove them when they are not needed
> case "$CPUTYPE" in
> i386/ppro|i386/pii|i386/piii)
> PERFMON_MOD="perfmon_p6"
> ;;
> i386/p6_mobile)
> PERFMON_MOD="perfmon_pm"
> ;;
> #FIXME need to handle em64t
> i386/p4|i386/p4-ht)
> PERFMON_MOD="perfmon_p4"
> ;;
> i386/athlon|x86-64/hammer)
> PERFMON_MOD="perfmon_amd"
> ;;
> mips/20K|mips/5K|mips/24K|mips/25K)
> PERFMON_MOD="perfmon_mips64"
> ;;
> mips/ice9a|mips/ice9b)
> PERFMON_MOD="perfmon_ice9"
> ;;
> esac
> modprobe $PERFMON_MOD
> if test "$?" != "0"; then
> echo "Unable to load module $PERFMON_MOD."
> # couldn't load the module
> exit 1
> fi
> ;;
> unspecified)
> case "$CPUTYPE" in
311a353,356
> esac
> ;;
> *)
> ;;
_______________________________________________
perfmon mailing list
[email protected]
http://www.hpl.hp.com/hosted/linux/mail-archives/perfmon/