OProfile port to perf_events: Patch 1 of 5

This patch introduces a new oprofile tool -- 'operf'.  This tool can
be used in place of opcontrol for profiling.  In this initial set of
five patches, only single-process profiling will be supported by operf.
For system-wide profiling, users can still use the 'legacy' opcontrol
tool.

Patch #1 makes changes to configure and Makefiles to handle the
building of new source files that leverage the kernel's 'perf_events'
support, which was introduced (in usable form) in kernel version 2.6.32.
This patch introduces the options that can be passed to operf and
implements the processing/handling of those arguments.  The patch also
lays the groundwork for the profiling mechanism by forking a "record"
process.  To keep this initial patch simple, no actual profile recording
is implemented here.  But the management of forked processes and error
handling is pretty well fleshed out.

One aspect of this patch to note is the incomplete implementation
(read "hack") for obtaining the cpu_type.  With the legacy opcontrol
command, we obtain the cpu_type from the oprofilefs at /dev/oprofile/cpu_type.
The oprofilefs is mounted and the cpu_type file is written to by the
oprofile kernel driver when the driver is init'ed (via 'opcontrol --init').
But this requires root authority to do, so -- ideally -- we want the
new operf tool to operate independently and not have any dependency
on a superuser having already run 'opcontrol --init'.  Thus, determining
the cpu_type takes a bit more finesse when /dev/oprofile/cpu_type
does not exist.  REVIEWERS: Please take a close look at libop/op_cpu_type.c
and give suggestions for how best to get the cpu_type for the architecture(s)
you are familiar with.

This patch compiles successfully and builds the 'operf' tool, which
can be run and passed various arguments -- but no output is produced.


---
 Makefile.am                    |    1 
 configure.in                   |   45 ++
 libabi/opimport.cpp            |    2 
 libop/op_cpu_type.c            |   71 +++
 libopt++/popt_options.cpp      |   37 +
 libopt++/popt_options.h        |    5 
 libutil/op_popt.c              |   59 ++
 libutil/op_popt.h              |   16 
 m4/kernelversion.m4            |   16 
 pe_profiling/Makefile.am       |   26 +
 pe_profiling/operf.cpp         |  810 +++++++++++++++++++++++++++++++++++++++++
 pe_profiling/operf.h           |   42 ++
 pe_profiling/operf_event.h     |   44 ++
 pp/common_option.cpp           |    2 
 utils/Makefile.am              |    4 
 utils/op_perf_events_checker.c |   70 +++
 utils/opcontrol                |    5 
 17 files changed, 1238 insertions(+), 17 deletions(-)

Index: oprof-PE-patchset/Makefile.am
===================================================================
--- oprof-PE-patchset.orig/Makefile.am
+++ oprof-PE-patchset/Makefile.am
@@ -19,6 +19,7 @@ SUBDIRS = \
 	events \
 	doc \
 	gui \
+	pe_profiling \
 	agents
 #### ATTENTION ####
 #    The agents directory must be kept as the last subdir
Index: oprof-PE-patchset/configure.in
===================================================================
--- oprof-PE-patchset.orig/configure.in
+++ oprof-PE-patchset/configure.in
@@ -12,7 +12,7 @@
 AC_PREREQ(2.13)
 
 AC_INIT(libop/op_config.h)
-AM_INIT_AUTOMAKE(oprofile, 0.9.8git)
+AM_INIT_AUTOMAKE(oprofile, 0.9.8_perf_events)
 AM_CONFIG_HEADER(config.h)
 
 AC_CHECK_DECLS([basename], [], [], [[#include <libgen.h>]])
@@ -63,6 +63,43 @@ AC_PROG_CXX
 AC_CHECK_PROG(LD,ld,ld,)
 test "$LD" || AC_ERROR(ld not found)
 
+dnl Check kernel version for perf_events supported
+AC_MSG_CHECKING([kernel version supports perf_events])
+AX_KERNEL_VERSION(2, 6, 31, <=, kernel_has_perf_events_support="yes",
+kernel_has_perf_events_support="no")
+
+if test "$kernel_has_perf_events_support" = "no"; then
+	AC_MSG_RESULT([This kernel does not have perf_events support; falling back to legacy oprofile])
+else
+	AC_MSG_RESULT([This kernel has perf_events support])
+fi
+
+AC_CHECK_FILE("/usr/include/linux/perf_event.h",PERF_EVENT_H_EXISTS="yes")
+AM_CONDITIONAL(BUILD_FOR_PERF_EVENT, test -n "$PERF_EVENT_H_EXISTS")
+if test "$PERF_EVENT_H_EXISTS" = "yes"; then
+	HAVE_PERF_EVENTS='1'
+else
+	HAVE_PERF_EVENTS='0'
+fi
+AC_DEFINE_UNQUOTED(HAVE_PERF_EVENTS, $HAVE_PERF_EVENTS, [Kernel support for perf_events exists])
+
+if test "$HAVE_PERF_EVENTS" = "1"; then
+	AC_CHECK_HEADER(libelf.h,,[
+	if test -f /usr/include/elfutils/libelf.h; then
+		CXXFLAGS="$CXXFLAGS -I /usr/include/elfutils"
+		CFLAGS="$FLAGS -I /usr/include/elfutils"
+	elif test -f /usr/include/libelf/libelf.h; then
+		CXXFLAGS="$CXXFLAGS -I /usr/include/libelf"
+		CFLAGS="$CFLAGS -I /usr/include/libelf"
+	else
+		AC_MSG_ERROR(libelf.h not found)
+	fi])
+
+	AC_CHECK_LIB(elf,elf_begin,,  AC_MSG_ERROR([elf library not found]))
+	ELF_LIB="-lelf"
+	AC_SUBST(ELF_LIB)
+fi
+
 AC_ARG_WITH(java,
 [  --with-java=java-home        Path to Java home directory (default is "no"; "yes" will use /usr as Java home)],
 JAVA_HOMEDIR=$with_java, [with_java=no])
@@ -278,6 +315,7 @@ OP_DOCDIR=`eval echo "${my_op_prefix}/sh
 AC_SUBST(OP_DOCDIR)
 
 AC_OUTPUT(Makefile \
+	pe_profiling/Makefile \
 	m4/Makefile \
 	libutil/Makefile \
 	libutil/tests/Makefile \
@@ -352,3 +390,8 @@ elif test "`getent passwd oprofile 2>/de
 	fi
 fi
 
+if  test "$PERF_EVENT_H_EXISTS" != "yes" && test "$kernel_has_perf_events_support" = "yes"; then
+	echo "Warning: perf_event.h not found.  Please install the kernel headers package if you"
+	echo "         want non-root support built into OProfile."
+fi
+
Index: oprof-PE-patchset/libabi/opimport.cpp
===================================================================
--- oprof-PE-patchset.orig/libabi/opimport.cpp
+++ oprof-PE-patchset/libabi/opimport.cpp
@@ -169,7 +169,7 @@ int main(int argc, char const ** argv)
 {
 
 	vector<string> inputs;
-	popt::parse_options(argc, argv, inputs);
+	popt::parse_options(argc, argv, inputs, false /*non_option is NOT an app*/);
 
 	if (inputs.size() != 1) {
 		cerr << "error: must specify exactly 1 input file" << endl;
Index: oprof-PE-patchset/libop/op_cpu_type.c
===================================================================
--- oprof-PE-patchset.orig/libop/op_cpu_type.c
+++ oprof-PE-patchset/libop/op_cpu_type.c
@@ -12,6 +12,8 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/utsname.h>
+#include <ctype.h>
 
 #include "op_cpu_type.h"
 #include "op_hw_specific.h"
@@ -103,6 +105,69 @@ static struct cpu_descr const cpu_descrs
  
 static size_t const nr_cpu_descrs = sizeof(cpu_descrs) / sizeof(struct cpu_descr);
 
+static op_cpu _get_ppc64_cpu_type(void)
+{
+	char line[100];
+	op_cpu cpu_type = CPU_NO_GOOD;
+	FILE * fp;
+	fp = fopen("/proc/cpuinfo", "r");
+	if (!fp) {
+		perror("Unable to open /proc/cpuinfo\n");
+		return cpu_type;
+	}
+	memset(line, 0, 100);
+	while (cpu_type == CPU_NO_GOOD) {
+		if (fgets(line, sizeof(line), fp) == NULL) {
+			fprintf(stderr, "Did not find processor type in /proc/cpuinfo.\n");
+			goto out;
+		}
+		if (!strncmp(line, "cpu", 3)) {
+			char cpu_name[64];
+			char *cpu = line + 3;
+			while (*cpu && isspace(*cpu))
+				++cpu;
+			if (sscanf(cpu, ":%s ", cpu_name) == 1) {
+				int i;
+				char cpu_type_str[64], cpu_name_lowercase[64];
+				size_t len = strlen(cpu_name);
+				for (i = 0; i < (int)len ; i++)
+					cpu_name_lowercase[i] = tolower(cpu_name[i]);
+
+				cpu_type_str[0] = '\0';
+				strcat(cpu_type_str, "ppc64/");
+				strncat(cpu_type_str, cpu_name_lowercase, len);
+				cpu_type = op_get_cpu_number(cpu_type_str);
+			}
+		}
+	}
+	out:
+	fclose(fp);
+	return cpu_type;
+}
+
+static op_cpu _get_x86_64_cpu_type(void)
+{
+	// TODO: Horrible HACK!!!
+	fprintf(stderr, "!!! WARNING !!! operf currently supports only arch_perfmon CPUs.\n");
+	return op_cpu_specific_type(CPU_ARCH_PERFMON);
+}
+
+static op_cpu __get_cpu_type_alt_method(void)
+{
+	struct utsname uname_info;
+	if (uname(&uname_info) < 0) {
+		perror("uname failed");
+		return CPU_NO_GOOD;
+	}
+	if (strncmp(uname_info.machine, "x86_64", 6) ==0) {
+		return _get_x86_64_cpu_type();
+	}
+	if (strncmp(uname_info.machine, "ppc64", 5) == 0) {
+		return _get_ppc64_cpu_type();
+	}
+	return CPU_NO_GOOD;
+}
+
 int op_cpu_variations(op_cpu cpu_type)
 {
 	switch (cpu_type) {
@@ -142,8 +207,10 @@ op_cpu op_get_cpu_type(void)
 		/* Try 2.6's oprofilefs one instead. */
 		fp = fopen("/dev/oprofile/cpu_type", "r");
 		if (!fp) {
-			fprintf(stderr, "Unable to open cpu_type file for reading\n");
-			fprintf(stderr, "Make sure you have done opcontrol --init\n");
+			if ((cpu_type = __get_cpu_type_alt_method()) == CPU_NO_GOOD) {
+				fprintf(stderr, "Unable to open cpu_type file for reading\n");
+				fprintf(stderr, "Make sure you have done opcontrol --init\n");
+			}
 			return cpu_type;
 		}
 	}
Index: oprof-PE-patchset/libopt++/popt_options.cpp
===================================================================
--- oprof-PE-patchset.orig/libopt++/popt_options.cpp
+++ oprof-PE-patchset/libopt++/popt_options.cpp
@@ -10,7 +10,8 @@
  */
 
 #include <iostream>
-
+#include <stdlib.h>
+#include <string.h>
 #include "op_popt.h"
 #include "op_version.h"
 
@@ -80,39 +81,55 @@ static struct poptOption appended_option
  * returned poptContext which contains  pointer inside the options array */
 static poptContext do_parse_options(int argc, char const ** argv,
                                     vector<poptOption> & options,
-                                    vector<string> & additional_params)
+                                    vector<string> & additional_params,
+                                    bool non_option_is_app)
 {
+	poptContext con;
 	options = popt_options();
 
 	int const nr_appended_options =
 		sizeof(appended_options) / sizeof(appended_options[0]);
-
 	options.insert(options.end(), appended_options,
 		       appended_options + nr_appended_options);
 
-	poptContext con = op_poptGetContext(NULL, argc, argv, &options[0], 0);
+	if (non_option_is_app) {
+		char ** app_params = (char **)calloc(2, sizeof(char **));
+		con = op_poptGetOptions_getApp(NULL, argc, argv, &options[0], app_params, 0);
+		if (app_params[0]) {
+			for (int i = 0; i < 2; i++) {
+				additional_params.push_back(app_params[i]);
+				if (strlen(app_params[i]))
+					free(app_params[i]);
+			}
+		}
+	} else {
+		con = op_poptGetContext(NULL, argc, argv, &options[0], 0);
+		char const * file;
+		while ((file = poptGetArg(con)) != 0) {
+			additional_params.push_back(file);
+		}
+	}
 
 	if (showvers)
 		show_version(argv[0]);
 
-	char const * file;
-	while ((file = poptGetArg(con)) != 0)
-		additional_params.push_back(file);
-
 	for (size_t i = 0 ; i < options_list().size() ; ++i)
 		options_list()[i]->post_process();
 
+
 	return con;
 }
 
 
 void parse_options(int argc, char const ** argv,
-                   vector<string> & additional_params)
+                   vector<string> & additional_params,
+                   bool non_option_is_app)
 {
 	vector<poptOption> options;
 
 	poptContext con =
-		do_parse_options(argc, argv, options, additional_params);
+			do_parse_options(argc, argv, options, additional_params,
+			                 non_option_is_app);
 
 	poptFreeContext(con);
 }
Index: oprof-PE-patchset/libopt++/popt_options.h
===================================================================
--- oprof-PE-patchset.orig/libopt++/popt_options.h
+++ oprof-PE-patchset/libopt++/popt_options.h
@@ -59,6 +59,8 @@ namespace popt {
  * @param argc like the parameter of main()
  * @param argv like the parameter of main()
  * @param additional_params additional options are stored here
+ * @param non_option_is_app true if app name is expected; otherwise
+ *        profile spec is expected
  *
  * Parse the given command line with the previous
  * options created. Multiple additional arguments
@@ -66,7 +68,8 @@ namespace popt {
  * vector.
  */
 void parse_options(int argc, char const ** argv,
-                   std::vector<std::string> & additional_params);
+                   std::vector<std::string> & additional_params,
+                   bool non_option_is_app);
 
 class option_base;
 
Index: oprof-PE-patchset/libutil/op_popt.c
===================================================================
--- oprof-PE-patchset.orig/libutil/op_popt.c
+++ oprof-PE-patchset/libutil/op_popt.c
@@ -11,6 +11,7 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include "op_libiberty.h"
 #include "op_popt.h"
 
@@ -41,3 +42,61 @@ poptContext op_poptGetContext(char const
 
 	return optcon;
 }
+
+poptContext op_poptGetOptions_getApp(char const * name, int argc,
+                                     char const ** argv,
+                                     struct poptOption const * options,
+                                     char **app_options, int flags)
+{
+	poptContext optcon;
+	const char * leftover = NULL;
+	int c;
+
+	xmalloc_set_program_name(argv[0]);
+
+#ifdef CONST_POPT
+	optcon = poptGetContext(name, argc, argv, options, flags);
+#else
+	optcon = poptGetContext((char *)name, argc, (char **)argv, options, flags);
+#endif
+
+	c = poptGetNextOpt(optcon);
+	if (c < 0) {
+		leftover = poptGetArg(optcon);
+		if (leftover) {
+			int arg_idx, app_name_found, length, num_app_args;
+			char * app_name = (char *)xcalloc(strlen(leftover) + 1, 1);
+			strncpy(app_name, leftover, strlen(leftover) + 1);
+			app_options[0] = app_name;
+			for (arg_idx = 1, app_name_found = 0, length = 0, num_app_args = 0;
+					arg_idx < argc;
+					arg_idx++) {
+				if (app_name_found) {
+					num_app_args++;
+					length += strlen(argv[arg_idx]) + 1;
+				}
+				if (!strcmp(argv[arg_idx], app_name)) {
+					app_name_found = 1;
+				}
+			}
+			if (num_app_args)
+				app_options[1] = (char *)xcalloc(length, 1);
+			else
+				app_options[1] = "";
+			for (arg_idx = argc - num_app_args; arg_idx < argc; arg_idx++) {
+				if (arg_idx > (argc - num_app_args))
+					app_options[1] = strcat(app_options[1], " ");
+				app_options[1] = strcat(app_options[1], argv[arg_idx]);
+			}
+		} else if (c < -1) {
+			fprintf(stderr, "%s: %s: %s\n", argv[0],
+			        poptBadOption(optcon, POPT_BADOPTION_NOALIAS),
+			        poptStrerror(c));
+			poptPrintHelp(optcon, stderr, 0);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	return optcon;
+
+}
Index: oprof-PE-patchset/libutil/op_popt.h
===================================================================
--- oprof-PE-patchset.orig/libutil/op_popt.h
+++ oprof-PE-patchset/libutil/op_popt.h
@@ -35,6 +35,22 @@ poptContext op_poptGetContext(char const
                 int argc, char const ** argv,
                 struct poptOption const * options, int flags);
 
+/**
+ * op_poptGetOptions_getApp
+ *
+ * Use this function when the argv array may be of the form:
+ *    <pgm> [options] <app-to-profile> [app-args]
+ * The <app-to-profile and app-args are passed back in app_options.
+ * The caller MUST allocate a char * array of size 2 and pass that
+ * array in app_options argument.  The first member of this array will
+ * be set to the app-to-profile pathname; the second member will be
+ * set to the app's args.
+ */
+poptContext op_poptGetOptions_getApp(char const * name, int argc,
+                                     char const ** argv,
+                                     struct poptOption const * options,
+                                     char **app_options, int flags);
+
 #ifdef __cplusplus
 }
 #endif
Index: oprof-PE-patchset/m4/kernelversion.m4
===================================================================
--- /dev/null
+++ oprof-PE-patchset/m4/kernelversion.m4
@@ -0,0 +1,16 @@
+dnl AX_KERNEL_VERSION(major, minor, level, comparison, action-if-true, action-if-false)
+AC_DEFUN([AX_KERNEL_VERSION], [
+SAVE_CFLAGS=$CFLAGS
+CFLAGS="-I$KINC -D__KERNEL__ -Werror"
+AC_TRY_COMPILE(
+  [
+  #include <linux/version.h>
+  ],
+  [
+  #if LINUX_VERSION_CODE $4 KERNEL_VERSION($1, $2, $3)
+  break_me_hard(\\\);
+  #endif
+  ],
+[$5],[$6],)
+CFLAGS=$SAVE_CFLAGS
+])
Index: oprof-PE-patchset/pe_profiling/Makefile.am
===================================================================
--- /dev/null
+++ oprof-PE-patchset/pe_profiling/Makefile.am
@@ -0,0 +1,26 @@
+LIBS=@POPT_LIBS@ @LIBERTY_LIBS@ @ELF_LIB@
+if BUILD_FOR_PERF_EVENT
+
+AM_CPPFLAGS = \
+	-I ${top_srcdir}/libabi \
+	-I ${top_srcdir}/libutil \
+	-I ${top_srcdir}/libop \
+	-I ${top_srcdir}/libopt++ \
+	-I ${top_srcdir}/libutil++ \
+	-I ${top_srcdir}/libdb \
+	-I ${top_srcdir}/pe_profiling
+
+operf_SOURCES = operf.cpp \
+	operf.h \
+	operf_event.h
+
+AM_CXXFLAGS = @OP_CXXFLAGS@
+bin_PROGRAMS = operf
+operf_LDADD =	../libopt++/libopt++.a \
+	../libutil++/libutil++.a \
+	../libdb/libodb.a \
+	../libop/libop.a \
+	../libutil/libutil.a \
+	../libabi/libabi.a
+
+endif
Index: oprof-PE-patchset/pe_profiling/operf.cpp
===================================================================
--- /dev/null
+++ oprof-PE-patchset/pe_profiling/operf.cpp
@@ -0,0 +1,810 @@
+/**
+ * @file operf.cpp
+ * Front-end (containing main) for handling a user request to run a profile
+ * using the new Linux Performance Events Subsystem.
+ *
+ * @remark Copyright 2011 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * Created on: Dec 7, 2011
+ * @author Maynard Johnson
+ * (C) Copyright IBM Corp. 2011
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <exception>
+#include <pwd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <string.h>
+#include <unistd.h>
+#include <asm/unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <ftw.h>
+#include <iostream>
+#include "operf.h"
+#include "popt_options.h"
+#include "op_libiberty.h"
+#include "string_manip.h"
+#include "cverb.h"
+#include "op_cpu_type.h"
+#include "op_cpufreq.h"
+#include "op_abi.h"
+#include "op_events.h"
+#include "op_string.h"
+
+using namespace std;
+
+typedef enum END_CODE {
+	ALL_OK = 0,
+	APP_ABNORMAL_END = -2,
+	PERF_RECORD_ERROR = -3
+} end_code_t;
+// Globals
+char * app_name = NULL;
+op_cpu cpu_type;
+double cpu_speed;
+char op_samples_current_dir[PATH_MAX];
+
+
+#define DEFAULT_OPERF_OUTFILE "operf.data"
+static char full_pathname[PATH_MAX];
+static char * app_name_SAVE = NULL;
+static char * app_args = NULL;
+static pid_t app_PID;
+static bool app_started;
+static pid_t operf_pid;
+static string samples_dir;
+static string outputfile;
+uint op_nr_counters;
+vector<operf_event_t> events;
+
+verbose vmisc("misc");
+
+namespace operf_options {
+bool system_wide;
+bool reset;
+int pid;
+int callgraph_depth;
+int mmap_pages_mult;
+string session_dir;
+bool separate_cpu;
+vector<string> evts;
+}
+
+namespace {
+vector<string> verbose_string;
+
+popt::option options_array[] = {
+	popt::option(verbose_string, "verbose", 'V',
+	             "verbose output", "debug,perf_events,misc,all"),
+	popt::option(operf_options::session_dir, "session-dir", '\0',
+	             "specify session path to hold sample data", "path"),
+	popt::option(operf_options::callgraph_depth, "callgraph", 'g',
+	             "callgraph depth", "depth"),
+	popt::option(operf_options::system_wide, "system-wide", 's',
+	             "profile entire system"),
+	popt::option(operf_options::reset, "reset", 'r',
+	             "clear out old profile data"),
+	popt::option(operf_options::pid, "pid", 'p',
+	             "process ID to profile", "PID"),
+	popt::option(operf_options::mmap_pages_mult, "kernel-buffersize-multiplier", 'k',
+	             "factor by which kernel buffer size should be increased", "buffersize"),
+	popt::option(operf_options::evts, "events", 'e',
+	             "comma-separated list of event specifications for profiling. Event spec form is:\n"
+	             "name:count[:unitmask[:kernel[:user]]]",
+	             "events"),
+	popt::option(operf_options::separate_cpu, "separate-cpu", 'c',
+	             "Categorize samples by cpu"),
+};
+}
+
+
+static void op_sig_stop(int val __attribute__((unused)))
+{
+	// Received a signal to quit, so we need to stop the
+	// app being profiled.
+	if (cverb << vdebug)
+		write(1, "in op_sig_stop ", 15);
+	kill(app_PID, SIGKILL);
+}
+
+void set_signals(void)
+{
+	struct sigaction act;
+	sigset_t ss;
+
+	sigfillset(&ss);
+	sigprocmask(SIG_UNBLOCK, &ss, NULL);
+
+	act.sa_handler = op_sig_stop;
+	act.sa_flags = 0;
+	sigemptyset(&act.sa_mask);
+	sigaddset(&act.sa_mask, SIGINT);
+
+	if (sigaction(SIGINT, &act, NULL)) {
+		perror("operf: install of SIGINT handler failed: ");
+		exit(EXIT_FAILURE);
+	}
+}
+
+static int app_ready_pipe[2], start_app_pipe[2], app_started_pipe[2], valid_profile_pipe[2];
+
+void run_app(void)
+{
+	char * app_fname = rindex(app_name, '/') + 1;
+	if (!app_fname) {
+		cerr << "Error trying to parse app name " <<  app_name << endl;
+		cerr << "usage: operf [options] --pid=<PID> | appname [args]" << endl;
+		exit(EXIT_FAILURE);
+	}
+
+	vector<string> exec_args_str;
+	if (app_args) {
+		size_t end_pos;
+		string app_args_str = app_args;
+		// Since the strings returned from substr would otherwise be ephemeral, we
+		// need to store them into the exec_args_str vector so we can reference
+		// them later when we call execvp.
+		do {
+			end_pos = app_args_str.find_first_of(' ', 0);
+			if (end_pos != string::npos) {
+				exec_args_str.push_back(app_args_str.substr(0, end_pos));
+				app_args_str = app_args_str.substr(end_pos + 1);
+			} else {
+				exec_args_str.push_back(app_args_str);
+			}
+		} while (end_pos != string::npos);
+	}
+
+	vector<const char *> exec_args;
+	exec_args.push_back(app_fname);
+	vector<string>::iterator it;
+	cverb << vdebug << "Exec args are: " << app_fname << " ";
+	// Now transfer the args from the intermediate exec_args_str container to the
+	// exec_args container that can be passed to execvp.
+	for (it = exec_args_str.begin(); it != exec_args_str.end(); it++) {
+		exec_args.push_back((*it).c_str());
+		cverb << vdebug << (*it).c_str() << " ";
+	}
+	exec_args.push_back((char *) NULL);
+	cverb << vdebug << endl;
+	// Fake an exec to warm-up the resolver
+	execvp("", ((char * const *)&exec_args[0]));
+	// signal to the parent that we're ready to exec
+	int startup = 1;
+	if (write(app_ready_pipe[1], &startup, sizeof(startup)) < 0) {
+		perror("Internal error on start_app_pipe");
+		_exit(EXIT_FAILURE);
+	}
+
+	// wait for parent to tell us to start
+	int startme = 0;
+	if (read(start_app_pipe[0], &startme, sizeof(startme)) == -1) {
+		perror("Internal error in run_app on start_app_pipe");
+		_exit(EXIT_FAILURE);
+	}
+	if (startme != 1)
+		goto fail;
+
+	cverb << vdebug << "parent says start app " << app_name << endl;
+	//sleep(1);
+	execvp(app_name, ((char * const *)&exec_args[0]));
+	cerr <<  "Failed to exec " << exec_args[0] << ": " << strerror(errno) << endl;
+	fail:
+	/* We don't want any cleanup in the child */
+	_exit(EXIT_FAILURE);
+
+}
+
+int start_profiling_app(void)
+{
+	// The only process that should return from this function is the process
+	// which invoked it.  Any forked process must do _exit() rather than return().
+
+	if (pipe(app_ready_pipe) < 0 || pipe(start_app_pipe) < 0) {
+		perror("Internal error: operf-record could not create pipe");
+		_exit(EXIT_FAILURE);
+	}
+	app_PID = fork();
+	if (app_PID < 0) {
+		perror("Internal error: fork failed");
+		_exit(EXIT_FAILURE);
+	} else if (app_PID == 0) { // child process for exec'ing app
+		run_app();
+	} else {  //parent
+		if (pipe(app_started_pipe) < 0) {
+			perror("Internal error: could not create pipe");
+			return -1;
+		}
+		if (pipe(valid_profile_pipe) < 0) {
+			perror("Internal error: could not create pipe");
+			return -1;
+		}
+		operf_pid = fork();
+		if (operf_pid < 0) {
+			return -1;
+		} else if (operf_pid == 0) { // operf-record process
+			pid_t appID = 0;
+			if (read(app_started_pipe[0], &appID, sizeof(appID)) == -1) {
+				perror("Internal error in _run: app_started_pipe");
+				return -1;
+			} else if (app_PID == 0) {
+		                cerr << "Failed to start app. Exiting." << endl;
+		                _exit(EXIT_FAILURE);
+		        }
+
+			// setup operf recording
+			// Placeholder for setting up and running perf_events profiling
+			// done
+			_exit(EXIT_SUCCESS);
+		} else {  // parent
+			int startup;
+			if (read(app_ready_pipe[0], &startup, sizeof(startup)) == -1) {
+				perror("Internal error on app_ready_pipe");
+				return -1;
+			} else if (startup != 1) {
+				cerr << "app is not ready to start; exiting" << endl;
+				return -1;
+			}
+			app_started = true;
+			// Tell app_PID to start the app
+			cverb << vdebug << "operf-record telling child to start app" << endl;
+			if (write(start_app_pipe[1], &startup, sizeof(startup)) < 0) {
+				perror("Internal error on start_app_pipe");
+				return -1;
+			}
+
+			// Let operf-record process know the app PID
+			cverb << vdebug << "writing " << app_PID << " app pid to pipe" << endl;
+			if (write(app_started_pipe[1], &app_PID, sizeof(app_PID)) < 0) {
+				perror("Internal error on app_started_pipe");
+				return -1;
+			}
+		}
+	}
+	// parent returns
+	return 0;
+}
+
+static end_code_t _run(void)
+{
+	int waitpid_status = 0;
+	end_code_t rc = ALL_OK;
+
+	// Fork processes with signals blocked.
+	sigset_t ss;
+	sigfillset(&ss);
+	sigprocmask(SIG_BLOCK, &ss, NULL);
+
+	if (start_profiling_app() < 0) {
+		perror("Internal error: fork failed");
+		return PERF_RECORD_ERROR;
+	}
+	// parent continues here
+	cverb << vdebug << "app " << app_PID << " is started" << endl;
+	set_signals();
+	cverb << vdebug << "going into waitpid on profiled app " << app_PID << endl;
+	if (waitpid(app_PID, &waitpid_status, 0) < 0) {
+		if (errno == EINTR) {
+			cverb << vdebug << "Caught ctrl-C.  Killed profiled app." << endl;
+		} else {
+			cerr << "waitpid errno is " << errno << endl;
+			perror("waitpid for profiled app failed");
+			rc = APP_ABNORMAL_END;
+		}
+	} else {
+		if (WIFEXITED(waitpid_status) && (!WEXITSTATUS(waitpid_status))) {
+			cverb << vdebug << "waitpid for profiled app returned OK" << endl;
+		} else if (WIFEXITED(waitpid_status)) {
+			cerr <<  "profiled app ended abnormally: "
+			     << WEXITSTATUS(waitpid_status) << endl;
+			rc = APP_ABNORMAL_END;
+		}
+	}
+
+	// stop operf-record process
+	if (kill(operf_pid, SIGUSR1) < 0) {
+		perror("Attempt to stop operf-record process failed");
+		rc = PERF_RECORD_ERROR;
+	} else {
+		if (waitpid(operf_pid, &waitpid_status, 0) < 0) {
+			perror("waitpid for operf-record process failed");
+			rc = PERF_RECORD_ERROR;
+		} else {
+			if (WIFEXITED(waitpid_status) && (!WEXITSTATUS(waitpid_status))) {
+				cverb << vdebug << "waitpid for operf-record process returned OK" << endl;
+			} else {
+				cerr <<  "operf-record process ended abnormally: "
+				     << WEXITSTATUS(waitpid_status) << endl;
+				rc = PERF_RECORD_ERROR;
+			}
+		}
+	}
+	return rc;
+}
+
+static void cleanup(void)
+{
+	string cmd = "rm -f " + outputfile;
+	free(app_name_SAVE);
+	free(app_args);
+	events.clear();
+	verbose_string.clear();
+	system(cmd.c_str());
+}
+
+static int __delete_sample_data(const char *fpath,
+                                const struct stat *sb  __attribute__((unused)),
+                                int tflag  __attribute__((unused)),
+                                struct FTW *ftwbuf __attribute__((unused)))
+{
+	if (remove(fpath)) {
+		perror("sample data removal error");
+		return FTW_STOP;
+	} else {
+		return FTW_CONTINUE;
+	}
+}
+
+static void complete(void)
+{
+	int rc;
+	string current_sampledir = samples_dir + "/current/";
+	current_sampledir.copy(op_samples_current_dir, current_sampledir.length(), 0);
+
+	if (!app_started) {
+		cleanup();
+		return;
+	}
+	if (operf_options::reset) {
+		int flags = FTW_DEPTH | FTW_ACTIONRETVAL;
+
+		if (nftw(current_sampledir.c_str(), __delete_sample_data, 32, flags) < 0 &&
+				errno != ENOENT) {
+			perror("nftw");
+			cleanup();
+			exit(1);
+		}
+	}
+	rc = mkdir(current_sampledir.c_str(), S_IRWXU);
+	if (rc && (errno != EEXIST)) {
+		cerr << "Error trying to create " << current_sampledir << " dir." << endl;
+		perror("mkdir failed with");
+		exit(EXIT_FAILURE);
+	}
+
+	/* Placeholder for reading perf_events-formatted profile data and
+	 * converting it to oprofile-formatted data.
+	 */
+	cleanup();
+}
+
+static int _get_sys_value(const char * filename)
+{
+	char str[10];
+	int _val = -999;
+	FILE * fp = fopen(filename, "r");
+	if (fp == NULL)
+		return _val;
+	if (!fgets(str, 9, fp))
+		return _val;
+	sscanf(str, "%d", &_val);
+	return _val;
+}
+
+static void handle_sys_values(void)
+{
+	int value;
+	// TODO: Iniital iterations of the perf tool required perf_event_paranoid to be -1
+	// in order for it to work with non-root users; however, this is not the case with
+	// recent distros (e.g., RHEL 6.2).  Need to figure out how perf can work with a
+	// paranoid setting of '1' so that we don't have this restriction with operf.
+	value = _get_sys_value("/proc/sys/kernel/perf_event_paranoid");
+	if (value != -1) {
+		if (value == -999) {
+			cerr << "--------------------------------------------------------------------------" << endl;
+			cerr << "WARNING: operf requires the /proc/sys/kernel/perf_event_paranoid system value" << endl
+			     << "         to be set to '-1', but we were unable to verify the setting." << endl;
+			if (errno)
+				cerr << "The following error message was received when trying to access this system value:" << endl
+				<< strerror(errno) << endl;
+			cerr << endl
+			     << "If you receive the following message:" << endl << endl
+			     << "\t\"failed to mmap: Operation not permitted\"" << endl << endl
+			     << "please ask your system administrator to change this value to '-1'." << endl;
+			cerr << "--------------------------------------------------------------------------" << endl;
+		} else {
+			cerr  << "ERROR: operf requires the /proc/sys/kernel/perf_event_paranoid system value" << endl
+			      << "       to be set to '-1', but the detected value is '" << value << "'." << endl
+			      << "       Please ask your system administrator to change this value to '-1'." << endl;
+			exit(EXIT_FAILURE);
+		}
+	}
+}
+
+static int find_app_file_in_dir(const struct dirent * d)
+{
+	if (!strcmp(d->d_name, app_name))
+		return 1;
+	else
+		return 0;
+}
+
+static int get_PATH_based_pathname(char * path_holder, size_t n)
+{
+	int retval = -1;
+
+	char * real_path = getenv("PATH");
+	char * path = (char *) xstrdup(real_path);
+	char * segment = strtok(path, ":");
+	while (segment) {
+		struct dirent ** namelist;
+		int rc = scandir(segment, &namelist, find_app_file_in_dir, NULL);
+		if (rc < 0) {
+			cerr << app_name << " cannot be found in your PATH." << endl;
+			break;
+		} else if (rc == 1) {
+			size_t applen = strlen(app_name);
+			size_t dirlen = strlen(segment);
+
+			if (applen + dirlen + 2 > n) {
+				cerr << "Path segment " << segment
+				     << " prepended to the passed app name is too long"
+				     << endl;
+				retval = -1;
+				break;
+			}
+			strncpy(path_holder, segment, dirlen);
+			strcat(path_holder, "/");
+			strncat(path_holder, app_name, applen);
+			retval = 0;
+			break;
+		}
+		segment = strtok(NULL, ":");
+	}
+	return retval;
+}
+int validate_app_name(void)
+{
+	int rc = 0;
+	struct stat filestat;
+	size_t len = strlen(app_name);
+
+	if (len > (size_t) (OP_APPNAME_LEN - 1)) {
+		cerr << "app name longer than max allowed (" << OP_APPNAME_LEN
+		     << " chars)\n";
+		cerr << app_name << endl;
+		rc = -1;
+		goto out;
+	}
+
+	if (index(app_name, '/')) {
+		strncpy(full_pathname, app_name, len);
+	} else {
+		rc = get_PATH_based_pathname(full_pathname, PATH_MAX);
+	}
+
+	if (rc) {
+		cerr << "Problem finding app name " << app_name << ". Aborting."
+		     << endl;
+		goto out;
+	}
+	app_name_SAVE = app_name;
+	app_name = full_pathname;
+	if (stat(app_name, &filestat)) {
+		char msg[OP_APPNAME_LEN + 50];
+		snprintf(msg, OP_APPNAME_LEN + 50, "Non-existent app name \"%s\"",
+		         app_name);
+		perror(msg);
+		rc = -1;
+	}
+
+	out: return rc;
+}
+
+static void __print_usage_and_exit(char * extra_msg)
+{
+	if (extra_msg)
+		cerr << extra_msg << endl;
+	cerr << "usage: operf [options] --pid=<PID> | appname [args]" << endl;
+	exit(EXIT_FAILURE);
+
+}
+
+static u32 _get_event_code(char name[])
+{
+	FILE * fp;
+	char oprof_event_code[9];
+	string command;
+	command = "ophelp ";
+	command += name;
+
+	fp = popen(command.c_str(), "r");
+	if (fp == NULL) {
+		cerr << "Unable to execute ophelp to get info for event "
+		     << name << endl;
+		exit(EXIT_FAILURE);
+	}
+	if (fgets(oprof_event_code, sizeof(oprof_event_code), fp) == NULL) {
+		cerr << "Unable to find info for event "
+		     << name << endl;
+		exit(EXIT_FAILURE);
+	}
+
+	return atoi(oprof_event_code);
+}
+
+static void _process_events_list(void)
+{
+	string cmd = "ophelp --check-events ";
+	for (unsigned int i = 0; i <  operf_options::evts.size(); i++) {
+		FILE * fp;
+		string full_cmd = cmd;
+		string event_spec = operf_options::evts[i];
+		full_cmd += event_spec;
+		fp = popen(full_cmd.c_str(), "r");
+		if (fp == NULL) {
+			cerr << "Unable to execute ophelp to get info for event "
+			     << event_spec << endl;
+			exit(EXIT_FAILURE);
+		}
+		if (fgetc(fp) == EOF) {
+			cerr << "Unable to find info for event "
+			     << event_spec << endl;
+			exit(EXIT_FAILURE);
+		}
+		char * event_str = op_xstrndup(event_spec.c_str(), event_spec.length());
+		operf_event_t event;
+		strncpy(event.name, strtok(event_str, ":"), OP_MAX_EVT_NAME_LEN);
+		event.count = atoi(strtok(NULL, ":"));
+		/* Name and count are required in the event spec in order for
+		 * 'ophelp --check-events' to pass.  But since unit mask is
+		 * optional, we need to ensure the result of strtok is valid.
+		 */
+		char * um = strtok(NULL, ":");
+		if (um)
+			event.evt_um = atoi(um);
+		else
+			event.evt_um = 0;
+		event.op_evt_code = _get_event_code(event.name);
+		event.evt_code = event.op_evt_code;
+		events.push_back(event);
+	}
+#if (defined(__powerpc__) || defined(__powerpc64__))
+	{
+	  /* This is a placeholder for architectures such as ppc[64] where we'll
+	   * need to convert the oprofile event code to the appropriate event
+	   * code to pass to the perf_event_open syscall.
+	   */
+	}
+#endif
+}
+
+static void get_default_event(void)
+{
+	operf_event_t dft_evt;
+	struct op_default_event_descr descr;
+	vector<operf_event_t> tmp_events;
+
+	op_default_event(cpu_type, &descr);
+	if (descr.name[0] == '\0') {
+		cerr << "Unable to find default event" << endl;
+		exit(EXIT_FAILURE);
+	}
+
+	memset(&dft_evt, 0, sizeof(dft_evt));
+	dft_evt.count = descr.count;
+	dft_evt.evt_um = descr.um;
+	strncpy(dft_evt.name, descr.name, OP_MAX_EVT_NAME_LEN - 1);
+	dft_evt.op_evt_code = _get_event_code(dft_evt.name);
+	dft_evt.evt_code = dft_evt.op_evt_code;
+	events.push_back(dft_evt);
+
+#if (defined(__powerpc__) || defined(__powerpc64__))
+	{
+          /* This is a placeholder for architectures such as ppc[64] where we'll
+           * need to convert the oprofile event code to the appropriate event
+           * code to pass to the perf_event_open syscall.
+           */
+	}
+#endif
+}
+
+static void _process_session_dir(void)
+{
+	if (operf_options::session_dir.empty()) {
+		char * cwd = NULL;
+		int rc;
+		cwd = (char *) xmalloc(PATH_MAX);
+		// set default session dir
+		cwd = getcwd(cwd, PATH_MAX);
+		operf_options::session_dir = cwd;
+		operf_options::session_dir +="/oprofile_data";
+		samples_dir = operf_options::session_dir + "/samples";
+		free(cwd);
+		rc = mkdir(operf_options::session_dir.c_str(), S_IRWXU);
+		if (rc && (errno != EEXIST)) {
+			cerr << "Error trying to create " << operf_options::session_dir << " dir." << endl;
+			perror("mkdir failed with");
+			exit(EXIT_FAILURE);
+		}
+		rc = mkdir(samples_dir.c_str(), S_IRWXU);
+		if (rc && (errno != EEXIST)) {
+			cerr << "Error trying to create " << samples_dir << " dir." << endl;
+			perror("mkdir failed with");
+			exit(EXIT_FAILURE);
+		}
+	} else {
+		struct stat filestat;
+		int rc;
+		if (stat(operf_options::session_dir.c_str(), &filestat)) {
+			perror("stat operation on passed session-dir failed");
+			exit(EXIT_FAILURE);
+		}
+		if (!S_ISDIR(filestat.st_mode)) {
+			cerr << "Passed session-dir " << operf_options::session_dir
+			     << " is not a directory" << endl;
+			exit(EXIT_FAILURE);
+		}
+		string tmp = operf_options::session_dir + "/oprofile_data";
+		rc = mkdir(tmp.c_str(), S_IRWXU);
+		if (rc && (errno != EEXIST)) {
+			cerr << "Error trying to create " << tmp << " dir." << endl;
+			perror("mkdir failed with");
+			exit(EXIT_FAILURE);
+		}
+		samples_dir = tmp + "/samples";
+		rc = mkdir(samples_dir.c_str(), S_IRWXU);
+		if (rc && (errno != EEXIST)) {
+			cerr << "Error trying to create " << samples_dir << " dir." << endl;
+			perror("mkdir failed with");
+			exit(EXIT_FAILURE);
+		}
+	}
+	cverb << vdebug << "Using samples dir " << samples_dir << endl;
+}
+
+static void process_args(int argc, char const ** argv)
+{
+	vector<string> non_options;
+	popt::parse_options(argc, argv, non_options, true/*non-options IS an app*/);
+
+	if (operf_options::callgraph_depth) {
+		cerr << "The --callgraph option is not yet supported." << endl;
+		exit(EXIT_FAILURE);
+	}
+
+	if (!non_options.empty()) {
+		if (operf_options::pid)
+			__print_usage_and_exit(NULL);
+
+		vector<string>::iterator it = non_options.begin();
+		app_name = (char *) xmalloc((*it).length() + 1);
+		strncpy(app_name, ((char *)(*it).c_str()), (*it).length() + 1);
+		if (it++ != non_options.end()) {
+			if ((*it).length() > 0) {
+				app_args = (char *) xmalloc((*it).length() + 1);
+				strncpy(app_args, ((char *)(*it).c_str()), (*it).length() + 1);
+			}
+		}
+		if (validate_app_name() < 0) {
+			exit(1);
+		}
+	} else if (operf_options::pid) {
+		if (operf_options::system_wide)
+			__print_usage_and_exit(NULL);
+		cerr << "The --pid option is not yet supported." << endl;
+		exit(EXIT_FAILURE);
+	} else if (operf_options::system_wide) {
+		cerr << "The --system-wide option is not yet supported." << endl;
+		exit(EXIT_FAILURE);
+	}
+	else {
+		__print_usage_and_exit(NULL);
+	}
+	/*  At this point, we know what kind of profile the user requested:
+	 *    - profile app by name
+	 *    - profile app by PID
+	 *    - profile whole system
+	 */
+
+	if (!verbose::setup(verbose_string)) {
+		cerr << "unknown --verbose= options\n";
+		exit(EXIT_FAILURE);
+	}
+
+	_process_session_dir();
+	outputfile = samples_dir + "/" + DEFAULT_OPERF_OUTFILE;
+
+	// TODO: Need to examine ocontrol to see what (if any) additional
+	// event verification is needed here.
+	if (operf_options::evts.empty()) {
+		// Use default event
+		get_default_event();
+	} else  {
+		_process_events_list();
+	}
+
+	return;
+}
+
+static int _check_perf_events_cap(void)
+{
+	/* If perf_events syscall is not implemented, the syscall below will fail
+	 * with ENOSYS (38).  If implemented, but the processor type on which this
+	 * program is running is not supported by perf_events, the syscall returns
+	 * ENOENT (2).
+	 */
+	struct perf_event_attr attr;
+	pid_t pid ;
+        memset(&attr, 0, sizeof(attr));
+        attr.size = sizeof(attr);
+        attr.sample_type = PERF_SAMPLE_IP;
+
+	pid = getpid();
+	syscall(__NR_perf_event_open, &attr, pid, 0, -1, 0);
+	return errno;
+
+}
+
+bool no_vmlinux;
+int main(int argc, char const *argv[])
+{
+	int rc;
+	// TODO:  For now, set no_vmlinux to true.  Need to implement vmlinux handling (with /proc/kallsyms?).
+	no_vmlinux = true;
+	if ((rc = _check_perf_events_cap())) {
+		if (rc == ENOSYS) {
+			cerr << "Your kernel does not implement a required syscall"
+			     << "  for the operf program." << endl;
+		} else if (rc == ENOENT) {
+			cerr << "Your kernel's Performance Events Subsystem does not support"
+			     << " your processor type." << endl;
+		} else if (rc == EACCES) {
+			handle_sys_values();
+			cerr << "Unexpected error running operf: " << strerror(rc) << endl;
+		}
+		cerr << "Please use the opcontrol command instead of operf." << endl;
+		exit(1);
+	}
+
+	cpu_type = op_get_cpu_type();
+	cpu_speed = op_cpu_frequency();
+	process_args(argc, argv);
+
+	if (cpu_type == CPU_NO_GOOD) {
+		cerr << "Unable to ascertain cpu type.  Exiting." << endl;
+		exit(1);
+	}
+	op_nr_counters = op_get_nr_counters(cpu_type);
+
+	uid_t uid = geteuid();
+	if (uid != 0)
+		handle_sys_values();
+
+	end_code_t run_result;
+	if ((run_result = _run())) {
+		if (app_started && (run_result != APP_ABNORMAL_END)) {
+			int rc;
+			cverb << vdebug << "Killing profiled app . . ." << endl;
+			rc = kill(app_PID, SIGKILL);
+			if (rc)
+				perror("Attempt to kill profiled app failed.");
+		}
+		if (run_result == PERF_RECORD_ERROR) {
+			cerr <<  "Error running profiler" << endl;
+			exit(1);
+		} else {
+			cerr << "WARNING: Profile results may be incomplete due to to abend of profiled app." << endl;
+		}
+	}
+	complete();
+	return 0;
+}
Index: oprof-PE-patchset/pe_profiling/operf.h
===================================================================
--- /dev/null
+++ oprof-PE-patchset/pe_profiling/operf.h
@@ -0,0 +1,42 @@
+/**
+ * @file operf.h
+ * Header file containing definitions for handling a user request to profile
+ * using the new Linux Performance Events Subsystem.
+ *
+ * @remark Copyright 2011 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * Created on: Dec 7, 2011
+ * @author Maynard Johnson
+ * (C) Copyright IBM Corp. 2011
+ *
+ */
+
+#ifndef OPERF_H_
+#define OPERF_H_
+
+#include <linux/perf_event.h>
+#include <vector>
+#include "config.h"
+#include "op_config.h"
+#include "op_types.h"
+#include "operf_event.h"
+
+using namespace std;
+namespace operf_options {
+extern bool system_wide;
+extern bool reset;
+extern int pid;
+extern int callgraph_depth;
+extern int mmap_pages_mult;
+extern string session_dir;
+extern bool separate_cpu;
+}
+
+extern bool no_vmlinux;
+
+#define OP_APPNAME_LEN 1024
+
+extern unsigned int op_nr_counters;
+
+#endif // OPERF_H_
Index: oprof-PE-patchset/pp/common_option.cpp
===================================================================
--- oprof-PE-patchset.orig/pp/common_option.cpp
+++ oprof-PE-patchset/pp/common_option.cpp
@@ -167,7 +167,7 @@ fail:
 options::spec get_options(int argc, char const * argv[])
 {
 	vector<string> non_options;
-	popt::parse_options(argc, argv, non_options);
+	popt::parse_options(argc, argv, non_options, false /*non_option is NOT an app*/);
 
 	// initialize paths in op_config.h
 	init_op_config_dirs(options::session_dir.c_str());
Index: oprof-PE-patchset/utils/Makefile.am
===================================================================
--- oprof-PE-patchset.orig/utils/Makefile.am
+++ oprof-PE-patchset/utils/Makefile.am
@@ -3,8 +3,10 @@ AM_CFLAGS = @OP_CFLAGS@
 
 LIBS=@POPT_LIBS@ @LIBERTY_LIBS@
 
-bin_PROGRAMS = ophelp
+bin_PROGRAMS = ophelp op-check-perfevents
 dist_bin_SCRIPTS = opcontrol
 
+op_check_perfevents_SOURCES = op_perf_events_checker.c
+
 ophelp_SOURCES = ophelp.c
 ophelp_LDADD = ../libop/libop.a ../libutil/libutil.a
Index: oprof-PE-patchset/utils/op_perf_events_checker.c
===================================================================
--- /dev/null
+++ oprof-PE-patchset/utils/op_perf_events_checker.c
@@ -0,0 +1,70 @@
+/*
+ * @file op-perf-events-checker.c
+ *
+ * Utility program for determining the existence and functionality
+ * of the Linux kernel's Performance Events Subsystem.
+ *
+ * @remark Copyright 2011 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * Created on: Dec 7, 2011
+ * @author Maynard Johnson
+ * (C) Copyright IBM Corp. 2011
+ *
+ */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <asm/unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include "config.h"
+#if HAVE_PERF_EVENTS
+#include <linux/perf_event.h>
+	struct perf_event_attr attr;
+	pid_t pid ;
+#endif
+
+static void usage(void)
+{
+	fprintf(stderr, "usage: op-check-perfevents [OPTION]\n");
+	fprintf(stderr, "\t-h, --help\t\tPrint this help message\n");
+	fprintf(stderr, "\t-v, --verbose\t\tPrint errno value of perf_event_open syscall\n");
+}
+
+int main(int argc, char **argv)
+{
+	int _verbose = 0;
+	if (argc > 1) {
+		if ((!strcmp(argv[1], "-h")) || (!strcmp(argv[1], "--help"))) {
+			usage();
+			return 0;
+		} else if ((!strcmp(argv[1], "-v")) || (!strcmp(argv[1], "--verbose"))) {
+			_verbose = 1;
+		} else {
+			usage();
+			return -1;
+		}
+	}
+
+#if HAVE_PERF_EVENTS
+	/* If perf_events syscall is not implemented, the syscall below will fail
+	 * with ENOSYS (38).  If implemented, but the processor type on which this
+	 * program is running is not supported by perf_events, the syscall returns
+	 * ENOENT (2).
+	 */
+        memset(&attr, 0, sizeof(attr));
+        attr.size = sizeof(attr);
+        attr.sample_type = PERF_SAMPLE_IP;
+
+	pid = getpid();
+	syscall(__NR_perf_event_open, &attr, pid, 0, -1, 0);
+	if (_verbose)
+		fprintf(stderr, "perf_event_open syscall returned %s\n", strerror(errno));
+	return errno;
+#else
+	return -1;
+#endif
+}
+
Index: oprof-PE-patchset/utils/opcontrol
===================================================================
--- oprof-PE-patchset.orig/utils/opcontrol
+++ oprof-PE-patchset/utils/opcontrol
@@ -1616,6 +1616,11 @@ do_param_setup()
 do_start_daemon()
 {
 
+	$OPDIR/op-check-perfevents
+	if [ "$?" = "0" ]; then
+		echo "ATTENTION: Use of opcontrol is discouraged.  Please see the man page for operf."
+	fi
+
 	if test -f "$LOCK_FILE"; then
 		kill -0 `cat $LOCK_FILE` 2>/dev/null
 		if test "$?" -eq 0; then
Index: oprof-PE-patchset/pe_profiling/operf_event.h
===================================================================
--- /dev/null
+++ oprof-PE-patchset/pe_profiling/operf_event.h
@@ -0,0 +1,44 @@
+/*
+ * @file pe_profiling/operf_event.h
+ * Definitions of structures and methods for handling perf_event data
+ * from the kernel.
+ *
+ * @remark Copyright 2011 OProfile authors
+ * @remark Read the file COPYING
+ *
+ * Created on: Dec 7, 2011
+ * @author Maynard Johnson
+ * (C) Copyright IBM Corp. 2011
+ */
+
+#ifndef OPERF_EVENT_H_
+#define OPERF_EVENT_H_
+
+#include <limits.h>
+#include <linux/perf_event.h>
+#include <vector>
+#include "op_types.h"
+
+
+using namespace std;
+
+#define OP_MAX_EVT_NAME_LEN 64
+#define OP_MAX_NUM_EVENTS 512
+
+
+typedef struct operf_event {
+	char name[OP_MAX_EVT_NAME_LEN];
+	// code for perf_events
+	u32 evt_code;
+	// code for oprofile sample file management; usually the same as evt_code, but
+	// different for certain architectures (e.g., ppc64)
+	u32 op_evt_code;
+	// Make the evt_um and count fields unsigned long to match op_default_event_descr
+	unsigned long evt_um;
+	unsigned long count;
+	u32 counter;
+	bool no_kernel;
+	bool no_hv;
+} operf_event_t;
+
+#endif /* OPERF_EVENT_H_ */