This patch adds the cpupcstat script that can be used to measure the DTLB miss
rate while executing a target program.  It is based on and borrows heavily from
the VMRegress tool written by Mel Gorman <m...@csn.ul.ie>.

cpupcstat currently uses oprofile to collect DTLB miss rate data, though the
data collection is modular enough that it should be simple to add another
collection method.  The number of new oprofile samples since the last report
and the sample rate for this interval.

Hopefully this will be useful to identify workloads that would benefit from
using hugepages.

Thanks to Mel Gorman for several contributions the cpupcstat tool and for
letting me cannibalize oprofile_start.sh and oprofile_map_events.pl from
vmregress.

Signed-off-by: Eric B Munson <ebmun...@us.ibm.com>
---
 Makefile               |   20 +++++-
 TLBC/DataCollect.pm    |   46 ++++++++++++
 TLBC/OpCollect.pm      |  123 ++++++++++++++++++++++++++++++++
 TLBC/Report.pm         |   58 +++++++++++++++
 cpupcstat              |  184 ++++++++++++++++++++++++++++++++++++++++++++++++
 man/cpupcstat.8        |   74 +++++++++++++++++++
 oprofile_map_events.pl |  121 +++++++++++++++++++++++++++++++
 oprofile_start.sh      |   85 ++++++++++++++++++++++
 8 files changed, 709 insertions(+), 2 deletions(-)
 create mode 100644 TLBC/DataCollect.pm
 create mode 100644 TLBC/OpCollect.pm
 create mode 100644 TLBC/Report.pm
 create mode 100755 cpupcstat
 create mode 100644 man/cpupcstat.8
 create mode 100755 oprofile_map_events.pl
 create mode 100755 oprofile_start.sh

diff --git a/Makefile b/Makefile
index 4909872..5fbeebf 100644
--- a/Makefile
+++ b/Makefile
@@ -5,13 +5,16 @@ LIBOBJS = hugeutils.o version.o init.o morecore.o debug.o 
alloc.o shm.o kernel-f
 LIBPUOBJS = init_privutils.o debug.o hugeutils.o kernel-features.o
 INSTALL_OBJ_LIBS = libhugetlbfs.so libhugetlbfs.a libhugetlbfs_privutils.so
 BIN_OBJ_DIR=obj
+PM_OBJ_DIR=TLBC
 INSTALL_BIN = hugectl hugeedit hugeadm pagesize
+INSTALL_STAT = cpupcstat oprofile_map_events.pl oprofile_start.sh
+INSTALL_PERLMOD = DataCollect.pm OpCollect.pm Report.pm
 INSTALL_HEADERS = hugetlbfs.h
 INSTALL_MAN1 = pagesize.1
 INSTALL_MAN3 = get_huge_pages.3 get_hugepage_region.3 \
                gethugepagesizes.3 getpagesizes.3
 INSTALL_MAN7 = libhugetlbfs.7
-INSTALL_MAN8 = hugectl.8 hugeedit.8 hugeadm.8
+INSTALL_MAN8 = hugectl.8 hugeedit.8 hugeadm.8 cpupcstat.8
 LDSCRIPT_TYPES = B BDT
 LDSCRIPT_DIST_ELF = elf32ppclinux elf64ppc elf_i386 elf_x86_64
 INSTALL_OBJSCRIPT = ld.hugetlbfs
@@ -138,6 +141,7 @@ LDSCRIPTDIR = $(PREFIX)/share/libhugetlbfs/ldscripts
 BINDIR = $(PREFIX)/share/libhugetlbfs
 EXEDIR = $(PREFIX)/bin
 DOCDIR = $(PREFIX)/share/doc/libhugetlbfs
+PMDIR = $(PREFIX)/lib/perl5/TLBC
 MANDIR1 = $(PREFIX)/share/man/man1
 MANDIR3 = $(PREFIX)/share/man/man3
 MANDIR7 = $(PREFIX)/share/man/man7
@@ -398,7 +402,19 @@ install-bin:
        for x in $(INSTALL_BIN); do \
                $(INSTALL) -m 755 $(BIN_OBJ_DIR)/$$x $(DESTDIR)$(EXEDIR); done
 
-install: install-libs install-bin install-man
+install-stat: install-perlmod
+       @$(VECHO) INSTALL_STAT $(DESTDIR)$(EXEDIR)
+       $(INSTALL) -d $(DESTDIR)$(EXEDIR)
+       for x in $(INSTALL_STAT); do \
+               $(INSTALL) -m 755 $$x $(DESTDIR)$(EXEDIR); done
+
+install-perlmod:
+       @$(VECHO) INSTALL_PERLMOD $(DESTDIR)$(PMDIR)
+       $(INSTALL) -d $(DESTDIR)$(PMDIR)
+       for x in $(INSTALL_PERLMOD); do \
+               $(INSTALL) -m 644 $(PM_OBJ_DIR)/$$x $(DESTDIR)$(PMDIR); done
+
+install: install-libs install-bin install-man install-stat
 
 install-docs:
        $(INSTALL) -d $(DESTDIR)$(DOCDIR)
diff --git a/TLBC/DataCollect.pm b/TLBC/DataCollect.pm
new file mode 100644
index 0000000..cc434d1
--- /dev/null
+++ b/TLBC/DataCollect.pm
@@ -0,0 +1,46 @@
+#
+# DataCollect.pm
+#
+# This module is the base class for DTLB data collection.  This class is a
+# interface class only, to add a new collection method inherit from this
+# class and use it in calc_missrate.pl
+# Licensed under LGPL 2.1 as packaged with libhugetlbfs
+# (c) Eric Munson 2009
+
+package TLBC::DataCollect;
+
+use warnings;
+use strict;
+use Carp;
+use base;
+
+sub new()
+{
+}
+
+##
+# The setup method should take care of setting up the data collector for
+# collecting DTLB miss data.  This method takes no args and returns $self
+
+sub setup()
+{
+}
+
+##
+# This method should the return the total event count as of its
+# invocation.  This method takes no args and it returns the total number
+# of DTLB misses.
+
+sub get_current_eventcount()
+{
+}
+
+##
+# The shutdown method should stop the data collection and do any clean up
+# necessary.  This method takes no args and returns $self
+
+sub shutdown()
+{
+}
+
+1;
diff --git a/TLBC/OpCollect.pm b/TLBC/OpCollect.pm
new file mode 100644
index 0000000..3bc41aa
--- /dev/null
+++ b/TLBC/OpCollect.pm
@@ -0,0 +1,123 @@
+#
+# OpCollect.pm
+#
+# This module contains all the setup, data collection, and cleanup methods
+# for collecting CPU performance counter information from oprofile.
+# Licensed under LGPL 2.1 as packaged with libhugetlbfs
+# (c) Eric Munson 2009
+
+package TLBC::OpCollect;
+
+use warnings;
+use strict;
+use Carp;
+
+use FindBin qw($Bin);
+use lib "$Bin/lib";
+use TLBC::DataCollect;
+
+our @ISA = qw(TLBC::DataCollect);
+
+my $count = 0;
+my $reference;
+
+#use interface 'DataCollect';
+
+sub _clear_oprofile()
+{
+       my $self = shift;
+       system("opcontrol --reset > /dev/null 2>&1");
+       system("opcontrol --stop > /dev/null 2>&1");
+       system("opcontrol --reset > /dev/null 2>&1");
+       system("opcontrol --deinit > /dev/null 2>&1");
+       return $self;
+}
+
+sub _setup_oprofile()
+{
+       my $self = shift;
+       my $vmlinux = shift;
+       my $event = shift;
+       my $cmd = "$Bin/oprofile_start.sh --vmlinux=$vmlinux " .
+                  "--event=$event  > /dev/null 2>&1";
+       system($cmd) == 0 or die "Failed to start oprofile\n";
+       return $self;
+}
+
+sub _get_event()
+{
+       my $self = shift;
+       my $event = shift;
+       my @vals;
+       my $lowlevel_event;
+       $lowlevel_event = `$Bin/oprofile_map_events.pl --event $event 
2>/dev/null`;
+       chomp($lowlevel_event);
+       if ($lowlevel_event eq "" || $lowlevel_event !~ /^[A-Z0-9_]+:[0-9]+/) {
+               die "Unable to find $event event for this CPU\n";
+       }
+
+       @vals = split(/:/, $lowlevel_event);
+       $count = $vals[1];
+       return $self;
+}
+
+sub new()
+{
+       my $class = shift;
+       if ($reference) {
+               return $reference;
+       }
+
+       $reference = {...@_};
+       bless($reference, $class);
+       return $reference;
+}
+
+sub setup()
+{
+       my $self = shift;
+       my $vmlinux = shift;
+       my $event = shift;
+       $self->_get_event($event);
+       $self->_clear_oprofile();
+       $self->_setup_oprofile($vmlinux, $event);
+       return $self;
+}
+
+sub samples()
+{
+       return $count;
+}
+
+sub get_current_eventcount()
+{
+       my @results;
+       my $line;
+       my $report;
+       my $hits = 0;
+       my $self = shift;
+       my $binName = shift;
+
+       system("opcontrol --dump > /dev/null 2>&1");
+       $report = `opreport`;
+       @results = split(/\n/, $report);
+       foreach $line (@results) {
+               if ($line =~ /$binName/) {
+                       chomp($line);
+                       $line =~ s/^\s+//;
+                       $line =~ s/\s+$//;
+                       my @vals = split(/ /, $line);
+                       $hits += $vals[0];
+               }
+       }
+       return $hits;
+}
+
+sub shutdown()
+{
+       my $self = shift;
+       _clear_oprofile();
+       return $self;
+}
+
+1;
diff --git a/TLBC/Report.pm b/TLBC/Report.pm
new file mode 100644
index 0000000..bea0c05
--- /dev/null
+++ b/TLBC/Report.pm
@@ -0,0 +1,58 @@
+#
+# Report.pm
+#
+# This very simple module is simply for keeping report generation
+# in the same place. The code is basically a glorified collection
+# of print statements
+# Licensed under LGPL 2.1 as packaged with libhugetlbfs
+# (c) Mel Gorman 2003
+
+package TLBC::Report;
+require Exporter;
+use vars qw (@ISA @EXPORT);
+use strict;
+my $verbose;
+
+...@isa    = qw(Exporter);
+...@export = qw(&setVerbose &printVerbose &reportPrint &reportOpen 
&reportClose);
+
+##
+# setVerbose - Set the verbose flag
+sub setVerbose {
+  $verbose = 1;
+}
+
+##
+# printVerbose - Print debugging messages if verbose is set
+# @String to print
+sub printVerbose {
+  $verbose && print @_;
+}
+
+##
+# reportPrint - Print a string verbatim to the report
+# @string:     String to print
+sub reportPrint {
+  my ($string) = @_;
+
+  print HTML $string;
+}
+
+##
+#
+# reportOpen - Open a new report
+# @filename: Filename of report to open
+sub reportOpen {
+  my ($filename) = @_;
+
+  open (HTML, ">$filename") or die("Could not open $filename");
+}
+
+##
+#
+# reportClose - Close the report
+sub reportClose {
+  close HTML;
+}
+
+1;
diff --git a/cpupcstat b/cpupcstat
new file mode 100755
index 0000000..8ea0dae
--- /dev/null
+++ b/cpupcstat
@@ -0,0 +1,184 @@
+#!/usr/bin/perl -w
+# This script starts a requested application after setting up oprofile to
+# collect TLB miss data.  It will use this data to calculate the TLB
+# apporximate TLB miss rate.
+# Licensed under LGPL 2.1 as packaged with libhugetlbfs
+# (c) Eric Munson 2009
+
+use Getopt::Long;
+use FindBin qw($Bin);
+use lib "$Bin";
+use POSIX ":sys_wait_h";
+use TLBC::OpCollect;
+use strict;
+
+my ($arch, $cputype);
+my $vmlinux;
+my $target;
+my $real_target;
+my $target_pid;
+my $misses;
+my $kern_misses;
+my $time_elapsed;
+my $wait_time = 10;
+my $time_limit;
+my $persist = 0;
+my $kernel;
+
+sub start_target()
+{
+       my $pid = fork();
+       if (not defined $pid) {
+               die "Failed to fork\n";
+       } elsif ($pid == 0) {
+               exec $target or die "Failed to exec '$target'\n";
+       } else {
+               return($pid);
+       }
+}
+
+sub run_profile()
+{
+       my $start_time;
+       my $end_time;
+       my @results;
+       my $binName;
+       my $pid;
+       my $ret;
+       my $prev = 0;
+       my $kern_prev = 0;
+       my $new;
+       my $collector = TLBC::OpCollect->new();
+
+       $start_time = time();
+
+       $collector->setup($vmlinux, "dtlb_miss");
+
+       if (defined $target_pid) {
+               $target = readlink("/proc/$target_pid/exe");
+               chomp($target);
+               $binName = $target;
+               $pid = $target_pid;
+       } elsif (defined $target) {
+               if (defined $real_target) {
+                       $binName = $real_target;
+               } else {
+                       @results = split(/ /, $target);
+                       $binName = $results[0];
+               }
+               $pid = start_target();
+       }
+
+       $binName = `basename $binName`;
+       chomp($binName);
+
+       printf("%20s%20s%24s\n", "Target Name", "DTLB Miss Samples",
+               "Samples/second");
+
+       printf("%20s%20s%24s\n", "", "Sample every " . $collector->samples(), 
"");
+       sleep($wait_time);
+
+       # While our target is still running and we have not exceeded our
+       # runtime, collect oprofile data every $wait_time seconds to display
+       # the dtlb miss rate.
+       while (waitpid($pid, WNOHANG) <= 0 || $persist) {
+               $ret = $collector->get_current_eventcount($binName);
+               $new = $ret - $prev;
+               printf("%20s%20d%24f\n", $binName, $new, $new / $wait_time);
+               $prev = $ret;
+               if ($kernel) {
+                       $ret = $collector->get_current_eventcount("vmlinux");
+                       $new = $ret - $kern_prev;
+                       printf("%20s%20d%24f\n", "vmlinux", $new,
+                               $new / $wait_time);
+                       $kern_prev = $ret;
+               }
+               $end_time = time();
+               $time_elapsed = $end_time - $start_time;
+               if (defined $time_limit && $time_elapsed > $time_limit) {
+                       last;
+               }
+               sleep($wait_time);
+       }
+       $end_time = time();
+       $time_elapsed = $end_time - $start_time;
+       $misses = $collector->get_current_eventcount($binName);
+       if ($kernel) {
+               $kern_misses = $collector->get_current_eventcount("vmlinux");
+       }
+
+       $collector->shutdown();
+}
+
+sub get_target()
+{
+       $target .= $_[0] . " ";
+}
+
+sub print_usage()
+{
+       print "Usage: cpupcstat [options] target
+       Options:
+       --vmlinux /path/to/vmlinux Sets the vmlinux file to use
+       --delay N                  Waits N seconds before rereading the
+                                   miss rate
+       --target-pid P             Watch the miss rate of P instead of a target
+       --real-target T            Watch T instead of target in case target is
+                                   a launcher script
+       --time-limit L             Sets a time limit for watching the target
+       --kernel                   Output DTLB miss data for the kernel as well
+                                   as the specified target
+       --help                     prints this message
+
+       Note: If --target-pid is specified, target will be ignored.\n";
+       exit(0);
+}
+
+sub exit_cleanup()
+{
+       my $collector = TLBC::OpCollect->new();
+       $collector->shutdown();
+       exit(0);
+}
+use sigtrap 'handler' => \&exit_cleanup, 'INT';
+
+Getopt::Long::Configure ('bundling');
+GetOptions ('v|vmlinux=s' => \$vmlinux,
+           'h|help' => \&print_usage,
+           'd|delay=i' => \$wait_time,
+           'p|target-pid=i' => \$target_pid,
+           'r|real-target=s' => \$real_target,
+           'l|time-limit=i' => \$time_limit,
+           'k|kernel' => \$kernel,
+           's|persist' => \$persist,
+           '<>' => \&get_target);
+
+if (!$target && not defined $target_pid) {
+       print_usage();
+}
+
+if (!$vmlinux) {
+       $vmlinux = "/boot/vmlinux-" . `uname -r`;
+}
+
+chomp($vmlinux);
+if ($target) {
+       chomp($target);
+}
+
+$misses = 0;
+$kern_misses = 0;
+run_profile();
+
+if ($misses > 0) {
+       print("\n$target saw $misses total DTLB miss samples over ",
+               "$time_elapsed seconds\n");
+       print("at rate of ", $misses / $time_elapsed, " samples/second\n");
+}
+
+if ($kern_misses > 0) {
+       print("The kernel saw $kern_misses total DTLB miss samples over ",
+               "$time_elapsed seconds\n");
+       print("at rate of ", $kern_misses / $time_elapsed, " samples/second\n");
+}
+
diff --git a/man/cpupcstat.8 b/man/cpupcstat.8
new file mode 100644
index 0000000..dd30f20
--- /dev/null
+++ b/man/cpupcstat.8
@@ -0,0 +1,74 @@
+.\"                                      Hey, EMACS: -*- nroff -*-
+.\" First parameter, NAME, should be all caps
+.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
+.\" other parameters are allowed: see man(7), man(1)
+.TH CPUCPSTAT 8 "9 June, 2009"
+.\" Please adjust this date whenever revising the manpage.
+.\"
+.\" Some roff macros, for reference:
+.\" .nh        disable hyphenation
+.\" .hy        enable hyphenation
+.\" .ad l      left justify
+.\" .ad b      justify to both left and right margins
+.\" .nf        disable filling
+.\" .fi        enable filling
+.\" .br        insert line break
+.\" .sp <n>    insert n+1 empty lines
+.\" for manpage-specific macros, see man(7)
+.SH NAME
+cpupcstat \- Measure the DTLB miss rate
+.SH SYNOPSIS
+.B cpupcstat [options] [target]
+.SH DESCRIPTION
+\fBcpupcstat\fP uses oprofile to measure the DTLB miss rate of a
+specified application or the kernel.  It configures oprofile to count the
+number of DTLB misses, optionally starts the \fBtarget\fP, and reports on the
+miss rate over a specified interval as \fBtarget\fP executes.
+
+The following options can be used to configure how \fBcpupcstat\fP works:
+
+.TP
+.B --vmlinux </path/to/vmlinux>
+
+This allows the user to specify where the appropriate vmlinux file is for their
+kernel.  If this is not specified, /boot/vmlinux\-\`uname \-r\` will be used.
+
+.TP
+.B --delay <seconds>
+
+This allows the user to specify the reporting interval.  The default is 10
+seconds.
+
+.TP
+.B --target-pid <pid>
+
+This allows the user to specify the pid of a process already that is already
+running.  If this option is specified, \fBtarget\fP will be ignored.
+
+.TP
+.B --real-target <real-target>
+
+Use this to specify the real name of the program to monitor if the \fBtarget\fP
+is a launcher script.  When this is specified, \fBtarget\fP is executed but the
+report will be for \fBreal-target\fP.
+
+.TP
+.B --time-limit <sec>
+
+This option sets the time limit for monitoring.  If this is specified the
+\fBtarget\fP or \fBpid\fP will only be monitored for \fBsec\fP seconds.  The
+default continues monitoring while \fBtarget\fP or \fBpid\fP are still alive.
+
+.TP
+.B --kernel
+
+This allows the user to request DTLB miss rate data be collected for the kernel
+as well as the \fBtarget\fP.
+
+.SH SEE ALSO
+.I oprofile(1)
+.br
+.SH AUTHORS
+Eric B Munson <ebmun...@us.ibm.com> is the primary author. See the 
documentation
+for other contributors.
+
diff --git a/oprofile_map_events.pl b/oprofile_map_events.pl
new file mode 100755
index 0000000..5fc4faf
--- /dev/null
+++ b/oprofile_map_events.pl
@@ -0,0 +1,121 @@
+#!/usr/bin/perl
+# This script attempts to map a high-level CPU event to the oprofile counter
+# of the current CPU
+# Licensed under LGPL 2.1 as packaged with libhugetlbfs
+# (c) Mel Gorman 2008
+
+use Getopt::Long;
+use FindBin qw($Bin);
+use lib "$Bin";
+
+use TLBC::Report;
+use strict;
+
+my ($arch, $cputype);
+my $opt_verbose;
+my $opt_event;
+my $opt_factor=1;
+my $p = "oprofile_map_events.pl";
+
+my $oprofile_event;
+my (%map_event_name, %map_event_mask);
+
+# CPU events miss table
+$map_event_name{"i386##dtlb_miss"} = "PAGE_WALK_TYPE:100000:0x01";
+$map_event_name{"i386##p4##timer"} = "GLOBAL_POWER_EVENTS:100000:0x01";
+$map_event_name{"i386##p4##dtlb_miss"} = "PAGE_WALK_TYPE:3000:0x01";
+$map_event_name{"i386##p4##l2cache_miss"} = "BSQ_CACHE_REFERENCE:3000:0x300";
+$map_event_name{"i386##p4-ht##timer"} = "GLOBAL_POWER_EVENTS:6000:0x01";
+$map_event_name{"i386##p4-ht##dtlb_miss"} = "PAGE_WALK_TYPE:3000:0x01";
+$map_event_name{"i386##p4-ht##l2cache_miss"} = 
"BSQ_CACHE_REFERENCE:6000:0x300";
+$map_event_name{"i386##core##timer"} = "CPU_CLK_UNHALTED:6000";
+$map_event_name{"i386##core##dtlb_miss"} = "DTLB_MISS:500";
+$map_event_name{"i386##core_2##dtlb_miss"} = "DTLB_MISSES:500:0x01";
+$map_event_name{"x86-64##timer"} = "CPU_CLK_UNHALTED:100000";
+$map_event_name{"x86-64##hammer##dtlb_miss"} = "L1_AND_L2_DTLB_MISSES:100000";
+$map_event_name{"x86-64##hammer##l1cache_miss"} = "DATA_CACHE_MISSES:500";
+$map_event_name{"x86-64##hammer##l2cache_miss"} = "L2_CACHE_MISS:500";
+$map_event_name{"x86-64##family10##dtlb_miss"} = 
"L1_DTLB_AND_L2_DTLB_MISS:500";
+$map_event_name{"x86-64##family10##l1cache_miss"} = "DATA_CACHE_MISSES:500";
+$map_event_name{"x86-64##family10##l2cache_miss"} = "L2_CACHE_MISS:500";
+$map_event_name{"x86-64##core_2##dtlb_miss"} = "DTLB_MISSES:500:0x01";
+$map_event_name{"ppc64##timer"} = "CYCLES:50000";
+$map_event_name{"ppc64##dtlb_miss"} = "PM_DTLB_MISS_GRP44:100000";
+$map_event_name{"ppc64##970MP##timer"} = "PM_CYC_GRP22:50000";
+$map_event_name{"ppc64##970MP##dtlb_miss"} = "PM_DTLB_MISS_GRP22:1000";
+$map_event_name{"ppc64##970MP##l1cache_ld_miss"} = "PM_LD_MISS_L1_GRP22:1000";
+$map_event_name{"ppc64##970MP##l1cache_st_miss"} = "PM_ST_MISS_L1_GRP22:1000";
+$map_event_name{"ppc64##970MP##timer50"} = "PM_CYC_GRP50:10000";
+$map_event_name{"ppc64##970MP##l1l2cache_miss"} = 
"PM_DATA_FROM_MEM_GRP50:1000";
+$map_event_name{"ppc64##power5##dtlb_miss"} = "PM_DTLB_MISS_GRP44:100000";
+
+GetOptions(
+       'verbose'               =>      \$opt_verbose,
+       'sample-factor|s=s'     =>      \$opt_factor,
+       'event|e=s'             =>      \$opt_event,
+       );
+setVerbose if $opt_verbose;
+
+if ($opt_event eq "" || $opt_event eq "default") {
+       print "default\n";
+       exit(0);
+}
+
+# Run --list-events to setup devices
+open (SETUP, "opcontrol --list-events|") || die("Failed to exec opcontrol");
+printVerbose("$p\::init list-events\n");
+while (!eof(SETUP)) {
+       $_ = <SETUP>;
+}
+close(SETUP);
+
+# Read the arch and CPU type
+open (CPUTYPE, "/proc/sys/dev/oprofile/cpu_type") ||
+       open (CPUTYPE, "/dev/oprofile/cpu_type") ||
+               die("Failed to open cpu_type oprofile device");
+($arch, $cputype) = split(/\//, <CPUTYPE>);
+close CPUTYPE;
+printVerbose("$p\::arch = $arch\n");
+printVerbose("$p\::cputype = $cputype\n");
+printVerbose("$p\::event = $opt_event\n");
+
+# Lookup the event for the processor
+$oprofile_event = $map_event_name{"$arch##$cputype##$opt_event"};
+printVerbose("$p\::lookup $arch##$cputype##$opt_event = $oprofile_event\n");
+if ($oprofile_event eq "") {
+       $oprofile_event = $map_event_name{"$arch##$opt_event"};
+       printVerbose("$p\:: lookup $arch##$opt_event = $oprofile_event\n");
+}
+
+# If unknown, exit with failure
+if ($oprofile_event eq "") {
+       print "UNKNOWN_EVENT\n";
+       exit(-2);
+}
+
+# Apply the sampling factor if specified
+if ($opt_factor != 1) {
+       my ($event, $sample, $mask) = split(/:/, $oprofile_event);
+       $sample *= $opt_factor;
+       if ($mask eq "") {
+               $oprofile_event = "$event:$sample";
+       } else {
+               $oprofile_event = "$event:$sample:$mask";
+       }
+}
+
+# Verify opcontrol agrees
+open (VERIFY, "opcontrol --list-events|") || die("Failed to exec opcontrol");
+my ($oprofile_event_name) = split(/:/, $oprofile_event);
+printVerbose("$p\::checking $oprofile_event_name\n");
+while (!eof(VERIFY)) {
+       if (<VERIFY> =~ /^$oprofile_event_name:/) {
+               close(VERIFY);
+               print "$oprofile_event\n";
+               exit(0);
+       }
+}
+close(VERIFY);
+printVerbose("$p\::opcontrol --list-events disagrees\n");
+print "UNKNOWN_OPROFILE_DISPARITY\n";
+exit(-3);
diff --git a/oprofile_start.sh b/oprofile_start.sh
new file mode 100755
index 0000000..5153320
--- /dev/null
+++ b/oprofile_start.sh
@@ -0,0 +1,85 @@
+#!/bin/bash
+# Script to start oprofile
+
+usage() {
+       echo "oprofile_start.sh (c) Mel Gorman 2008"
+       echo This script starts the oprofile daemon
+       echo
+       echo "Usage: oprofile_start.sh [options]"
+       echo "    --event         High-level oprofile event to track"
+       echo "    --vmlinux       Path to vmlinux"
+       echo "    --sample-factor Factor which to slow down sampling by"
+       echo "    --systemmap     Guess"
+       echo "    -v, --vmr       VMRegress install directory (default: 
$VMREGRESS_DIR)"
+       echo "    -h, --help     Print this help message"
+       echo
+       exit
+}
+
+# Parse command-line arguements
+SCRIPTROOT=`echo $0 | sed -e 's/oprofile_start.sh$//' | sed -e 's/^\.\///'`
+EVENT=default
+VMLINUX=/boot/vmlinux-`uname -r`
+SYSTEMMAP=/boot/System.map-`uname -r`
+FACTOR=
+export PATH=$SCRIPTROOT:$PATH
+ARGS=`getopt -o hv: --long help,vmr:,event:,vmlinux:,systemmap:,sample-factor: 
-n oprofile_start.sh -- "$@"`
+
+# Cycle through arguements
+eval set -- "$ARGS"
+while true ; do
+  case "$1" in
+       -v|--vmr)        VMREGRESS_DIR="$2"; shift 2;;
+       --event)         EVENTS="$EVENTS $2"; shift 2;;
+       --vmlinux)       VMLINUX=$2; shift 2;;
+       --sample-factor) FACTOR="--sample-factor $2"; shift 2;;
+       --systemmap)     SYSTEMMAP=$2; shift 2;;
+        -h|--help) usage;;
+        *) shift 1; break;;
+  esac
+done
+
+# Map the events
+for EVENT in $EVENTS; do
+       LOWLEVEL_EVENT="$LOWLEVEL_EVENT --event `oprofile_map_events.pl $FACTOR 
--event $EVENT`"
+       if [ $? -ne 0 ]; then
+               echo Failed to map event $EVENT to low-level oprofile event. 
Verbose output follows
+               oprofile_map_events.pl --event $EVENT --verbose
+               exit -1
+       fi
+done
+
+# Check vmlinux file exists
+if [ "$VMLINUX" = "" -o ! -e $VMLINUX ]; then
+       echo vmlinux file \"$VMLINUX\" does not exist
+       exit -1
+fi
+
+echo Stage 1: Shutting down if running and resetting
+bash opcontrol --reset
+bash opcontrol --stop
+bash opcontrol --reset
+bash opcontrol --deinit
+echo
+
+# Setup the profiler
+echo Stage 2: Setting up oprofile
+echo High-level event: $EVENTS
+echo Low-level event: `echo $LOWLEVEL_EVENT | sed -e 's/--event //'`
+echo vmlinux: $VMLINUX
+echo opcontrol --setup $LOWLEVEL_EVENT --vmlinux=$VMLINUX
+bash opcontrol --setup $LOWLEVEL_EVENT --vmlinux=$VMLINUX 
+if [ $? -ne 0 ]; then
+       echo opcontrol --setup returned failed
+       exit -1
+fi
+
+# Start the profiler
+echo Stage 3: Starting profiler
+bash opcontrol --start
+if [ $? -ne 0 ]; then
+       echo opcontrol --start returned failure
+       exit -1
+fi
+
+exit 0
-- 
1.6.1.2


------------------------------------------------------------------------------
Crystal Reports - New Free Runtime and 30 Day Trial
Check out the new simplified licensing option that enables unlimited
royalty-free distribution of the report engine for externally facing 
server and web deployment.
http://p.sf.net/sfu/businessobjects
_______________________________________________
Libhugetlbfs-devel mailing list
Libhugetlbfs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/libhugetlbfs-devel

Reply via email to